参考来源:
CSDN:torch.contiguous() 方法
CSDN:python——Contiguous 用法
**x.is_contiguous()**:判断 **tensor** 是否连续。
**x.contiguous()**:把 **tensor** 变成在内存中连续分布的形式。**contiguous**:**view** 只能用在 **contiguous** 的 **variable** 上。如果在 **view** 之前用了 **transpose**、**permute** 等,需要用 **contiguous()** 来返回一个 **contiguous copy** 。
**torch.contiguous()** 方法语义上是“连续的”,经常与 **torch.permute()**、**torch.transpose()**、**torch.view()** 方法一起使用,要理解这样使用的缘由,得从 pytorch 多维数组的低层存储开始说起:**touch.view()** 方法对张量改变“形状”其实并没有改变张量在内存中真正的形状,可以理解为:
view方法没有拷贝新的张量,没有开辟新内存,与原张量共享内存;view方法只是重新定义了访问张量的规则,使得取出的张量按照我们希望的形状展现。
pytorch 与 numpy 在存储 M x N 的数组时,均是按照行优先将数组拉伸至一维存储,比如对于一个二维张量
# An highlighted blockt = torch.tensor([[2, 1, 3], [4, 5, 9]])
在内存中实际上是
[2, 1, 3, 4, 5, 9]
按照行优先原则,数字在语义和在内存中都是连续的,当我们使用 torch.transpose() 方法或者 torch.permute() 方法对张量翻转后,改变了张量的形状
# An highlighted blockt2 = t.transpose(0, 1)print(t2)"""tensor([[2,4],[1,5],[3,9])"""
此时如果对 t2 使用 view 方法,会报错:
t2.view((2,3))"""Traceback (most recent call last):File "test.py", line 14, in <module>t2.view((2,3))RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead."""
原因是:改变了形状的 t2 语义上是 3 行 2 列的,在内存中还是跟 t 一样,没有改变,导致如果按照语义的形状进行 view 拉伸,数字不连续,此时 torch.contiguous() 方法就派上用场了
。
# An highlighted blockt3 = t2.contiguous()print(t3)"""tensor([[2,4],[1,5],[3,9])"""
可以看到 t3 与 t2 一样,都是 3 行 2 列的张量,此时再对 t3 使用 view 方法:
# An highlighted blockt4 = t3.view(-1)print(t4)"""tensor([2, 4, 1, 5, 3, 9])"""
t3 已经按照语义的形状展开了,t2 与 t 共享内存是怎样的呢?
# An highlighted blockprint(t.view(-1))"""tensor([2, 1, 3, 4, 5, 9])"""
可以看出 contiguous 方法改变了多维数组在内存中的存储顺序,以便配合 view 方法使用;
**torch.contiguous()** 方法首先拷贝了一份张量在内存中的地址,然后将地址按照形状改变后的张量的语义进行排列。
