查看张量的一部分

时间:2020-02-11 00:15:20

标签: pytorch

我有一个多维张量,让我们以这个简单的张量为例:

out = torch.Tensor(3, 4, 5)

我必须获取该张量out[:,0,:]的一部分/子部分,然后应用方法view(-1),但这是不可能的:

 out[:,0,:].view(-1)

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 ../aten/src/TH/generic/THTensor.cpp:203

一种解决方案是克隆子部分:

 out[:,0,:].clone().view(-1)

有比克隆更好/更快的解决方案吗?

1 个答案:

答案 0 :(得分:2)

您所做的一切都会很好。也就是说,一种更可移植的方法是使用reshape,它将在可能时返回视图,但是在必要时将创建连续的副本。这样,它将做最快的事情。根据您的情况,必须复制数据,但是始终使用reshape有时将无法生成副本。

因此您可以使用

out[:,0,:].reshape(-1)

Gotcha

这里有一个重要的陷阱。如果对reshape的输出执行就地操作,则可能会或不会影响原始张量,具体取决于是否返回视图或副本。

例如,假设out已经连续,那么在这种情况下

>>> x = out[:,0,:].reshape(-1)    # returns a copy
>>> x[0] = 10
>>> print(out[0,0,0].item() == 10)
False

x是副本,因此对其所做的更改不会影响out。但是在这种情况下

>>> x = out[:,:,0].reshape(-1)     # returns a view
>>> x[0] = 10
>>> print(out[0,0,0].item() == 10)
True

x是一个视图,因此对x的就地更改也会更改out


替代

几个替代方法是

out[:,0,:].flatten()    # .flatten is just a special case of .reshape

out[:,0,:].contiguous().view(-1)

尽管如果您想要最快的方法,我建议您使用contiguous().view 后一种方法,因为通常来说,它比reshapeflatten更有可能返回副本。这是因为contiguous将创建一个副本,即使基础数据在后续条目之间具有相同数量的字节。因此,两者之间是有区别的

out[:,:,0].contiguous().view(-1)       # creates a copy

out[:,:,0].flatten()                   # creates a non-contiguous view (b/c underlying data has uniform spacing of out.shape[2] values between entries)

由于contiguous().view不连续,因此out[:,:,0]方法强制执行复制,但是flatten / reshape将创建视图,因为基础数据是均匀间隔的。

有时候contiguous()不会创建副本,例如比较

out[0,:,:].contiguous().view(-1)       # creates a view b/c out[0,:,:] already is contiguous

out[0,:,:].flatten()                   # creates a view

由于out[0,:,:]已经是连续的,因此它们都可以生成原始数据的视图而无需复制。


如果要确保out与扁平化的对象完全分离,那么使用.clone()的原始方法是可行的方法。