← 機械学習テキスト 一覧
🎓 レベル:標準 | 重要度:A(必須)
📎 前提:パーセプトロンと多層パーセプトロン | 土台:勾配降下法(勾配で下る)・凸最適化の基礎(連鎖律の文脈)
要点(BLUF)
- 誤差逆伝播法(backpropagation)は、ニューラルネットの損失 L の全パラメータに対する勾配を、連鎖律を出力側から再利用しながら計算するアルゴリズムです。学習則そのものではなく「勾配を効率よく求める計算手続き」です。
- 鍵は各層の誤差信号 δ(l)=∂L/∂z(l) を出力層から入力層へ再帰的に伝えること。一度上流から流れてきた δ を使い回すので、素朴に全パラメータを個別微分するより圧倒的に速くなります。
- その計算量は順伝播と同じオーダー。「順伝播1回ぶんのコストで、何百万パラメータぶんの勾配が全部そろう」——これが深層学習を現実的にしている核心です。
1. なぜ必要か — 素朴な微分は破綻する
ニューラルネットの学習は 勾配降下法 で見たとおり、損失 L(θ) を勾配の逆向きに下るだけです:
θ←θ−η∇θL(θ)
問題は「∇θL をどう計算するか」です。θ は全層の重み・バイアスをまとめたもので、現代のモデルでは数百万〜数十億個あります。
素朴にやるなら、各パラメータ θk について有限差分
∂θk∂L≈εL(θ+εek)−L(θ)
を計算すればよさそうですが、これは破綻します。1個の偏微分にネットワークの順伝播(forward)が1回必要なので、パラメータが P 個あれば順伝播 P 回。P が百万なら、勾配を1ステップ出すのに順伝播を百万回——非現実的です。
そこで連鎖律を「出力側から1回だけ」流して、共通する計算を全パラメータで使い回す。 これが誤差逆伝播法の発想です。結論を先に言うと、これで**順伝播1回+逆伝播1回(≈順伝播と同コスト)**で全勾配がそろいます。P 倍が定数倍に化けるわけです。
2. 計算グラフと順伝播(forward)
まず順伝播を定式化します。ネットワークを L 層とし、第 l 層を次のように書きます(ϕ は活性化関数):
z(l)=W(l)h(l−1)+b(l),h(l)=ϕ(z(l))
- h(l−1):前層の出力(活性化後)。入力層は h(0)=x
- W(l):第 l 層の重み行列、b(l):バイアスベクトル
- z(l):プレ活性化(pre-activation)。重み付き和そのもの
- h(l):活性化(activation)。z(l) に非線形 ϕ を通したもの
最終層の出力 h(L)=y^ から損失 L=ℓ(y^,y) を計算します。これら一連の演算(行列積 → 加算 → 活性化 → … → 損失)を計算グラフ(computational graph)——各ノードが演算、各エッジが値の流れ——として並べたものが、順伝播です。
要するに:入力 x を W,b,ϕ で順に変換して損失 L という1つのスカラーにたどり着く、その「変換の連なり」が計算グラフです。逆伝播はこのグラフを逆向きにたどります。
用語メモ:z(l)(プレ活性化)と h(l)(活性化後)を区別するのが導出の要です。誤差信号 δ は z に関する微分として定義し、h ではなく z で再帰を回すと式がきれいになります。
3. 連鎖律(chain rule)の復習
逆伝播の数学的な中身は合成関数の微分(連鎖律)一本です。スカラー L が u を介して v に依存するとき、
∂v∂L=∂u∂L∂v∂u
多変数で、L が複数の中間変数 u1,…,um を経由して v に依存するなら、すべての経路の寄与を足します:
∂v∂L=∑j=1m∂uj∂L∂v∂uj
これが計算グラフ上では「そのノードに合流してくる全エッジの(上流の勾配)×(局所の勾配)を足し合わせる」という規則になります。
要するに:「ゴール(損失)の微分」は「経路上の微分の積」、経路が複数あればその和。逆伝播は各ノードでこの掛け算と足し算を機械的に繰り返すだけです。
各ノードは2つだけ知っていれば動きます——(1) 上流から流れてきた勾配(upstream gradient)、(2) 自分の出力を自分の入力で微分した局所勾配(local gradient)。この2つを掛けたものを下流へ流す。ネットワーク全体の構造をノードが知る必要はありません(モジュラリティ)。
4. 逆伝播(backward)の導出 — 誤差信号 δ
ここが本題です。各層の誤差信号を、プレ活性化 z(l) に関する損失の勾配として定義します:
δ(l)≡∂z(l)∂L
「層 l のプレ活性化を少し揺らすと損失がどれだけ動くか」という感度ベクトルです。これさえ各層で求まれば、後述のとおり重み・バイアスの勾配は一発で出ます。δ を出力層から入力層へ再帰的に求めるのが逆伝播です。
(BP1) 出力層の誤差信号
最終層 z(L) は、活性化 h(L)=ϕ(z(L)) を経て損失 L に届きます。z(L) の各成分 zi(L) は活性化 hi(L)=ϕ(zi(L)) だけに(要素ごとに)影響するので、連鎖律から
δi(L)=∂zi(L)∂L=∂hi(L)∂L∂zi(L)∂hi(L)=∂hi(L)∂Lϕ′(zi(L))
全成分まとめてベクトルで書くと、
δ(L)=∇hL⊙ϕ′(z(L))
ここで ⊙ はアダマール積(要素ごとの積)、∇hL は損失を出力 h(L) で微分したベクトルです。
要するに:出力層の誤差は「損失が出力をどれだけ気にするか(∇hL)」に「活性化がプレ活性化にどれだけ反応するか(ϕ′)」を要素ごとに掛けたもの。
補足:損失と出力活性化の相性が良いと ∇hL⊙ϕ′ がきれいに簡約されます。たとえばソフトマックス出力+交差エントロピー損失や恒等出力+二乗損失では δ(L)=y^−y(予測と正解の差)という非常に簡潔な形になります。この「誤差=予測−正解」が δ を「誤差信号」と呼ぶ由来です。
(BP2) 隠れ層の誤差信号(再帰式)
隠れ層 z(l) は、次層のプレ活性化 z(l+1)=W(l+1)h(l)+b(l+1) を経由してのみ損失に影響します。z(l) → h(l) → z(l+1) → L という経路です。連鎖律で成分ごとに書くと、zi(l) は hi(l)=ϕ(zi(l)) を通って、次層の全ニューロン zk(l+1) に流れ込みます:
δi(l)=∂zi(l)∂L=hi(l)経由で次層へ(k∑∂zk(l+1)∂L∂hi(l)∂zk(l+1))∂zi(l)∂hi(l)
各部品を埋めます。∂zk(l+1)∂L=δk(l+1)(次層の誤差信号、もう求まっている)、∂hi(l)∂zk(l+1)=Wki(l+1)(次層の重み)、∂zi(l)∂hi(l)=ϕ′(zi(l))。代入すると、
δi(l)=(∑kWki(l+1)δk(l+1))ϕ′(zi(l))
括弧内は W(l+1)⊤ と δ(l+1) の行列・ベクトル積(第 i 成分)そのものです。よってベクトルで、
δ(l)=(W(l+1)⊤δ(l+1))⊙ϕ′(z(l))
要するに:層 l の誤差は「次層の誤差 δ(l+1) を、重みの転置 W(l+1)⊤ で逆向きに配り直し(=順伝播 W(l+1)h(l) の逆操作)」、さらに「この層の活性化の傾き ϕ′ を要素ごとに掛けた」もの。順伝播が「W を掛けて前へ」なら、逆伝播は「W⊤ を掛けて後ろへ」です。
これが再帰式です。δ(L) を (BP1) で求め、(BP2) で δ(L−1),δ(L−2),…,δ(1) と出力から入力へドミノ式に降りていきます。同じ δ(l+1) を使い回すので、層をまたいだ微分の重複計算が消えます——これが効率の源です。
(BP3)(BP4) パラメータの勾配
肝心の重み・バイアスの勾配は、δ が手元にあればその層だけで即座に出ます。z(l)=W(l)h(l−1)+b(l) を直接微分します。
重み:zi(l)=∑jWij(l)hj(l−1)+bi(l) なので ∂Wij(l)∂zi(l)=hj(l−1)。連鎖律で
∂Wij(l)∂L=∂zi(l)∂L∂Wij(l)∂zi(l)=δi(l)hj(l−1)
これは外積(列ベクトル×行ベクトル)の形なので、行列でまとめて
∂W(l)∂L=δ(l)(h(l−1))⊤
バイアス:∂bi(l)∂zi(l)=1 なので、
∂b(l)∂L=δ(l)
要するに:ある層の重みの勾配は「その層に流れ込んだ入力 h(l−1)」と「その層の誤差信号 δ(l)」の外積。バイアスの勾配は誤差信号そのもの。δ さえ伝播できれば、勾配は機械的に出ます。
計算グラフ上の順伝播 → 逆伝播
flowchart LR
X["入力 x = h⁽⁰⁾"] -->|"forward →"| Z1["z⁽¹⁾ = W⁽¹⁾h⁽⁰⁾ + b⁽¹⁾"]
Z1 -->|"φ"| H1["h⁽¹⁾ = φ(z⁽¹⁾)"]
H1 -->|"forward →"| Z2["z⁽²⁾ = W⁽²⁾h⁽¹⁾ + b⁽²⁾"]
Z2 -->|"φ"| H2["h⁽²⁾ = ŷ"]
H2 --> Loss["損失 L = ℓ(ŷ, y)"]
Loss -. "δ⁽²⁾ = ∇hL ⊙ φ'(z⁽²⁾)" .-> Z2
Z2 -. "δ⁽¹⁾ = (W⁽²⁾ᵀδ⁽²⁾)⊙ φ'(z⁽¹⁾)" .-> Z1
Z2 -. "← backward(W²ᵀで配り直す)" .-> Z1
Z2 ==> G2["∂L/∂W⁽²⁾ = δ⁽²⁾h⁽¹⁾ᵀ"]
Z1 ==> G1["∂L/∂W⁽¹⁾ = δ⁽¹⁾h⁽⁰⁾ᵀ"]
実線が順伝播(左→右で損失まで)、点線が逆伝播(損失→左へ δ を伝播)、太矢印が各層で取り出すパラメータ勾配です。
手続きのまとめ
flowchart TD
A["順伝播:x から各層の z⁽ˡ⁾・h⁽ˡ⁾ を計算し保存"] --> B["損失 L を計算"]
B --> C["出力層の誤差信号<br/>δ⁽ᴸ⁾ = ∇hL ⊙ φ'(z⁽ᴸ⁾)"]
C --> D{"l = L から 1 まで"}
D --> E["パラメータ勾配を取り出す<br/>∂L/∂W⁽ˡ⁾ = δ⁽ˡ⁾h⁽ˡ⁻¹⁾ᵀ , ∂L/∂b⁽ˡ⁾ = δ⁽ˡ⁾"]
E --> F["1つ前の層へ誤差を伝播<br/>δ⁽ˡ⁻¹⁾ = (W⁽ˡ⁾ᵀδ⁽ˡ⁾)⊙ φ'(z⁽ˡ⁻¹⁾)"]
F --> D
D -- "完了" --> G["全勾配 ∇θL がそろう<br/>→ θ ← θ − η∇θL で更新"]
5. 計算量 — 順伝播と同オーダー(効率の核心)
誤差逆伝播法が「効率的」と言われる理由を定量化します。
第 l 層の主役は行列積です。
- 順伝播 z(l)=W(l)h(l−1)+b(l):W(l) が nl×nl−1 なら、行列・ベクトル積で約 nlnl−1 回の積和。
- 逆伝播 δ(l−1)=(W(l)⊤δ(l))⊙ϕ′:同じ W(l) の転置を掛けるだけなので、これも約 nlnl−1 回。
- 勾配 ∂L/∂W(l)=δ(l)(h(l−1))⊤:外積でやはり約 nlnl−1 回。
つまり逆伝播の各演算は、対応する順伝播の演算と同じ重みサイズの行列を1〜2回触るだけ。全層を合わせると、
逆伝播のコスト≈(定数倍)×順伝播のコスト
となり、両者は同じオーダー O(∑lnlnl−1) です。これは自動微分の言葉で言えば「スカラー出力に対するリバースモード自動微分は、関数評価と同じ漸近計算量で勾配を返す」という一般的事実の特別な場合です。
要するに:パラメータが P 個あっても、勾配は P 回の順伝播ではなく、順伝播1回ぶん+逆伝播1回ぶんでまるごとそろう。素朴な有限差分(O(P) 回の順伝播)に対する圧倒的な勝利が、深層学習を計算可能にしています。
注意(メモリとのトレードオフ):逆伝播は速い代わりにメモリを食います。δ(l) や ∂L/∂W(l) の計算に順伝播で求めた h(l−1),z(l) が必要なので、順伝播の中間値を全層ぶん保持しておかねばなりません。深いネットや長い系列でメモリが逼迫する原因はこれで、勾配チェックポインティング(一部を捨てて再計算)などで対処します。
6. 勾配消失・爆発への伏線
再帰式 (BP2) をよく見ると、δ を1層後ろへ運ぶたびに W(l+1)⊤ と ϕ′(z(l)) が掛け算で入ります。出力層から k 層さかのぼると、
δ(L−k)∼(W(L)⊤diagϕ′)(W(L−1)⊤diagϕ′)⋯
のように、ϕ′ と重みの積が k 回連なります。ここから深いネットの病が見えます。
- 勾配消失(vanishing gradient):∣ϕ′∣<1(sigmoid は最大でも 0.25)が何度も掛かると、δ は指数的に 0 へ萎んで、入力に近い層の勾配がほぼ消えます。浅い層が学習しなくなります。
- 勾配爆発(exploding gradient):逆に重みのスケールが大きいと積が指数的に発散し、更新が暴れて発散します。
要するに:逆伝播は「掛け算の連鎖」なので、ϕ′ や W の大きさが 1 からずれると深さに対して指数的に効いてくる。これが活性化関数の選び方(ReLU 系で ϕ′≈1 を保つ)や初期化・正規化が深層学習で死活的に重要になる理由です。詳細は 活性化関数・重み初期化と正規化 で扱います。
7. 自動微分(autodiff)との関係
現代では誤差逆伝播法を手で実装することはまずありません。PyTorch / TensorFlow / JAX などのフレームワークが、順伝播のコードを実行する裏で計算グラフを自動構築し、各演算の局所勾配を知っているので、loss.backward() 一行で逆伝播(リバースモード自動微分)を走らせて全パラメータの .grad を埋めてくれます。
ポイントは、誤差逆伝播法はニューラルネット専用の特別な魔法ではなく、計算グラフ上のリバースモード自動微分の一適用だということです。スカラー(損失)への入力次元が出力次元より遥かに大きい状況(まさにパラメータ多数の学習)で、リバースモードが最も得をします。各演算ノードに「局所勾配の計算規則」さえ定義しておけば、任意の合成関数で同じ仕組みが回ります。
8. ⚠️ よくある誤解・落とし穴
- 「backprop=学習アルゴリズム」ではない:誤差逆伝播法は勾配を計算するだけの手続きです。その勾配で実際にパラメータを動かすのは 勾配降下法・モーメンタムとAdam系最適化 の役目。「backprop で学習する」は正確には「backprop で勾配を出し、勾配降下で学習する」です。
- δ を h で定義すると混乱する:誤差信号は z(プレ活性化)に関する微分 ∂L/∂z(l) として定義するのが標準で、再帰がきれいになります。∂L/∂h(l) で回そうとすると ϕ′ の掛かる位置がずれて式が汚くなります。
- 順伝播の中間値を捨ててはいけない:逆伝播は順伝播の h(l−1),z(l) を使います。推論(inference)だけなら中間値は不要ですが、学習では保持が必須。だから訓練時は推論時よりメモリを食います。
- 勾配チェック(gradient check)を本番で常用しない:自前で逆伝播を実装したとき、有限差分 2εL(θ+ε)−L(θ−ε) と突き合わせて実装ミスを検出するのが勾配チェックです。これはデバッグ用であって、遅いので学習ループでは使いません(速いから backprop を使うのに、遅い有限差分を毎回回したら本末転倒)。
- 「逆伝播は生物学的に正しい」わけではない:脳が誤差を重みの転置でそのまま逆流させている証拠はありません(重み対称性問題など)。あくまで効率的な数値計算手法と割り切るのが無難です。
9. まとめ
誤差逆伝播法は、(1) 損失を計算グラフとして並べ(順伝播で z(l),h(l) を保存)、(2) 出力層の誤差 δ(L)=∇hL⊙ϕ′(z(L)) を起点に、(3) 再帰式 δ(l)=(W(l+1)⊤δ(l+1))⊙ϕ′(z(l)) で誤差を後ろへ伝え、(4) 各層で ∂L/∂W(l)=δ(l)(h(l−1))⊤、∂L/∂b(l)=δ(l) を取り出す——これだけの手続きです。連鎖律を出力側から使い回すことで計算量を順伝播と同オーダーに抑え、数百万パラメータの勾配を一括で得ます。この勾配を モーメンタムとAdam系最適化 に渡せば、深層学習の学習ループが完成します。次は再帰式に現れた ϕ′ の主役、活性化関数 へ進みます。
対応するシミュレーション
simulations/backprop_check.py:小さな MLP(2→3→1)で、誤差逆伝播で求めた解析的な勾配と、損失を ±ε 動かして得る数値微分(有限差分)の勾配を突き合わせます。相対誤差が 10−9 前後とほぼ一致し、BP の連鎖律による勾配計算が正しいことを検証できます(gradient checking)。
関連ノート