教科書 › 第III部 深層学習:何の前提を足すか
CHAPTER 3

差を下まで届ける ── 誤差逆伝播

無料14分

第1章で、重みを動かす向きは p−yp - y(予測と正解の差)が決めることを見ました。あれは層が1枚のときの話です。層を重ねると、差が分かるのは一番上だけになります。下の層の重みは出力に直接触れていないので、「どれだけ間違えたか」を自分では知りようがありません。

それをどうやって下まで届けるか。答えは第0部の第2章で先に出ています。つなぐ所はかけ算、分かれる所はたし算——連鎖律だけです。この章は、その規則を層の形に書き下ろし、数値微分と突き合わせて確かめ、最後に「届かない」場合(勾配消失)を実測します。新しい原理は1つも出てきません。

1. 前向きの式

層 l=1,…,Ll = 1, \dots, L を

z(l)=W(l)a(l−1)+b(l),a(l)=φ(z(l))z^{(l)} = W^{(l)} a^{(l-1)} + b^{(l)}, \qquad a^{(l)} = \varphi\big(z^{(l)}\big)
(1)

と書きます。a(0)=xa^{(0)} = x が入力、a(L)a^{(L)} が出力です。φ\varphi は成分ごとに当てる活性化関数(第0部の第2章の(b))。

損失 ℓ\ell は出力だけの関数で、重みは LL 枚ぶんあります。知りたいのは全部の W(l)W^{(l)} についての勾配です。

2. 連鎖律を層の形に書く

鍵になる量を1つ置きます。その層の入力 z(l)z^{(l)} を少し動かすと損失がどれだけ動くかです。

δ(l)  =  ∂ℓ∂z(l)  ∈  Rnl\delta^{(l)} \;=\; \frac{\partial \ell}{\partial z^{(l)}} \;\in\; \mathbb{R}^{n_l}

出力層では、第1章で出した形がそのまま使えます(交差エントロピー+softmax なら)。

δ(L)  =  p−y\delta^{(L)} \;=\; p - y
(2)

ここから下へ降ります。z(l)z^{(l)} が損失に効く経路は、a(l)=φ(z(l))a^{(l)} = \varphi(z^{(l)}) を通って z(l+1)z^{(l+1)} へ入る道だけです。第0部の第2章の式(7)(Jf∘g=JfJgJ_{f\circ g} = J_f J_g)を当てると

δ(l)  =  (W(l+1)⊤δ(l+1))∘φ′(z(l))\delta^{(l)} \;=\; \Big( W^{(l+1)\top} \delta^{(l+1)} \Big) \circ \varphi'\big(z^{(l)}\big)
(3)

この1本が誤差逆伝播のすべてです。 読み方は2つ。

  • W(l+1)⊤W^{(l+1)\top} を掛ける=上の層の差を、重みの大きさに応じて配り直す。前向きで強く効いた経路ほど、戻ってくる差も大きい。
  • ∘ φ′(z(l))\circ\, \varphi'(z^{(l)}) =その層の活性化がどれだけ反応する場所にいたかを掛ける。傾きが寝ている所(飽和)では、差はほとんど通りません。
式(3)にアダマール積 $\circ$ が出るのは、記法の都合ではありません。成分ごとの活性化のヤコビアンが対角行列だからです(第0部の第2章の(b))。対角行列を掛けることは要素ごとに掛けることと同じで、$(128,128)$ の行列を作らず $(128,)$ のベクトル1本で済みます——128分の1の記憶で足ります。

δ\delta が手に入れば、重みの勾配は掛け算1回です。

∂ℓ∂W(l)  =  δ(l)(a(l−1))⊤,∂ℓ∂b(l)  =  δ(l)\frac{\partial \ell}{\partial W^{(l)}} \;=\; \delta^{(l)} \big(a^{(l-1)}\big)^{\top}, \qquad \frac{\partial \ell}{\partial b^{(l)}} \;=\; \delta^{(l)}
(4)

a(l−1)a^{(l-1)} は前向きのときの値です。だから前向きで通った中間値を捨てられません(第5節)。

