LSTM は 隠れ状態 $h$ に加えて記憶セル $c$ を導入することで RNN の勾配消失問題を解決します。

記法

本ドキュメントは以下の記法で統一しています。

記号 意味
$\cdot$ 行列のドット積(行列積)
$\odot$ 要素積(アダマール積、element-wise product)

勾配消失問題

勾配消失は 逆伝播 で問題になります( 順伝播 では問題になりません)。

中間変数 $$1$ を定義(活性化関数への入力):

\[a = h_{t-1} \cdot W_h + x_t \cdot W_x + b\] \[h_t = \tanh(a)\]

逆伝播と勾配消失のメカニズム

$h_{t-1}$ の勾配:$\frac{\partial L}{\partial h_{t-1}}$

\[\frac{\partial L}{\partial h_{t-1}} = \frac{\partial L}{\partial h_t} \odot \underbrace{(1 - h_t^2)}_{\tanh の微分} \cdot W_h^\top\]

$h_{t-2}$ の勾配:$\frac{\partial L}{\partial H_{t-2}}$

\[\frac{\partial L}{\partial h_{t-2}} = \lbrace \frac{\partial L}{\partial h_t} \odot (1 - h_t^2) \cdot W_h^\top \rbrace \odot (1-h_{t-2}^2) \cdot W_h^\top\]

[!NOTE]
️ $W_h^\top$ の $\top$ は転置を表します。

t ステップ遡ると $W_h^\top$ の積が t 回繰り返される:

\[\frac{\partial L}{\partial h_1} \propto \frac{\partial L}{\partial h_t} \cdot \underbrace{(W_h)^\top \cdot (W_h)^\top \cdot ...... \cdot (W_h)^\top }_{t 回 の行列積}\]

[!NOTE]
$\propto$ は「比例する」の意味です。他の係数を省略して本質的な部分だけ示しています。

勾配消失の 2 つの要因

要因 値の範囲 問題
$\tanh$ の微分は $(1 - h_t^2)$ 。tanh の値域は 0 < y < 1 なので $1-h_t^\top$ は常に [0, 1] 常に $[0, 1]$ 掛けるたびに小さくなる
$W_h$ のスペクトル半径 $\rho < 1$ 固有値の絶対値 < 1 t 乗で 0 に収束

固有値

定義

正方行列 $$1$ に対して、ゼロでないベクトル $v$ とスカラー $λ$ が以下の関係を満たすとき $λ$ を $$1$ の固有値、$v$ を $λ$ に対応する固有ベクトルといいます。

\[A \mathbf{v} = \lambda \mathbf{v}\]
  • 固有値は 正方行列全体 に対して定義されます
  • $n \times n$ 行列には n 個の固有値が存在します(複素数を含む)
記号 意味
$\mathbf{v}$ 固有ベクトル(掛けても方向が変わらない特別なベクトル)
$\lambda$ 固有値(その方向に何倍伸び縮みするか)

具体例

\[A = \begin{pmatrix} 2 & 0 \\ 0 & 3 \end{pmatrix}\]
  • $\mathbf{v} = \begin{pmatrix} 1 \ 0 \end{pmatrix}$ → 固有値 $\lambda = 2$(2倍に伸びる)
  • $\mathbf{v} = \begin{pmatrix} 0 \ 1 \end{pmatrix}$ → 固有値 $\lambda = 3$(3倍に伸びる)

固有値と勾配消失・爆発の関係

$\rho(W_h) = \max_i \lambda_i $(最大固有値の絶対値)をスペクトル半径と呼びます。
条件 $W_h^T$ の挙動 結果
$\rho < 1$(全固有値の絶対値 < 1) $\to 0$ 勾配消失
$\rho = 1$ 安定 安定
$\rho > 1$(ある固有値の絶対値 > 1) $\to \infty$ 勾配爆発

[!NOTE]
消失と爆発が同時に発生刷る場合もあります(ある成分は 0 へ、別の成分は $\infty$ へ)

LSTM による解決策

RSS で導入した(勾配消失問題を持つ)隠れ状態 $h_t$ に加えて記憶セル $c_t$ を導入します。 以下に $c_t$ について勾配消失の影響を受けない理由を説明します。

セル状態 $c_t$ の順伝播

