最近被 [pytorch](https://so.csdn.net/so/search?q=pytorch&spm=1001.2101.3001.7020) 的几种 Tensor 维度转换方式搞得头大,故钻研了一下,将钻研历程和结果简述如下 _**注意:torch.__version__ == '1.2.0’**_ ## [torch](https://so.csdn.net/so/search?q=torch&spm=1001.2101.3001.7020).transpose() 和 torch.permute() 两者作用相似,都是用于交换不同维度的内容。但其中`torch.transpose()`是交换指定的两个维度的内容,`permute()`则可以一次性交换多个维度。具体情况如 code 所示: **transpose()**: 两个维度的交换 ``` >>> a = torch.Tensor([[[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15]], [[-1,-2,-3,-4,-5], [-6,-7,-8,-9,-10], [-11,-12,-13,-14,-15]]]) >>> a.shape torch.Size([2, 3, 5]) >>> print(a) tensor([[[ 1., 2., 3., 4., 5.], [ 6., 7., 8., 9., 10.], [ 11., 12., 13., 14., 15.]], [[ -1., -2., -3., -4., -5.], [ -6., -7., -8., -9., -10.], [-11., -12., -13., -14., -15.]]]) >>> b = a.transpose(1,2) # 使用transpose,将维度1和2进行交换。这个很好理解。转换后tensor与其shape如下 >>> print(b, b.shape) (tensor([[[ 1., 6., 11.], [ 2., 7., 12.], [ 3., 8., 13.], [ 4., 9., 14.], [ 5., 10., 15.]], [[ -1., -6., -11.], [ -2., -7., -12.], [ -3., -8., -13.], [ -4., -9., -14.], [ -5., -10., -15.]]]), torch.Size([2, 5, 3]))) ``` **permute()**:一次性做任意维度的交换 ``` >>> c = a.permute(2, 0, 1) >>> print(c, c.shape) # 此举将原维度0,1,2的次序变为2,1,0,所以shape也发生了相应的变化。 (tensor([[[ 1., 6., 11.], [ -1., -6., -11.]], [[ 2., 7., 12.], [ -2., -7., -12.]], [[ 3., 8., 13.], [ -3., -8., -13.]], [[ 4., 9., 14.], [ -4., -9., -14.]], [[ 5., 10., 15.], [ -5., -10., -15.]]]), torch.Size([5, 2, 3])) ``` transpose() 和 permute() 之间的转化: ``` >>> b = a.permute(2,0,1) >>> c = a.transpose(1,2).transpose(0,1) >>> print(b == c, b.shape) (tensor([[[True, True, True], [True, True, True]], [[True, True, True], [True, True, True]], [[True, True, True], [True, True, True]], [[True, True, True], [True, True, True]], [[True, True, True], [True, True, True]]]), torch.Size([5, 2, 3])) ``` 如代码所示,先将 [Tensor](https://so.csdn.net/so/search?q=Tensor&spm=1001.2101.3001.7020) a 的 1,2 维度进行交换,再将得到的 Tensor 的 0,1 维度再交换,得到的结果和 permute 是一样的。 ## transpose() 和 view() `view()`是个在 pytorch 中很常见的函数。该函数也起到转换 Tensor 维度的作用,但它转换的方式和 transpose()/permute() 截然不同。如果说`tranpose()`是按照 Tensor 的原有维度忠实地进行交换,那么`view()`就直接而且简单的多——首先,view() 函数会将 Tensor 所有维度拉平成一维,然后再根据传入的的维度信息重构出一个 Tensor。code 如下: ``` # 还是上面的Tensor a >>> print(a.shape) torch.Size([2, 3, 5]) >>> print(a.view(2,5,3)) tensor([[[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.], [ 10., 11., 12.], [ 13., 14., 15.]], [[ -1., -2., -3.], [ -4., -5., -6.], [ -7., -8., -9.], [-10., -11., -12.], [-13., -14., -15.]]]) >>> c = a.transpose(1,2) >>> print(c, c.shape) (tensor([[[ 1., 6., 11.], [ 2., 7., 12.], [ 3., 8., 13.], [ 4., 9., 14.], [ 5., 10., 15.]], [[ -1., -6., -11.], [ -2., -7., -12.], [ -3., -8., -13.], [ -4., -9., -14.], [ -5., -10., -15.]]]), torch.Size([2, 5, 3])) ``` 如代码所示。即使`view()`和`transpose()`最终得到的 Tensor 的 shape 是一样的,但二者内容并不相同。view 函数只是按照给定的 (2,5,3) 的 Tensor 维度,将元素**按顺序**一个个填进去;而 transpose 函数,则的确是在进行第一个第二维度的**转置**。 此外,有些情况下转置 (transpose) 后的 Tensor 是无法被 **view** 的,原因在于,转置后的 Tensor 不是 “连续”(non-contiguous)的。关于 contiguous array 的问题 numpy 里也一样,在这里有个[很棒的解释](https://stackoverflow.com/questions/26998223/what-is-the-difference-between-contiguous-and-non-contiguous-arrays/26999092#26999092)