FIG 1第0部の第2章と同じ図。「つなぐ」面の積が式(3)の縦の流れ(層から層へ)、「分かれる」面の和が、1つの値が複数の経路に効くときの合流にあたる。経路を1本落とすと合計が実測から外れる——層をまたぐ実装で分岐を1本忘れたときに起きるのは、これと同じこと

3. 本当に合っているかを測る

導出は短いぶん、符号や転置を1つ間違えても式の形は保たれます。動くけれど間違っている実装がいくらでも書けるので、機械で確かめます。使うのは第0部の第2章の式(2)、中心差分です。

実測しました。入力4・中間6と5・出力3の小さなネットで、損失を 12∥出力−y∥2\tfrac{1}{2}\lVert \text{出力} - y \rVert^2 とし、全パラメータ83個それぞれについて式(4)の値と中心差分(h=10−6h = 10^{-6})を突き合わせます。

活性化 照合したパラメータ数 最大の差
sigmoid 83 4.2×10−114.2\times10^{-11}
tanh 83 2.5×10−102.5\times10^{-10}
ReLU 83 1.1×10−111.1\times10^{-11}

一致します。 差の大きさは中心差分そのものの誤差(h2h^2 の程度)で、逆伝播の側の誤差ではありません。

この検算は書いた直後に1回やれば済む種類のものです。学習には使えません——パラメータ1つにつき前向き計算が2回要るので、1億パラメータなら2億回です(第0部の第2章)。確かめるための道具であって、学習の手段ではありません。

4. なぜ「逆」向きなのか

第0部の第2章で見たとおり、行列の積は掛ける順番が自由で、順番で計算量が変わります。損失は出力1つ、入力(パラメータ)は何百万個。この形では左から掛ける=出力側から順に降りるのが安い。

同じ3段(J1∈R1×10J_1 \in \mathbb{R}^{1\times10}、J2∈R10×128J_2 \in \mathbb{R}^{10\times128}、J3∈R128×784J_3 \in \mathbb{R}^{128\times784})で、左からなら乗算 101,632101{,}632 回、右からなら 1,011,3601{,}011{,}360 回——9.95倍でした。左から掛けるかぎり手元に残るのは常に行ベクトル(=δ\delta)で、大きな行列を一度も作りません。

「逆伝播」という名前は、計算の順番を言っているだけです。微分の規則は前向きも逆向きも同じ連鎖律で、どちらから掛けるかの選択しかしていません。入力が1つで出力が何百万個の問題なら、前向きに掛けるほうが安くなります(自動微分の前進モード)。

5. 払う代償 ── 中間値を全部覚えておく

式(4)に a(l−1)a^{(l-1)} が出てきます。逆向きに降りるとき、前向きで計算した値がもう一度要る。 つまり前向きのあいだ、各層の出力を捨てられません。

バッチ32・幅1024・24層なら 32×1024×24×4 バイト=3.00 MB32 \times 1024 \times 24 \times 4\,\text{バイト} = 3.00\ \text{MB}。バッチを256にすると 24.00 MB です(8倍)。実際のモデルではこれが層の種類ぶん積み上がるので、学習時のメモリはモデルの大きさより活性の保存量で決まることが多い。バッチサイズを上げた途端にメモリが足りなくなるのはこれが理由です。

6. 届かないことがある ── 勾配消失

式(3)を LL 回繰り返すと、第1層に届く δ\delta は各層の(重み)×(活性化の傾き)の積になります。1層あたりの倍率が1を下回れば、層を重ねるほど指数的に細ります(第0部の第2章の図で見た 0.42n0.42^n と同じ形)。

幅128・20層で実測しました。重みは N(0, g2/nin)\mathcal{N}(0,\, g^2/n_{\text{in}}) で初期化し、gg をゲインと呼びます。

