📝

NumPy配列を微分する

2022/08/19に公開約25,600字

最適化アルゴリズムを数式で表す場合、和、積、微分などの演算は大抵、行列による演算を基本に作られる。一直線に並んだ数字は必要に応じて列ベクトルとか行ベクトルとかとして扱われる。けれども、実際にアルゴリズムを組み立ててプログラムに書き起こしていく際には、値の並びは基本的に配列として取り扱うことになる。

\begin{align*} a \times b\textrm{ matrix }&\bm X &\leftrightarrow&& (a,b)\textrm{ array }&X\\ a\textrm{-dim vector }&\vec x &\leftrightarrow&& (a)\textrm{ array }&x \end{align*}

すると、数式では行列、プログラム上では配列という方法で実装を進めていくことになるのだが、これが時々困惑の原因になる。というのも、数式を見ながらプログラミングしていく際に「列ベクトルと行ベクトルの積をどう表現しようか」とか、「行列を並べたデータはどう表現したものか」など、本質には関わらない割とどうでもいいところで脳のリソースが消費されてしまうのである。

このようなときに、配列を直接数式として表す方法を手元に置いておき、また配列による和、積、微分などの演算を理解しておけば、幾分かはマシになるかもしれない。そこで、この記事では特にNumPyによる配列の演算に準拠して、配列による微分演算を考える。

配列の演算

成分どうしの和

NumPyにおける+演算に相当。

# A: numpy.ndarray
# B: numpy.ndarray

A + B

配列同士の加算は、基本的に同じ形状の配列同士で実行される。

\begin{align*} A &= \begin{bmatrix} a_1&a_2&a_3 \end{bmatrix} &&\in \R^{(3)} \\ B &= \begin{bmatrix} b_1&b_2&b_3 \end{bmatrix} &&\in \R^{(3)} \\ A+B &= \begin{bmatrix} a_1+b_1&a_2+b_2&a_3+b_3 \end{bmatrix} &&\in \R^{(3)} \end{align*}

異なる形状の配列どうしは、原則、加算することができない。

\begin{align*} A &= \begin{bmatrix} \begin{bmatrix} a_{11}&a_{12} \end{bmatrix} \\ \begin{bmatrix} a_{21}&a_{22} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,2)} \\ B &= \begin{bmatrix} b_1&b_2&b_3 \end{bmatrix} &&\in \R^{(3)} \\ A+B &= \left<\textrm{broadcast error}\right> \end{align*}

アスタリスク積

NumPyにおける*演算に相当。

# A: numpy.ndarray
# B: numpy.ndarray

A * B

配列の要素どうしの積を計算する。

\begin{align*} A &= \begin{bmatrix} a_1&a_2&a_3 \end{bmatrix} &&\in \R^{(3)} \\ B &= \begin{bmatrix} b_1&b_2&b_3 \end{bmatrix} &&\in \R^{(3)} \\ A \ast B &= \begin{bmatrix} a_1b_1&a_2b_2&a_3b_3 \end{bmatrix} &&\in \R^{(3)} \end{align*}

和と同様に、原則として同じ形状の配列どうしでないと計算できない。

\begin{align*} A &= \begin{bmatrix} \begin{bmatrix} a_{11}&a_{12} \end{bmatrix} \\ \begin{bmatrix} a_{21}&a_{22} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,2)} \\ B &= \begin{bmatrix} b_1&b_2&b_3 \end{bmatrix} &&\in \R^{(3)} \\ A \ast B &= \left<\textrm{broadcast error}\right> \end{align*}

ドット積

NumPyにおけるnumpy.dot(A, B)で行われる演算。

# A: numpy.ndarray
# B: numpy.ndarray

numpy.dot(A, B)

公式ドキュメントによると、計算規則は次のとおり。

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

2階の配列同士では、線形代数における行列と同様の演算となる。

