5

dotnumpy の関数がそのように動作する理由を理解しようとしています。

M = np.ones((9, 9))
V1 = np.ones((9,))
V2 = np.ones((9, 5))
V3 = np.ones((2, 9, 5))
V4 = np.ones((3, 2, 9, 5))

np.dot(M, V1)これで、期待どおりにnp.dot(M, V2)動作します。しかしV3V4結果は私を驚かせます:

>>> np.dot(M, V3).shape
(9, 2, 5)
>>> np.dot(M, V4).shape
(9, 3, 2, 5)

私は期待(2, 9, 5)し、(3, 2, 9, 5)それぞれ。一方、np.matmul 私が期待することはありますか: 行列の乗算は、2 番目の引数の最初のN - 2次元にわたってブロードキャストされ、結果は同じ形状になります:

>>> np.matmul(M, V3).shape
(2, 9, 5)
>>> np.matmul(M, V4).shape
(3, 2, 9, 5)

np.dotだから私の質問はこれです:それがそうするように振る舞う理由は 何ですか?それは何らかの特定の目的に役立つのでしょうか、それとも何らかの一般的な規則を適用した結果なのでしょうか?

4

4 に答える 4

7

のドキュメントnp.dotから:

2 次元配列の場合は行列の乗算に相当し、1 次元配列の場合はベクトルの内積 (複素共役なし) に相当します。N 次元の場合、 の最後の軸との最後から 2 番目の軸の積の合計ですab

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

についてnp.dot(M, V3)は、

(9, 9 ), (2, 9 , 5) --> (9, 2, 5)

についてnp.dot(M, V4)は、

(9, 9 ), (3, 2, 9 , 5) --> (9, 3, 2, 5)

取り消し線は、合計された寸法を表しているため、結果には表示されません。


対照的に、N次元配列を 2D 行列の「スタック」としてnp.matmul扱います。

動作は、次のように引数に依存します。

  • 両方の引数が 2 次元の場合、従来の行列のように乗算されます。
  • いずれかの引数が ND、N > 2の場合、最後の 2 つのインデックスに存在する行列のスタックとして扱われ、それに応じてブロードキャストされます。

どちらの場合も同じリダクションが実行されますが、軸の順序が異なります。np.matmul基本的に次と同等のことを行います:

for ii in range(V3.shape[0]):
    out1[ii, :, :] = np.dot(M[:, :], V3[ii, :, :])

for ii in range(V4.shape[0]):
    for jj in range(V4.shape[1]):
        out2[ii, jj, :, :] = np.dot(M[:, :], V4[ii, jj, :, :])
于 2015-11-29T12:13:58.753 に答える
4

のドキュメントからnumpy.matmul:

matmuldotとは 2 つの重要な点で異なります。

  • スカラーによる乗算は許可されていません。
  • 行列のスタックは、行列が要素であるかのように一緒にブロードキャストされます。

結論として、これは標準的な行列 - 行列の乗算です。

一方、numpy.dotは 2 次元配列の行列 - 行列乗算にのみ相当します。より大きな寸法の場合、...

a の最後の軸と b の最後から 2 番目の軸の合計積です。

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

[ソース: のドキュメントnumpy.dot]

これは、内積 (ドット) に似ています。ベクトルの場合、内積をnumpy.dot返します。配列はベクトルのコレクションと見なされ、それらの内積が返されます。

于 2015-11-29T12:05:27.417 に答える
2

理由について:

dotmatmultは両方とも 2D*2D 行列乗算の一般化です。しかし、数学の性質、放送規則などによると、それらは多くの可能な選択肢です...

選択肢は次のとおりでdotありmatmul、非常に異なります。 ここに画像の説明を入力

の場合dot、一部の次元 (ここでは緑) は最初の配列専用であり、他の次元 (青) は 2 番目の配列専用です。

matmulブロードキャスト ルールに関するスタックの調整が必要です。

Numpy は画像解析のコンテキストで生まれ、dotいくつかのタスクを簡単に管理できますout=dot(image(s),transformation(s))( numpy bookの初期バージョン、p92のドット ドキュメントを参照してください)。

例として:

from pylab import *
image=imread('stackoverflow.png')

identity=eye(3)
NB=ones((3,3))/3
swap_rg=identity[[1,0,2]]
randoms=[rand(3,3) for _ in range(6)]

transformations=[identity,NB,swap_rg]+randoms
out=dot(image,transformations)

for k in range(9): 
    subplot(3,3,k+1)
    imshow (out[...,k,:])

それで

現代matmulの は古い と同じことを行うことができますが、マトリックスdotのスタックを考慮する必要があります。(ここ)。matmul(image,transformations[:,None])

他の文脈でそれが優れていることは間違いありません。

于 2016-03-16T23:38:01.440 に答える
1

同等のeinsum式は次のとおりです。

In [92]: np.einsum('ij,kjm->kim',M,V3).shape
Out[92]: (2, 9, 5)
In [93]: np.einsum('ij,lkjm->lkim',M,V4).shape
Out[93]: (3, 2, 9, 5)

このように表現すると、dot同等の 'ij,lkjm->ilkm' は、'matmul' の同等の 'ij,lkjm->lkim' と同じように自然に見えます。

于 2015-11-29T22:16:16.000 に答える