アプローチ#1はここを使用してmatrix-multiplication
とワンライナーベクトル化のアプローチだとNumPy broadcasting
-
dWout -= (np.arange(dW.shape[1])[:,None] == y).dot(X).T
説明:何が起こっているか理解するために、小さな例を見てみましょう -
入力を:
In [259]: X
Out[259]:
array([[ 0.80195208, 0.40566743, 0.62585574, 0.53571781],
[ 0.56643339, 0.4635662 , 0.4290103 , 0.14457036],
[ 0.31823491, 0.12329964, 0.41682841, 0.09544716]])
In [260]: y
Out[260]: array([1, 2, 2])
まず、dWの第2軸の長さに渡ってy
インデックスの2Dマスクを作成します。
dW
を4 x 5
の形状の配列とする。だから、マスクは次のようになります。これは2D
マスクを作成するためにここにNumPy broadcasting
を使用している
In [261]: mask = (np.arange(dW.shape[1])[:,None] == y)
In [262]: mask
Out[262]:
array([[False, False, False],
[ True, False, False],
[False, True, True],
[False, False, False],
[False, False, False]], dtype=bool)
。アップ
次に、我々は和集合体には、同じインデックスをy
からマトリックス乗算を使用 -
In [264]: mask.dot(X)
Out[264]:
array([[ 0. , 0. , 0. , 0. ],
[ 0.80195208, 0.40566743, 0.62585574, 0.53571781],
[ 0.8846683 , 0.58686584, 0.84583872, 0.24001752],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]])
したがって、第二および第三列でTrue
値を持つマスクの第3行に対応する、我々 2番目と3番目の行をX
からその行列乗算で合計します。これは、乗算出力の第3行として配置される。
元のループコードでは、列全体でdW
を更新しているので、乗算結果を転置して更新する必要があります。
アプローチ#2ここでワンライナーがnp.add.reduceat
使用していないが、別のベクトル化の方法だ - ベクトル化する簡単な方法は次のようになり
sidx = y.argsort()
unq,shift_idx = np.unique(y[sidx],return_index=True)
dWout[:,unq] -= np.add.reduceat(X[sidx],shift_idx,axis=0).T
Pythonでの索引付けは1つのことです。 NumPyのインデックス作成は別のものです。 Python + NumPyコンボは強力なツールですが、まったく新しい言語に似ています。 –