就像在前面的答案中contigous()分配连续的内存块一样 ,当我们将张量传递给c或c ++后端代码(其中张量作为指针传递)时,这将很有帮助


0

0

从pytorch文档中 :
contiguous()→张量
Returns a contiguous tensor containing the same data as self
张量。如果自张量是连续的,则此函数返回自张量。
此处contiguous
是指内存中连续。因此, contiguous
函数根本不会影响目标张量,它只是确保将其存储在连续的内存块中。
0

在PyTorch中,对Tensor进行的操作很少真正改变张量的内容,而仅改变如何将张量的索引转换为字节位置。这些操作包括:
narrow()
,view()
,expand()
和transpose()
例如:当您调用transpose()
,PyTorch不会使用新的布局生成新的张量,它只是修改Tensor对象中的元信息,因此offset和stride用于新形状。转置张量和原始张量确实共享内存!
x = torch.randn(3,2)
y = torch.transpose(x, 0, 1)
x[0, 0] = 42
print(y[0,0])
# prints 42
这是连续的概念来自英寸以上x
是连续的但y
不是因为它的内存布局是比从头制成相同形状的张量不同。请注意, “连续”一词有点误导,因为它不是张量的内容散布在未连接的内存块周围。这里字节仍然分配在一个内存块中,但是元素的顺序不同!
当您调用contiguous()
,它实际上会复制张量,因此元素的顺序将与从头开始创建的具有相同形状的张量相同。
通常,您无需为此担心。如果PyTorch期望连续张量,但如果不是,那么您将得到RuntimeError: input is not contiguous
,然后只需添加对contiguous()
的调用即可。
0

tensor.contiguous()将创建张量的副本,并且副本中的元素将以连续方式存储在内存中。当我们首先对张量进行transpose()并对其进行整形(查看)时,通常需要contiguous()函数。首先,让我们创建一个连续的张量:
aaa = torch.Tensor( [[1,2,3],[4,5,6]] )
print(aaa.stride())
print(aaa.is_contiguous())
#(3,1)
#True
stride()返回(3,1)的意思是:当沿着第一维移动每一步(逐行)时,我们需要在内存中移动3步。沿第二维(逐列)移动时,我们需要在内存中移动1步。这表明张量中的元素是连续存储的。
现在我们尝试将come函数应用于张量:
bbb = aaa.transpose(0,1)
print(bbb.stride())
print(bbb.is_contiguous())
ccc = aaa.narrow(1,1,2) ## equivalent to matrix slicing aaa[:,1:3]
print(ccc.stride())
print(ccc.is_contiguous())
ddd = aaa.repeat(2,1 ) # The first dimension repeat once, the second dimension repeat twice
print(ddd.stride())
print(ddd.is_contiguous())
## expand is different from repeat if a tensor has a shape [d1,d2,1], it can only be expanded using "expand(d1,d2,d3)", which
## means the singleton dimension is repeated d3 times
eee = aaa.unsqueeze(2).expand(2,3,3)
print(eee.stride())
print(eee.is_contiguous())
fff = aaa.unsqueeze(2).repeat(1,1,8).view(2,-1,2)
print(fff.stride())
print(fff.is_contiguous())
#(1, 3)
#False
#(3, 1)
#False
#(3, 1)
#True
#(3, 1, 0)
#False
#(24, 2, 1)
#True
好的,我们可以发现transpose(),narrow()和张量切片以及expand()将使生成的张量不连续。有趣的是,repeat()和view()不会使其不连续。所以现在的问题是: 如果我使用不连续张量会怎样?
答案是view()函数不能应用于不连续的张量。这可能是因为view()要求将张量连续存储,以便可以在内存中进行快速整形。例如:
bbb.view(-1,3)
我们将得到错误:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-63-eec5319b0ac5> in <module>()
----> 1 bbb.view(-1,3)
RuntimeError: invalid argument 2: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Call .contiguous() before .view(). at /pytorch/aten/src/TH/generic/THTensor.cpp:203
为了解决这个问题,只需将contiguous()添加到不连续的张量中,以创建连续的副本,然后应用view()
bbb.contiguous().view(-1,3)
#tensor([[1., 4., 2.],
[5., 3., 6.]])
- 社区规范
- 提出问题
- 进行投票
- 个人资料
- 优化问题
- 回答问题
1
我正在通过github (link)上的LSTM语言模型的这个例子。对我来说,它的一般功能非常清楚。但是我仍然在努力理解调用
contiguous()
作用,这在代码中多次发生。例如,在代码的第74/75行中,创建了LSTM的输入和目标序列。数据(存储在
ids
)是二维的,其中第一维是批量大小。举一个简单的例子,当使用批处理大小1和
seq_length
10个inputs
和targets
看起来像这样:因此,总的来说,我的问题是,
contiguous()
是什么?为什么需要它?此外,我不明白为什么要针对目标序列而不是针对输入序列调用该方法,因为这两个变量都包含相同的数据。
targets
怎么可能是不连续的而inputs
仍然是连续的?编辑: 我试图省去调用
contiguous()
,但这在计算损失时会导致错误消息。因此,显然在此示例中调用
contiguous()
是必要的。(为了保持可读性,我避免在此处发布完整的代码,可以使用上面的GitHub链接找到它。)
提前致谢!