3秒でわかる
ニューラルネットワークで入力から出力へ向かって計算を進める処理。予測値を出す唯一の経路で、学習でも推論でもまずここを通ります。
30秒図解
もう少し詳しく
どういうものか
順伝播は、ニューラルネットワークに入力データを入れ、層を順番にたどって出力までを計算する処理です。各層でやることは同じで、入力に重みを掛け、バイアスを足し、活性化関数を通す。これを出力層まで繰り返します。
行列の掛け算と足し算、そして非線形関数が一つ。実体はこれだけです。
なぜ必要か
モデルから予測値を得る経路は順伝播しかありません。学習済みモデルを使う推論では、順伝播を 1 回走らせて終わりです。
学習中の役割はもう一段あります。まず順伝播で予測値を出し、正解との差を損失関数で数値にします。その差を出力側から入力側へ配り直して各重みの直し方を決めるのが逆伝播です。つまり順伝播は、逆伝播が使う材料(各層の途中の値)を作る工程でもあります。順伝播の結果を保存していないと、勾配は計算できません。
具体例
import numpy as np
def relu(x):
return np.maximum(0, x)
def softmax(x):
e = np.exp(x - x.max(axis=1, keepdims=True))
return e / e.sum(axis=1, keepdims=True)
# 入力 4 次元 -> 隠れ層 8 -> 出力 3 クラス
x = np.random.randn(10, 4) # (バッチ10, 特徴4)
W1 = np.random.randn(4, 8) * 0.01
b1 = np.zeros(8)
W2 = np.random.randn(8, 3) * 0.01
b2 = np.zeros(3)
z1 = x @ W1 + b1 # (10, 8)
a1 = relu(z1) # 活性化関数を通す
z2 = a1 @ W2 + b2 # (10, 3)
y = softmax(z2) # 各行の合計が 1 になる確率
print(y.shape, y[0].sum()) # (10, 3) 1.0つまずきやすいところ
最初に必ず詰まるのが行列の形です。入力が (バッチ数, 特徴数) なら、重みは (特徴数, 出力数) でないと掛けられません。形が合わないというエラーが出たら、層ごとに shape を出力して境目を探すのが早道です。
理屈の面で見落としがちなのが活性化関数です。これを入れ忘れると、何層積んでも行列の掛け算が続くだけで、結局 1 層の線形変換と等価になります。層を深くした意味が消えるので、精度が上がらない原因として実際によく起きます。
PyTorch を使う場合は二つあります。推論のときに torch.no_grad() で囲まないと、逆伝播用の計算グラフを保持し続けてメモリを食います。そして model.eval() を呼ばないと、ドロップアウトやバッチ正規化が学習時の挙動のまま動き、同じ入力でも結果がぶれます。
似た用語との違い
| 用語 | 向き | やること |
|---|---|---|
| 順伝播 | 入力から出力へ | 予測値を計算する |
| 逆伝播 | 出力から入力へ | 各重みの勾配を求める |
| 推論 | 順伝播のみ | 学習済みモデルで予測を出す |
| 学習 | 順伝播と逆伝播の往復 | 重みを更新する |
覚え方
前へ進んで答えを出し、後ろへ戻って直す。往路が順伝播、復路が逆伝播です。