Backpropagation
誤差逆伝播法は、ニューラルネットワークを逆方向にたどって連鎖律を適用し、1回のパスですべての重みの勾配を求めます。数式、計算コスト、コードを解説します。
誤差逆伝播(backpropagation)は「誤差の逆方向伝播」を短縮した用語で、予測の誤差に各重みがどれほど寄与したかをニューラルネットワーク内で計算するアルゴリズムです。損失関数から始めて、連鎖律をレイヤーごとに入力方向へ適用し、中間結果を再利用するため、1回の逆方向の走査で、モデルのパラメーターが数千個でも数十億個でも、すべての重みの勾配が得られます。次にオプティマイザーが勾配を使って重みを更新します。このため、誤差逆伝播はほぼすべてのディープラーニングモデルの学習を支えるステップです。Rumelhart、Hinton、Williamsは、1986年のNature論文誤差逆伝播による表現学習で、ニューラルネットワークへの誤差逆伝播の利用を広めました。
誤差逆伝播の仕組み#
バッチのトレーニングでは、2回のパスを実行します。順伝播では、各レイヤーに入力を通し、中間の活性化値を保存して、最後に損失を計算します。逆伝播は損失から始まり、レイヤーを逆順に処理します。各レイヤーは、上流勾配と呼ばれる出力に対する損失の勾配を受け取り、それに自身の局所微分を掛けて2つの結果を生成します。1つはオプティマイザー用に保持するレイヤーの重みの勾配で、もう1つはレイヤーの入力に対する勾配です。後者は下位レイヤーの上流勾配になります。
各レイヤーが必要とするのは上流勾配と保存済みの活性化値だけなので、微分を2回計算することはありません。自動微分の用語では、誤差逆伝播はネットワークの計算グラフに対する逆モード微分です。PyTorchは順伝播中にこのグラフを構築し、loss.backward()を呼び出すと逆方向にたどります。重みが2つのネットワークでは、PyTorchのautogradの結果を、連鎖律を手計算して確認できます。
import torch
# A two-weight network: prediction = w2 * tanh(w1 * x)
x, target = torch.tensor(1.5), torch.tensor(0.5)
w1 = torch.tensor(0.8, requires_grad=True)
w2 = torch.tensor(-1.2, requires_grad=True)
# Forward pass, keeping the hidden activation h for the backward pass
h = torch.tanh(w1 * x)
loss = (w2 * h - target) ** 2
# Backward pass: autograd applies the chain rule from the loss back to each weight
loss.backward()
# The same chain rule by hand, reusing the upstream gradient dL/dy for both weights
dL_dy = 2 * (w2 * h - target)
dL_dw2 = dL_dy * h
dL_dw1 = dL_dy * w2 * (1 - h**2) * x
print(f"autograd: dL/dw1 = {w1.grad:.4f}, dL/dw2 = {w2.grad:.4f}")
print(f"by hand: dL/dw1 = {dL_dw1:.4f}, dL/dw2 = {dL_dw2:.4f}")どちらの行もdL/dw1 = 1.6475, dL/dw2 = -2.5016を出力します。手書きの方法ではdL_dyを1回計算して両方の重みで再利用します。この再利用によって、autogradは数十億個の重みを持つネットワークも処理できます。時間方向の誤差逆伝播(BPTT)は、この同じアルゴリズムを時間ステップに展開したリカレントニューラルネットワークに適用したものです。
誤差逆伝播とオプティマイザーの比較#
誤差逆伝播は勾配を計算するだけで、重みは変更しません。確率的勾配降下法(SGD)やAdamなどの最適化アルゴリズムは、学習率でスケーリングした勾配を重みの更新に変換します。PyTorchは各逆伝播の結果を、重みにすでに保存されている勾配に加算するため、1回のオプティマイザーステップで複数のバッチをまとめて処理できます。
Ultralytics YOLOのトレーニングでは、この勾配累積を使って、名目上のバッチサイズを画像64枚(nbs=64)にします。ウォームアップ後のbatch=16実行では、各バッチで誤差逆伝播を行いますが、オプティマイザーのステップは4バッチごとに実行し、その前に累積勾配をノルム10にクリッピングします。
勾配消失と勾配爆発#
誤差逆伝播では局所微分を層ごとに乗算するため、勾配の大きさは深さに応じて幾何級数的に縮小または増大します。飽和したsigmoidユニットのように、ほとんどの係数が1未満の場合、初期層にはほとんど信号が届かず、これが勾配消失問題です。ほとんどの係数が1を超える場合は、勾配爆発問題によって大きな更新が発生し、NaNの損失が生じます。ReLU系の活性化関数、スケーリングした重み初期化、バッチ正規化、および残差ネットワークのスキップ接続により、数百層にわたって勾配の大きさを安定させます。
計算コストとメモリコスト#
局所微分で必要となるすべての活性化値は、順伝播から逆伝播で参照されるまでメモリに保持する必要があります。そのため、学習時のメモリ使用量はバッチサイズ、入力解像度、深さに応じて増加し、学習には推論よりはるかに多くのメモリが必要です。勾配チェックポイントでは一部の活性化値だけを保存し、残りを逆伝播中に再計算することで、計算量の増加と引き換えにメモリ使用量を削減します。また、混合精度ではほとんどの活性化値を16ビット形式で保持するため、32ビット浮動小数点数の半分の容量で済みます。計算量については、各層で重みと入力の両方の勾配を計算するため、逆伝播のコストは順伝播の約2倍です。そのため、スケーリング則の推定では、学習トークンあたりパラメーター1つにつき約6回の浮動小数点演算を数えます。内訳は順伝播が2回、逆伝播が4回です。