\begin{align*} A &= \begin{bmatrix} \begin{bmatrix} a_{11}&a_{12}&a_{13} \end{bmatrix} \\ \begin{bmatrix} a_{21}&a_{22}&a_{23} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,3)} \\ B &= \begin{bmatrix} \begin{bmatrix} b_{11}&b_{12}&b_{13}&b_{14} \end{bmatrix} \\ \begin{bmatrix} b_{21}&b_{22}&b_{23}&b_{24} \end{bmatrix} \\ \begin{bmatrix} b_{31}&b_{32}&b_{33}&b_{34} \end{bmatrix} \end{bmatrix} &&\in \R^{(3,4)} \\ A \cdot B &= \sum_{i=1}^3 \begin{bmatrix} \begin{bmatrix} a_{1i}b_{i1}&a_{1i}b_{i2}&a_{1i}b_{i3}&a_{1i}b_{i4} \end{bmatrix} \\ \begin{bmatrix} a_{2i}b_{i1}&a_{2i}b_{i2}&a_{2i}b_{i3}&a_{2i}b_{i4} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,4)} \end{align*}

3階以上の配列では

\begin{align*} A &= \begin{bmatrix} \begin{bmatrix} a_{11}&a_{12}&a_{13} \end{bmatrix} \\ \begin{bmatrix} a_{21}&a_{22}&a_{23} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,3)} \\ B &= \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} b_{111}&b_{112}&b_{113}&b_{114} \end{bmatrix} \\ \begin{bmatrix} b_{121}&b_{122}&b_{123}&b_{124} \end{bmatrix} \\ \begin{bmatrix} b_{131}&b_{132}&b_{133}&b_{134} \end{bmatrix} \end{bmatrix} \end{bmatrix} &&\in \R^{(1,3,4)} \\ A \cdot B &= \sum_{i=1}^3 \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} a_{1i}b_{1i1}&a_{1i}b_{1i2}&a_{1i}b_{1i3}&a_{1i}b_{1i4} \end{bmatrix} \end{bmatrix} \\ \begin{bmatrix} \begin{bmatrix} a_{2i}b_{1i1}&a_{2i}b_{1i2}&a_{2i}b_{1i3}&a_{2i}b_{1i4} \end{bmatrix} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,1,4)} \end{align*}

となる。


パッと見では何が起こっているかわからないので、もう少し良く見てみよう。演算結果を

\begin{align*} C &= A \cdot B \\ C &= \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} c_{111}&c_{112}&c_{113}&c_{114} \end{bmatrix} \end{bmatrix} \\ \begin{bmatrix} \begin{bmatrix} c_{211}&c_{212}&c_{213}&c_{214} \end{bmatrix} \end{bmatrix} \end{bmatrix} \end{align*}

と書き、上の式と照らし合わせてみる。すると、

\begin{align*} c_{111} &= \sum_{i=1}^{3}a_{1i}b_{1i1} \\ c_{112} &= \sum_{i=1}^{3}a_{1i}b_{1i2} \\ &\qquad \vdots \\ c_{214} &= \sum_{i=1}^{3}a_{2i}b_{1i4} \end{align*}

となっている。どうやら、「\cdot」の左側にあるA (第1オペランド) の要素の番号の最後と、右側にあるB (第2オペランド) の要素の番号の最後から2番めに着目して積和をとっているらしい。そして、残った番号と、その要素を配置する箇所が一致するようになっている。


以上の考察からわかるように、第1オペランドの配列の形状の最後の番号と、第2オペランドの配列の形状の最後から2番めの番号が一致していなければならない。つまり、たとえば

\begin{align*} A &\in \R^{(1,2,X)} \\ B &\in \R^{(3,4,5,X,6)} \\ A \cdot B &\in \R^{(1,2,3,4,5,6)} \end{align*}

のような場合には正常に計算ができ、演算結果C = A \cdot Bの要素については

c_{ABCDEF} = \sum_{x=1}^{X} a_{ABx}b_{CDExF}

が成り立つ。

import numpy as np

A = np.random.rand(1,2,10)
B = np.random.rand(3,4,5,10,6)

print(A.shape)
# (1,2,10)

print(B.shape)
# (3,4,5,10,6)

print(np.dot(A, B).shape)
# (1,2,3,4,5,6)

このような条件を満たさない配列は、演算を行うことができない。

\begin{align*} A &\in \R^{(1,2,3)} \\ B &\in \R^{(4,5,6,7)} \\ A \cdot B & = \left<\textrm{not aligned}\right> \end{align*}
A = np.random.rand(1,2,3)
B = np.random.rand(4,5,6,7)

print(A.shape)
# (1,2,3)

print(B.shape)
# (4,5,6,7)

print(np.dot(A, B).shape)
# ValueError

テンソルドット積

NumPyにおけるnumpy.tensordot(A, B, axes)で行われる演算。

