体系 › 深層学習の基礎
·無料·12分で読めます

誤差逆伝播を1から解説 — 連鎖律だけで全部わかる

1000万個のパラメータの勾配を、なぜ順伝播1回ぶんの手間で全部求められるのか。連鎖律の復習から計算グラフ、2層ネットの手計算1ステップ、そして勾配消失が起きる理由までを、記号を1つずつ説明しながら追います。

要点

  • 数値微分はパラメータ1個につき順伝播が1回必要で、1000万個なら1ステップに1000万回の順伝播が要る。
  • 誤差逆伝播は順伝播1回ぶんと同じオーダーの手間で、連鎖律により全パラメータの勾配を一度に出す。
  • 各頂点は「上流から降ってきた勾配 × 自分の局所微分」を下流へ渡し、そのために順伝播の中間値を保持する必要がある。
  • 逆向きが効率的なのは損失がスカラーで、各頂点の感度1個をそのパラメータ全体で使い回せるからである。
  • 連鎖律は掛け算なので、項が1未満なら勾配消失、1超なら勾配爆発となり、シグモイド微分は最大0.25で10層なら0.25^10になる。
対象textタスクbasics

スープが塩辛い。犯人はどの調味料か

作ったスープが塩辛すぎたとします。原因は塩か、醤油か、煮詰めすぎか。あなたが本当に知りたいのは「どれをどれだけ減らせば、しょっぱさがどれだけ和らぐか」です。

素朴なやり方は、塩だけをほんの少し減らしてもう一度作り、味を比べること。次は醤油だけを変えてもう一度。調味料が20種類なら20回作り直します。これを数式にしたのが数値微分です。

∂L∂θi≈L(θ+εei)−L(θ)ε\frac{\partial L}{\partial \theta_i} \approx \frac{L(\theta + \varepsilon e_i) - L(\theta)}{\varepsilon}

記号を1つずつ説明します。LL は損失(モデルの間違い具合を表す1つの数値)、θ\theta は全パラメータをまとめたもの、θi\theta_i はそのうち ii 番目の1個、ε\varepsilon(イプシロン)はごく小さい数、eie_i は「ii 番目だけ1で他は全部0」というベクトルです。∂\partial(ラウンド・ディー)は、他を固定して1つの変数だけで微分する記号です。

この式が言っているのは要するに、つまみを1個だけほんの少し回して、損失がどれだけ変わったかを測るということ。正しい方法ですが、致命的に遅い。パラメータ1個につき順伝播(入力を通して出力を出す計算)が1回必要なので、1000万個なら1回の学習ステップに1000万回の順伝播が要ります。これでは終わりません。

誤差逆伝播(backpropagation)は、レシピの手順を逆向きに辿ることで、順伝播1回ぶんと同じオーダーの手間で全パラメータの勾配を一度に出す方法です。魔法ではなく、高校で習う連鎖律をひたすら適用しているだけです。

なお本記事はニューラルネットワークの基礎——ニューロンが σ(w⊤x+b)\sigma(w^\top x + b) を計算していること、順伝播が行列積の連鎖であること——を前提にします。

連鎖律 — 微分は「倍率」、連鎖律は「倍率の掛け算」

連鎖律は次の1行です。

dzdx=dzdy⋅dydx\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx}

xx が変われば yy が変わり、yy が変われば zz が変わる、という3段の関係を考えています。

この式が言っているのは要するに、倍率は掛け算で繋がるということです。xx を1だけ動かすと yy が3動く(倍率3)、yy が1動くと zz が2動く(倍率2)。なら xx を1動かしたとき zz は6動く。歯車を噛み合わせたときの回転比と同じ理屈です。

微分とは、この「局所的な倍率」のことです。ある点でほんの少し入力をずらしたら出力が何倍ずれるか。それだけの意味しかありません。そして深いネットワークは、この歯車が何十段も噛み合った装置にすぎません。

計算グラフ — 順方向で値、逆方向で勾配

ネットワークを、演算を頂点・値の流れを辺とする計算グラフとして見ます。w1xw_1 x の掛け算が1つの頂点、+b1+ b_1 の足し算が次の頂点、ReLU がその次、という具合です。

このグラフの上で、逆伝播は驚くほど機械的な作業になります。各頂点が知っている必要があるのは自分の局所微分——自分の入力を少し動かしたら自分の出力がどれだけ動くか——だけです。あとは、

上流から降ってきた勾配 × 自分の局所微分 = 下流へ渡す勾配

を計算して隣に渡す。これを出力側から入力側へ繰り返すだけで、巨大な式を展開する必要はありません。頂点が自分の足元しか知らなくても全体の勾配が正しく求まる——ここが逆伝播の美しいところです。

