参考书目:张校捷,《深入浅出PyTorch:从模型到源码》
假设存在一个k维张量,其维数为[ n 1 , n 2 . . . n k n_1,n_2...n_k n1,n2...nk],在计算机的实际存储过程中为一个1维的向量,向量的大小为 n 1 ∗ n 2 ∗ . . . ∗ n k n_1*n_2*...*n_k n1∗n2∗...∗nk。在读取张量某一位置的元素数据时,假设此元素的下标为 ( k 1 , k 2 . . . k k ) (k_1,k_2...k_k) (k1,k2...kk),则在读取时读取的是内存中第 i 1 ∗ ( n 2 ∗ . . . ∗ n k ) + i 2 ∗ ( n 3 ∗ . . . ∗ n k ) + . . . + i k − 1 ∗ n k + i k i_1*(n_2*...*n_k)+i_2*(n_3*...*n_k)+...+i_{k-1}*n_k+i_k i1∗(n2∗...∗nk)+i2∗(n3∗...∗nk)+...+ik−1∗nk+ik位置的数据,其中 ( n 2 ∗ . . . ∗ n k ) , ( n 3 ∗ . . . ∗ n k ) , n k , 1 (n_2*...*n_k), (n_3*...*n_k), n_k,1 (n2∗...∗nk),(n3∗...∗nk),nk,1称为对应维度的步长(Stride)或者系数(Offset)。例如下表为一 2 ∗ 2 ∗ 4 2*2*4 2∗2∗4张量在内存中的存储。
000 | 001 | 002 | 003 | 010 | 011 | 012 | 013 | 100 | 101 | 102 | 103 | 110 | 111 | 112 | 113 |
---|
在pytorch中对张量tensor
维度及维度数目的获取可以有以下方法:ndimension
方法可以获取张量的维数,nelement
方法可以获取张量总的元素个数。想要获得张量的每个维度的大小,也就是张量的形状信息,可以通过tensor.size()
或者tensor.shape
得到。这两者不同的是tensor.szie()
调用的是方法,tensor.shape
访问的是张量的属性。相同的是两者返回的结果的数据类型都为torch.Size
。想要获得特定维度的大小可以在使用size方法时输入想要的维度。
tensor0=torch.randn(1,3,28,28)
tensor0.ndimension(),tensor0.nelement()
Out[4]: (4, 2352)
tensor0.size(),tensor0.shape,tensor0.size(1)
Out[5]: (torch.Size([1, 3, 28, 28]), torch.Size([1, 3, 28, 28]), 3)
在Pytorch中想要对张量的维度进行改变主要采用的方法时view
方法和reshape
方法。他们的作用都是将原有张量转换为想要的形状大小,前提是张量的元素总量保持一致,当view()或reshape()方法的输入中某一维度为-1时,作用是将这一维度的元素数量设为活动值,具体数值由其他维度确定例如
tensor0.view(1,-1,28).shape
Out[7]: torch.Size([1, 84, 28])
tensor0.reshape(1,-1,28).shape
Out[8]: torch.Size([1, 84, 28])
这里-1对应的维度的元素个数就是 ( 1 ∗ 3 ∗ 28 ∗ 28 ) / ( 1 ∗ 28 ) = 84 (1*3*28*28)/(1*28)=84 (1∗3∗28∗28)/(1∗28)=84的结果
view
方法与reshape
方法的不同之处在于view
方法不改变张量底层的数据,只改变维度的步长信息。在使用view
方法之后使用contiguous
可以重新生成一个张量。使用reshape()
方法直接对底层数据进行了更改相当于先后调用了view()
方法和contiguous
方法。
contiguous
方法的作用是应对张量的步长和维度不兼容时的方法,同样也常用于narrow()
,expand()
,transpose()
和permute()
这种只改变维度步长信息而不改变底层数据本身的方法之后,不然可能出现报错。