なぜディープラーニングに線形代数が必要なのか ReLUで手計算する順伝播と逆伝播
こんにちは。ゆうせいです。
ディープラーニングを学び始めると、必ず行列とベクトルが出てきます。そして多くの人が、ここでつまずきます。
「ライブラリが計算してくれるのに、なぜ自分で理解する必要があるのか」
この記事では、その答えを実際の手計算で示します。ただし、いきなり完全な形は扱いません。二段階に分けます。
第1ステップでは、バイアスを外します。式は だけです。行列積、ReLU、転置による逆伝播。この三つの骨格に集中します。
第2ステップで、バイアスを戻します。何が変わり、何が変わらないのかを確認します。
数値は、すべて電卓なしで計算できるように選びました。第1ステップの計算は、更新の直前まですべて整数です。紙とペンだけで最後まで追えます。
結論
線形代数が必要な理由は、三つあります。
一つ目は、書き切れないからです。実際のモデルでは掛け算と足し算が何億回も現れます。一つずつ式に書くことは不可能です。行列は、その全体を一行で表す記法です。
二つ目は、逆伝播が転置で説明できるからです。順伝播で を掛けたなら、逆伝播では
を掛けます。この対応を知っていれば、層ごとに式を暗記する必要がありません。
三つ目は、誤りの大半が形の不一致だからです。実装でつまずく原因のほとんどは、数学の難しさではなく行列の形が合っていないことです。形を追える人は、原因を数分で特定できます。
以下、手を動かして確認していきます。
なぜバイアスなしから始めるのか
いきなり を扱うと、初学者は三つのことを同時に処理することになります。
- 行列積の計算
- ベクトルの加算
- 逆伝播での二つの勾配
バイアスを外せば、 だけになります。覚えることが減り、行列積そのものの働きが見えやすくなります。
そして重要なのは、逆伝播の骨格がバイアスの有無で変わらないことです。転置が現れる理由も、アダマール積を使う理由も、バイアスとは無関係です。
つまり、バイアスは後から足せる部品です。先に骨格を組み、後から部品を付ける。この順序が理解を早めます。
なお、バイアスがないと表現力は落ちます。入力が0のとき出力も必ず0になるためです。原点を通る直線しか引けない、と考えてください。この制約は第2ステップで解消します。
準備 ReLUという活性化関数
計算に入る前に、使う活性化関数を確認します。
定義
正の値はそのまま通し、負の値は0にします。それだけです。
微分
正なら1、負なら0です。 では厳密には微分できませんが、実装上は0または1と決めて扱います。
門番だと思ってください
イメージとしては、門番が近いでしょう。
正の値が来たら、そのまま通します。負の値が来たら、通行止めにして0にします。
そして逆伝播でも同じ判断をします。順伝播で通した経路には誤差もそのまま通し、止めた経路には誤差も通しません。
この対応が、計算を極端に単純にしています。指数関数が一切出てこないため、手計算に向いています。
第1ステップ バイアスなしで骨格をつかむ
使用するネットワーク
入力が2つ、中間層が2つ、出力が1つの構成です。バイアスはありません。
| 層 | 要素数 | 活性化関数 |
|---|---|---|
| 入力層 | 2 | なし |
| 中間層 | 2 | ReLU |
| 出力層 | 1 | なし(恒等) |
記号の意味
先に、使う記号をすべて確認します。ここを飛ばさないでください。
| 記号 | 意味 | 形 |
|---|---|---|
| 入力ベクトル | 2行1列 | |
| 入力層から中間層への重み | 2行2列 | |
| 中間層の活性化前の値 | 2行1列 | |
| 中間層の出力 | 2行1列 | |
| 中間層から出力層への重み | 1行2列 | |
| 予測値 | 1行1列 | |
| 正解値 | 1行1列 |
初期値
すべて整数にしました。
正解値は次の通りです。

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

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