活性化 ゲイン gg 第1層の ∥δ∥\lVert\delta\rVert / 最終層の ∥δ∥\lVert\delta\rVert
sigmoid 1 1.4×10−121.4\times10^{-12}
tanh 1 0.933
tanh 2 87.787.7
ReLU 1 1.8×10−31.8\times10^{-3}
ReLU 2\sqrt{2} 1.37
FIG 2層ごとの ‖δ‖ を最終層との比で積んだもの(縦は常用対数)。0の線に乗っていれば大きさが保たれている。活性化を切り替え、ゲインを動かすと、同じ活性化のまま消えも爆発もする。層の数を増やすと、1層あたりのわずかな差が指数で効いてくる

(図は幅64で自前の重みを引くので、表の数字とぴったりは合いません。実測で ReLU の g=1g=1 は表 1.8×10−31.8\times10^{-3}・図 0.0018、sigmoid の g=1g=1 は 1.4×10−121.4\times10^{-12}・1.0×10−121.0\times10^{-12} と近く、tanh の g=1g=1 は 0.933 対 0.442 とやや開きます。一致するのは並びのほうで、1本の測定値そのものではありません。)

よくある誤解: 「勾配が消えるのは活性化関数のせい」

半分だけ当たっています。上の表の2行目と3行目を見てください。同じ tanh、同じ20層で、ゲインを1から2に変えただけで 0.933→87.70.933 \to 87.7。消えるどころか爆発しています。逆にゲインを下げると消えます。

tanh のゲイン 比(第1層/最終層)
0.5 2.1×10−62.1\times10^{-6}
1.0 0.933
1.5 9.31
2.0 87.7
3.0 1.6×1031.6\times10^{3}

ReLU も同じです。g=1g=1 では 1.8×10−31.8\times10^{-3} まで縮み、g=2g=\sqrt{2} にすると 1.37 に戻ります。「ReLU なら勾配は消えない」も正しくありません。 効いているのは活性化そのものではなく、1層あたり(重みの大きさ)×(活性化の傾き)の積です。2\sqrt{2} という数字は、ReLU が入力の半分を0にする分をちょうど埋め合わせる値として出てきます。

ただし、活性化そのものの性質も確かにあります。 sigmoid は微分の最大値が 0.250.25 しかないので、ゲインを上げて取り返そうとすると——

sigmoid のゲイン 比
1 1.4×10−121.4\times10^{-12}
2 5.1×10−85.1\times10^{-8}
4 2.2×10−42.2\times10^{-4}
8 7.2×10−27.2\times10^{-2}

