ブロードキャスト
配列と配列の間で行われる四則演算は、同じ形状のもの同士で行われる。
もし形状が異なる場合には、よりサイズの小さいものを大きいものと同じサイズに展開し、同じサイズに揃えようとする処理が試みられる。これをブロードキャストという。NumPy の配列や PyTorch のテンソルを用いた計算を行う際に行われている。 
code:broadcast1.py
import numpy as np
a = np.array(3) # 0次元(スカラー)
b = np.array(1, 2, 3) # 1次元
c = np.array(1, 2, 3], [4, 5, 6) # 2次元
print('# 形状の確認')
print(a.shape, '\n', a) # 0次元
print(b.shape, '\n', b) # 1次元
print(c.shape, '\n', c) # 2次元
まず、配列を用意した。
0次元と1次元の計算
0次元(スカラー型、角括弧無しで表示されるもの)と1次元の配列の間で計算を行う例を示す。
code:(続き).py
print('# 0次元と1次元')
x = a + b # (1)
y = a * b
z = a / b
print(x)
print(y)
print(z)
上の計算式のうちで、加算演算子「+」の場合 (1) で行われる処理を説明する。
$ a + \left[\begin{array}{ccc} b_0 & b_1 & b_2 \end{array}\right]
まずサイズが小さい方の$ aが、$ bと同じ形状に展開され、1次元の配列が生成される。
$ \Rightarrow \left[\begin{array}{c|c|c} a & a & a \end{array}\right] + \left[\begin{array}{ccc} b_0 & b_1 & b_2 \end{array}\right]
そのうえで、対応する要素毎に、演算子に基づいた計算が行われる。
$ \Rightarrow \left[\begin{array}{ccc} a + b_0 & a + b_1 & a + b_2 \end{array}\right]
0次元と2次元の計算
code:(続き).py
print('# 0次元と2次元')
x = a + c
y = a * c # (1)
z = a / c
print(x)
print(y)
print(z)
乗算演算子「*」の場合、
$ a * \left[\begin{array}{ccc} c_{00} & c_{01} & c_{02} \\ c_{10} & c_{11} & c_{12} \end{array}\right]
スカラ型の変数$ aは下/横方向に展開され、2次元の配列が生成される。
$ \Rightarrow \left[\begin{array}{c|c|c} a & a & a \\ \hline a & a & a \end{array}\right] * \left[\begin{array}{ccc} c_{00} & c_{01} & c_{02} \\ c_{10} & c_{11} & c_{12} \end{array}\right]
対応する要素同士で演算が行われる。
$ \Rightarrow \left[\begin{array}{ccc} a * c_{00} & a * c_{01} & a * c_{02} \\ a * c_{10} & a * c_{11} & a * c_{12} \end{array}\right]
1次元と2次元の計算
code:(続き).py
print('# 1次元と2次元')
x = b - c
y = b * c
z = b / c
print(x)
print(y)
print(z)
減算演算子「$ -」の場合、
$ \left[\begin{array}{ccc} b_{0} & b_{1} & b_{2} \end{array}\right] - \left[\begin{array}{ccc} c_{00} & c_{01} & c_{02} \\ c_{10} & c_{11} & c_{12} \end{array}\right]
$ bは縦方向に展開される。
$ \Rightarrow \left[\begin{array}{ccc} b_{0} & b_{1} & b_{2} \\ \hline b_{0} & b_{1} & b_{2} \end{array}\right] - \left[\begin{array}{ccc} c_{00} & c_{01} & c_{02} \\ c_{10} & c_{11} & c_{12} \end{array}\right]
要素毎に計算が行われる。
$ \Rightarrow \left[\begin{array}{ccc} b_0 - c_{00} & b_1 - c_{01} & b_2 - c_{02} \\ b_0 - c_{10} & b_1 - c_{11} & b_2 - c_{12} \end{array}\right]
以上のように、1次元配列$ bを展開し、2次元配列$ cと同じ形状に揃えた上で、やはり対応する要素の間で計算を行う。
2次元同士だが、形状が異なる場合
code:broadcast2.py
import numpy as np
x = np.array(2, 8, 6], [6, 3, 9)
y = np.array(2], [3)
z = x / y
print('# 形状の確認')
print('x:', x.shape, '\n', x)
print('y:', y.shape, '\n', y)
print('z:', z.shape, '\n', z)
これは
$ \left[\begin{array}{ccc} x_{00} & x_{01} & x_{02} \\ x_{10} & x_{11} & x_{12} \end{array}\right] / \left[\begin{array}{c} y_{0} \\ y_{1} \end{array}\right]
yが横方向に展開される。
$ \Rightarrow \left[\begin{array}{ccc} x_{00} & x_{01} & x_{02} \\ x_{10} & x_{11} & x_{12} \end{array}\right] / \left[\begin{array}{c|c|c} y_{0} & y_{0} & y_{0} \\ y_{1} & y_{1} & y_{1} \end{array}\right]
要素ごとに除算が行われる。
$ \Rightarrow \left[\begin{array}{ccc} x_{00} / y_{0} & x_{01}/y_{0} & x_{02}/y_{0} \\ x_{10}/y_{1} & x_{11}/y_{1} & x_{12}/y_{1} \end{array}\right]
もし、形状を揃えることが出来なければエラーを吐いて停止する。
/icons/hr.icon
※ ブラウザのバックボタンで戻る
https://scrapbox.io/files/65041f13dff5b1001bdd1427.png