\[c_t = \underbrace{f_t \odot c_{t-1}}_{\text{過去を保持}} + \underbrace{g_t \odot i_t}_{\text{新情報を追加}}\]

セル状態 $c_t$ の逆伝播

$c_t$ を $c_{t-1}$ で微分すると:

\[\frac{\partial c_t}{\partial c_{t-1}} = f_t\]
  • $f_t \odot c_{t-1}$ を $c_{t-1}$ で微分 : $f_t$ が残る
  • $i_t \odot \tilde{c}t$ を $c{t-1}$ で微分 : $c_{t-1}$ を含まないので 0 になる(加算項は消える)

t 時刻について展開すると:

\[\frac{\partial L}{\partial c_0} = \frac{\partial L}{\partial c_T} \cdot \prod_{k=1}^{T} f_k\]

単純 RNN との比較

  単純 RNN LSTM
逆伝播で掛かるもの 固定の $W_h$(変えられない) 時刻 t ごとに異なる $f_t$(学習で制御できる)
値の範囲 固有値に依存(正確にはスペクトル半径) sigmoid なので $(0, 1)$
制御 困難 $f_t \approx 1$ に学習できる
長期依存 学習困難 学習できる

LSTM が勾配消失に強い理由

理由 1. $f_t$ が時刻ごとに独立(異なる値)

  • 単純 RNN は 同じ $W_h$ の t 乗:固有値(スペクトル半径)に支配される
  • LSTM は 毎時刻異なる $f_t$ の積:固有値問題が起きない

理由 2. $f_t$ を学習で制御できる

$f_t$ は $\text{sigmoid}$ なので値の範囲は $(0, 1)$ です。

[!NOTE]

  • $f_t \approx 1$ に学習:勾配がほぼそのまま過去へ流れます(長期記憶を保持)
  • $f_t \approx 0$ に学習:意図的に過去の情報を遮断できます(忘却)

[!NOTE] この仕組みを定常誤差カルーセル(CEC: Constant Error Carousel)と呼ぶ

$f_t$ を制御刷る方法う

\[y = \sigma(x) = \frac{1}{1 + \exp(-x)}\]

\[\begin{aligned} a_t^f = h_{t-1} \cdot W_h^f + x \cdot W_x^f + b \\ f_t = \sigma (a_t^f) \end{aligned}\]

sigmoid 関数( $\sigma$ )に渡す $a_t^f$ を大きくすれば $f_t$ は 1 に近づきます。
もっとも簡単な方法はバイアス $b$ を大きくすることです。

加算構造が勾配のハイウェイとして機能する理由

$c_t$ の更新式を 2 項の加算として見ると:

\[c_t = \underbrace{f_t \odot c_{t-1}}_{\text{項A}} + \underbrace{g_t \odot i_t}_{\text{項B}}\]

逆伝播で上流から勾配 $\frac{\partial L}{\partial c_t}$ が来たとき、加算ノードはそれをそのまま 1 倍で項 A・項 B の両方に流します。

\[\frac{\partial L}{\partial (f_t \odot c_{t-1})} = \frac{\partial L}{\partial c_t} \times 1 = \frac{\partial L}{\partial c_t}\]

項 A への勾配は減衰しません。これが「加算がハイウェイとして機能する」という意味です。

[!NOTE]
項 A の内部 $f_t \odot c_{t-1}$ はさらに乗算なので、$c_{t-1}$ まで遡ると $f_t$ が掛かります。 最終的な勾配消失の制御は前半の $f_t$ の議論(理由 1・2 )に帰着します。 加算構造は「勾配が通る経路を確保する」補強であり、両者が合わさって初めて完結します。

LSTM 詳細

LSTM とは短期記憶( short term memory )を長い( long )時間継続すること意味します。 具体的には勾配消失を受けにくい(制御できる)記憶セル $c_t$ を導入します。

順伝播

LSTM 2

LSTM 3

LSTM は状態を保持する隠れ状態 $h_t$ に加えて記憶を表すセル状態 $c_t$ を持ちます。
$c_t$, $h_t$ の順伝播は以下のとおりです。

