STEP 23:GRU(Gated Recurrent Unit)

⚡ STEP 23: GRU(Gated Recurrent Unit)

LSTMをシンプルに!少ないパラメータで同等の性能

📋 このステップで学ぶこと

  • GRUとは何か?LSTMとの違い
  • 2つのゲート(更新ゲート・リセットゲート)
  • GRUの計算フロー
  • LSTMとGRUの使い分け
  • Kerasでの実装方法
  • 性能比較実験

⚡ 1. GRUとは何か?

1-1. GRUの登場背景

GRU(Gated Recurrent Unit)は、2014年にChoらによって提案された、LSTMを簡略化したアーキテクチャです。

🚗 車の例え

LSTM:高性能セダン
・機能が豊富(3つのゲート + セルステート)
・パーツが多い(パラメータ多)
・燃費がやや悪い(計算量多)

GRU:コンパクトカー
・必要十分な機能(2つのゲートのみ)
・パーツが少ない(パラメータ少)
・燃費が良い(計算量少)

目的地に着く速さは同じくらい!

1-2. LSTMとの主な違い

📊 LSTM vs GRU

LSTM:
・3つのゲート(忘却・入力・出力)
・セルステート(c)と隠れ状態(h)が別
・パラメータ数:多い

GRU:
・2つのゲート(更新・リセット)
・隠れ状態(h)のみ
・パラメータ数:LSTMの約75%

⚙️ 2. GRUの構造

2-1. 2つのゲート

ゲート 役割 LSTMとの対応
更新ゲート(Update Gate) 新旧の情報をどの割合で混ぜるか 忘却ゲート + 入力ゲートを統合
リセットゲート(Reset Gate) 過去の情報をどれだけリセットするか 新しい概念

2-2. GRUの仕組み

以下の図は横スクロールできます。

【GRUの構造】 h_{t-1} │ ┌─────────┼─────────┐ │ │ │ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 更新 │ │ リセット │ │ 候補 │ │ ゲート z│ │ ゲート r │ │ h̃ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ └────┬────┘ │ │ ▼ ▼ ┌─────────────────────────┐ │ h_t = (1-z)×h_{t-1} │ │ + z × h̃ │ └─────────────────────────┘ │ ▼ h_t z = 更新ゲート(0〜1) ・z ≈ 1 → 新しい情報を採用 ・z ≈ 0 → 古い情報を保持 r = リセットゲート(0〜1) ・r ≈ 1 → 過去の情報を使って候補を作成 ・r ≈ 0 → 過去を無視して新しく作成

2-3. GRUの計算式

📐 GRUの計算ステップ

1. 更新ゲート:
z_t = σ(W_z × [h_{t-1}, x_t] + b_z)

2. リセットゲート:
r_t = σ(W_r × [h_{t-1}, x_t] + b_r)

3. 候補隠れ状態:
h̃_t = tanh(W × [r_t × h_{t-1}, x_t] + b)

4. 隠れ状態更新:
h_t = (1 – z_t) × h_{t-1} + z_t × h̃_t

※ LSTMより計算が少ない!

📌 計算の流れを日本語で
  1. 更新ゲート:新しい情報をどれだけ取り入れるか決定
  2. リセットゲート:候補作成時に過去をどれだけ参照するか決定
  3. 候補作成:新しい隠れ状態の候補を計算
  4. 混合:古い状態と候補を更新ゲートの割合で混合

📊 3. LSTMとGRUの比較

3-1. パラメータ数の比較

【パラメータ数の比較(units=64, input_dim=32の場合)】 ■ LSTM 4つの重み行列 × (入力×units + units×units + units) = 4 × (32×64 + 64×64 + 64) = 4 × 6208 = 24,832 パラメータ ■ GRU 3つの重み行列 × (入力×units + units×units + units) = 3 × (32×64 + 64×64 + 64) = 3 × 6208 = 18,624 パラメータ GRUはLSTMの約75%のパラメータ数!

3-2. 使い分けの指針

