在pytorch中,需要对tensor进行各种型式的维度、复制等操作,比如squeeze, view, gather,expand,contiguous,copy
等,下面对这些操作进行介绍。
1) squeeze & unsqueeze
torch.squeeze(input, dim=None, out=None)
是将输入张量形状中的1 去除并返回。
- 输入是形如(A×1×B×1×C×1×D),那么输出形状就为: (A×B×C×D)。
- 当给定dim时,那么挤压操作只在给定维度上。例如,输入形状为: (A×1×B), squeeze(input, 0) 将会保持张量不变,只有用 squeeze(input, 1),形状会变成 (A×B)。
- 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
torch.unsqueeze(input, dim,out=None)
返回一个张量,对输入的制定位置插入维度 1。
- 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。如果dim为负,则将会被转化dim+input.dim()+1
2) contiguous & view & resize
contiguous()
→ Tensor返回一个内存连续的有相同数据的tensor,如果原tensor内存连续则返回原tensor。
view(*args)
→ Tensor, 返回一个有相同数据但大小不同的tensor。 返回的tensor必须有与原tensor相同的数据和相同数目的元素,但可以有不同的形状。一个tensor必须是连续的contiguous()才能使用view()函数。
resize_(*size)
将tensor的大小调整为指定的大小。如果元素个数比当前的内存大小大,就将底层存储大小调整为与新元素数目一致的大小。如果元素个数比当前内存小,则底层存储不会被改变。原来tensor中被保存下来的元素将保持不变,但新内存将不会被初始化。
3) gather
torch.gather(input, dim, index, out=None)
是沿给定轴dim,将输入索引张量index指定位置的值进行聚合。其中,在dim方向上,input和index必须有相同的维数;非dim方向上,input和index必须有相同的形状,即非dim方向的size相同。
假设 \[src \in \mathbb{R}^{m \times n}, idx \in \mathbb{R}^{m \times n}\],
若trg = torch.gather(src,dim=0,idx)
,则
1 | tmp = idx[i][j] |
若trg = torch.gather(src,dim=1,idx)
,则
1 | tmp = idx[i][j] |
4) expand vs. repeat
expand(*sizes),返回tensor的一个新视图,单个维度扩大为更大的尺寸。比如[12,15]的矩阵想expand成[12,15,7]的张量,需要先unsqueeze成[12,15,1],然后再expand成[12,15,7],也就是说expand()只能从单个维度扩展到多个维度(1->n),而不能新增维数。
expand_as(a)这是tensor变量的一个内置方法,如果使用b.expand_as(a)就是将b进行扩充,扩充到a的维度,需要说明的是a的低维度需要比b大,例如b的shape是31,如果a的shape是32不会出错,但是是2*2就会报错了。
repeat(sizes)沿着指定的维度重复tensor。不同与expand(),本函数复制的是tensor中的数据。参数:size(torch.size ot int…)-沿着每一维重复的次数
5) cat, stack vs. split, chunk
拼接
torch.cat((in1,in2,in3), dimension=dim)
实现张量拼接。in1, in2,in3在非dim的维度上应size完全相同。
torch.stack(sequence, dim=0, out=None)
,做tensor的拼接。sequence表示Tensor列表,dim表示拼接的维度。注意这个函数和cat是不同的,cat是在已有的维度上拼接,而stack是建立一个新的维度,然后再在该维度上进行拼接。
分隔
torch.split(tensor, split_size, dim=0)
,将输入张量分割成相等形状的chunks。 如果沿指定维的张量形状大小不能被split_size 整分, 则最后一个分块会小于其它分块。
torch.chunk(tensor, chunks, dim=0)
,在给定维度(轴)上将输入张量进行分块儿。其中chunks (int) – 分块的个数,dim (int) – 沿着此维度进行分块。
6) clone, copy & ‘=’
a. 共享内存
tesB = tesA, 使用这种复制方式是共享内存的,即tesB, tesA的内存地址相同,改变任何一个tensor,另一个随之改变。
b. 浅拷贝
tesC=copy.copy(tesA),使用浅拷贝复制。此时只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。例如:
1 | 1,2,[3,4]] #第三个值为列表[3,4],即内部元素 a=[ |
c. 深拷贝
tesC=copy.deepcopy(tesA),使用深拷贝复制。内部元素的内存也独立。
d. clone()
clone() → Tensor,返回与原tensor有相同大小和数据类型的tensor,且与原tensor内存地址不同,若未指定cuda_device(),默认与原tensor的GPU相同。
1 | var_x.data = y.clone() # y is a tensor, var_x is variable |
7) other func
- 注意: 会改变tensor的函数操作会用一个下划线后缀来标示。比如,torch.FloatTensor.abs_()会在原地计算绝对值,并返回改变后的tensor,而tensor.FloatTensor.abs()将会在一个新的tensor中计算结果。
- 使用Tensor型数据进行比较的时候需要注意,如果比较的是其中的值,那么必须将其化为普通值再进行比较,即使是一维的单个数据,也要用[0]操作符来进行读取。
- torch.transpose(input, dim0, dim1, out=None)返回输入矩阵input的转置。交换维度dim0和dim1。 输出张量与输入张量共享内存,所以改变其中一个会导致另外一个也被修改。