webエンジニアの日常

RubyやPython, JSなど、IT関連の記事を書いています

多次元配列のドット積の次元について

こんにちは、エンジニアのさもです。

機械学習で画像などを扱っていると、多次元配列をよく目にすると思います。

あとそれらのドット積もよくしますよね?(たぶん)

多次元配列同士のドット積の結果が、どんな形(次元)の配列になるのかよく分からなかったので調べてみました。

スポンサーリンク

import numpy as np

a = np.zeros((2,3))
b = np.zeros((3,4))

z = np.dot(a,b)

np.dotがドット積のことです。

行列(2次配列)同士のドット積であれば、


M(x,m) * N(m, y) = S(x,y)

となります。 M(x,m)は「x行m列の行列M」という意味です。

掛け算を行った結果の行列の行数は、左の行列の行数になり、列数は右の行列の列数になります。

また、かける行列同士の内側の次元(左の行列の列数と右の行列の行数)は一致していなくてはなりません。

f:id:s-uotani-zetakansu:20170915170150p:plain

内側が打ち消しあって、外側を結合するイメージです。

なんですが、3次以上の多次元配列のドット積の次元はどうなるのでしょう。

いくつか例を出してみます

  • 例1
a = np.zeros((1,2,3))
b = np.zeros((3,2,1))

np.dot(a,b).shape
#=> エラー(ValueError: shapes (1,2,3) and (3,2,1) not aligned: 3 (dim 2) != 2 (dim 1))
  • 例2
a = np.zeros((1,2,3))
b = np.zeros((2,3,1))

np.dot(a,b).shape #=> (1,2,2,1)
  • 例3
a = np.zeros((1,2,3))
b = np.zeros((3,1))

np.dot(a,b).shape #=> (1,2,1)

なんとなく分かったかも?

  • 例4
a = np.zeros((4,5,3,6,2,9))
b = np.zeros((11,12,9,13))
np.dot(a,b).shape
#=> (4, 5, 3, 6, 2, 11, 12, 13)

こんな感じです。

結論

ソースを確認していないので、確実とはいえませんが、いくつか試してみた結果、

左の配列の次元を  (l_{1}, l_{2},...,l_{n})

右の配列の次元を  (r_{1}\, r_{2},...,r_{m})

とすると、ドット積の結果の次元は、

 (l_{1}, l_{2},...,l_{n-1}, r_{1}, r_{2},...,r_{m-2},r_{m})

となりました。

 l_{n} r_{m-1}は一致している必要があるみたいです。