人工知能エンジニア修行日記

主に機械学習、深層学習、Python、数学について覚え書きを記します

ニューラルネットワーク計算準備としてNumPyで多次元配列処理(内積=ドット積)

f:id:kaeken:20161105113024p:plain 『ゼロから作るDeep Learning』3章続き。 ニューラルネットワークの実装で多次元配列が必要。 そこでPythonのNumPyの多次元配列操作を改めて詳しく学ぶ。

>>> import numpy as np
>>> A = np.array([ [1,2], [3,4], [5,6] ])

>>> A
array([[1, 2],
       [3, 4],
       [5, 6]])

>>> A.shape # 配列の各次元の大きさをタプルで返す
(3, 2)

>>> A.ndim # 配列の次元数
2

# 次元が統一されていない場合は、1次元扱いの様子
>>> B = np.array([ [1], [2,3], [4,5,6] ])
>>> B
array([[1], [2, 3], [4, 5, 6]], dtype=object)
>>> B.shape
(3,)
>>> B.ndim
1

>>> C = np.array([ [1,2,3], [4,5], [6] ])
>>> C
array([[1, 2, 3], [4, 5], [6]], dtype=object)
>>> C.shape
(3,)
>>> C.ndim
1

# 続いて内積
# 行列の内積とは、行と列の要素ごとの積と和によって計算する
# 2次元配列は行列matrixと呼び、横方向の行rowと縦方向の列columnがある

>>> A = np.array([ [1,2], [3,4] ]) 
>>> A
array([[1, 2],
       [3, 4]])
>>> A.shape
(2, 2)

>>> B = np.array([ [5,6], [7,8] ])
>>> B
array([[5, 6],
       [7, 8]])
>>> B.shape
(2, 2)

>>> np.dot(A, B) # 行列A,Bの内積(ドット積)
array([[19, 22],
       [43, 50]])

#計算内容内訳
>>> 1*5 + 2*7
19
>>> 3*5 + 4*7
43
>>> 1*6 + 2*8
22
>>> 3*6 + 4*8
50

#行列の積は、被演算子(A,B)の順番が異なると結果も異なる
>>> np.dot(B, A)
array([[23, 34],
       [31, 46]])

#続いて、2x3の行列と3x2の行列の積
>>> C = np.array([ [1,2,3], [4,5,6] ])
>>> C
array([[1, 2, 3],
       [4, 5, 6]])
>>> C.shape
(2, 3)

>>> D = np.array([ [1,2], [3,4], [5,6] ])
>>> D
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> D.shape
(3, 2)

>>> np.dot(C, D)
array([[22, 28],
       [49, 64]])
>>> np.dot(C, D).shape
(2, 2)

#逆
>>> np.dot(D, C)
array([[ 9, 12, 15],
       [19, 26, 33],
       [29, 40, 51]])
>>> np.dot(D, C).shape
(3, 3)


>>> # 内積できる行列の形状には条件がある
... # 行列Aの1次元目の要素数(列数)と
... # 行列Bの0次元目の要素数(行数)を同じにする必要がある

>>> # 2x3行列と3x2行列は内積できるが、
... # 2x3行列と2x3行列の内積はできない

>>> C
array([[1, 2, 3],
       [4, 5, 6]])
>>> E = C
>>> E
array([[1, 2, 3],
       [4, 5, 6]])

>>> C.shape
(2, 3)
>>> E.shape
(2, 3)

>>> np.dot(C, E)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shapes (2,3) and (2,3) not aligned: 3 (dim 1) != 2 (dim 0)

# 再度確認
>>> C.shape[1]
3
>>> D.shape[0]
3
>>> E.shape[0]
2

# バリデーション
>>> if C.shape[1] == D.shape[0]:
...   print('.dot() OK!')
... else:
...   print('.dot() NG!')
...
.dot() OK!

>>> if C.shape[1] == E.shape[0]:
...   print('.dot() OK!')
... else:
...   print('.dot() NG!')
...
.dot() NG!

以上、行列演算を活用してニューラルネットワークの計算を効率化していく。

参考:

行列の乗法 - Wikipedia