pytorch之Tensor维度变化

常见用法

1、view用来改变shape。

调整Tensor的shape(通过返回一个新的Tensor),在老版本中这个函数是view(),功能上都是一样的。

a=torch.rand(4,1,28,28)
print(a.shape)#torch.Size([4, 1, 28, 28])
#将后3维合并
print(a.view(4,28*28))#
print(a.view(4,28*28).shape)#torch.Size([4, 784])
#将前3维合并
print(a.view(4*28,28).shape)
#将前2维合并
print(a.view(4*1,28,28).shape)

注意在view之后如果想恢复到原来的维数是要进行记录的,否则直接恢复是不行的。


2、unsqueeze增加维度

正的索引是在那个维度原本的位置前面插入这个新增加的维度,负的索引是在那个位置之后插入。

a=torch.rand(4,1,28,28)
print(a.shape)
print(a.unsqueeze(0).shape) # 在0号维度位置插入一个维度
print(a.unsqueeze(-1).shape) # 在最后插入一个维度
print(a.unsqueeze(3).shape) # 在3号维度位置插入一个维度
输出:

torch.Size([4, 1, 28, 28])
torch.Size([1, 4, 1, 28, 28])
torch.Size([4, 1, 28, 28, 1])
torch.Size([4, 1, 28, 1, 28])

在相应的index的维度添加一维。

例子:

a = torch.rand(4,1,28,28)
a.unsqueeze(0)
a.shape
#[1,4,1,28,28]

unsqueeze的参数是index,而index的范围是[-a.dim()-1,a.dim()+1)

-5 -4  -3   -2   -1
[   4 , 1 , 28 , 28 ]
    0   1    2    3    4

如果是0 1 2 3 4的话就是在0 1 2 3 4的前面插入一维,而如果是-5 - 4- 3- 2 -1的话就是在-5 - 4- 3- 2 -1的后面插入一维

⭐例子二:

a = a.torch.tensor([1.2,2.3])#这里的数据的维度为【2】
a.unsqueeze(-1)#在最后一个后面添加一维:【2,1】
#[ [1.2] , [2.3]   ]    于是就是先是两维,然后是一维

a.unsqueeze(0)#在第一维前面添加一维“【1,2】
#[ [1.2 , 2.3] ]         于是就是先是一维,里面是两维

⭐实例:

f表示4张14*14的拥有32个通道的图片,而b表示给图片的每个channel上的所有的像素添加一个偏置,我们的目标就是把b叠加在f上面,所以要将b的维度变换与f相同才可以进行,然后再进行b的扩张。

b = torch.rand(32)
f = torch.rand(4,32,14,14)
b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
#[32]      [32,1]      [32,1,1]       [1,32,1,1]

3、squeeze用来删减维度

删减维度实际上是一个压榨的过程,直观地看是把那些多余的[]给去掉,也就是只是去删除那些size=1的维度。

squeeze的索引是指哪个就删哪个,除非该维度的维数不是1就不能删。

import torch
a = torch.Tensor(1, 4, 1, 9)
print(a.shape)
print(a.squeeze().shape) # 能删除的都删除掉
print(a.squeeze(0).shape) # 尝试删除0号维度,ok
print(a.squeeze(2).shape) # 尝试删除2号维度,ok
print(a.squeeze(3).shape) # 尝试删除3号维度,3号维度是9不是1,删除失败

输出:

torch.Size([1, 4, 1, 9])
torch.Size([4, 9])
torch.Size([4, 1, 9])
torch.Size([1, 4, 9])
torch.Size([1, 4, 1, 9])

4、expand用来维度扩展

expand就是在某个size=1的维度上改变size,改成更大的一个大小,实际就是在每个size=1的维度上的标量的广播操作。

import torch

b = torch.rand(32)
f = torch.rand(4, 32, 14, 14)

# 想要把b加到f上面去

# 先进行维度增加
b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
print(b.shape)#torch.Size([1, 32, 1, 1])

# 再进行维度扩展
b = b.expand(4, -1, 14, 14)  # -1表示这个维度保持不变,这里写32也可以
print(b.shape)

运行结果:

torch.Size([1, 32, 1, 1])