確かに改善しますが、8倍にしても1に届きません。ゲインを上げると今度は飽和する(入力が大きくなり φ′\varphi' が0に近い領域へ入る)ので、取り返した分を取り返されます。sigmoid を深く積むのが難しいのは、この板挟みです。

結論は「活性化を変えろ」でも「初期化を直せ」でもなく、積を見ろです。深いモデルで学習が進まないとき、見るべきは層ごとの $\lVert\delta\rVert$ の並びで、上の図がその並びそのものです。活性化だけ取り替えて直らないのは、残り半分(重みの大きさ)を触っていないからです。

演習

答えは閉じてあります。手を動かしてから開いてください。

演習1. 式(3)について。(a) W(l+1)⊤W^{(l+1)\top} の形は何行何列ですか(層 ll の幅を nln_l として)。(b) なぜ転置が付くのですか。(c) ∘ φ′\circ\,\varphi' が行列積ではなくアダマール積である理由は。

答えを見る

(a) nl×nl+1n_l \times n_{l+1}。 前向きの W(l+1)W^{(l+1)} は nl+1×nln_{l+1} \times n_l(出力の数 × 入力の数)なので、転置すると縦横が入れ替わります。δ(l+1)∈Rnl+1\delta^{(l+1)} \in \mathbb{R}^{n_{l+1}} を掛けて Rnl\mathbb{R}^{n_l} が出る——形が合います。

(b) ヤコビアンを左から掛けているから。 z(l+1)=W(l+1)a(l)z^{(l+1)} = W^{(l+1)}a^{(l)} のヤコビアンは W(l+1)W^{(l+1)} そのもの(第0部の第2章の(a))。連鎖律は ∂ℓ/∂a(l)=(∂ℓ/∂z(l+1)) W(l+1)\partial\ell/\partial a^{(l)} = (\partial \ell/\partial z^{(l+1)})\, W^{(l+1)} で、これを縦ベクトルで書き直すと転置が出ます。新しい規則ではなく、行ベクトルを縦に書いた結果です。

(c) 成分ごとの活性化のヤコビアンが対角行列だから。 ai=φ(zi)a_i = \varphi(z_i) は zjz_j(j≠ij \neq i)を含まないので非対角成分は0。対角行列を掛けることは要素ごとに掛けることと同じです。(nl,nl)(n_l, n_l) の行列を作る必要がなく、(nl,)(n_l,) のベクトル1本で済みます。

演習2. 20層のネットで、1層あたり δ\delta が平均0.8倍になっているとします。(a) 第1層に届く δ\delta は最終層の何倍ですか。(b) 40層ならどうなりますか。(c) 1層あたりを0.95倍に改善できたとき、20層での比は。

答えを見る

(a) 0.819≈1.4×10−20.8^{19} \approx 1.4\times10^{-2}(層をまたぐのは19回)。おおよそ100分の1です。

(b) 0.839≈1.7×10−40.8^{39} \approx 1.7\times10^{-4}。 層を2倍にすると、比は2乗になります。深さは指数の肩に乗るので、1層あたりのわずかな差が深いところで桁になります。

(c) 0.9519≈0.3770.95^{19} \approx 0.377。 1層あたり 0.8 → 0.95 という小さな改善が、20層では 1.4×10−2→0.3771.4\times10^{-2} \to 0.377(約26倍)になります。初期化や正規化が効くのは、1層あたりの倍率を1へ寄せるからです。

演習3. 自分で書いた逆伝播を検算します。(a) どうやって確かめますか。(b) 差がどれくらいなら合格ですか。(c) この方法を学習そのものに使えない理由は。

答えを見る

(a) 中心差分と突き合わせます(第0部の第2章の式(2))。パラメータを1つだけ ±h\pm h 動かして損失を2回測り、(L+−L−)/2h(L_+ - L_-)/2h を逆伝播の値と比べる。全パラメータでやるのが大事で、1つだけ合っていても転置の間違いは見つかりません(本文は83個すべてで照合しています)。

(b) h=10−6h = 10^{-6} なら 10−910^{-9} 程度まで。 本文の実測は 10−1110^{-11}〜10−1010^{-10} でした。hh を小さくしすぎると引き算の桁落ちでかえって悪化するので、10−810^{-8} より小さい hh は使いません。ReLU のように折れ曲がりがある関数では、ちょうど折れ点を跨いだパラメータだけ大きくずれます——それは実装の誤りではありません。

(c) 回数が釣り合わないから。 パラメータ1つにつき前向きが2回要るので、nn 個なら 2n2n 回。逆伝播は前向き1回ぶんの数倍で全パラメータの勾配を出します。1億パラメータなら2億回——比較になりません。

この章で言っていないこと

  • 自動微分の実装(計算グラフをどう表現し、どの演算に逆向きの規則を登録するか)は書いていません。式(3)(4)は全結合層に限った形で、畳み込みや注意機構では別の形になります——が、導き方は同じ連鎖律です。
  • 勾配消失・爆発への手当て(残差接続・正規化層・勾配クリッピング・初期化の設計)は名前だけです。第5章以降で扱います。本文の実測は「何が起きているか」までで、「どう直すか」は入っていません。
  • 本文の数値は合成データ・固定の初期値での1回の測定です。深さ・幅・活性化を変えれば値は変わります。変わらないのは「1層あたりの倍率が指数で効く」という形のほうです。
  • メモリの見積りは活性だけで、勾配・最適化器の状態(Adam なら重みの2倍)・一時バッファは入れていません。
  • 本文の数値はすべて実際に計算して確かめています(3つの活性化それぞれで全83パラメータの中心差分照合、20層での層ごとの ∥δ∥\lVert\delta\rVert、tanh と sigmoid のゲイン掃引、メモリの見積り)。

もっと詳しく

コメント

コメントにはログインが必要です