axesをうまく指定することで変幻自在に計算できるが、これを数式で表すのはひらすら面倒くさいので、ここではaxesは整数値のみを取るものとする。

# A: numpy.ndarray
# B: numpy.ndarray

numpy.tensordot(A, B, axes=2)

axes=0の場合には、次のようになる。ここではテンソル積の記号を借りて\otimesと書くことにする (が、通常の意味のテンソル積とは異なるので注意)。

\begin{align*} A &= \begin{bmatrix} a_1&a_2 \end{bmatrix} &&\in \R^{(2)} \\ B &= \begin{bmatrix} \begin{bmatrix} b_{11}&b_{12}&b_{13} \end{bmatrix} \\ \begin{bmatrix} b_{21}&b_{22}&b_{23} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,3)} \\ A \otimes B &= \begin{bmatrix} a_1 \begin{bmatrix} \begin{bmatrix} b_{11}&b_{12}&b_{13} \end{bmatrix} \\ \begin{bmatrix} b_{21}&b_{22}&b_{23} \end{bmatrix} \end{bmatrix} \\ a_2 \begin{bmatrix} \begin{bmatrix} b_{11}&b_{12}&b_{13} \end{bmatrix} \\ \begin{bmatrix} b_{21}&b_{22}&b_{23} \end{bmatrix} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,2,3)} \end{align*}

axes=1の場合には、次のようになる。ここでは\odotと書くことにする。

\begin{align*} A &= \begin{bmatrix} a_1&a_2 \end{bmatrix} &&\in \R^{(2)} \\ B &= \begin{bmatrix} \begin{bmatrix} b_{11}&b_{12}&b_{13} \end{bmatrix} \\ \begin{bmatrix} b_{21}&b_{22}&b_{23} \end{bmatrix} \end{bmatrix} &&\in \R^{(2,3)} \\ A \odot B &= \sum_{i=1}^{2} \begin{bmatrix} a_ib_{i1}&a_ib_{i2}&a_ib_{i3} \end{bmatrix} &&\in \R^{(3)} \end{align*}

axes=1の場合、2階以下の配列についてはドット積と同じ結果が得られるが、3階以上の配列については次のように、第1オペランドの最後の要素番号と第2オペランドの最初の要素番号に着目して積和を取るため、異なる結果が得られる。

\begin{align*} A &\in \R^{(1,2,3,4)} \\ B &\in \R^{(4,5,6,7)} \\ A \odot B &\in \R^{(1,2,3,5,6,7)} \end{align*}
A = np.random.rand(1,2,3,4)
B = np.random.rand(4,5,6,7)

np.tensordot(A, B, 1)
# (1,2,3,5,6,7)

axes=2以上では次のようになる。axesの数値を表すために、演算子の右下に数字を書いておく。

\begin{align*} A &\in \R^{(1,2,3,4)} \\ B &\in \R^{(3,4,5,6)} \\ A \odot_2 B &\in \R^{(1,2,5,6)} \end{align*}
\begin{align*} A &\in \R^{(1,2,3,4)} \\ B &\in \R^{(2,3,4,5)} \\ A \odot_3 B &\in \R^{(1,5)} \end{align*}
\begin{align*} A &\in \R^{(1,2,3,4)} \\ B &\in \R^{(1,2,3,4)} \\ A \odot_4 B &\in \R^{()} \end{align*}

その他

配列をテンソルとみなして演算するための演算子に、@なるものがある。

# A: numpy.ndarray
# B: numpy.ndarray

A @ B

これは行列やベクトルの演算を線形代数におけるそれと同じように計算してくれる便利なやつだが、これを扱う際には少々注意が必要である。というのも、第1オペランドが1階の配列の場合には行ベクトルとして取り扱われ、第2オペランドが1階の配列の場合には列ベクトルとして取り扱われるのである。

このようなことが行われる背景には、1階の配列は行ベクトルでも列ベクトルでもないという事情がある。

\begin{bmatrix} 1 & 2 & 3& 4 \end{bmatrix} \to \textrm{array}

行ベクトルと列ベクトルを明確に区別しなければいけない場合には、行ベクトルは(1,n)配列として、列ベクトルは(n,1)配列として表現する必要がある。

