这里有一些完全矢量化的方法 –
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)
使用的技巧和经验教训
>使用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
看起来einsum再次以100倍的加速速度展示了它的魔力!