なぜディープラーニングに線形代数が必要なのか ReLUで手計算する順伝播と逆伝播
こんにちは。ゆうせいです。
ディープラーニングを学び始めると、必ず線形代数が出てきます。行列、ベクトル、転置、内積。数学から離れていた人にとっては、ここが最初の関門です。
そして、多くの人がこう思います。
「ライブラリが計算してくれるのに、なぜ自分で理解する必要があるのか」
この記事では、その答えを実際の計算で示します。小さなネットワークを一つ用意し、順伝播と逆伝播を最後まで手で計算します。
活性化関数にはReLUを使います。微分値が0か1しかないため、指数関数の計算が一切不要です。電卓すら要りません。紙とペンだけで追えます。
計算を終えたとき、線形代数が「便利な道具」ではなく「そう書くしかない書き方」だと分かるはずです。
結論
線形代数が必要な理由は、三つあります。
一つ目は、書き切れないからです。実際のモデルでは、掛け算と足し算が何億回も現れます。一つずつ式に書くことは物理的に不可能です。行列は、その全体を一行で表す記法です。
二つ目は、逆伝播の構造が線形代数で説明できるからです。順伝播で を掛けたなら、逆伝播では
を掛けます。この対応関係を知っていれば、逆伝播の式を暗記する必要がありません。
三つ目は、誤りの大半が形の不一致だからです。実装でつまずく原因のほとんどは、数学の難しさではなく、行列の形が合っていないことです。形を追える人は、原因を数分で特定できます。
以下、順に確認していきます。
準備 ReLUという活性化関数
計算に入る前に、使う活性化関数を確認します。
定義
正の値はそのまま通し、負の値は0にする。それだけの関数です。
日本語では正規化線形関数と呼ばれますが、現場ではReLUと呼ぶのが一般的です。
微分
正なら1、負なら0です。
では厳密には微分できませんが、実装上は0または1と決めて扱います。浮動小数点の計算でちょうど0になることはほぼないため、実用上の問題にはなりません。
なぜこれを使うのか
理由は三つあります。
一つ目は、計算が簡単なことです。指数関数が不要です。手計算に向いています。
二つ目は、非線形であることです。折れ曲がりがあるため、層を重ねる意味が生まれます。
三つ目は、微分値が1であることです。逆伝播で誤差が減衰しません。この性質は、後で深い層の話をするときに効いてきます。
通す門番だと思ってください
イメージとしては、門番が近いでしょう。
正の値が来たら「どうぞ」と、そのまま通します。負の値が来たら「通行止め」で、0にします。
そして逆伝播のときも同じです。順伝播で通した経路には、誤差もそのまま通します。止めた経路には、誤差も通しません。
この対応関係が、計算を単純にしています。
使用するネットワーク
計算に使う小さなネットワークを定義します。
入力が2つ、中間層が2つ、出力が1つの構成です。
| 層 | 要素数 | 活性化関数 |
|---|---|---|
| 入力層 | 2 | なし |
| 中間層 | 2 | ReLU |
| 出力層 | 1 | なし(恒等) |
記号の意味
先に、使う記号をすべて説明します。ここを飛ばさないでください。
| 記号 | 意味 | 形 |
|---|---|---|
| 入力ベクトル | 2行1列 | |
| 入力層から中間層への重み | 2行2列 | |
| 中間層のバイアス | 2行1列 | |
| 中間層の活性化前の値 | 2行1列 | |
| 中間層の出力 | 2行1列 | |
| 中間層から出力層への重み | 1行2列 | |
| 出力層のバイアス | 1行1列 | |
| 予測値 | 1行1列 | |
| 正解値 | 1行1列 |
初期値
計算しやすい値を選びました。
正解値は次の通りです。