状況 推奨 理由
データが少ない GRU パラメータが少なく過学習しにくい
長いシーケンス LSTM セルステートが長期記憶に有利
計算リソースが限られる GRU 計算量が少なく高速
どちらか迷ったら 両方試す タスクによって最適解が異なる
💡 実務でのアドバイス

多くの研究で、LSTMとGRUの性能差はタスク依存であり、
どちらが優れているとは一概に言えません。

まずはGRUで試して、性能が不足ならLSTMを試すのが効率的です。

💻 4. Kerasでの実装

4-1. GRUレイヤーの基本

from tensorflow.keras.layers import GRU # GRUレイヤー GRU( units=64, # 隠れ状態の次元数 return_sequences=False, # 最後の出力のみ dropout=0.0, # 入力に対するドロップアウト recurrent_dropout=0.0 # 再帰接続に対するドロップアウト )

4-2. LSTM vs GRU 比較実験

import numpy as np import time from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, GRU, Dense, Embedding from tensorflow.keras.datasets import imdb from tensorflow.keras.preprocessing.sequence import pad_sequences # ===== データ準備 ===== max_features = 10000 maxlen = 200 (X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=max_features) X_train = pad_sequences(X_train, maxlen=maxlen) X_test = pad_sequences(X_test, maxlen=maxlen) # ===== LSTMモデル ===== def build_lstm(): model = Sequential([ Embedding(max_features, 128, input_length=maxlen), LSTM(64, dropout=0.2), Dense(1, activation=’sigmoid’) ]) model.compile(optimizer=’adam’, loss=’binary_crossentropy’, metrics=[‘accuracy’]) return model # ===== GRUモデル ===== def build_gru(): model = Sequential([ Embedding(max_features, 128, input_length=maxlen), GRU(64, dropout=0.2), Dense(1, activation=’sigmoid’) ]) model.compile(optimizer=’adam’, loss=’binary_crossentropy’, metrics=[‘accuracy’]) return model # ===== 比較 ===== print(“=” * 50) print(“LSTM vs GRU 比較実験”) print(“=” * 50) # LSTMの学習 lstm_model = build_lstm() print(f”\nLSTMパラメータ数: {lstm_model.count_params():,}”) start = time.time() lstm_model.fit(X_train, y_train, epochs=3, batch_size=64, validation_split=0.2, verbose=0) lstm_time = time.time() – start _, lstm_acc = lstm_model.evaluate(X_test, y_test, verbose=0) # GRUの学習 gru_model = build_gru() print(f”GRUパラメータ数: {gru_model.count_params():,}”) start = time.time() gru_model.fit(X_train, y_train, epochs=3, batch_size=64, validation_split=0.2, verbose=0) gru_time = time.time() – start _, gru_acc = gru_model.evaluate(X_test, y_test, verbose=0) # 結果 print(f”\n{‘=’*50}”) print(f”結果:”) print(f”LSTM – 精度: {lstm_acc:.4f}, 学習時間: {lstm_time:.1f}秒”) print(f”GRU – 精度: {gru_acc:.4f}, 学習時間: {gru_time:.1f}秒”) print(f”{‘=’*50}”)
実行結果:
==================================================
LSTM vs GRU 比較実験
==================================================

LSTMパラメータ数: 1,346,177
GRUパラメータ数: 1,329,793

==================================================
結果:
LSTM - 精度: 0.8567, 学習時間: 245.3秒
GRU  - 精度: 0.8523, 学習時間: 198.7秒
==================================================

→ 精度はほぼ同等、GRUの方が約20%高速!

🎯 5. 実践:時系列予測モデル

