参考来源:
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 block
t = torch.tensor([[2, 1, 3], [4, 5, 9]])
在内存中实际上是
[2, 1, 3, 4, 5, 9]
按照行优先原则,数字在语义和在内存中都是连续的,当我们使用 torch.transpose()
方法或者 torch.permute()
方法对张量翻转后,改变了张量的形状
# An highlighted block
t2 = 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 block
t3 = t2.contiguous()
print(t3)
"""
tensor([[2,4],
[1,5],
[3,9])
"""
可以看到 t3
与 t2
一样,都是 3
行 2
列的张量,此时再对 t3
使用 view
方法:
# An highlighted block
t4 = t3.view(-1)
print(t4)
"""
tensor([2, 4, 1, 5, 3, 9])
"""
t3
已经按照语义的形状展开了,t2
与 t
共享内存是怎样的呢?
# An highlighted block
print(t.view(-1))
"""
tensor([2, 1, 3, 4, 5, 9])
"""
可以看出 contiguous
方法改变了多维数组在内存中的存储顺序,以便配合 view
方法使用;
**torch.contiguous()**
方法首先拷贝了一份张量在内存中的地址,然后将地址按照形状改变后的张量的语义进行排列。