上一篇博客讲述了如何根据自己的实际需要在pytorch中创建tensor,这一篇主要来探讨关于tensor的基本数据变换,是pytorch处理数据的基本方法。
文章目录
- 1 tensor数据查看与提取
- 2 tensor数据变换
- 2.1 重置tensor形状:pytorch.view()
- 2.2 增加/减少tensor维度:torch.unsqueeze()/torch.squeeze()
- 2.3 tensor扩充:torch.expand()/torch.repeat()
- 2.4 tensor维度交换/重新排序:torch.transpose()/torch.permute()
- 3 总结
1 tensor数据查看与提取
tensor数据的查看与提取主要是通过索引和切片实现的。主要方法有:
- 直接索引:
tensor[index]
- 选定数据范围切片:
tensor[s:d]
- 步长切片:
tensor[s:d:step]
- 数据筛选:
torch.masked_select(tensor,mask)
,其中mask是和tensor等shape的Bool类型矩阵,函数将以一维矩阵的形式返回mask中值为1对应位置tensor矩阵的值
################################################
#1、直接索引
a = torch.rand(4,1,16,16)
b = a[0]
print(b.size())
"""
输出结果:
torch.Size([1, 16, 16])
"""
################################################
#2、选定索引的维度范围
c = a[1:3,:,:,:]
print(c.size())
"""
输出结果:
torch.Size([2, 1, 16, 16])
"""
################################################
#3、按步长索引
c = a[0:3:2,:,:,:]
print(c.size())
"""
输出结果:
torch.Size([2, 1, 16, 16])
"""
################################################
#4、按mask筛选索引
d = torch.rand(2,3)
mask = torch.BoolTensor([[0,1,0],
[1,0,1]])
res = torch.masked_select(d,mask)
print(d)
print(res)
"""
输出结果:
tensor([[0.2507, 0.8419, 0.6681],
[0.0940, 0.8476, 0.5883]])
tensor([0.8419, 0.0940, 0.5883])
"""
2 tensor数据变换
本部分主要介绍的是将已有的tensor数据改变shape的方法,这是pytorch变换数据的基本操作。
2.1 重置tensor形状:pytorch.view()
torch.view()
主要实现重新定义tensor的shape,对tensor中的元素进行重排列,在view过程中tensor的总元素个数保持不变。该方法的缺点是会丢失维度信息。
#############################################
a = torch.rand(4,4,16,16)
b = a.view(4,32,32)
print(a.shape)
print(b.shape)
"""
输出结果:
torch.Size([4, 4, 16, 16])
torch.Size([4, 32, 32])
#注:在view前后必须保证tensor的总元素个数不变
# 在本例中:4*4*16*16 = 4*32*32
"""
2.2 增加/减少tensor维度:torch.unsqueeze()/torch.squeeze()
-
torch.unsqueeze(index)
:在原tensor的index索引位置对应的维度前增加一个维度, -
torch.squeeze(index)
:去掉index索引位置对应的维度,注意:这里index对应的维度必须是1维的,也就是压缩(删除)此维度并不会改变数据的元素个数,当不指定index时,函数会将tensor中所有数值为1的维度压缩。例如:现有tensor(1,4,1,16,16),tensor.squeeze(0)的值为:(4,1,16,16),函数压缩了0这个维度;当不指定index时,tensor.squeeze()的返回值为:(4,16,16),这时函数将tensor上数值为1的维度全部压缩
#############################################
a = torch.rand(4,4,16,16)
b = a.unsqueeze(0)
c = torch.rand(1,4,1,16,16).squeeze()
print(a.shape)
print(b.shape)
print(c.shape)
"""
输出结果:
torch.Size([4, 4, 16, 16])
torch.Size([1, 4, 4, 16, 16])
torch.Size([4, 16, 16])
"""
2.3 tensor扩充:torch.expand()/torch.repeat()
-
torch.expand()
:接收参数是将对应元素扩充的指定维度,函数只把原来维度为1的拓展成指定的维度,其它原来维度不是1的接收参数要与其原来维度数保持一致,否则会报错 -
torch.repeat()
:接收参数是将对应元素复制的次数,函数会将所有维度复制对应的次数,形成新的tensor
示例及讲解:
#############################################
a = torch.rand(4,1,16,16)
#a中只有a[1]是1维度,这里要将它扩充至4,因此expand中第二个参数为4,其它维度不是1,所以要与a保持一致(否则会报错)
b = a.expand(4,4,16,16)
#repeat中的参数都是,代表这要将a中对应维度的元素都复制两次
c = a.repeat(2,2,2,2)
print(a.shape)
print(b.shape)
print(c.shape)
"""
输出结果:
#这是原来a变量的shape
torch.Size([4, 1, 16, 16])
#这是经过expand后的a变量(b)的shape
#可以看出,expand成功将原理index=1位置处的1维度扩充成了对应的4维度
torch.Size([4, 4, 16, 16])
#这是经过repeat后的a变量的shape
#可以看出,repeat将每个维度都复制了2次,即:(4*2,1*2,16*2,16*2)
torch.Size([8, 2, 32, 32])
"""
2.4 tensor维度交换/重新排序:torch.transpose()/torch.permute()
-
torch.tanspose()
:接收参数为指定对换的两个维度索引a,b,函数将返回维度互换后的新tensor -
torch.permute()
:接收参数为新排序的维度索引(原来的索引值),函数将返回维度重新排列的新tensor
#############################################
a = torch.rand(4,1,12,16)
b = a.transpose(0,2) #第0个维度和第2个维度互换,即:4和12互换
c = a.permute(3,2,0,1) #将原有的3, 2, 0,1维度作为新tensor的0,1,2,3维度
print(a.shape)
print(b.shape)
print(c.shape)
"""
输出结果:
torch.Size([4, 1, 12, 16]) #a.shape
torch.Size([12, 1, 4, 16]) #b.shape (4,1,12,16)-互换4,12->(12,1,4,16)
torch.Size([16, 12, 4, 1]) #c.shape 重新对a进行排列(a[3],a[2],a[0],a[1])->(16,12,4,1)
"""
3 总结
tensor变换的核心理念是为了更好的服务于高维向量运算,这部分的变换技巧和相关的方法有很多。关于这部分的内容我的建议是:不需要花费大量的时间去刻意记忆,只要知道有这些方法,在编程需要的时候能想起来用这些方法可以解决即可。