ただし条件が1つあります。局所微分を計算するには順伝播のときの値が必要なので、順伝播で通った中間の値を捨てずに覚えておく必要があります。学習時にメモリを大量に食う理由はここにあります。

そして「自分の局所微分」の代表格が、活性化関数の傾きです。次の図で傾きの大きさを確かめておいてください。ここで見た傾きの値が、そのまま逆伝播で掛け算される数字になります。

FIG 1グラフ上の点をドラッグして「傾き」を見てください。この傾きが局所微分で、逆伝播ではこの数字が層ごとに掛け合わされていきます。シグモイドの両端で傾きがほぼ0になることに注目

2層ネットを、実際の数値で1ステップ追う

言葉だけでは腹に落ちないので、最小のネットワークで手を動かします。入力1個、隠れ層1ユニット(ReLU)、出力1個。パラメータは4つだけです。

初期値は x=2.0x = 2.0、w1=0.5w_1 = 0.5、b1=0b_1 = 0、w2=1.5w_2 = 1.5、b2=0b_2 = 0、正解は y=0.5y = 0.5。損失は二乗誤差 L=12(y^−y)2L = \tfrac{1}{2}(\hat{y} - y)^2 を使います(12\tfrac{1}{2} は微分したとき係数2が消えて式がきれいになるための慣習です)。

順伝播(値を1つずつ記録しながら進みます)

ここで zz は活性化関数を通す前の値、aa は通した後の値です。この区別が逆伝播では重要になります。

逆伝播(出力側から遡ります)

重みの勾配が「上流から来た勾配 × その重みに入ってきた値」になっている点に注目してください。w2w_2 には a1a_1 が、w1w_1 には xx が掛かっています。よく使われる入力ほど、その重みの責任は大きい——直感どおりです。

更新

θ←θ−η∂L∂θ\theta \leftarrow \theta - \eta \frac{\partial L}{\partial \theta}

θ\theta は任意のパラメータ、η\eta(イータ)は学習率、←\leftarrow は代入です。この式が言っているのは要するに、損失が増える向きの逆へ、勾配の大きさに比例して動かすということ。η=0.1\eta = 0.1 で更新すると、w1=0.2w_1 = 0.2、b1=−0.15b_1 = -0.15、w2=1.4w_2 = 1.4、b2=−0.1b_2 = -0.1 になります。

もう一度順伝播すると z1=0.25z_1 = 0.25、a1=0.25a_1 = 0.25、y^=0.25\hat{y} = 0.25、損失は 0.031250.03125。0.50.5 から1ステップで大きく下がりました。ただし予測は 1.51.5(正解より上)から 0.250.25(正解より下)へ飛び越えています。誤差の符号が反転した——これが学習率を上げすぎたときに起こることの芽です。

一般の層に拡張する

同じ手続きを行列で書くと、任意の層数に一般化できます。

δ(l)=(W(l+1)⊤δ(l+1))⊙σ′(z(l))\delta^{(l)} = \left( W^{(l+1)\top} \delta^{(l+1)} \right) \odot \sigma'(z^{(l)})

∂L∂W(l)=δ(l)(a(l−1))⊤\frac{\partial L}{\partial W^{(l)}} = \delta^{(l)} \left( a^{(l-1)} \right)^\top

記号の説明です。δ(l)\delta^{(l)}(デルタ)は ll 層目の事前活性化 z(l)z^{(l)} に対する損失の感度——さきほど手計算した ∂L/∂z1\partial L / \partial z_1 の一般形です。W(l+1)⊤W^{(l+1)\top} は次の層の重み行列の転置(行と列を入れ替えたもの)。⊙\odot は要素ごとの積で、行列積ではなく同じ位置の成分同士を掛けます。a(l−1)a^{(l-1)} は1つ手前の層の出力です。

1本目の式が言っているのは要するに、次の層の責任を重み行列で振り分け直し、自分の活性化関数の傾きを掛ける。2本目は、重みの勾配は「その層の責任 × その重みに入ってきた値」。手計算でやったことと、字面が違うだけで中身は同じです。

なぜ「逆」向きだと効率的なのか

鍵は、損失がスカラー(数値1個)であることです。

出力から遡ると、各頂点には「この値が動いたら損失がどれだけ動くか」という感度がただ1つ定まります。そして一度求めたその1個の数値を、その頂点にぶら下がるすべてのパラメータで使い回せます。さきほどの手計算でも、∂L/∂z1=1.5\partial L / \partial z_1 = 1.5 を1回求めたあと、w1w_1 の勾配にも b1b_1 の勾配にも同じ値を使いました。層が深くなるほど、この共有が効いてきます。