\begin{alignat*}{2} \begin{bmatrix} \begin{bmatrix} 1&2&3&4 \end{bmatrix} \end{bmatrix} &\to&& \textrm{ row vector} \\ \begin{bmatrix} [1] \\ [2] \\ [3] \\ [4] \end{bmatrix} &\to&& \textrm{ column vector} \end{alignat*}

したがって、たとえば、

\begin{pmatrix}1\\2\\3\\4\end{pmatrix} \begin{pmatrix}1&2&3&4\end{pmatrix} = \begin{pmatrix} 1&2&3&4\\ 2&4&6&8\\ 3&6&9&12\\ 4&8&12&16\end{pmatrix}

みたいなことをやりたいときは、次のような挙動となることを理解しておきたい。

import numpy as np

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

print(A.shape)
# (4,)
print(B.shape)
# (4,)

print(A @ B)
# 30

print(np.array([A]).T @ np.array([B]))
#[[ 1  2  3  4]
# [ 2  4  6  8]
# [ 3  6  9 12]
# [ 4  8 12 16]]

これは、numpy.dot(A, B)を使用する場合も同様。

配列の微分

1階の配列同士の配列

X = \begin{bmatrix} x_1 & x_2\end{bmatrix} \in \mathbb R^{(2)}Y = \begin{bmatrix}y_1 & y_2 & y_3 \end{bmatrix} \in \mathbb R^{(3)}とする。このとき、\partial Y / \partial Xの結果としては、それが(2, 3)配列になるのか、(3, 2)配列になるのかの2通りの方法を考えることができるが、ここでは前者を採用することにする。すなわち、

\frac{\partial Y}{\partial X} = \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_1} & \dfrac{\partial y_2}{\partial x_1} & \dfrac{\partial y_3}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_2} & \dfrac{\partial y_2}{\partial x_2} & \dfrac{\partial y_3}{\partial x_2} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,3)}

これは次のように考えると分かりやすい。

\frac{\partial Y}{\partial X} = \begin{bmatrix} \dfrac{\partial Y}{\partial x_1} & \dfrac{\partial Y}{\partial x_2} \end{bmatrix} = \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_1} & \dfrac{\partial y_2}{\partial x_1} & \dfrac{\partial y_3}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_2} & \dfrac{\partial y_2}{\partial x_2} & \dfrac{\partial y_3}{\partial x_2} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,3)}

そういうわけで、以降、配列で微分した結果は、配列の各要素で微分したものを並べたものとなるというルールに従うことにする。

2階の配列を1階の配列で微分

微分される側のY(3, 4)配列にするとどうなるか。

Y = \begin{bmatrix} \begin{bmatrix} y_{11} & y_{12} & y_{13} & y_{14} \end{bmatrix} \\ \begin{bmatrix} y_{21} & y_{22} & y_{23} & y_{24} \end{bmatrix} \\ \begin{bmatrix} y_{31} & y_{32} & y_{33} & y_{34} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(3,4)}

先ほどと同じ理屈でいえば、これをXの各要素で偏微分して並べればよい。

\begin{align*} \frac{\partial Y}{\partial X} &= \begin{bmatrix} \dfrac{\partial Y}{\partial x_1} & \dfrac{\partial Y}{\partial x_2} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_{11}}{\partial x_1} & \dfrac{\partial y_{12}}{\partial x_1} & \dfrac{\partial y_{13}}{\partial x_1} & \dfrac{\partial y_{14}}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{21}}{\partial x_1} & \dfrac{\partial y_{22}}{\partial x_1} & \dfrac{\partial y_{23}}{\partial x_1} & \dfrac{\partial y_{24}}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{31}}{\partial x_1} & \dfrac{\partial y_{32}}{\partial x_1} & \dfrac{\partial y_{33}}{\partial x_1} & \dfrac{\partial y_{34}}{\partial x_1} \end{bmatrix} \end{bmatrix} \\ \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_{11}}{\partial x_2} & \dfrac{\partial y_{12}}{\partial x_2} & \dfrac{\partial y_{13}}{\partial x_2} & \dfrac{\partial y_{14}}{\partial x_2} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{21}}{\partial x_2} & \dfrac{\partial y_{22}}{\partial x_2} & \dfrac{\partial y_{23}}{\partial x_2} & \dfrac{\partial y_{24}}{\partial x_2} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{31}}{\partial x_2} & \dfrac{\partial y_{32}}{\partial x_2} & \dfrac{\partial y_{33}}{\partial x_2} & \dfrac{\partial y_{34}}{\partial x_2} \end{bmatrix} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,3,4)} \end{align*}

