pytorch|pytorch_lesson2 张量的索引+torch.index_select+torch.view+张量的分片函数+张量的合并操作+张量的维度变换
文章目录
- 前言
- 一、张量的符号索引
-
- 1、一维张量索引
- 2、二维张量索引
- 3、三维张量索引
- 二、张量的函数索引torch.index_select()方法
- 三、tensor.view()方法
- 四、张量的分片函数
-
- 1、分块:chunk函数
- 2、拆分:split函数
- 四、张量的合并操作
-
- 1、cat
- 2、stack堆叠
- 六、张量维度变换
-
- 1、squeeze函数:删除不必要的维度
- 2、unsqueeze函数:手动升维
前言 张量作为有序的序列,也是具备数值索引的功能,并且基本索引方法和Python原生的列表、NumPy中的数组基本一致,当然,所有不同的是,PyTorch中还定义了一种采用函数来进行索引的方式。而作为PyTorch中基本数据类型,张量即具备了列表、数组的基本功能,同时还充当着向量、矩阵、甚至是数据框等重要数据结构,因此PyTorch中也设置了非常完备的张量合并与变换的操作。
一、张量的符号索引 1、一维张量索引
import torch
t1 = torch.arange(1, 11)
print(t1)
#tensor([ 1,2,3,4,5,6,7,8,9, 10])#从左到右,从零开始
print(t1[0])
#tensor(1)#冒号分割,表示对某个区域进行索引,也是切片
print(t1[1: 8])
#tensor([2, 3, 4, 5, 6, 7, 8])
#第二个冒号,表示索引的间隔
print(t1[1: 8: 2]) #索引其中第2-9个元素,左闭右开,每隔2个取一个值
#tensor([2, 4, 6, 8])
注:在张量的索引中,step位必须大于0
2、二维张量索引
t2 = torch.arange(1, 10).reshape(3, 3)
print(t2)
'''
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
'''print(t2[0, 1])
#提取第一行,第二列的数值
#tensor(2)print(t2[0, ::2])#在第一行中每隔一个数取一个值
#tensor([1, 3])print(t2[0, [0, 2]])#提取第一行中第一列和第三列的数值
#tensor([1, 3])print(t2[::2, ::2]) #每隔1行取一行,取出来的数值里面每隔一列取一个数值
'''
tensor([[1, 3],
[7, 9]])
'''print(t2[[0, 2], 1])
#提取第2列里面,第一行、第三行的数值
#tensor([2, 8])
3、三维张量索引 torch.index_select(张量,维度, 索引值)
这里注意喔,索引值必须是一个tensor值
t3 = torch.arange(1, 28).reshape(3, 3, 3)
print(t3)
'''
tensor([[[ 1,2,3],
[ 4,5,6],
[ 7,8,9]],[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])
'''print(t3.shape)
#torch.Size([3, 3, 3])print(t3[1, 1, 1]) #提取第二堆里第二行,第三列的数值
#tensor(14)print(t3[1, ::2, ::2])#提取第二堆里面数值,每隔一行取一行,每隔一列取一个值
'''
tensor([[10, 12],
[16, 18]])
'''print(t3[::2, ::2, ::2])#每隔一堆取一堆,取出来的堆里面每隔一行取一行,在这些数值里面每隔一列取一个值
'''
tensor([[[ 1,3],
[ 7,9]],[[19, 21],
[25, 27]]])
'''print(t3.shape)
#torch.Size([3, 3, 3])
二、张量的函数索引torch.index_select()方法
print(t1)
#tensor([ 1,2,3,4,5,6,7,8,9, 10])
print(t1.ndim)
#1
indices = torch.tensor([1, 2])#设置了一个索引标,索引是一维数组,由两个数值组成
print(indices)
#tensor([1, 2])
print(t1[1: 3])
#tensor([2, 3])
print(t1[[1, 2]])
#tensor([2, 3])
print(torch.index_select(t1, 0, indices))
#torch.index_select 里面第一个参数是张量,第二个参数是维度即从第几个维度上提取数据,indices是我们的索引号
#tensor([2, 3])t2 = torch.arange(12).reshape(4, 3)
print(t2)
'''
tensor([[ 0,1,2],
[ 3,4,5],
[ 6,7,8],
[ 9, 10, 11]])
'''
print(t2.shape)
#torch.Size([4, 3])
print(torch.index_select(t2, 0, indices))#维度是从外到里依次排列的,在第一个维度上取索引值为1和2的数值,即取第二行和第三行的数值
'''
tensor([[3, 4, 5],
[6, 7, 8]])
'''print(torch.index_select(t2, 1, indices))
#在第二个维度上取索引值为1和2的数值,即取第二、三列值
'''
tensor([[ 1,2],
[ 4,5],
[ 7,8],
[10, 11]])
'''
三、tensor.view()方法 “视图”的作用就是节省空间,而值得注意的是,在接下来介绍的很多切分张量的方法中,返回结果都是“视图”,而不是新生成一个对象。
t = torch.arange(6).reshape(2, 3)
print(t)
'''
tensor([[0, 1, 2],
[3, 4, 5]])
'''te = t.view(3, 2)
#其作用类似于reshape
print(te)
'''
tensor([[0, 1],
[2, 3],
[4, 5]])
'''#view是浅拷贝的,改变te中的某个值,原tensor值也会发生变化
print(te[0][0])
#tensor(0)te[0][0] = 1
print(te)
'''
tensor([[1, 1],
[2, 3],
[4, 5]])
'''
print(t)
'''
tensor([[1, 1, 2],
[3, 4, 5]])
'''tr = t.view(1, 2, 3)
print(tr)
'''
tensor([[[1, 1, 2],
[3, 4, 5]]])
'''
四、张量的分片函数 1、分块:chunk函数 chunk函数能够按照某维度,对张量进行均匀切分,并且返回结果是原张量的视图。
#chunk介绍
t2 = torch.arange(12).reshape(4, 3)
print(t2)
'''
tensor([[ 0,1,2],
[ 3,4,5],
[ 6,7,8],
[ 9, 10, 11]])
'''te = torch.chunk(t2, 4, dim=0)#在第一维度上分为四块,即将每一行的数值进行拆分
print(te)
'''
(tensor([[0, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]]))
'''#注意:chunk返回的结果是一个视图,不是新生成了一个对象,可以验证一下
print(te[0][0][0])
#tensor(0)te[0][0][0] = 1
print(te)
'''
(tensor([[1, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]]))
'''
print(t2)
'''
tensor([[ 1,1,2],
[ 3,4,5],
[ 6,7,8],
[ 9, 10, 11]])
'''
当原张量不能均分时,chunk不会报错,但会返回其他均分的结果
t3 = torch.chunk(t2, 3, dim=0)
#对行进行操作,将4行数据分割成3组数据,由于无法均等分为3组,所以会自动分成2组数据
print(t3)
'''
(tensor([[1, 1, 2],
[3, 4, 5]]),
tensor([[ 6,7,8],
[ 9, 10, 11]]))
'''print(len(t3)) #2t4 = torch.chunk(t2, 5,dim=0)
print(t4)
#(tensor([[1, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]]))
2、拆分:split函数 split既能进行均分,也能进行自定义切分。当然,需要注意的是,和chunk函数一样,split返回结果也是view。
t2 = torch.arange(12).reshape(4, 3)
print(t2)
'''
tensor([[ 0,1,2],
[ 3,4,5],
[ 6,7,8],
[ 9, 10, 11]])
'''t = torch.split(t2, 2, 0) #第2个参数同样表示需要拆分成几块,第三个参数代表在第几个维度上进行操作
print(t)
'''
(tensor([[0, 1, 2],
[3, 4, 5]]),
tensor([[ 6,7,8],
[ 9, 10, 11]]))
'''tr = torch.split(t2, [1, 3], 0) #第二个参数是一个序列的时候,表明需要按照序列中的数值进行切分,也就是对行进行操作,按照1行和3行的数量进行查费
print(tr)
'''
(tensor([[0, 1, 2]]),
tensor([[ 3,4,5],
[ 6,7,8],
[ 9, 10, 11]]))
'''
注意,当第二个参数位输入一个序列时,序列的各数值的和必须等于对应维度下形状分量的取值。例如,上述代码中,是按照第一个维度进行切分,而t2总共有4行,因此序列的求和必须等于4,也就是1+3=4,而序列中每个分量的取值,则代表切块大小。
te = torch.split(t2, [1, 1, 1, 1], 0)
print(te)
#(tensor([[0, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]]))
#切分为了四个二维数据,每个二维数据都是由4个数组成的一维张量构成的tq = torch.split(t2, [1, 2, 1], 0)
print(tq)
'''
(tensor([[0, 1, 2]]),
tensor([[3, 4, 5],
[6, 7, 8]]),
tensor([[ 9, 10, 11]]))
'''tw = torch.split(t2, [1, 2], 1)#对列进行操作,切分成一列和两列二维张量
print(tw)
'''
(tensor([[0],
[3],
[6],
[9]]),
tensor([[ 1,2],
[ 4,5],
[ 7,8],
[10, 11]]))
'''
四、张量的合并操作 张量的合并操作类似与列表的追加元素,可以拼接、也可以堆叠。
1、cat 注意理解,拼接的本质是实现元素的堆积,也就是构成a、b两个二维张量的各一维张量的堆积,最终还是构成二维向量。
a = torch.zeros(2, 3)
print(a)
'''
tensor([[0., 0., 0.],
[0., 0., 0.]])
'''b = torch.ones(2, 3)
print(b)
'''
tensor([[1., 1., 1.],
[1., 1., 1.]])
'''c = torch.zeros(3, 3)
print(c)
'''
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
'''d = torch.cat([a, b]) #对行进行操作,扩展行数,dim默认取值为0,前提条件是列数要一致
print(d)
'''
tensor([[0., 0., 0.],
[0., 0., 0.],
[1., 1., 1.],
[1., 1., 1.]])
'''e = torch.cat([a, b], 1)#对列进行操作,扩展列数,将dim设置为1,前提条件是行数要一致
print(e)
'''
tensor([[0., 0., 0., 1., 1., 1.],
[0., 0., 0., 1., 1., 1.]])
'''
2、stack堆叠 和拼接不同,堆叠不是将元素拆分重装,而是简单的将各参与堆叠的对象分装到一个更高维度的张量里。
print(a)
'''
tensor([[0., 0., 0.],
[0., 0., 0.]])
'''
print(b)
'''
tensor([[1., 1., 1.],
[1., 1., 1.]])
'''
f = torch.stack([a, b])
print(f)
'''
tensor([[[0., 0., 0.],
[0., 0., 0.]],[[1., 1., 1.],
[1., 1., 1.]]])
'''
print(f.shape)
#torch.Size([2, 2, 3])
注意对比二者区别,拼接之后维度不变,堆叠之后维度升高。拼接是把一个个元素单独提取出来之后再放到二维张量中,而堆叠则是直接将两个二维张量封装到一个三维张量中,因此,堆叠的要求更高,参与堆叠的张量必须形状完全相同。
六、张量维度变换 此前我们介绍过,通过reshape方法,能够灵活调整张量的形状。而在实际操作张量进行计算时,往往需要另外进行降维和升维的操作,当我们需要除去不必要的维度时,可以使用squeeze函数,而需要手动升维时,则可采用unsqueeze函数。
1、squeeze函数:删除不必要的维度
#将一维张量转变为二维张量
a2 = a.reshape(1, 4)
print(a2)
#tensor([[0, 1, 2, 3]])#很明显,最外层的维度没什么用,所以我们将这一个维度压缩
a3 = torch.squeeze(a2)
print(a3)
#tensor([0, 1, 2, 3])
print(a3.shape)
#torch.Size([4]) 由4个数组成的一维张量t = torch.zeros(1, 1, 3, 1)
print(t)
'''
tensor([[[[0.],
[0.],
[0.]]]])
'''
print(torch.squeeze(t)) #tensor([0., 0., 0.])
print(torch.squeeze(t).shape) #torch.Size([3])t1 = torch.zeros(1, 1, 3, 2, 1, 2)
print(t1.shape)
#torch.Size([1, 1, 3, 2, 1, 2])
print(torch.squeeze(t1).shape)
#torch.Size([3, 2, 2])
2、unsqueeze函数:手动升维 注意理解维度和shape返回结果一一对应的关系,shape返回的序列有几个元素,张量就有多少维度。
t1 = torch.zeros(1, 1, 3, 2, 1, 2)
print(t1.shape)
#torch.Size([1, 1, 3, 2, 1, 2])
print(torch.squeeze(t1).shape)
#torch.Size([3, 2, 2])t = torch.zeros(1, 2, 1, 2)
print(t.shape)
#torch.Size([1, 2, 1, 2])
t1 = torch.unsqueeze(t, dim=0) #在维度索引值为0的地方增加一个维度
print(t1.shape)
#torch.Size([1, 1, 2, 1, 2])t2 = torch.unsqueeze(t, dim=1) #在维度索引值为1的地方增加一个维度
print(t2.shape)
#torch.Size([1, 1, 2, 1, 2])t3 = torch.unsqueeze(t, dim=4)
print(t3.shape)
#torch.Size([1, 2, 1, 2, 1])
推荐阅读
- 深度学习|【深度学习】Yolov5标签归一化处理——json转换为txt
- sklearn|t-SNE非线性降维
- python|python编写冒泡算法
- Python|Pandas合并数据集
- VUE|Flask+VUE 实现页面增删改查显示开发+测试(图文教程附源码)
- #|Python学习笔记 - Python编程规范
- 计算机视觉|Faster rcnn 训练自己的数据集 解决方案
- python练习题|python基础20道小练习
- 【原创】Selenium获取请求头、响应头