\[\begin{aligned} c_t = f_t \odot c_{t-1} + g_t \odot i_t \quad \text{※ c の添字が t-1 に注意} \\ h_t = o \odot \tanh(c_t) \quad \text{※ の添字が t に注意} \\ \\ o_t = \sigma( h_{t-1} \cdot W_h^o + x_t \cdot W_x^o + b) \\ f_t = \sigma( h_{t-1} \cdot W_h^f + x_t \cdot W_x^f + b) \\ i_t = \sigma( h_{t-1} \cdot W_h^i + x_t \cdot W_x^i + b) \\ g_t = \tanh( h_{t-1} \cdot W_h^g + x_t \cdot W_x^g + b) \\ \\ W_x^f \neq W_x^i \neq W_x^g \neq W_x^o​ \\ W_h^f \neq W_h^i \neq W_h^g \neq W_h^o \end{aligned}\]
  • $f_t \odot c_{t-1}$:過去の記憶を $f_t$ の割合で残す
  • $g_t \odot i$:新しい情報 $g_t$ を $i_t$ の割合で追加する
  • $\tanh(c_t)$:セル状態を $(-1, 1)$ に正規化
  • $o \odot$:出力ゲートで「どれだけ外に出すか」を制御
  • $h_t$, $c_t$ は ゲート $f_t, i_t, g_t, o_t$ の影響を受ける
  • $f, i, o$ は情報を反映する割合を表すので活性化関数は sigmoid 関数を使用するので各要素が 0 < y < 1 の $(N, H)$ 次元の配列
  • $g$ は追加する情報の大きさを表すので活性化関数として tanh 関数を使用するので各要素が -1 < y < 1 の $(N, H)$ 次元の配列

効率的に計算するため $f, i, g, o$ の Affine 変換をまとめて計算できるようにします。

\[\begin{aligned} A = h_{t-1} \cdot W_h + x_t \cdot W_x + b \\ \\ W_x^f \neq W_x^i \neq W_x^g \neq W_x^o​ \\ W_h^f \neq W_h^i \neq W_h^g \neq W_h^o \end{aligned}\]

コード

以下 forget を $f$ 、input を $i$、 generate を $g$ 、output を $o$ で表します。

  • バッチサイズ:N
  • 入力の分散表現の次元:D
    • $x_t$ の次元:$(N, D)$
    • $W_x$ の次元: $(D, 4H)$
      • $W_x^f \neq W_x^i \neq W_x^g \neq W_x^o​$ をまとめて $W_x$ と表記(各重み行列は $(D, H)$ )
  • 隠れ状態の分散表現の次元:H
    • $h_t$ の次元: $(N, H)$
    • $W_h$ の次元: $(H, 4H)$
      • $W_h^f \neq W_h^i \neq W_h^g \neq W_h^o$ をまとめて$ $W_h$ と表記(各重み行列は $(H, H)$ )
    • forget, input, output ゲートおよび generate をまとめて考える場合
  • セル状態(記憶)の次元: H
    • $c_t$ の次元; $(N, H)$
  • $b$ の次元:$(1, 4H)$
import numpy as np

# h_t-1(h_prev), c_t-1(c_prev) は所与とする

input_size = 3
H = hidden_size = 4
bach_size = 10

# 作成  = (4, 4 * 4) 版
W_h = np.random.randn(hidden_size, 4 * hidden_size)  # shape: (4, 16)
# W_x の同様に求める
W_x = np.random.randn(input_size, 4 * hidden_size) # shape: (3, 16)

# Affine 部分( h_prev は h_{t-1} で (3, 4) のミニバッチ
# x @ Wx (10, 16), h_prev @ Wh (10, 16) なので加算可能
A = np.dot(x, Wx) + np.dot(h_prev, Wh) + b

f = A[:, :H]
g = A[:, H:2*H]
i = A[:, 2*H:3*H]
o = A[:, 3*H:]

# 活性化関数に適用
# sigmoid は定義済みとする
f = sigmoid(f)
g = np.tanh(g)
i = sigmoid(i)
o = sigmoid(o)


# c_t, h_t を取得
c_next = f * c_prev + g * i
h_next = o * np.tanh(c_next)

# 補足:取り出し(列方向)
# W_h_f = W_h[:, 0 * hidden_size : 1 * hidden_size]   # forget gate
# W_h_i = W_h[:, 1 * hidden_size : 2 * hidden_size]   # input gate
# W_h_g = W_h[:, 2 * hidden_size : 3 * hidden_size]   # cell gate
# W_h_o = W_h[:, 3 * hidden_size : 4 * hidden_size]   # output gate