1階の配列を2階の配列で微分

微分する側についても考えたい。Y(3)配列に戻し、X(2, 4)配列に変更する。

X = \begin{bmatrix} \begin{bmatrix} x_{11} & x_{12} & x_{13} & x_{14} \end{bmatrix} \\ \begin{bmatrix} x_{21} & x_{22} & x_{23} & x_{24} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,4)}

この場合には、次のように考える。

\begin{align*} \frac{\partial Y}{\partial X} &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial Y}{\partial x_{11}}& \dfrac{\partial Y}{\partial x_{12}}& \dfrac{\partial Y}{\partial x_{13}}& \dfrac{\partial Y}{\partial x_{14}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial Y}{\partial x_{21}}& \dfrac{\partial Y}{\partial x_{22}}& \dfrac{\partial Y}{\partial x_{23}}& \dfrac{\partial Y}{\partial x_{24}} \end{bmatrix} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{11}}&\dfrac{\partial y_2}{\partial x_{11}}&\dfrac{\partial y_3}{\partial x_{11}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{12}}&\dfrac{\partial y_2}{\partial x_{12}}&\dfrac{\partial y_3}{\partial x_{12}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{13}}&\dfrac{\partial y_2}{\partial x_{13}}&\dfrac{\partial y_3}{\partial x_{13}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{14}}&\dfrac{\partial y_2}{\partial x_{14}}&\dfrac{\partial y_3}{\partial x_{14}} \end{bmatrix} \end{bmatrix} & \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{21}}&\dfrac{\partial y_2}{\partial x_{21}}&\dfrac{\partial y_3}{\partial x_{21}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{22}}&\dfrac{\partial y_2}{\partial x_{22}}&\dfrac{\partial y_3}{\partial x_{22}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{23}}&\dfrac{\partial y_2}{\partial x_{23}}&\dfrac{\partial y_3}{\partial x_{23}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_{24}}&\dfrac{\partial y_2}{\partial x_{24}}&\dfrac{\partial y_3}{\partial x_{24}} \end{bmatrix} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,4,3)} \end{align*}

2階の配列を2階の配列で微分

2階の配列同士の微分はどうなるのか調べていく。あまり要素を増やしすぎると書ききれなくなるので、ここではX(1,2)配列、Y(3,4)配列とする。

X = \begin{bmatrix} \begin{bmatrix} x_{11} & x_{12} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(1,2)}
Y = \begin{bmatrix} \begin{bmatrix} y_{11} & y_{12} & y_{13} & y_{14} \end{bmatrix} \\ \begin{bmatrix} y_{21} & y_{22} & y_{23} & y_{24} \end{bmatrix} \\ \begin{bmatrix} y_{31} & y_{32} & y_{33} & y_{34} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(3,4)}

やることは変わらない。

\begin{align*} \frac{\partial Y}{\partial X} &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial Y}{\partial x_{11}} & \dfrac{\partial Y}{\partial x_{12}} \end{bmatrix} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_{11}}{\partial x_{11}} & \dfrac{\partial y_{12}}{\partial x_{11}} & \dfrac{\partial y_{13}}{\partial x_{11}} & \dfrac{\partial y_{14}}{\partial x_{11}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{21}}{\partial x_{11}} & \dfrac{\partial y_{22}}{\partial x_{11}} & \dfrac{\partial y_{23}}{\partial x_{11}} & \dfrac{\partial y_{24}}{\partial x_{11}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{31}}{\partial x_{11}} & \dfrac{\partial y_{32}}{\partial x_{11}} & \dfrac{\partial y_{33}}{\partial x_{11}} & \dfrac{\partial y_{34}}{\partial x_{11}} \end{bmatrix} \end{bmatrix} \\ \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_{11}}{\partial x_{12}} & \dfrac{\partial y_{12}}{\partial x_{12}} & \dfrac{\partial y_{13}}{\partial x_{12}} & \dfrac{\partial y_{14}}{\partial x_{12}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{21}}{\partial x_{12}} & \dfrac{\partial y_{22}}{\partial x_{12}} & \dfrac{\partial y_{23}}{\partial x_{12}} & \dfrac{\partial y_{24}}{\partial x_{12}} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_{31}}{\partial x_{12}} & \dfrac{\partial y_{32}}{\partial x_{12}} & \dfrac{\partial y_{33}}{\partial x_{12}} & \dfrac{\partial y_{34}}{\partial x_{12}} \end{bmatrix} \end{bmatrix} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(1,2,3,4)} \end{align*}

