からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

5.2:連鎖率【ゼロつく1のノート(数学)】

はじめに

 「機械学習・深層学習」学習初手『ゼロから作るDeep Learning』民のための数学攻略ノートです。『ゼロつく1』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。

 NumPy関数を使って実装できてしまう計算について、数学的背景を1つずつ確認していきます。

 この記事は、5.2節「連鎖率」の内容になります。解析的な微分・偏微分の求め方と、連鎖率(合成関数の微分)と計算グラフの対応関係について説明します。

【前節の内容】

www.anarchive-beta.com

【他の節の内容】

www.anarchive-beta.com

【この節の内容】

微分

 4.3節では数値微分について説明しました。この節では解析的に求める微分について(本で必要になる内容のみ)説明します。

 変数$x$の関数を$f(x)$としたとき、導関数

$$ \frac{d f(x)}{d x} = \lim_{h \leftarrow 0} \frac{ f(x + h) - f(x) }{ h } \tag{4.4} $$

を求めることを微分すると言います。この導関数$\frac{d f(x)}{d x}$は、変数$x$が微小に変化したときの関数$f(x)$の変化量を表すのでした。また$\frac{d f(x)}{d x}$は、$f(x)$の(上の点$(x, f(x))$を接点とする)接線の傾きになるのでした。
 数値微分では、$h$に小さな値を代入して計算することで、導関数を求める(微分する)のでした(4.3.1項)。

 解析的な微分では、次の公式に従い導関数$\frac{d f(x)}{d x}$を求めます(微分します)。(それ以上のことは専門書を読んでください、、、一応ここに書いた事柄だけでこの先の内容を理解できるように書いています(つもりです)。)

 関数$f(x)$を

$$ f(x) = a x^n + b $$

とすると、$\frac{d f(x)}{d x}$は

$$ \frac{d f(x)}{d x} = a n x^{n-1} $$

になります。このことを「式を

$$ y = a x^n + b $$

として、$y$を$x$で微分すると

$$ \frac{d y}{d x} = a n x^{n-1} $$

になります。」といった表現をすることもありますが、やっていることは同じです。

 つまり変数$x$の、係数(この例だと$a$)と指数(この例だと$n$)と指数から1を引いた$x^{n-1}$の積になります。また変数に関わらない項(定数:この例だと$b$)は0になります。

 ちなみに、$x$を$x$で微分すると($x = x^1$なので)

$$ \begin{aligned} \frac{d x}{d x} &= 1 * x^{1-1} \\ &= 1 \end{aligned} $$

になります。

 これは上の(でも下のでもどれでもいいので)式$y$を$y$で微分しても$\frac{d y}{d y} = 1$になるということです。これはつまり$a x^n + b$を変数として、$y$(すなわち$a x^n + b$)を$a x^n + b$で微分すると1になることを表します。

 ちなみにちなみに、$x$の0乗は1です。これは

$$ \begin{aligned} x^2 &= x^2 \\ x^1 &= x \\ x^0 &= 1 \\ x^{-1} &= \frac{1}{x} \\ x^{-2} &= \frac{1}{x^2} \end{aligned} $$

という関係を並べると理解しやすいと思います。マイナスの指数は分数を表します!

 $x^2 = x^1 * x^1$であるように、$x^0 = 1$に$x^1$を掛けると$x^1 = x$になり、$x^{-1} = \frac{1}{x}$に$x^1$を掛けると$x^0 = 1$になりますよね。では$x^{-2}$と$x^{-3}$の積は?$x^{-2} * x^{-3} = x^{-2+(-3)} = \frac{1}{x^5}$です!

 分数も公式に従って解析的に微分の計算ができます。$\frac{1}{x}$を$x$で微分すると

$$ \begin{aligned} \frac{d x^{-1}}{d x} &= -1 * x^{-1-1} \\ &= - x^{-2} \\ &= -\frac{1}{x^2} \end{aligned} $$

になります。

 この内容が必要になる場合は、上の内容を適宜注釈として書いているので、今すぐに覚えなくても大丈夫です。このレジュメを進めていれば自然と記憶に残ると思います!

 では話戻って、具体的な値を使って微分を解析的に求めてみましょう!

$$ y = 2 x^2 + 2 $$

を$x$で微分すると

$$ \begin{aligned} \frac{d y}{d x} &= 2 * 2 * x^{2-1} + 0 \\ &= 4 x \end{aligned} $$

となります。

 プログラムからも確認してみましょう。接点の$x$軸の値を5とします。

