Numpy 大张量上的n维智能索引-存储效率

Numpy 大张量上的n维智能索引-存储效率,numpy,indexing,theano,Numpy,Indexing,Theano,我使用的是大张量,所以临时张量的numpy内存分配开始显著影响执行时间+代码有时会在这些中间步骤中引发内存分配错误。这里有两种方法可以用另一个张量的int值来索引一个张量(比如,result_ijk=a[i,b[i,j],k]),我提出了这两种方法,尽管第二种方法看起来更节省内存,但我觉得创建这个巨大的索引矩阵并迭代它的所有值(即使是并行的)有点像有线的(并且经常达到内存限制): def test(): i、 j,k,l=10,20,30,40#实际上,它们就像1e3..1e6 a=np.ran

我使用的是大张量,所以临时张量的numpy内存分配开始显著影响执行时间+代码有时会在这些中间步骤中引发内存分配错误。这里有两种方法可以用另一个张量的
int
值来索引一个张量(比如,
result_ijk=a[i,b[i,j],k]
),我提出了这两种方法,尽管第二种方法看起来更节省内存,但我觉得创建这个巨大的索引矩阵并迭代它的所有值(即使是并行的)有点像有线的(并且经常达到内存限制):

def test():
i、 j,k,l=10,20,30,40#实际上,它们就像1e3..1e6
a=np.random.rand(i,j,k)
b=np.random.randint(0,j,size=i*l)。重塑((i,l))
#c_ilk=c[i,b[i,l],k];形状(c)=(10,40,30)
tmp=a[:,b,:]#一些方法:

i,j,k,l=[100]*4
a = np.random.randint(0,5,(i, j, k))
b = np.random.randint(0, j,(i, l))

def test1():
    # c_ilk = c[i, b[i, l], k]; shape(c) = (2,3,5)
    tmp = a[:, b, :] # <= i*ijk additional memory allocated (!) crazy
    c1 = np.diagonal(tmp, axis1=0, axis2=1).transpose([2, 0, 1])
    return c1

def test2():
    ii, ll = np.indices((i, l)) # <= 2*i*l of temporary ints allocated
    tmp2 = b[ii, ll] # i*l of ints allocated, slow ops
    c2 = a[ii, tmp2] # slow ops over tensor
    #print(c2.shape)
    return c2

def test3():
    c3=np.empty((i,l,k),dtype=a.dtype)   
    for ii in range(i):
        for ll in range(l):
                c3[ii,ll]=a[ii,b[ii,ll]]
    return c3        

from numba import jit
test4=jit(test3)
这似乎表明(参见@Eelco Hoogendoorn注释),第二种方法对于大尺寸的产品几乎是最佳的,而第一种方法是一个糟糕的选择


对于numba,您只需使用这部分代码,并在非“jited”函数中应用梯度。

您只需分配长度为
i
的整数数组即可获得所需结果:

i_idx = np.arange(i)
c = a[i_idx[:, None], b[i_idx, :], :]
# or you can use the terser c = a[i_idx[:, None], b[i_idx]]
广播负责根据需要动态复制值,而不必为它们分配内存


如果对大型ish数组执行此操作,您会注意到它只比第二种方法稍微快一点:正如其他人所指出的,中间索引数组将比您的总体计算小几个数量级,因此优化它对总运行时间或内存占用的影响很小。

在我看来就像i*l i与您的全部数据相比,它很小,因此您的第二种方法对我来说似乎很好。如果这成为您完整代码中的实际瓶颈,我会非常惊讶。(仅限那些可能稍后阅读它的人:
。张量c=a[I_idx[:,None],b[I_idx]]
-那里没有逗号,但我无法确定
In [54]: %timeit test1()
1 loop, best of 3: 720 ms per loop

In [55]: %timeit test2()
100 loops, best of 3: 7.79 ms per loop

In [56]: %timeit test3()
10 loops, best of 3: 43.7 ms per loop

In [57]: %timeit test4()
100 loop, best of 3: 4.99 ms per loop
i_idx = np.arange(i)
c = a[i_idx[:, None], b[i_idx, :], :]
# or you can use the terser c = a[i_idx[:, None], b[i_idx]]