$$1$ を使って f, i, g, o を求める Python コードです。

スライス 取り出す列 shape
A[:, :H] $0 \sim H$ $(N, H)$
A[:, H:2*H] $H \sim 2H$ $(N, H)$
A[:, 2*H:3*H] $2H \sim 3H$ $(N, H)$
A[:, 3*H:] $3H \sim 4H$ $(N, H)$

LSTM と RNN の比較

入力と隠れ状態

内容 RNN LSTM
引数 x, h_prev x, h_prev, c_prev
返り値 h_next h_next, c_next
記憶 $h$(隠れ状態)のみ $h$(隠れ状態)+ $c$(セル状態)

c( cell state )は LSTM が新たに持つ長期記憶。

重みの shape

RNN との比較:

パラメータ RNN LSTM
$W_x$ $(D, H)$ $(D, 4H)$
$W_h$ $(H, H)$ $(H, 4H)$
$b$ $(1, H)$ $(1, 4H)$

4つのゲート分をまとめて1つの行列に格納しています。

4つのゲート

記号 名前 活性化関数 役割
$f$ forget gate sigmoid 過去の記憶 $c_{t-1}$ をどれだけ忘れるか
$g$ cell gate tanh セル状態に加える新しい情報
$i$ input gate sigmoid $g$ をどれだけセル状態に反映するか
$o$ output gate sigmoid セル状態 $c_t$ からどれだけ出力するか

なぜ sigmoid と tanh を使い分けるか

関数 値域 用途
sigmoid $(0, 1)$ 割合・比率(どれだけ通すか)→ ゲート制御
tanh $(-1, 1)$ 情報量(値の大きさ・方向)→ 新情報・出力

$f$、$i$、$o$ は「0 〜 1 の割合」として機能するので sigmoid。
$g$ は新しい情報そのものなので符号を含む tanh。

逆伝播

LSTM 2

$\frac{\partial L}{\partial W_h^f}$

逆伝播の例として重み行列 $W_h^f$ の勾配 $\frac{\partial L}{\partial W_h^f}$ を考えます。
連鎖律は $\frac{\partial L}{\partial c_t} \odot \frac{\partial c_t}{\partial f} \odot \frac{\partial f}{\partial A^f} \odot \frac{\partial A^f}{\partial W_h^f}$ になります( 経路: $L \rightarrow c_t \rightarrow f \rightarrow A^f \rightarrow W_h^f$ )。

\[\frac{\partial L}{\partial W_h^f} = \frac{\partial L}{\partial c_t} \odot \frac{\partial c_t}{\partial f} \odot \frac{\partial f}{\partial A^f} \odot \frac{\partial A^f}{\partial W_h^f}\]

$\frac{\partial L}{\partial c_t}$

\[\frac{\partial L}{\partial c_t} = dc\_next + dh\_next \odot o \odot (1−\tanh^2(c_t​)) = ds\]

$c_t$ の逆伝播は t + 1 が返す dc_next と t 自身ので $dh_next \odot o \odot (1−\tanh^2(c_t​))$ の和になります。

勾配 意味 ゼロから作る Deep Learning 2 のコード変数
$\frac{\partial L}{\partial h_t}$ 時刻 t + 1 の LSTM が $h_t$​ に対して求めた勾配 $dh_next
$\frac{\partial L}{\partial c_t}$ の一部 時刻 t + 1 の LSTM が $c_t$​ に対して求めた勾配 の一部(経路 1) ​dc_next
$\frac{\partial L}{\partial c_t}$ とイコール $c_t$​ に対する完全な勾配(経路 1 は t + 1 から、経路 2 は t 自身で計算) ​ds

$c_t$ の経路:

  • 経路 1 ( $c_t \rightarrow c_{t+1}$ ):t + 1 のステップが dc_next として返してくれる
  • 経路 2 ($c_t \rightarrow h_t$ ):ステップ T で計算する $dh_next \odot o \odot (1−tanh^2(c_t))$

$\frac{\partial c_t}{\partial f} = c_{t-1}$

$\frac{\partial c_t}{\partial f}$ を求めるために $f \odot c_{t−1} + g \odot i$ を $f$ で微分します。

\[\frac{\partial c_t}{\partial f} = c_{t-1}\]

