numpy数组的计算/操作

Kev*_*vin 4 python performance numpy sum numpy-einsum

希望尽快进行此计算.我有X作为nxm numpy数组.我想将Y定义为以下内容:

Y_11 = 1 / (exp(X_11-X_11) + exp(X_11-X_12) + ... exp(X_11 - X_1N) ).

或Y_00

1/np.sum(np.exp(X[0,0]-X[0,:]))

所以基本上,Y也是nxm,其中i,j元素是1/sum_j'exp(X_ij - X_ij')

任何提示都会很棒!谢谢.

请求的示例代码:

np.random.seed(111)
J,K = 110,120
X = np.random.rand(J,K)
Y = np.zeros((J,K))
for j in range(J):
    for k in range(K):
        Y[j,k] = 1/np.sum(np.exp(X[j,k]-X[j,:]))

# note each row will sum to 1 under this operation
np.sum(Y,axis=1)
Run Code Online (Sandbox Code Playgroud)

Div*_*kar 6

这里有一些完全矢量化的方法 -

def vectorized_app1(X):
    return 1/np.exp(X[:,None] - X[...,None]).sum(1)

def vectorized_app2(X):
    exp_vals = np.exp(X)
    return 1/(exp_vals[:,None]/exp_vals[...,None]).sum(1)

def vectorized_app3(X):
    exp_vals = np.exp(X)
    return 1/np.einsum('ij,ik->ij',exp_vals,1/exp_vals)
Run Code Online (Sandbox Code Playgroud)

使用的技巧和经验教训

  • 扩展尺寸None/np.newaxis以引入广播并以矢量化方式执行所有操作.

  • np.exp是一项昂贵的操作.因此,在广播的大阵列上使用它将是昂贵的.所以,使用的技巧是:exp(A-B) = exp(A)/exp(B).因此,我们np.exp(X)先前执行,然后执行广播的部门.

  • 这些总和减少可以用np.einsum.这带来了内存效率,因为我们不必创建巨大的广播阵列,这会带来巨大的性能提升.

运行时测试 -

In [111]: # Setup input, X
     ...: np.random.seed(111)
     ...: J,K = 110,120
     ...: X = np.random.rand(J,K)
     ...: 

In [112]: %timeit original_approach(X)
1 loop, best of 3: 322 ms per loop

In [113]: %timeit vectorized_app1(X)
10 loops, best of 3: 124 ms per loop

In [114]: %timeit vectorized_app2(X)
100 loops, best of 3: 14.6 ms per loop

In [115]: %timeit vectorized_app3(X)
100 loops, best of 3: 3.01 ms per loop
Run Code Online (Sandbox Code Playgroud)

看起来像加速einsum再次显示它的魔力100x+!