在看代码的时候发现了torch.contiguous()这个函数,那么它有什么用途呢?
1)背景知识
首先得知道一个tensor的shape和stride的区别。以二维矩阵为例,shape = [row, column]是指几行乘几列,stride = [stride1, stride2]分别是指到下一行需要跳过几个元素,到下一列需要跳过几个元素。由于python的底层是C实现的,遵从行优先的原则。
2)什么时候要用到contiguous
那么什么时候能够用得上contiguous操作呢?
在使用view操作的时候需要连续内存空间的tensor,如果当前的tensor经过了transpose等改变stride的操作,那么需要对这个tensor进行contiguous,然后才能执行view操作。
In [40]: t = torch.arange(1,13).reshape(3,4)
In [41]: t
Out[41]:
tensor([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
# t.stride() = (4,1)每隔4个元素到下一行,每隔1个元素到下一列
In [43]: t.stride()
Out[43]: (4, 1)
# 将行和列交换位置,transpose
In [44]: t2 = t.transpose(1,0)
In [45]: t2
Out[45]:
tensor([[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11],
[ 4, 8, 12]])
# t2.stride() = (1,4)每隔1个元素到下一行,每隔4个元素到下一列(在原来t的基础上)
In [46]: t2.stride()
Out[46]: (1, 4)
In [47]: t.is_contiguous()
Out[47]: True
In [48]: t2.is_contiguous()
Out[48]: False
# 无论是t还是t2还是t3,摊平展开之后的结果都是一样的,flatten
In [49]: t.flatten()
Out[49]: tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
In [50]: t2.flatten()
Out[50]: tensor([ 1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12])
In [51]: t3 = t2.contiguous()
In [52]: t3.flatten()
Out[52]: tensor([ 1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12])
# 非连续位置存储的元素在进行view操作的时候会报错,t2.view(12,1)报错
In [54]: t2.view(12,1)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-54-52b9424f2a69> in <module>
----> 1 t2.view(12,1)
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.
In [55]: t.view(12,1)
Out[55]:
tensor([[ 1],
[ 2],
[ 3],
[ 4],
[ 5],
[ 6],
[ 7],
[ 8],
[ 9],
[10],
[11],
[12]])
# t2.contiguous()变为连续顺序存储,结果就不会报错,可以进行view操作
In [56]: t3.view(12,1)
Out[56]:
tensor([[ 1],
[ 5],
[ 9],
[ 2],
[ 6],
[10],
[ 3],
[ 7],
[11],
[ 4],
[ 8],
[12]])