2 回答

TA貢獻(xiàn)1872條經(jīng)驗(yàn) 獲得超4個(gè)贊
好吧,其中一個(gè)軸在A(第一個(gè))和B(最后一個(gè))中保持對齊,并且也保持在輸出中(最后一個(gè))并且是一個(gè)非常小的循環(huán)數(shù)4。因此,我們可以簡單地循環(huán)使用 withnp.tensordot來減少張量和。4x在處理如此大的數(shù)據(jù)集時(shí),減少內(nèi)存擁塞的好處可能會克服 4 倍循環(huán),因?yàn)槊看蔚挠?jì)算量也4x更少。
因此,一個(gè)解決方案tensordot是 -
def func1(A, B):
out = np.empty(A.shape[1:3] + B.shape[1:])
for i in range(len(A)):
out[...,i] = np.tensordot(A[i], B[...,i],axes=(-1,0))
return out
時(shí)間 -
In [70]: A = np.random.rand(4,50,60,200) # Random NDarray
...: B = np.random.rand(200,1000,4) # Random NDarray
...: out = np.einsum('ijkl,lui->jkui', A, B, optimize="optimal")
# Einsum solution without optimize
In [71]: %timeit np.einsum('ijkl,lui->jkui', A, B)
2.89 s ± 109 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# Einsum solution with optimize
In [72]: %timeit np.einsum('ijkl,lui->jkui', A, B, optimize="optimal")
2.79 s ± 9.31 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# @Paul Panzer's soln
In [74]: %timeit np.stack([np.tensordot(a,b,1) for a,b in zip(A,B.transpose(2,0,1))],-1)
183 ms ± 6.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [73]: %timeit func1(A,B)
158 ms ± 3.35 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
只是為了重申內(nèi)存擁塞和計(jì)算要求的重要性,假設(shè)我們也想求和減少最后一個(gè)長度軸4,那么我們將看到版本時(shí)間上的顯著差異optimal-
In [78]: %timeit np.einsum('ijkl,lui->jkui', A, B, optimize="optimal")
2.76 s ± 9.36 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [79]: %timeit np.einsum('ijkl,lui->jku', A, B, optimize="optimal")
93.8 ms ± 3.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
因此,在這種情況下,最好使用einsum.
具體到給定的問題
鑒于A和 的維度B保持不變,數(shù)組初始化out = np.empty(A.shape[1:3] + B.shape[1:])可以作為一次性事件完成,并循環(huán)遍歷對數(shù)似然函數(shù)的每次調(diào)用,并建議循環(huán)使用tensordot和更新輸出out。

TA貢獻(xiàn)1963條經(jīng)驗(yàn) 獲得超6個(gè)贊
即使在小循環(huán)中使用也tensordot快 10 倍以上:
timeit(lambda:np.einsum('ijkl,lui->jkui', A, B, optimize="optimal"),number=5)/5
# 3.052245747600682
timeit(lambda:np.stack([np.tensordot(a,b,1) for a,b in zip(A,B.transpose(2,0,1))],-1),number=10)/10
# 0.23842503569903784
out_td = np.stack([np.tensordot(a,b,1) for a,b in zip(A,B.transpose(2,0,1))],-1)
out_es = np.einsum('ijkl,lui->jkui', A, B, optimize="optimal")
np.allclose(out_td,out_es)
# True
添加回答
舉報(bào)