一般化

ここから先、3階の配列、4階の配列、…といきたいところではあるが、これ以上増やしていっても凄まじい結果になることは目に見えているので、ここではもっと賢明に、配列の形状に着目して一般化していく。

ここまでの1階の配列、2階の配列の微分についてまとめると、

\begin{align*} X &\in \mathbb R^{(2)} & Y &\in \mathbb R^{(3)} & \implies && \frac{\partial Y}{\partial X} &\in \mathbb R^{(2,3)} \\ X &\in \mathbb R^{(2)} & Y &\in \mathbb R^{(3,4)} & \implies && \frac{\partial Y}{\partial X} &\in \mathbb R^{(2,3,4)} \\ X &\in \mathbb R^{(2,4)} & Y &\in \mathbb R^{(3)} & \implies && \frac{\partial Y}{\partial X} &\in \mathbb R^{(2,4,3)} \\ X &\in \mathbb R^{(1,2)} & Y &\in \mathbb R^{(3,4)} & \implies && \frac{\partial Y}{\partial X} &\in \mathbb R^{(1,2,3,4)} \end{align*}

であった。このことから一般に\alpha, \betaを整数値のタプルとするとき、

\begin{align*} X &\in \mathbb R^{\alpha} & Y &\in \mathbb R^{\beta} & \implies && \frac{\partial Y}{\partial X} &\in \mathbb R^{(\alpha,\beta)} \end{align*}

が成り立つように見える。たとえば\alpha = (1,2,3,4), \beta = (5,6,7)であるような場合には、

\frac{\partial Y}{\partial X} \in \R^{(1,2,3,4,5,6,7)}

と考えるのが妥当だろう。

実際、配列で微分するときは、配列の各要素で偏微分したものを並べるのだというルールに従えば、これは確かに成り立つことがわかる (詳細は略)。

合成関数の微分

1階の配列の合成関数の微分

関数f:\mathbb R^2 \to \mathbb R^3を用いて

Y = f(X) \in \mathbb R^{(3)}

関数g: \mathbb R^3 \to \mathbb R^4を用いて

Z = g(Y) \in \mathbb R^{(4)}

とする。ZXで微分すると、

\begin{align*} \frac{\partial Z}{\partial X} &= \begin{bmatrix} \dfrac{\partial Z}{\partial x_1} & \dfrac{\partial Z}{\partial x_2} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial z_1}{\partial x_1} & \dfrac{\partial z_2}{\partial x_1} & \dfrac{\partial z_3}{\partial x_1} & \dfrac{\partial z_4}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial x_2} & \dfrac{\partial z_2}{\partial x_2} & \dfrac{\partial z_3}{\partial x_2} & \dfrac{\partial z_4}{\partial x_2} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,4)} \end{align*}

である。一方、

\begin{align*} \frac{\partial Z}{\partial Y} &= \begin{bmatrix} \dfrac{\partial Z}{\partial y_1}& \dfrac{\partial Z}{\partial y_2}& \dfrac{\partial Z}{\partial y_3} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} & \dfrac{\partial z_2}{\partial y_1} & \dfrac{\partial z_3}{\partial y_1} & \dfrac{\partial z_4}{\partial y_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial y_2} & \dfrac{\partial z_2}{\partial y_2} & \dfrac{\partial z_3}{\partial y_2} & \dfrac{\partial z_4}{\partial y_2} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial y_3} & \dfrac{\partial z_2}{\partial y_3} & \dfrac{\partial z_3}{\partial y_3} & \dfrac{\partial z_4}{\partial y_3} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(3,4)} \end{align*}
\frac{\partial Y}{\partial X} = \begin{bmatrix} \dfrac{\partial Y}{\partial x_1} & \dfrac{\partial Y}{\partial x_2} \end{bmatrix} = \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_1} & \dfrac{\partial y_2}{\partial x_1} & \dfrac{\partial y_3}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_2} & \dfrac{\partial y_2}{\partial x_2} & \dfrac{\partial y_3}{\partial x_2} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,3)}

