2016-09-19 14 views
4

この計算をできるだけ迅速に行うために探します。私はn×m numpyの配列としてXを持っています。だから、基本的に、Yはまた、ここで、i n×m個され、j個の要素が「1/sum_jあるnumpy配列の計算/操作

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を定義したいです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) 
+1

「exp」呼び出しは、2番目の式のどこにありますか? – user2357112

+0

私がexp()を落としたことを発見してくれてありがとう。私もいくつかのコードを追加しました。 – Kevin

+0

これは良い質問です。将来的には、今のように前書きを書くことができれば素晴らしいだろう。 –

答えて

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) 

使用したテクニックと教訓

  • 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 

einsum100x+スピードアップして再びその魔法を示したように見えます!

+0

非常に便利な答えです。すべての説明をありがとう。 –

+0

ありがとうございました!ただし、AまたはBの値が大きいため、エラーが発生することがあります。 exp(A-B)に行くことについての私の考えは、私がそれらの多くを縮め、エラーを避けるためにnp.min(A-B、200)または同様のものを入れることができるということです。他のアイデア? – Kevin

+0

@ケビンどのようなエラーが正確ですか?それは何と言いますか? expのオーバーフロー。 – Divakar

2

ここでは、二重ループを減らすことで、最初のステップです:

def foo2(X): 
    Y = np.zeros_like(X) 
    for k in range(X.shape[1]): 
     Y[:,k]=1/np.exp(X[:,[k]]-X[:,:]).sum(axis=1) 
    return Y 

私はまたkループを削除することができます疑いがあるが、私は費やす必要がそれが何をしているのかをより多くの時間把握する。そのX[:,[k]]-X[:,:]は明らかではありません(大きな画像で)。

もう一つのステップ:

Z = np.stack([X[:,[k]]-X for k in range(X.shape[1])],2) 
Y = 1/np.exp(Z).sum(axis=1) 

Z = X[:,None,:]-X[:,:,None] 
+0

偉大な答え。非常に軽微なコメント:あなたの最後のかっこでは、 "試行錯誤しすぎる" *を意味する可能性があります。 –

+0

いいえ、私はいくつかの選択肢を試しました。 'X'を3dに展開する方法はいろいろあります。そして、それを合計できる3軸。私は体系的ではなかった。 – hpaulj

関連する問題