torch.Size([4, 32, 14, 14])

补充:

input = torch.randn(4, 3)
input.size()#(4,3)
input = input.expand(2, -1, -1)#后面的两个-1表示原来input的后两维不动,只在第一维扩充
#但是这种做法仅限于要扩展的tensor和原来的tensor只差一个维度,且在第一维扩充,如果需要在其它维度扩展,需要先用unsqueeze增加维度,然后再扩展。

5、repeat维度重复

repeat就是将每个位置的维度都重复至指定的次数,以形成新的Tensor。repeat会重新申请内存空间。

# 维度增加...
print(b.shape)

# 维度重复,32这里不想进行重复,所以就相当于"重复至1次"
b = b.repeat(4, 1, 14, 14)
print(b.shape)

结果:

torch.Size([1, 32, 1, 1])
torch.Size([4, 32, 14, 14])

expand和repeat两种方法的区别

两种方法在效果方面是等效的,但是expand只在需要的时候进行数据的复制,而repeat会直接复制数据。所以推荐使用expand

局限性:

1.要求expand之前之后的dimension必须一样。

2.只能在之前维数为1的地方进行expand,而如果之前的维数为3是没有办法扩张到m的。

【3,32,14,14】——b.expand(4,32,14,14)报错

例子2:不像进行变动的地方使用-1代替就可以

b = torch.randn(1,32,1,1)
b.expand(4,32,-1,-1)
#[4,32,1,1]

6、.t() 转置

进行tensor的转置,但是要注意:只能进行2D tensor的转置,即矩阵的转置。

c = torch.Tensor(2, 4)
print(c.t().shape)#torch.Size([4, 2])

7、transpose维度交换

注意这种交换使得存储不再连续,再执行一些reshape的操作肯定是执行不了的,所以要调用一下contiguous()使其变成连续的维度。

  1. d = torch.Tensor(6, 3, 1, 2)
  2. print(d.transpose(1, 3).contiguous().shape) # 1号维度和3号维度交换

结果:torch.Size([6, 2, 1, 3])

下面这个例子比较一下每个位置上的元素都是一致的,来验证一下这个交换->压缩shape->展开shape->交换回去是没有问题的。

e = torch.rand(4, 3, 6, 7)
e2 = e.transpose(1, 3).contiguous().reshape(4, 7 * 6 * 3).reshape(4, 7, 6, 3).transpose(1, 3)
print(e2.shape)
# 比较下两个Tensor所有位置上的元素是否都相等
print(torch.all(torch.eq(e, e2)))

运行结果:

torch.Size([4, 3, 6, 7])
tensor(1, dtype=torch.uint8)

例子:

b = torch.randn(4,3,32,32)
b = b.transpose(1,3)
#[4,32,32,3]
# 0  1  2  3

例子2:这样变换前后的二者是一样的(contiguous()表示进行transpose之后数据不再是按顺序存放的,使用该方法进行顺序的调整)

a2 = b.transpose(1,3).contiguous().view(4,3*32*32).view(4,3,32,32).transpose(1,3)

注意:[B C H W] → [B W H C] → [B W * H * C] →[B C W H]这样的变换是不行的 W与H的顺序变换了,图像也会处出现变换

⭐例子3:

a = torch.rand(4,3,28,28)#[B C H W]
a.transpose(1,3)#[B W H C]
a.transpose(1,2)#[B H W C]

由于[B H W C]是numpy中储存图片的方式,所以这样变换以后才能导出numpy

8、permute

如果四个维度表示上节的[batch,channel,h,w] ,如果想把channel 放到最后去,形成[batch,h,w,channel] ,那么如果使用前面的维度交换,至少要交换两次(先13交换再12交换)。而使用permute可以直接指定维度新的所处位置,方便很多。

h = torch.rand(4, 3, 6, 7)
print(h.permute(0, 2, 3, 1).shape)

结果:torch.Size([4, 6, 7, 3])

转载

自用Pytorch学习笔记(六:Tensor变换)(基于1.1版本) - 知乎 (zhihu.com)

【pytorch学习】tensor的维度变换 - 知乎 (zhihu.com)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值