行列演算 | Python
Numpy を使った演算
リスト(配列)
Python はリスト [ ] を使って生の配列を定義します。
arr = ['a', 'b', 'c']
print(arr)
['a', 'b', 'c']
type(arr)
# <clas `list`>
Numpy ndarray ( N-dimensional array )
Numpy はベクトル・行列・テンソルを扱う ndarray を提供しています。
ベクトル
import numpy as np
arr = np.array([0, 2, 3, 4, 5])
print(arr)
# [0, 2, 3, 4, 5]
print(type(arr))
<class 'numpy.ndarray'>
行列
行列を以下のように定義する。
import numpy as np
matrix = np.array([
[1, 3, 4],
[2, 2, 1]
])
print(matrix)
# [[1 3 4]
# [2 2 1]]
print(matrix.shape)
# (1, 3)
print(np.shape(matrix))
# (1, 3)
print(np.ndim(matrix))
# 1
np.array().reshape() でも作成できます。
import numpy as np
matrix = np.array([1, 3, 4, 2, 2, 1]).reshape(2, 3)
print(matrix)
# [[1 3 4]
# [2 2 1]]
print(matrix.shape)
# (1, 3)
print(np.shape(matrix))
# (1, 3)
print(np.ndim(matrix))
# 1
Numpy の演算
スカラー積
import numpy as np
matrix = np.array([
[0, 2],
[2, 4]
])
scalar = 9
print(matrix * scalar)
# [[0 20]
# [18 40]]
スカラー和
ブロードキャストされます。
import numpy as np
matrix = np.array([
[0, 2],
[2, 4]
])
scalar = 9
print(matrix + scalar)
# [[10 12]
# [12 14]]
行列積
Numpy は行列積を $@$ またはドット積( np.dot() )で求めます。
$@$ は Python3.5 以降されました。
[!NOTE] ndarray の
*を使った積は後述するように各要素をかけ合せる演算を表します。
import numpy as np
m1 = np.array([
[0, 2],
[2, 4]
])
m2 = np.array([
[2, 2],
[0, 2]
])
print(np.dot(m1, m2))
# [[ 4 6]
# [12 14]]
$@$ でも同様に行列積を求めることができます。
import numpy as np
m1 = np.array([
[0, 2],
[2, 4]
])
m2 = np.array([
[2, 2],
[0, 2]
])
print(m1 @ m2)
# [[ 4 6]
# [12 14]]
積( * )
* 演算子は各要素の積を算出する。
このときシェイプが異なる場合はブロードキャストされる。
import numpy as np
m = np.array([
[0, 2],
[2, 4]
])
v = np.array([9, 20])
print(m * v)
# [[9 40]
# [29 80]]
ndarray メタ情報
ndarray メタ情報は ndarray.shape 、 ndarray.ndim で求めます。
import numpy as np
matrix = np.array([0, 1, 2, 3, 4, 5]).reshape(2, 3)
print(x)
# array([[0, 1, 2],
# [3, 4, 5]])
print(x.shape)
# (2, 3)
print(x.dim)
# 2
matrix1 = np.arange(0, 6).reshape(2, 3)
matrix2 = np.arange(6, 12).reshape(2, 3)
print(martix1)
# [[0 1 2]
# [3 4 5]]
print(matrix2)
# [[ 6 7 8]
# [ 9 10 11]
tensor = np.stack([matrix1, matrix2]) # 3 階テンソル( 3 次元配列)
tensor.shape
(2, 2, 3)
tensor.ndim
3
ndarray.ndim は以下のとおり。
- 1 => ベクトル
- 2 => 行列
- 3 => 3 階テンソル
テンソル
matrix1 = np.arange(0, 6).reshape(2, 3)
# [[0 1 2]
# [3 4 5]]
matrix2 = np.arange(6, 12).reshape(2, 3)
# [[ 6 7 8]
# [ 9 10 11]
# 3 階テンソル( 3 次元配列)
tensor = np.stack([matrix1, matrix2])
tensor = np.array([matrix1, matrix2])
# [[[ 0 1 2],
# [ 3 4 5]],
# [[ 6 7 8],
# [ 9 10 11]]]
np.arange(12).reshape(2, 2, 3)
# [[[ 0 1 2],
# [ 3 4 5]],
# [[ 6 7 8],
# [ 9 10 11]]]
ndarray の初期化
np.random.randn
matrix = np.random.randn(2, 3) # 平均 0, 標準偏差 1 で初期化
print(matrix)
# [[ 0.34865773 -0.11704851 0.66940347]
# [ 1.42817345 -1.23289827 -1.46875888]]
matrix = np.random.randn(2, 3) / np.sqrt(100)
>>> print(matrix)
# 標準偏差: 1/√D = 1/√100 = 0.1
# 分散: 1/D = 1/100 = 0.01
# [[-0.14391807 0.12261132 0.02211319]
# [-0.1235343 -0.15567155 0.14128749]]
np.zeros_like
NumPy で使用される関数で、「指定した配列と同じ形状(shape)とデータ型(dtype)を持ち、要素がすべて 0 の配列」を新しく作成します。
import numpy as np
# 元となる配列
a = np.array([[1, 2, 3], [4, 5, 6]])
# a と同じ形・データ型で、中身が 0 の配列を作成
b = np.zeros_like(a)
print(b)
# 出力:
# [[0 0 0]
# [0 0 0]]
Numpy axis
Numpy の axis の覚え方のコツは axis は「動く方向」として捉えて、番号の軸に沿って走ると理解する。
- axis=0 => 行の軸を走る 縦方向(行から行へ)に移動しながら計算します。結果として「列ごと」の集計値が出ます。
- axis=1 => 列の軸を走る 横方向(列から列へ)に移動しながら計算します。結果として「行ごと」の集計値が出ます。
ミニバッチを使った全結合層
# N バッチ数
# T RNN のステップ数
# D 単語 ID の分散表現の要素数
# H 隠れ状態の要素数
import numpy as np
N, T, D, H = 10, 5, 100, 10
xs = np.arange(N*T*D, dtype=float).reshape(N, T, D)
Wx = np.random.randn(D, H) # 重み行列 (D, H)
hs = np.zeros((N, T, H)) # 結果を格納 hs = np.empty((N, T, H)) などでも良い
for t in range(T):
xt = xs[:, t, :] # (N, D)
hs[:, t, :] = xt @ Wx # (N, D) @ (D, H) = (N, H)
print(hs.shape) # (10, 5, 10)