第1部 順伝播を手で計算する
順伝播とは、入力から予測値を求める計算です。
なぜ行列で書くのか
まず、行列を使わずに書いてみます。
2行で済んでいます。しかし、中間層が100個あれば100行、入力が784個あれば1行あたり785項になります。
これを行列で書くと、次の一行になります。
中間層が何個でも、入力が何個でも、この式は変わりません。これが行列を使う第一の理由です。
手順1 中間層の入力を求める
計算します。
1行目を計算します。
バイアスを足します。
2行目を計算します。
バイアスを足します。
結果は次の通りです。
ここで確認してほしいことがあります。行列の積では、和を取る操作が入ります。 と
の情報が混ざって、
という一つの値になりました。
これが、ニューラルネットワークが特徴を作り出す仕組みです。複数の入力を混ぜ合わせ、新しい値を生み出しています。
手順2 ReLUを通す
は正なので、そのまま通ります。
も正なので、そのまま通ります。
計算らしい計算がありません。値を見て、正か負かを判断するだけです。
ここで重要な点があります。ReLUは、各要素に独立して適用されます。1番目の出力は1番目の入力にしか依存しません。
行列の積では情報が混ざりましたが、活性化関数では混ざりません。この違いが、後の逆伝播で効いてきます。
手順3 出力を求める
計算します。
足し合わせます。
バイアスを足します。
予測値は1.22になりました。
手順4 損失を求める
二乗誤差を使います。定義は次の通りです。
係数の は、微分したときに2が消えて式が簡単になるために付けます。数学的な必然性はありません。
計算します。
損失は0.2592です。正解は0.5なのに1.22を出力したので、誤差が出ています。
第2部 逆伝播を手で計算する
逆伝播とは、損失を減らすために各パラメータをどう変えればよいかを求める計算です。
何を求めたいのか
求めたいのは、次の四つです。
それぞれ、そのパラメータを少し増やしたとき損失がどれだけ変わるかを表します。
値が正なら、そのパラメータを減らせば損失が下がります。値が負なら、増やせば下がります。
逆から辿る理由
損失は、出力の関数です。出力は、 と
の関数です。
は
の関数で、
は
と
の関数です。
つまり、次の連鎖になっています。
が損失に与える影響を知るには、この連鎖を逆に辿る必要があります。これが連鎖律です。
手順1 出力層の誤差
まず、損失を予測値で微分します。
導出を確認します。
係数 を付けた理由が、ここで分かります。
出力層は恒等関数なので、 です。したがって次のようになります。
この を、出力層の誤差と呼びます。
手順2 出力層のパラメータの勾配
でしたので、次のようになります。
を転置している点に注目してください。
が1行1列、
が1行2列なので、結果は1行2列になります。
と同じ形です。
勾配の形は、必ず対応するパラメータの形と一致します。これは強力な検算になります。
計算します。
バイアスについては、 を
で微分すると1になるので、次の通りです。
手順3 中間層へ誤差を伝える
ここが逆伝播の核心です。
転置が現れました。なぜでしょうか。
順伝播では、2つの値から1つの値を作りました。逆伝播では、1つの誤差を2つに配分します。方向が逆なので、行列も転置されます。
形で確認します。 は2行1列、
は1行1列なので、結果は2行1列です。
と同じ形になっています。
計算します。
重みが大きいほど、大きな誤差が配分されています。影響が大きかった経路には、責任も大きく割り当てられる、という理屈です。
手順4 ReLUを逆に通る
は、どちらも正でした。したがって微分は次の通りです。
これを掛けます。
ここで はアダマール積、つまり同じ位置どうしを掛ける演算です。
なぜ行列の積ではないのでしょうか。ReLUが各要素に独立して適用されたからです。1番目の出力は1番目の入力にしか依存しないので、混ざりようがありません。
計算します。
値がそのまま通りました。門番の例えで言えば、順伝播で通した経路なので、誤差もそのまま通したことになります。
手順5 中間層のパラメータの勾配
形を確認します。 が2行1列、
が1行2列なので、結果は2行2列です。
と一致します。
計算します。
1行目です。
2行目です。
2列目の値が1列目の2倍になっています。入力 が
の2倍だからです。大きな入力に掛かる重みほど、変更の影響が大きい。この関係が数値に現れています。
バイアスの勾配は次の通りです。
手順6 パラメータを更新する
学習率を とします。更新式は次の通りです。
を更新します。
を更新します。
を更新します。
を更新します。
手順7 本当に損失が下がったか確かめる
ここが最も納得できる部分です。更新後の値で、もう一度順伝播を計算します。
どちらも正なので、ReLUはそのまま通します。
出力を計算します。
損失を計算します。
結果を比較します。
| 項目 | 更新前 | 更新後 |
|---|---|---|
| 予測値 | 1.2200 | 0.7866 |
| 損失 | 0.2592 | 0.0411 |
損失が約84%減少しました。予測値が正解の0.5に近づいています。
これが学習です。この計算を、データを変えながら何万回も繰り返します。
第3部 負の値が出るとどうなるか
ここまでの計算では、 がどちらも正でした。負になる場合を確認しておきます。
設定を変える
の1行目を、次のように変えてみます。
他の値はそのままです。
順伝播
ReLUを通します。1番目は負なので0になります。
出力を計算します。
損失を計算します。
逆伝播
ReLUの微分を求めます。 は負なので0、
は正なので1です。
アダマール積を計算します。
1番目がゼロになりました。
の勾配を計算します。
1行目がすべてゼロです。この入力に関しては、1番目のユニットに繋がる重みは更新されません。
これは正しい挙動
一見すると問題に見えますが、これは正しい動作です。
1番目のユニットは、この入力に対して0を出力しました。出力に何も寄与していません。寄与していないのだから、責任もありません。したがって勾配もゼロになります。
門番の例えで言えば、通行止めにした経路には誤差も流れない、ということです。
ただし、注意点もあります。学習率が大きすぎて重みが極端な負の値になると、どの入力に対しても となり、そのユニットが二度と復活しなくなる場合があります。これを死んだReLU問題といいます。
対策としては、学習率を適切に設定することや、負の側でもわずかに勾配を残すLeaky ReLUなどの改良版を使う方法があります。初学者の段階では、そういう現象があると知っておけば十分です。
第4部 なぜ線形代数でなければならないのか
手計算を終えたところで、最初の問いに戻ります。
理由1 規模が違いすぎる
今回のネットワークのパラメータ数を数えます。
合計9個です。手計算で追えました。
では、手書き数字認識でよく使われる構成ではどうでしょうか。入力784、中間層128、出力10とします。
合計は次の通りです。
約10万個です。1つの計算に5秒かかるとして、順伝播1回に必要な時間を求めます。
約509,000秒、日数に直します。
順伝播1回に約6日かかります。学習には数万回の繰り返しが必要ですから、人間の手には負えません。
さらに、GPT-2の小さいモデルでは、1つの層だけで次の規模になります。
これが12層分あり、それ以外のパラメータも加わります。個別の式として書き下すことは、原理的に不可能です。
行列は、この規模を扱うための唯一の記法です。
理由2 順伝播と逆伝播が対応している
計算した式を並べてみます。
| 方向 | 式 |
|---|---|
| 順伝播 | |
| 逆伝播(前の層へ) | |
| 逆伝播(重みへ) |
順伝播で を掛けたなら、逆伝播では
を掛けます。この対応は、どの層でも変わりません。
この規則を知っていれば、逆伝播の式を層ごとに暗記する必要がありません。転置するだけです。
なぜ転置になるのか。直感的には、情報の流れる向きが逆になるからです。順伝播では入力から出力へ、逆伝播では出力から入力へ。行と列の役割が入れ替わります。
理由3 形が合っているかが検算になる
計算の途中で、形を何度も確認しました。まとめます。
| 量 | 形 | 対応するもの |
|---|---|---|
| 2行1列 | ||
| 2行2列 | ||
| 2行1列 |
勾配の形は、必ず対応するパラメータの形と一致します。一致しなければ、どこかで間違えています。
実装でつまずく原因のほとんどは、数学の難しさではなく形の不一致です。形を追える人は、エラーの原因を数分で特定できます。追えない人は、何時間も試行錯誤することになります。
理由4 まとめて計算できる
実際の学習では、データを1件ずつではなく、まとめて処理します。これをミニバッチといいます。
入力を1件から4件に増やすと、 の形が2行1列から2行4列に変わります。
計算式は変わりません。
が2行2列、
が2行4列なので、
は2行4列になります。4件分の結果が一度に得られました。
式を書き換えずに、データ量だけを増やせる。これが行列で書く利点です。
そして、この形の計算はGPUが得意とする処理です。多数の乗算と加算を並列に実行できるため、CPUより桁違いに速くなります。
線形代数で書けることと、ハードウェアで高速化できることは、直結しています。
理由5 ReLUだからこそ見える構造
今回、活性化関数の微分がすべて1か0でした。おかげで、逆伝播の本質が見えやすくなっています。
括弧の中は行列の積です。誤差を前の層の次元へ戻しています。
括弧の外はアダマール積です。通す経路と止める経路を選別しています。
混ぜる操作と選別する操作。この二つが交互に現れるのが、ニューラルネットワークの構造です。線形代数の二つの演算が、そのまま役割分担しています。
練習問題
自分で手を動かして確認してください。解答は各問題の直後にあります。
問題1 順伝播
本文と同じ重みとバイアスを使い、入力を次のように変えて順伝播を計算してください。
、
、
、
を求めてください。正解値は
です。
解答を示します。
を計算します。
1行目です。
2行目です。
どちらも正なので、ReLUはそのまま通します。
出力を計算します。
損失を計算します。
補足します。本文の入力 と今回の
は、成分の値は同じで順序だけが違います。それでも結果は異なりました。行列の積では、どの位置の値にどの重みが掛かるかが決まっているためです。
問題2 形の理解
入力784、中間層128、出力10のネットワークについて答えてください。
(1) 、
、
、
の形をそれぞれ答えてください。 (2) パラメータの総数を求めてください。 (3)
の形を答えてください。
解答を示します。
(1) それぞれ次の通りです。
は128行784列です。
で、
が784行1列、
が128行1列になる必要があるためです。
は128行1列です。
は10行128列です。
は10行1列です。
(2) 総数を計算します。
101,770個です。
(3) 128行784列です。勾配の形は、対応するパラメータと必ず一致します。
補足します。行数が出力側、列数が入力側になる点を押さえてください。 が
の形をしているから、
で次元が変換されます。
問題3 出力層の逆伝播
次の値が与えられているとき、 と
を求めてください。
解答を示します。
を計算します。
形が1行2列で、 と一致しています。
を計算します。
形が2行1列で、 と一致しています。
補足します。二つの式で、掛ける相手が違うことに注目してください。重みの勾配を求めるときは入力側の値を、前の層へ伝えるときは重みの転置を使います。混同しやすい部分です。
問題4 ReLUの微分
中間層の値が で、
のとき、
を求めてください。
解答を示します。
ReLUの微分を求めます。正なら1、負なら0です。
なので1です。
なので0です。
なので1です。
なので0です。
アダマール積を計算します。
補足します。2番目と4番目には勾配が流れません。この入力に関しては、それらのユニットに繋がる重みが更新されないことになります。
特に4番目に注目してください。 の値が0.9と最も大きかったにもかかわらず、
が負のためゼロになりました。誤差が大きくても、順伝播で寄与していなければ責任を問われない、ということです。
問題5 中間層の勾配
、
のとき、
を求めてください。また、なぜ1列目の値が3列目相当に大きくなるのか説明してください。
解答を示します。
1行目です。
2行目です。
理由を説明します。
1列目は入力 に掛かる重みです。
という関係から、
を少し変えたときの
の変化は
倍になります。入力が大きいほど、重みの変更が結果に強く反映されます。
は
の3倍なので、勾配も3倍になっています。
補足します。この性質が、入力データの正規化が必要な理由の一つです。入力のスケールがばらばらだと、勾配の大きさもばらばらになり、学習が不安定になります。
問題6 ミニバッチ
が2行2列、入力
が2行4列のとき、次の問いに答えてください。
(1) の形を答えてください。 (2)
の4という数字は何を表していますか。 (3)
は2行1列ですが、形の違う
にどうやって足すのですか。
解答を示します。
(1) 2行4列です。行列の積では、内側の次元が消えて外側が残ります。
(2) データの件数です。4件分の入力をまとめて処理しています。
(3) ブロードキャストという仕組みによって、 が4列に自動的に複製され、各列に同じ値が足されます。
補足します。ブロードキャストは便利な仕組みですが、注意も必要です。意図しない形の組み合わせでもエラーが出ずに計算が通ってしまうことがあります。計算の前後で形を確認する習慣をつけてください。
問題7 総合
本文と同じネットワークで、学習率だけを に変えた場合、
の更新後の値はいくつになりますか。また、この学習率の設定について考えられる問題を述べてください。
解答を示します。
更新後の値を計算します。
問題点を述べます。
学習率が大きすぎると、最小値を通り越して反対側へ行ってしまう可能性があります。次の更新でまた行き過ぎると、値が振動し、場合によっては発散します。
ReLUを使っている場合、さらに固有の危険があります。重みが大きく負の方向へ振れると、 が常に負になり、そのユニットが死んだReLUの状態に陥ります。一度そうなると、勾配がゼロのままなので復活しません。
一方、学習率が小さすぎると、更新量が小さくなり、学習に膨大な回数が必要になります。
一般には0.001から0.1程度から試し、損失の推移を見ながら調整します。
問題8 発展
ReLUではなくシグモイド関数を使った場合、逆伝播で掛かる値は最大でも0.25であることが知られています。
(1) 20層のネットワークで、勾配が最大どれだけ小さくなるか求めてください。 (2) ReLUの場合はどうなりますか。 (3) この結果から言えることを述べてください。
解答を示します。
(1) 計算します。
を使って概算します。
約1兆分の1になります。
(2) 正の領域では微分が1なので、次のようになります。
減衰しません。
(3) シグモイド関数を中間層に使うと、深いネットワークでは入力側の層が実質的に学習しません。これを勾配消失問題といいます。
ReLUを使えば、正の領域では勾配が減衰しないため、この問題を大幅に緩和できます。ReLUの登場が、深いネットワークの実用化を後押しした理由の一つです。
補足します。今回の手計算でReLUの微分が常に1だったことは、単に計算が楽だったという話ではありません。深層学習が成立するための、本質的な性質でした。
学習の進め方
初学者がこの分野を学ぶ順序を示します。
| 段階 | 内容 |
|---|---|
| 1 | ベクトルと行列の表記に慣れる |
| 2 | 行列の積を手で計算できるようにする |
| 3 | 形の規則を理解する |
| 4 | 順伝播を手で計算する |
| 5 | 連鎖律を理解する |
| 6 | 逆伝播を手で計算する |
| 7 | 更新後に損失が下がることを確認する |
| 8 | 負の値が出る場合も計算する |
7番を必ず実施してください。ここまでやると、計算が正しいことを自分で確認できます。理屈を聞くだけの状態から、納得した状態に変わります。
つまずきやすいのは3番と5番です。3番は面倒に感じますが、後で最も役に立ちます。5番は、微分の連鎖を一度きちんと追っておくと、以降の理解が速くなります。
振り返り
次の問いに答えられるか確認してください。
- 順伝播で
を掛けたとき、逆伝播では何を掛けますか
- 勾配の形は、何と一致しますか
- ReLUの微分はいくつになりますか。場合分けして答えてください
- 活性化関数の逆伝播でアダマール積を使うのはなぜですか
が負のとき、その経路の勾配はどうなりますか。またそれはなぜ正しいのですか
- ミニバッチにすると、式のどこが変わりますか
すべて答えられれば、この記事の内容は理解できています。
まとめと次の学習ステップ
線形代数が必要な理由は、便利だからではありません。それ以外に書きようがないからです。
10万個のパラメータを個別の式で書くことはできません。行列という記法があって初めて、この規模の計算を人間が扱えるようになります。
そして、線形代数を理解していると、逆伝播が暗記の対象ではなくなります。順伝播で を掛けたなら逆伝播では
を掛ける。勾配の形はパラメータの形と一致する。この二つの規則で、大半の式が導けます。
今回の計算で、損失が0.2592から0.0411に下がることを確認しました。この一回の更新を、データを変えながら何万回も繰り返す。それがディープラーニングの学習です。
ReLUを使ったおかげで、指数関数を一度も計算せずに済みました。しかもこの選択は、手計算を楽にするためだけのものではありません。微分が1であることが、深いネットワークの学習を可能にしています。
次の学習ステップとしては、同じ計算をPythonで実装してみてください。手計算の結果と一致すれば、理解が確かなものになります。ライブラリを使う前に、まずNumPyだけで書いてみることをおすすめします。
その先には、より深いネットワーク、畳み込み層、そして注意機構が待っています。いずれも、今回扱った行列の積と転置、そしてアダマール積の組み合わせで構成されています。土台は、すでにできています。
セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。
投稿者プロフィール

- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
海外放浪の末、2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。