逆に前向きに求めようとすると、パラメータごとに別々の追跡が必要になり、パラメータの数だけパスが要ります。数値微分が遅かったのと同じ理由です。

出力が1個で入力(パラメータ)が大量にあるときは、出力から遡るほうが圧倒的に安い。 逆伝播が普遍的に使われているのは、機械学習の損失が常にスカラー1個だからです。

勾配消失は、掛け算の連鎖から自動的に生まれる

連鎖律が掛け算である以上、避けられない副作用があります。各層1ユニットの鎖で書くと本質が見えます。

∂L∂z(1)=∂L∂z(L)∏l=2Lw(l)σ′ ⁣(z(l−1))\frac{\partial L}{\partial z^{(1)}} = \frac{\partial L}{\partial z^{(L)}} \prod_{l=2}^{L} w^{(l)} \sigma'\!\left(z^{(l-1)}\right)

∏\prod(パイ)は「並んだ項を全部掛ける」記号、LL は層の総数です。この式が言っているのは要するに、入り口の層に届く勾配は、途中の「重み × 活性化関数の傾き」を全部掛け合わせたものだということ。

掛け算なので、挙動は極端です。各項が1より小さければ結果は指数的に0へ潰れ(勾配消失)、1より大きければ指数的に膨らみます(勾配爆発)。前回見たとおりシグモイドの微分は最大でも0.25なので、10層あれば 0.25100.25^{10}、およそ100万分の1。入り口付近の層はほとんど学習しません。

対策はすべて「掛け算の鎖を守る」という一点に向いています。ReLU は正側の傾きを1にして減衰をなくし、残差接続は勾配に「1」で通り抜ける抜け道を作り、正規化層は各層の入力スケールを揃えて項が極端になるのを防ぎます。爆発側には勾配クリッピング(大きさに上限を設ける)が使われます。

FIG 2逆伝播が求めた勾配は、この等高線の「最も急な下り坂の向き」です。学習率を上げると経路が谷を飛び越え、モーメンタムを足すと谷底での振動が減る様子を確かめてください

numpyで書く逆伝播

さきほど手で追った計算が、そのままコードになります。

def backward(x, y, w1, b1, w2, b2):
    z1 = w1 * x + b1
    a1 = np.maximum(0, z1)        # ReLU
    y_hat = w2 * a1 + b2          # 順伝播: 中間値を保存しておく

    d_yhat = y_hat - y            # dL/dŷ
    d_w2, d_b2 = d_yhat * a1, d_yhat
    d_a1 = d_yhat * w2            # 重みで責任を振り分け直す
    d_z1 = d_a1 * (z1 > 0)        # 活性化の傾きを掛ける(ReLUの微分)
    d_w1, d_b1 = d_z1 * x, d_z1
    return d_w1, d_b1, d_w2, d_b2

(z1 > 0) が ReLU の微分です。真偽値が1と0として扱われるので、正なら傾き1、負なら0が掛かります。逆伝播が順伝播の裏返しであること、順伝播の値(a1、z1)を使い回していることが一目で分かります。

実務で効く3つのポイント

1. 自前実装なら必ず勾配チェックをする 解析的に求めた勾配と数値微分した勾配を突き合わせます。倍精度ならごく小さい相対誤差に収まるはずで、桁が合わなければバグがあります。逆伝播のバグは「学習が少し遅い」という形で現れて気づきにくいので、実装直後に潰すのが得です。

2. 学習時のメモリの正体は中間値 逆伝播には順伝播の中間値が要るので、バッチサイズを2倍にすれば保存すべき活性化も概ね2倍。「推論は動くのに学習でメモリが足りない」の主因はこれです。gradient checkpointing は中間値を捨てて必要時に再計算する手法で、メモリを計算時間と交換します。

3. NaN が出たら、勾配ではなく順伝播を先に疑う 勾配が NaN になったとき、原因は逆伝播そのものより順伝播側にあることが多い。log⁡(0)\log(0)、0除算、学習率が大きすぎて値が発散した、などです。勾配クリッピングは症状を抑えますが原因は消しません。

まとめ

PyTorch や JAX の autograd は、ここまでの手続きを計算グラフから自動生成しているだけです。detach() や no_grad() は「ここで鎖を切る」という宣言だと理解すれば挙動に迷いません。次は、この土台の上に立つAttention機構へ進んでください。

🎬 この内容の解説動画(Manim・字幕つき)

運営: TechAthletes · 編集方針 · 出典の付け方 · 訂正の記録

コメント

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