1. Yuu-Miino

    Posted

    Yuu-Miino
Changes in title
+NumPy における行列積(matmul)についての考察
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,74 @@
+# 背景
+線形代数においては,慣例的にベクトルを列ベクトル(column vector)で定義することが多い.
+
+すなわち,$\boldsymbol{x} = \begin{bmatrix}a&b&c\end{bmatrix}$ ではなく,
+$$
+\boldsymbol{x} = \begin{bmatrix}a\\\\ b \\\\ c\end{bmatrix}
+$$
+と定義する.
+
+行列の乗法では,例えば $A$ と $B$ の積 $AB$ を考える場合には,$A$ の列数と $B$ の行数を同じ数に揃えなくてはいけない.すなわち,$A$ が $n \times m$ の行列であれば $B$ は $m \times p$ のような形でなければ,積を定義できない.
+
+列ベクトル $\boldsymbol{x}$ に 行列 $A$ を作用させる場合には,$A$ を左から掛けて $A\boldsymbol{x}$ とする.
+一方で,行ベクトル $\boldsymbol{x}$ に 行列 $A$ を作用させる場合には,$A$ を右から掛けて $\boldsymbol{x}A$ としなくてはならない.このような表記は一般的ではない[^1].
+
+# numpy.matmal での行ベクトルの扱い
+Python/NumPy の多次元配列で行列とベクトルの積([numpy.matmal](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html))を計算してみる.
+
+```Python
+>>> import numpy as np
+>>> A = np.array([[1, 2], [3, 4]])
+>>> x = np.array([[1], [2]])
+>>> A @ x # 行列積(matmul)には @ を用いる
+array([[5],
+ [11]])
+```
+
+> \* (dot product) は対象とする行列(あるいはテンソル)の次元によって異なる挙動を示すため,推奨されない.スカラ倍する場合などは \* で問題ない.
+
+これは至って問題のない結果といえる.では次の計算はどうか.
+
+```Python
+>>> A = np.array([[1, 2], [3, 4]])
+>>> x = np.array([1, 2])
+>>> A @ b
+array([5, 11])
+```
+
+これは数学的には矛盾のある結果といえる.背景部分で説明したとおり,$2 \times 2$ の行列と $1 \times 2$ のベクトルはこの順序で積を取ることができない.しかしながら,
+上記プログラムはこれを実行して結果を返している.
+
+一つ前の例からも明らかであるが, ここでは(数式的には)以下の処理が行われている.
+
+$$
+\left(A\boldsymbol{x}^\top\right)^\top
+$$
+
+すなわち,**「指定されたベクトルが行ベクトルだったので,列ベクトルになおして積を取り,結果として得られる列ベクトルを再び行ベクトルに戻して返す」**という処理を行っているのである.便利といえば便利だが,線形代数に詳しい人は少し困惑するのではなかろうか.
+
+もちろん,$\boldsymbol{x}$ が列ベクトルであるので,以下の計算については矛盾がない.
+
+```Python
+>>> b @ A
+array([7, 10])
+```
+
+それでは,再び $\boldsymbol{x}$ を行ベクトルに戻して $\boldsymbol{x} A$ の計算結果がどのようになるか見てみよう.これまでの実験の結果から,「列ベクトルも行ベクトルになおして積をとってくれるのでは」との推察が自然に導かれる.
+
+```Python
+>>> A = np.array([[1, 2], [3, 4]])
+>>> x = np.array([[1], [2]])
+>>> x @ A
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 1)
+```
+
+ところが,列ベクトルは行ベクトルへ変換されず,エラーとなってしまう.
+これはもちろん数学的には期待通りのエラーであるが,上記の推察からは外れてしまっている.
+
+# 結論
+`numpy.matmul` における**行ベクトル**は,そのコンテキストに応じて内部で列ベクトルに変換され,出力時には再度,行ベクトルへと戻される.ただし,列ベクトルについてはかような解釈は実装されていない.
+
+
+[^1]: 2020/08/07 現在