# この節で利用するライブラリを読み込む
import numpy as np
import matplotlib.pyplot as plt


# 値を指定
a = 2
b = 2
n = 2
x = 5

# 微分:接線の傾き
dx = a * n * x ** (n - 1)

# 接点のy軸の値
y = a * x ** n + b

# 接線の切片
b2 = y - dx * x

# 作図用のx軸の値
x_vec = np.arange(-10.0, 10.0, 0.1)

# 作図
plt.plot(x_vec, a * x_vec ** n + b, label="f(x)") # 元の関数
plt.plot(x_vec, dx * x_vec + b2, label="f'(x)") # 接線
plt.xlabel("x") # x軸ラベル
plt.ylabel("y") # y軸ラベル
plt.legend() # 凡例
plt.show()

$f(x)$と$f'(x)$の関係

 次は少し式を難しくして

$$ y = 2 x^3 + 4 $$

を$x$で微分すると

$$ \begin{aligned} \frac{d y}{d x} &= 2 * 3 * x^{3-1} + 0 \\ &= 6 x^2 \end{aligned} $$

となります。

 これも作図してみます(変数(オブジェクト)の値を変えただけです)。

$f(x)$と$f'(x)$の関係

 ちゃんと接線の傾きとなっていますね!

偏微分

 変数が複数ある関数の場合に、1つの変数のみに注目して他の変数を定数として微分することを偏微分と呼ぶのでした(4.3.3項)。解析的に求める偏微分も微分と同様に、公式に従って求められます。

 変数を$\mathbf{x} = (x_1, x_2)$として、その関数

$$ f(\mathbf{x}) = \beta_0 + \beta_1 x_1 + \beta_2 x_2 $$

を$x_1$で偏微分すると

$$ \begin{aligned} \frac{\partial f(\mathbf{x})}{\partial x_1} &= 0 + \beta_1 * 1 + 0 \\ &= \beta_1 \end{aligned} $$

になります。後の項はあくまで$x_2$であって$x_1$とは無関係なので、0になります。

 式を

$$ y = \beta_0 + \beta_1 x_1^m + \beta_2 + x_2^n $$

として、この式を$x_2$で偏微分すると

$$ \begin{aligned} \frac{\partial y}{\partial x_2} &= 0 + 0 + \beta_2 * n * x_2^{n-1} \\ &= \beta_2 n x_2^{n-1} \end{aligned} $$

になります。$x_2$で偏微分する場合は$x_1$を定数として扱います。

 偏微分の導関数$\frac{\partial y}{\partial x_2}$を示す$\partial$は、$d$のギリシャ文字に由来する文字です。要は違う(でも意味合いは近い)記号を使うことで、微分と偏微分を区別しているだけです。レジュメ(本)では、$y$を$x_1$で偏微分することを$x_1$に関する$y$の微分のように、微分と言うことが多々あります。

5.2 連鎖率

5.2.2 連鎖率とは

 変数$x$と$y$の関数

$$ z = (2 x + y)^2 $$

を$x$で微分することを考えます。この関数は、2つの関数

$$ \begin{align} z &= t^2 \\ t &= x + y \tag{5.1} \end{align} $$

によって構成されているといえます。このように、複数の関数によって構成される関数を合成関数と呼びます。
 このとき、$x$に関する$z$の微分$\frac{\partial z}{\partial x}$は

$$ \frac{\partial z}{\partial x} = \frac{\partial z}{\partial t} \frac{\partial t}{\partial x} \tag{5.2} $$

で求めることができます。このように合成関数の微分は、「$t$に関する$z$の微分$\frac{\partial z}{\partial t}$」と「$x$に関する$t$の微分$\frac{\partial t}{\partial x}$」の積のように、それぞれの関数の微分の積で求められます。また合成関数の微分のことを連鎖率とも呼びます。

 よってそれぞれの項を計算すると

$$ \frac{\partial z}{\partial t} = 2 t $$

であり、また

$$ \frac{\partial t}{\partial x} = 1 $$

なので、2つの積は

$$ \begin{align} \frac{\partial z}{\partial x} &= \frac{\partial z}{\partial t} \frac{\partial t}{\partial x} \tag{5.2}\\ &= 2 t * 1 \\ &= 2 (x + y) \tag{5.4} \end{align} $$

となります。(流石に最初の式の括弧の指数を下ろしてきて指数から1引いただけで求まるわけではないですよ。これは括弧の中身が簡単だったからなだけです。)

 これで証明になる訳ではありませんが、最初の式を展開して微分してみましょう。