であり、これらのドット積を取ると

\begin{align*} \frac{\partial Y}{\partial X} \cdot \frac{\partial Z}{\partial Y} &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial y_1}{\partial x_1} & \dfrac{\partial y_2}{\partial x_1} & \dfrac{\partial y_3}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial y_1}{\partial x_2} & \dfrac{\partial y_2}{\partial x_2} & \dfrac{\partial y_3}{\partial x_2} \end{bmatrix} \end{bmatrix} \cdot \begin{bmatrix} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} & \dfrac{\partial z_2}{\partial y_1} & \dfrac{\partial z_3}{\partial y_1} & \dfrac{\partial z_4}{\partial y_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial y_2} & \dfrac{\partial z_2}{\partial y_2} & \dfrac{\partial z_3}{\partial y_2} & \dfrac{\partial z_4}{\partial y_2} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial y_3} & \dfrac{\partial z_2}{\partial y_3} & \dfrac{\partial z_3}{\partial y_3} & \dfrac{\partial z_4}{\partial y_3} \end{bmatrix} \end{bmatrix} \\ &= \begin{bmatrix} \dfrac{\partial y_1}{\partial x_1} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} \\ \dfrac{\partial z_2}{\partial y_1} \\ \dfrac{\partial z_3}{\partial y_1} \\ \dfrac{\partial z_4}{\partial y_1} \end{bmatrix} + \dfrac{\partial y_2}{\partial x_1} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_2} \\ \dfrac{\partial z_2}{\partial y_2} \\ \dfrac{\partial z_3}{\partial y_2} \\ \dfrac{\partial z_4}{\partial y_2} \end{bmatrix} + \dfrac{\partial y_3}{\partial x_1} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_3} \\ \dfrac{\partial z_2}{\partial y_3} \\ \dfrac{\partial z_3}{\partial y_3} \\ \dfrac{\partial z_4}{\partial y_3} \end{bmatrix} \\ \dfrac{\partial y_1}{\partial x_2} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} \\ \dfrac{\partial z_2}{\partial y_1} \\ \dfrac{\partial z_3}{\partial y_1} \\ \dfrac{\partial z_4}{\partial y_1} \end{bmatrix} + \dfrac{\partial y_2}{\partial x_2} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_2} \\ \dfrac{\partial z_2}{\partial y_2} \\ \dfrac{\partial z_3}{\partial y_2} \\ \dfrac{\partial z_4}{\partial y_2} \end{bmatrix} + \dfrac{\partial y_3}{\partial x_2} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_3} \\ \dfrac{\partial z_2}{\partial y_3} \\ \dfrac{\partial z_3}{\partial y_3} \\ \dfrac{\partial z_4}{\partial y_3} \end{bmatrix} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} \dfrac{\partial y_1}{\partial x_1} + \dfrac{\partial z_1}{\partial y_2} \dfrac{\partial y_2}{\partial x_1} + \dfrac{\partial z_1}{\partial y_3} \dfrac{\partial y_3}{\partial x_1} \\ \dfrac{\partial z_2}{\partial y_1} \dfrac{\partial y_1}{\partial x_1} + \dfrac{\partial z_2}{\partial y_2} \dfrac{\partial y_2}{\partial x_1} + \dfrac{\partial z_2}{\partial y_3} \dfrac{\partial y_3}{\partial x_1} \\ \dfrac{\partial z_3}{\partial y_1} \dfrac{\partial y_1}{\partial x_1} + \dfrac{\partial z_3}{\partial y_2} \dfrac{\partial y_2}{\partial x_1} + \dfrac{\partial z_3}{\partial y_3} \dfrac{\partial y_3}{\partial x_1} \\ \dfrac{\partial z_4}{\partial y_1} \dfrac{\partial y_1}{\partial x_1} + \dfrac{\partial z_4}{\partial y_2} \dfrac{\partial y_2}{\partial x_1} + \dfrac{\partial z_4}{\partial y_3} \dfrac{\partial y_3}{\partial x_1} \\ \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial y_1} \dfrac{\partial y_1}{\partial x_2} + \dfrac{\partial z_1}{\partial y_2} \dfrac{\partial y_2}{\partial x_2} + \dfrac{\partial z_1}{\partial y_3} \dfrac{\partial y_3}{\partial x_2} \\ \dfrac{\partial z_2}{\partial y_1} \dfrac{\partial y_1}{\partial x_2} + \dfrac{\partial z_2}{\partial y_2} \dfrac{\partial y_2}{\partial x_2} + \dfrac{\partial z_2}{\partial y_3} \dfrac{\partial y_3}{\partial x_2} \\ \dfrac{\partial z_3}{\partial y_1} \dfrac{\partial y_1}{\partial x_2} + \dfrac{\partial z_3}{\partial y_2} \dfrac{\partial y_2}{\partial x_2} + \dfrac{\partial z_3}{\partial y_3} \dfrac{\partial y_3}{\partial x_2} \\ \dfrac{\partial z_4}{\partial y_1} \dfrac{\partial y_1}{\partial x_2} + \dfrac{\partial z_4}{\partial y_2} \dfrac{\partial y_2}{\partial x_2} + \dfrac{\partial z_4}{\partial y_3} \dfrac{\partial y_3}{\partial x_2} \\ \end{bmatrix} \end{bmatrix} \\ &= \begin{bmatrix} \begin{bmatrix} \dfrac{\partial z_1}{\partial x_1} & \dfrac{\partial z_2}{\partial x_1} & \dfrac{\partial z_3}{\partial x_1} & \dfrac{\partial z_4}{\partial x_1} \end{bmatrix} \\ \begin{bmatrix} \dfrac{\partial z_1}{\partial x_2} & \dfrac{\partial z_2}{\partial x_2} & \dfrac{\partial z_3}{\partial x_2} & \dfrac{\partial z_4}{\partial x_2} \end{bmatrix} \end{bmatrix} \in \mathbb R^{(2,4)} \end{align*}