$\frac{\partial f}{\partial A^f}$, $\frac{\partial i}{\partial A^i}$, $\frac{\partial g}{\partial A^g}$, $\frac{\partial o}{\partial A^o}$

\[A = h_{t-1} \cdot W_h + x_t \cdot W_x + b\] \[A^f = h_{t-1} \cdot W_h^f + x_t \cdot W_x^f + b \\ A^i = h_{t-1} \cdot W_h^i + x_t \cdot W_x^i + b \\ A^g = h_{t-1} \cdot W_h^g + x_t \cdot W_x^g + b \\ A^o = h_{t-1} \cdot W_h^o + x_t \cdot W_x^o + b\] \[f = \sigma( A^f) \\ i = \sigma( A^i) \\ g = \tanh( A^g) \\ o = \sigma( A^o)\]

上記より:

\[\frac{\partial f}{\partial A^f} = \frac{\partial \sigma}{\partial A^f} = f(1-f) \\ \frac{\partial i}{\partial A^i} = \frac{\partial \sigma}{\partial A^i} = i(1-i) \\ \frac{\partial g}{\partial A^g} = \frac{\partial \tanh}{\partial A^g} = (1-g^2) \\ \frac{\partial o}{\partial A^o} = \frac{\partial \sigma}{\partial A^o} = o(1-o)\]

$\frac{\partial A^f}{\partial W_h^f}$, $\frac{\partial A^i}{\partial W_h^i}$, $\frac{\partial A^g}{\partial W_h^g}$, $\frac{\partial A^o}{\partial W_h^o}$

f を例にとると $A^f = h_{t-1} \cdot W_h^f + x_t \cdot W_x^f + b$ を $W_h^f$ で偏微分して $\frac{\partial A^f}{\partial W_h^f} = h_{t-1}$ を求めます。
同様に $A^i$, $A^g$,$A^o$ の偏微分 $\frac{\partial A^i}{\partial W_h^i}$, $\frac{\partial A^g}{\partial W_h^g}$, $\frac{\partial A^o}{\partial W_h^o}$ を求めます。

\[\frac{\partial A^f}{\partial W_h^f} = h_{t-1} \\ \frac{\partial A^i}{\partial W_h^i} = h_{t-1} \\ \frac{\partial A^g}{\partial W_h^g} = h_{t-1} \\ \frac{\partial A^o}{\partial W_h^o} = h_{t-1}\]

[!NOTE]
実際の計算は以下のようになります。

$\frac{\partial L}{\partial W_h^f} = h_{t-1}^\top \cdot \frac{\partial L}{\partial A^f}$

$h_{t-1}^\top$ を掛ける方向:
$A^f = h_{t-1} \cdot W_h^f + x_t \cdot W_x^f + b$ の形なので $W_h^f$ の勾配は $h_{t-1}^\top$ を左から掛ます。

$\frac{\partial L}{\partial W_h^f}$

上述の微分を連鎖律で繋げて $\frac{\partial L}{\partial W_h^f}$ を求めます。

\[\frac{\partial L}{\partial W_h^f} = \frac{\partial L}{\partial c_t} \odot \frac{\partial c_t}{\partial f} \odot \frac{\partial f}{\partial A^f} \odot \frac{\partial A^f}{\partial W_h^f}\]

$\frac{\partial L}{\partial c_{t-1}} = \frac{\partial L}{\partial c_t} \odot \frac{\partial c_t}{\partial c_{t-1}} = ds \odot f$

$\frac{\partial L}{\partial W_h^f}$ の算出には使用しません。

$\frac{\partial c_t}{\partial c_{t-1}}$ を求めるために $f \odot c_{t−1} + g \odot i$ を $c_{t-1}$ で微分します。

\[\frac{\partial c_t}{\partial c_{t-1}} = f\]

$\frac{\partial A^f}{\partial h_{t-1}}$, $\frac{\partial A^i}{\partial h_{t-1}}$, $\frac{\partial A^g}{\partial h_{t-1}}$, $\frac{\partial A^o}{\partial h_{t-1}}$

$\frac{\partial L}{\partial W_h^f}$ の算出には使用しません。

\(A^f = h_{t-1} \cdot W_h^f + x_t \cdot W_x^f + b \\ A^i = h_{t-1} \cdot W_h^i + x_t \cdot W_x^i + b \\ A^g = h_{t-1} \cdot W_h^g + x_t \cdot W_x^g + b \\ A^o = h_{t-1} \cdot W_h^o + x_t \cdot W_x^o + b\) 微分係数を求めます。