“”” GRUによる時系列予測(完成コード) “”” import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import GRU, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping # ===== データ作成 ===== def create_sequences(data, seq_length): X, y = [], [] for i in range(len(data) – seq_length): X.append(data[i:i+seq_length]) y.append(data[i+seq_length]) return np.array(X), np.array(y) # sin波 + ノイズ np.random.seed(42) time_steps = 2000 data = np.sin(np.linspace(0, 50, time_steps)) + np.random.normal(0, 0.1, time_steps) # シーケンス作成 seq_length = 50 X, y = create_sequences(data.reshape(-1, 1), seq_length) # 訓練/テスト分割 split = int(len(X) * 0.8) X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] print(f”X_train: {X_train.shape}, y_train: {y_train.shape}”) # ===== GRUモデル ===== model = Sequential([ GRU(64, return_sequences=True, input_shape=(seq_length, 1)), Dropout(0.2), GRU(32), Dropout(0.2), Dense(1) ]) model.compile(optimizer=’adam’, loss=’mse’) # ===== 学習 ===== early_stop = EarlyStopping(monitor=’val_loss’, patience=10, restore_best_weights=True) history = model.fit( X_train, y_train, epochs=50, batch_size=32, validation_split=0.2, callbacks=[early_stop], verbose=1 ) # ===== 評価 ===== test_loss = model.evaluate(X_test, y_test) print(f”\nテストMSE: {test_loss:.6f}”) print(f”テストRMSE: {np.sqrt(test_loss):.6f}”)
実行結果:
X_train: (1560, 50, 1), y_train: (1560, 1)

Epoch 1/50 - loss: 0.1234 - val_loss: 0.0567
...
Epoch 25/50 - loss: 0.0089 - val_loss: 0.0092

テストMSE: 0.009876
テストRMSE: 0.099377

→ sin波 + ノイズを高精度で予測!

📝 STEP 23 のまとめ

✅ このステップで学んだこと
  • GRU:LSTMを簡略化したアーキテクチャ
  • 更新ゲート:新旧情報の混合比率を決定
  • リセットゲート:候補作成時に過去をどれだけ参照するか
  • パラメータ数:LSTMの約75%
  • 性能:多くの場合LSTMと同等
  • 使い分け:まずGRU、必要ならLSTM
💡 覚えておくべきコード
# GRUの基本パターン model = Sequential([ GRU(64, return_sequences=True, input_shape=(timesteps, features)), Dropout(0.2), GRU(32), Dense(num_classes, activation=’softmax’) ])
🚀 次のステップへ

GRUを習得したので、次のSTEP 24では双方向RNNとAttention入門を学びます。

シーケンスを両方向から処理し、「どこに注目すべきか」を学習する技術です!

📝 練習問題

問題1 やさしい

GRUのゲート数

GRUには何種類のゲートがありますか?

  • A. 1種類
  • B. 2種類
  • C. 3種類
  • D. 4種類
正解:B

GRUには更新ゲート(Update Gate)とリセットゲート(Reset Gate)の2種類のゲートがあります。LSTMの3つのゲートを簡略化しています。

問題2 やさしい

GRUの特徴

GRUとLSTMの比較として、正しいものを選んでください。

  • A. GRUの方がパラメータ数が多い
  • B. GRUにはセルステートがある
  • C. GRUの方がパラメータ数が少ない
  • D. GRUの方が必ず高精度
正解:C

GRUはLSTMを簡略化したもので、パラメータ数は約75%です。セルステートはなく、性能差はタスク依存です。

問題3 ふつう

更新ゲートの役割

GRUの更新ゲートzが1に近い場合、何が起きますか?

  • A. 古い隠れ状態がそのまま保持される
  • B. 新しい候補状態が採用される
  • C. 出力が0になる
  • D. 学習が停止する
正解:B

更新式 h_t = (1-z)×h_{t-1} + z×h̃_t より、z≈1のとき h_t ≈ h̃_t となり、新しい候補状態が採用されます。逆にz≈0のときは古い状態が保持されます。

問題4 むずかしい

GRUを選ぶべき状況

GRUがLSTMより適している状況として、最も適切なものを選んでください。

  • A. 非常に長いシーケンス(1000ステップ以上)を扱う場合
  • B. 訓練データが少なく、計算リソースが限られている場合
  • C. 最高精度が必要で時間に制限がない場合
  • D. セルステートの可視化が必要な場合
正解:B

GRUはパラメータ数が少なく、訓練データが少ない場合の過学習を防ぎやすく、計算も高速です。長いシーケンスではLSTMのセルステートが有利な場合があります。

📝

学習メモ

ディープラーニング基礎 - Step 23

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE