高效地堆叠一个数组/一个torch张量的副本?

9

我是一个Python/Pytorch用户。首先,假设我有一个大小为LxL的数组M,在numpy中,我想要得到以下数组:A=(M,...,M),大小为NxLxL,有没有比以下方法更优雅/更节省内存的方式:

A=np.array([M]*N) ?

有关torch张量的相同问题! 现在,如果M是一个Variable(torch.tensor),我必须执行以下操作:

A=torch.autograd.Variable(torch.tensor(np.array([M]*N))) 

which is ugly !


numpy has tile and repeat. Using them may require M[None,...] - hpaulj
你可能只需要进行广播。 (我不确定PyTorch是否已经具备了广播功能; 最近已经实现,但我不确定它是否可用。) - user2357112
还有expand,它有点像手动广播。 - user2357112
3个回答

16
请注意,您需要决定是为扩展后的数组分配新内存,还是仅需要原始数组现有内存的新视图。
在PyTorch中,这种区别引出了两种方法expand()repeat()。前者只在现有张量上创建一个新视图,在其中将大小为一的维度通过将步长设置为0而扩展到较大的大小。任何大小为1的维度都可以扩展到任意值而无需分配新内存。相比之下,后者会复制原始数据并分配新内存。
在PyTorch中,您可以按照以下方式使用expand()repeat() 来实现您的目的:
import torch

L = 10
N = 20
A = torch.randn(L,L)
A.expand(N, L, L) # specifies new size
A.repeat(N,1,1) # specifies number of copies
在Numpy中,有许多更优雅和高效的方法来实现您上面所做的操作。对于您特定的目的,我建议使用np.tile()而不是np.repeat(),因为np.repeat()是设计用于在数组的特定元素上进行操作,而np.tile()是设计用于在整个数组上进行操作。因此,
import numpy as np

L = 10
N = 20
A = np.random.rand(L,L)
np.tile(A,(N, 1, 1))

np.tile 使用 np.repeat,每个维度使用一次。它不使用 repeat 的能力来应用每个元素的不同数量,但除此之外,它只是 repeat 的扩展。它的代码是易读的 Python。 - hpaulj

4

如果您不介意创建新的内存:

  • 在numpy中,您可以使用 np.repeat()np.tile()。考虑效率,应选择根据您的目的组织内存的一种方式,而不是事后重排:
    • np.repeat([1, 2], 2) == [1, 1, 2, 2]
    • np.tile([1, 2], 2) == [1, 2, 1, 2]
  • 在pytorch中,您可以使用tensor.repeat()注意:这与np.tile匹配,而不是np.repeat

如果您不想创建新内存:

  • 在numpy中,您可以使用np.broadcast_to()。这会创建一个只读视图。
  • 在pytorch中,您可以使用tensor.expand()。这将创建一个可编辑的视图,因此像+=这样的操作会产生奇怪的影响。

np.tile is different from np.repeat - Nicolas Gervais
@NicolasGervais 很好。它们有什么不同之处?我想更新答案。 - Multihunter
1
如果输入“abc”,则输出“abcabcabc”,如果重复,则输出“aaabbbccc”。 - Nicolas Gervais

-1
在编程中,numpyrepeat 更快:
np.repeat(M[None,...], N,0)

我扩展了M的维度,然后沿着这个新维度重复。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接