$$ \begin{aligned} z &= (x + y)^2 \\ &= x^2 + 2 x y + y^2 \end{aligned} $$

なので、$x$で微分すると

$$ \begin{aligned} \frac{\partial z}{\partial x} &= 2 x + 2 y \\ &= 2(x + y) \end{aligned} $$

となります。

5.2.3 連鎖率と計算グラフ

 合成関数$z$を構成する2つの関数(計算)を計算グラフで表現したものが図5-7になります。この項では、合成関数の計算を計算グラフから解釈していきます。

 まず

$$ t = x + y $$

の計算は、変数$x$と$y$が「$+$」(加算)ノードに入力し、$t$を出力することを視覚的に表しています。
 次に

$$ z = t^2 $$

の計算は、変数$t$が「$**2$」(2乗)ノードに入力し、$z$が出力されます。

 この流れを順伝播と呼び、式(5.1)の計算を表します。

 次に合成関数の微分、つまり式(5.4)を計算グラフで考えます。

 順伝播の出力$z$の$z$での微分

$$ \frac{\partial z}{\partial z} = 1 $$

が「$**2$」ノードに入力します。これは1なので、式(5.4)では省略されています。
 そして「$**2$」ノードの微分$\frac{\partial z}{\partial t}$との積

$$ \frac{\partial z}{\partial z} \frac{\partial z}{\partial t} $$

が出力されます。またこれが次の「$+$」ノードの入力となります。
 そして「$+$」ノードの微分$\frac{\partial t}{\partial x}$との積

$$ \frac{\partial z}{\partial z} \frac{\partial z}{\partial t} \frac{\partial t}{\partial x} $$

が出力されます。
 これが最終的な出力

$$ \frac{\partial z}{\partial x} = \frac{\partial z}{\partial t} \frac{\partial t}{\partial x} \frac{\partial t}{\partial x} \tag{5.4} $$

となり、連鎖率の式と一致します。

 つまり合成関数(グラフ全体)の微分は、各関数(各ノードあるいは「局所的な計算」)の微分の積で求められることを、計算グラフで表現できることが分かりました。これはどれだけ複雑な関数になっても1つ1つの計算をノードで表し、そのノードごとの微分の積で求められます。また変数が複数ある場合も、逆伝播の入力と目的の変数とをつなぐノードの微分の積で連鎖率の式を表現しています。
 ノードの微分の積を丁寧に言うと、各ノードの順伝播の出力の入力での微分の積です。これが目的の変数の方へと流れていくことから、逆伝播と呼びます。

・微分の簡易表現

 本としては余談ですが、合成関数の微分は次のような簡易表現をよくされます。

 次の2つの関数

$$ \begin{aligned} z &= f(t) \\ t &= g(x) \end{aligned} $$

で構成される合成関数を次のように書きます。

$$ z = f(g(x)) $$

 この合成関数を微分は

$$ \{f(g(x))\}' = f'(g(x)) * g'(x) $$

2つの関数の微分の積になります。微分を$'$(ダッシュ)で表現します。ただしこの表現だと、変数が複数ある場合にはどの変数での偏微分なのか明示されないため、文脈等で判断する必要があります。

 これを本との表記を対応させると

$$ \begin{align} f'(g(x)) &= \frac{\partial z}{\partial t} \\ g'(x) &= \frac{\partial t}{\partial x} \\ \{f(g(x))\}' &= f'(g(x)) * g'(x) = \frac{\partial z}{\partial x} \end{align} $$

です。本では使わない表現ですが、ググったらこっちの表現もよく見ることになります。

参考文献

  • 斎藤康毅『ゼロから作るDeep Learning』オライリー・ジャパン,2016年.

おわりに

 連載再開!5章の中でこの節をほぼ最後に書いたので、他の分は既にほぼ完成しております。という訳で10日ほど続きます!よろしくお願いいたします。

 この章は数学の話がメインなので大変でした。基本的な内容になるほど拙さに恥ずかしさが増すので、正直この記事は上げるか迷いました。が、折角(レジュメとして)書いたので記事にしておきます。大体他のも気付けないだけで拙さに違いは、、無知の無恥です!恥ずかしさを感じるのも感じないのも意欲になったりならなかったりするので、それはそれで。あと、1年後くらいに書き直すとレベルアップを感じられて善きですよ(意外と気力がいるけど)。

 あ、間違い等あれば教えてほしいです。これは本当にお願いします。

【次節の内容】

www.anarchive-beta.com