\[\frac{\partial A^f}{\partial h_{t-1}} = W_h^f \\ \frac{\partial A^i}{\partial h_{t-1}} = W_h^i \\ \frac{\partial A^g}{\partial h_{t-1}} = W_h^g \\ \frac{\partial A^o}{\partial h_{t-1}} = W_h^o\]

$\frac{\partial L}{\partial h_{t-1}}$ の逆伝播

LSTM 2

経路

$h_{t-1}$ は $f$・$i$・$g$・$o$ の 4 つすべてに影響するためそれぞれの経路の勾配を足し合わせます。

\[L \rightarrow c_t \rightarrow \{f, i, g\} \rightarrow A^{\{f,i,g\}} \rightarrow h_{t-1} \quad \text{※} \ c_t = f \odot c_{t-1} + g \odot i \ \text{より} \\ L \rightarrow h_t \rightarrow o \rightarrow A^o \rightarrow h_{t-1} \quad \text{※} \ h_t = o \odot \tanh(c_t) \ \text{より} \\\]

$$1$ の勾配

連鎖律の繋ぎ方(各因子の関係を示す)はすべて $\odot$ で表します。

ゲート 連鎖律 $da$ の値
$dA^f$ $dc_t \odot \frac{\partial c_t}{\partial f} \odot \frac{\partial f}{\partial A^f}$ $dc_t \odot c_{t-1} \odot f \odot (1-f)$
$dA^i$ $dc_t \odot \frac{\partial c_t}{\partial i} \odot \frac{\partial i}{\partial A^i}$ $dc_t \odot g \odot i \odot (1-i)$
$dA^g$ $dc_t \odot \frac{\partial c_t}{\partial g} \odot \frac{\partial g}{\partial A^g}$ $dc_t \odot i \odot (1-g^2)$
$dA^o$ $dh_t \odot \frac{\partial h_t}{\partial o} \odot \frac{\partial o}{\partial A^o}$ $dh_t \odot \tanh(c_t) \odot o \odot (1-o)$

$\frac{\partial L}{\partial h_{t-1}}$ の計算

Step 1. $dA$ を求める

4 つのゲートの勾配を横に連結します。

\[dA = \left[ dA^f \mid dA^i \mid dA^g \mid dA^o \right] \quad \text{shape: } (N, 4H)\]

Step 2. $\frac{\partial L}{\partial h_{t-1}}$ を求める(最終的な勾配)

実際の計算( shape を意識した最終形)は $dA$ で一括で求められます。

\[\frac{\partial L}{\partial h_{t-1}} = dA \cdot W_h^\top\]

$dA$ の中に 4 ゲートの寄与がすべて含まれているため、行列積 1 回で $f$・$i$・$g$・$o$ それぞれの $h_{t-1}$ への寄与が自動的に足し合わされます。

補足:$\frac{\partial L}{\partial W_h^f}$ との対比

$W_h^f$ と $h_{t-1}$ はどちらも $A^f = h_{t-1} \cdot W_h^f$ から来ています。

勾配 実際の計算
$\frac{\partial L}{\partial W_h^f}$ $h_{t-1}^\top \cdot dA^f$($h_{t-1}^\top$ を左からドット積)
$\frac{\partial L}{\partial h_{t-1}}$ $dA \cdot W_h^\top$($W_h^\top$ を右からドット積)

活性化関数

ハイパボリックタンジェント/双曲線正接( tanh function )

\[tanh(x) = \frac{e^x-e^{-x}}{e^{x} + e^{-x}}\]

tanh

  • tanh 関数の出力範囲は ( −1, 1 )で Sigmoid 関数( 0 - 1 )と異なり負の値を取れるため出力の平均がゼロに近く(zero-centered)なり次の層への入力が偏りにくく学習が安定しやすい
  • 最大勾配が 1( x=0 付近)で Sigmoid 関数の最大勾配 0.25 の 4 倍で勾配消失が起きにくい(ただし、 x が大きくなると勾配はほぼ 0 になるため深いネットワークでは依然として勾配消失問題が発生する)
    • ReLU は勾配消失がさらに起きにくい