ただし、最後の行ではスカラーの偏微分の連鎖律

\frac{\partial z_1}{\partial x_1} = \frac{\partial z_1}{\partial y_1} \frac{\partial y_1}{\partial x_1} + \frac{\partial z_1}{\partial y_2} \frac{\partial y_2}{\partial x_1} + \frac{\partial z_1}{\partial y_3} \frac{\partial y_3}{\partial x_1}

を適用した。以上のことから、1階の配列どうしについてはドット積を用いた連鎖律が成り立つことがわかる。

\frac{\partial Z}{\partial X} = \frac{\partial Y}{\partial X} \cdot \frac{\partial Z}{\partial Y}

高階の配列の合成関数の微分

より高階の配列についても同様のことが言える。たとえば、Yが2階の配列であるような場合、形状を見ると

\begin{align*} & \left\{\begin{aligned} Z &\in \R^{(2)} \\ Y &\in \R^{(3,4)} \\ X &\in \R^{(5,6)} \end{aligned}\right. \\ \implies& \left\{\begin{aligned} \frac{\partial Z}{\partial Y} &\in \R^{(3,4,2)} \\ \frac{\partial Y}{\partial X} &\in \R^{(5,6,3,4)} \\ \frac{\partial Z}{\partial X} &\in \R^{(5,6,2)} \end{aligned}\right. \\ \implies& \left\{\begin{aligned} \frac{\partial Y}{\partial X} \odot_2 \frac{\partial Z}{\partial Y} &\in \R^{(5,6,2)} \end{aligned}\right. \end{align*}

であり、またスカラーの連鎖律を利用することで、

\frac{\partial Z}{\partial X} = \frac{\partial Y}{\partial X} \odot_2 \frac{\partial Z}{\partial Y}

が容易に示せる (めっっっっちゃ煩雑になるけど)。より一般に、Yの階数がn_yであるような場合、

\frac{\partial Z}{\partial X} = \frac{\partial Y}{\partial X} \odot_{n_y} \frac{\partial Z}{\partial Y}

が成り立つ。

まとめ

  • NumPy配列独自の計算ルールがあるが、慣れれば怖くない。数式でも表せる。
  • ベクトルと1階の配列は別物なので、特に注意。
  • 2階の配列はベクトルや行列との互換性がある。
  • 配列での微分は、「微分する方の各要素」で「微分される方の各要素」を偏微分したものを並べれば良い。
  • 配列での微分にも、連鎖律を考えることができる。

参考文献

  1. NumPy 公式ドキュメント https://numpy.org/doc/stable/reference/generated/numpy.dot.html

Discussion

ログインするとコメントできます