假设我们有一个大小为[a,b,c]
的Tensors
,它不一定是连续的,并且b>>1
。
我想把它在第二维展开(但不是复制)n次,得到一个大小为[a,nb,c]
的Tensor。
问题是,如果不显式地复制内存中的数据,我就找不到一种方法来执行此操作。
s.repeat_interleave(n,dim=1)
s.unsqueeze(-2).expand(-1,-1,n,-1).contiguous().view([a,-1,c])
s.unsqueeze(-2).expand(-1,-1,n,-1).reshape([a,-1,c])
将执行复制步骤,并显著降低速度。
有人知道解决办法吗?
提前感谢!
1条答案
按热度按时间vof42yt11#
我认为这是不可能的,这里有一个最小的例子来说明我的观点。
考虑一个 Torch 。Tensor
[1, 2, 3]
,大小为(3,)
。如果我们想在不执行复制的情况下扩展它,我们将创建一个新的Tensorview。例如,假设我们想创建一个包含原始Tensor值两倍的视图。即[1, 2, 3, 1, 2, 3]
,其大小为(2*3,)
。但是,不可能定义仅使用步幅的视图,原因如下:为了从1
步进到2
,或者从2
步进到3
,我们需要步幅值为1。但是为了从3
步进到1
,我们需要步幅值为-2
,但是所实现的步幅系统对于给定轴不能具有不同的值。我不能100%肯定这是不可能的。也许存在一个非常聪明的技巧,通过使用
torch.as_strided()
函数的storage_offset
参数,或其他东西。而且,也许这个功能将在未来的版本中实现,例如,如果你试图设置一个负的步幅值,你会有错误这表明这个功能将来可能会改变(这里我使用了pytorch1.13.0版)。
有人可能会说,你可以先用
torch.Tensor.expand()
展开一个新的维度,然后用flatten()
得到结果,但这是行不通的,让我来解释为什么。在expand()
的文档中,解释了这个函数返回Tensor的新的view
(所以这并不做任何复制),在flatten()
的文档中,解释了这个函数将尝试返回展平Tensor的视图,如果不可能,它将返回一个副本。那么让我们试试这个方法,并使用tensor.storage().nbytes()
检查每一步Tensor的存储器大小:正如我们所看到的,
flatten()
似乎不能返回展平Tensor的视图,因为c
占用的内存是a
的两倍。如果flatten()
的pyTorch实现不能做到这一点,这可能意味着它确实不可能做到。