上記の勾配の性質より現在の深いネットワークの Affine レイヤの活性化関数は ReLU が主流だが RNN 、LSTM の内部ゲートの活性化関数には tanh を使用する場合が多い。

LeLU 関数

ReLU 関数

勾配消失

$x > 0$ のとき x( $x \le 0$ のとき 0 )なので勾配消失を抑えることができます。

補足

LSTM が勾配消失に強い理由

1. RNN の問題:勾配消失

RNN の逆伝播では dh_prev を求めるたびに $W_h^\top$ を掛け続ける。

\[\frac{\partial L}{\partial h_{t-1}} = \frac{\partial L}{\partial a} \cdot W_h^\top\]

これが $T$ ステップ分繰り返されるので、遠くのステップに勾配が届かない(消失する)。


2. LSTM のセル状態 $c$ による解決

LSTM はセル状態 $c$ を足し算で更新する。

\[c_t = f \odot c_{t-1} + g \odot i\]

足し算の逆伝播は「上流の勾配をそのまま流す」ため、$c$ の経路では勾配が減衰しにくい。

dc_prev の逆伝播

dc_prev = ds * f
\[\frac{\partial L}{\partial c_{t-1}} = \frac{\partial L}{\partial c_t} \odot f\]

$T$ ステップ繰り返すと:

\[\frac{\partial L}{\partial c_0} = \frac{\partial L}{\partial c_T} \odot f_T \odot f_{T-1} \odot \cdots \odot f_1\]
  • 掛けるのは固定の $W_h^\top$ ではなく、各ステップで異なる $f$(forget gate)
  • $f \approx 1$ に学習することで勾配をほぼそのまま流せる
  • 「覚えておくべき情報がある」とき、ネットワークは $f \approx 1$ を出力するよう学習する

3. 「dWh は消失しないのか?」という疑問

LSTM でも dWh の計算自体は RNN と同じ。

dWh = np.dot(h_prev.T, dA)

遠くのステップからの勾配は dWh の経路では届きにくい。
ただし dc_prev の経路を通って遠くの情報が dA に届き、dWh に反映される

経路 遠距離の勾配 役割
dh_prev(RNN と同じ) 消失しやすい 短期の依存関係を学習
dc_prev(LSTM 固有) 消失しにくい 長期の依存関係を学習

4. 役割分担まとめ

経路 何を学習するか
dWh / dWx 直近の文脈(短期依存)
dc_prev 遠く離れたステップの情報(長期依存)

具体例

彼女は日本人だ。だから彼女の母国語は__だ。

  • 「母国語」の直前の文脈(短期)→ dWh / dWx の経路
  • 遠く離れた「日本人」という情報(長期)→ dc_prev の経路でセル $c$ に保持

両方の経路があることで、RNN では難しかった長距離依存を学習できる。

5. RNN vs LSTM まとめ

  長距離の勾配経路 結果
RNN dh_prev のみ($W_h^\top$ を $T$ 回掛ける) 遠くのステップに勾配が届かない
LSTM dc_prev がある($f$ を掛けるだけ) 遠くのステップにも勾配が届く

違いの本質:遠くから勾配を届ける経路があるかどうか。

シグモイド関数( Sigmoid function )

\[y = \frac{1}{1 + \exp(-x)}\]

シグモイド関数

シグモイド関数の定義は以下のとおり。 特徴は定義域 $-\infty$ <= x <= $\infty$ に対して y は 0 < y < 1 で $x = 0 のとき y = 0.5$

Python コード

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

勾配消失問題

x の値 sigmoid(x)
0 0.25(最大)
±1 ≈ 0.05
±3 ≈ 0.004

層が深くなるほど勾配が 0 に収束して学習が止まります。

補足 Affine 変換

Affine 変換

数学的には「線形変換+平行移動」のことで、Deep Learning では全結合層の計算を指します。

\[A = x W_x + h_{prev} W_h + b\]

用語の対応

文脈 用語
ゼロつく・教育系 Affine 変換 class Affine としてレイヤー実装
PyTorch 公式 Linear 変換 nn.Linear
論文・一般 全結合 / FC (Fully Connected) FC layer

どれも同じ計算 $xW + b$ を指します。

[!NOTE] ゼロつくでは Affine 変換後にスライス → 活性化関数という流れで LSTM を実装します。 4ゲート分を1つの大行列でまとめて計算することで、行列積を1回で済ませられます(効率化)。