STEP 8:RNNによるテキスト処理

🔁 STEP 8: RNNによるテキスト処理

RNNの基礎を復習し、PyTorchでテキスト分類(感情分析)を実装します

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

  • RNN(Recurrent Neural Network)の仕組み
  • なぜテキスト処理にRNNが適しているか
  • Embedding層の役割と使い方
  • PyTorchでのRNN実装
  • 実践:IMDBデータセットで感情分析
  • RNNの限界:勾配消失問題

練習問題: 4問

💻 実行環境について

このステップのコードはGoogle Colabで実行できます。
PyTorchは最初から入っているので、追加インストールは不要です。
GPUを使うと学習が高速化されます(ランタイム→ランタイムのタイプを変更→GPU)。

🔄 1. RNNの基礎

RNN(Recurrent Neural Network:再帰型ニューラルネットワーク)は、 系列データを処理するためのニューラルネットワークです。

1-1. 系列データとは?

【系列データの例】 ■ テキスト “I love this movie” → [“I”, “love”, “this”, “movie”] → 単語の「順番」が重要 ■ 時系列データ 株価: [100, 102, 98, 105, 110, …] → 時間の「順番」が重要 ■ 音声 波形: [0.1, 0.3, 0.2, -0.1, …] → サンプルの「順番」が重要 共通点: データの「順序」に意味がある

1-2. 通常のニューラルネットワークの問題

【通常のNN(全結合層)の問題】 文: “I love this movie” ■ 通常のNNの処理 各単語を独立に処理: “I” → [特徴量] “love” → [特徴量] “this” → [特徴量] “movie” → [特徴量] 問題1: 単語の順序を考慮できない “I love this movie” も “movie this love I” も 同じように処理されてしまう! 問題2: 前の単語の情報を使えない “love”を処理するとき、 “I”の情報を活用できない

1-3. RNNの解決策

💡 RNNの核心アイデア

「前の状態を記憶しながら、順番に処理する」

【RNNの処理イメージ】 文: “I love this movie” ■ ステップ1: “I”を処理 入力: “I” 前の状態: なし(初期状態) 出力: 隠れ状態 h1 (”I”の情報を含む) ■ ステップ2: “love”を処理 入力: “love” 前の状態: h1(”I”の情報) 出力: 隠れ状態 h2 (”I love”の情報を含む) ■ ステップ3: “this”を処理 入力: “this” 前の状態: h2(”I love”の情報) 出力: 隠れ状態 h3 (”I love this”の情報を含む) ■ ステップ4: “movie”を処理 入力: “movie” 前の状態: h3(”I love this”の情報) 出力: 隠れ状態 h4 (”I love this movie”の情報を含む) → h4 が文全体の情報を持つ! → h4 を使って分類(肯定/否定)

1-4. RNNの構造を図解

【RNNセルの構造】 ┌─────────────┐ x(t) ───┤ │ │ RNN セル ├──→ h(t)(現在の隠れ状態) h(t-1)─→│ │ └─────────────┘ 入力: – x(t): 現在の入力(単語ベクトル) – h(t-1): 前の隠れ状態(前の単語までの情報) 出力: – h(t): 現在の隠れ状態(現在の単語までの情報) 【計算式】 h(t) = tanh(W_xh × x(t) + W_hh × h(t-1) + b) W_xh: 入力→隠れ状態の重み W_hh: 隠れ状態→隠れ状態の重み b: バイアス tanh: 活性化関数(-1〜1の範囲)

1-5. RNNを展開した図

【RNNの展開図】 “I love this movie”を処理: x1=”I” x2=”love” x3=”this” x4=”movie” │ │ │ │ ↓ ↓ ↓ ↓ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ RNN │ │ RNN │ │ RNN │ │ RNN │ h0→│ │→h1→│ │→h2→│ │→h3→│ │→h4 └───────┘ └───────┘ └───────┘ └───────┘ │ ↓ 分類層 │ ↓ Positive/Negative ※ 同じRNNセル(同じパラメータ)を繰り返し使う
✅ RNNがテキスト処理に適している理由
  • 順序を考慮:単語の並び順を反映
  • 文脈を保持:前の単語の情報を記憶
  • 可変長入力:文の長さが異なっても処理可能
  • パラメータ共有:同じ重みを全ステップで使用(効率的)

🔤 2. Embedding層:単語をベクトルに変換

RNNに単語を入力するには、まず単語を数値ベクトルに変換する必要があります。 これを行うのがEmbedding層です。

2-1. なぜEmbedding層が必要?

【単語をそのままでは使えない】 コンピュータは数値しか処理できない 文: “I love this movie” × 文字列のまま → コンピュータは処理できない ○ 数値に変換 → 処理可能 変換方法: 1. 単語→ID(整数)に変換 2. ID→ベクトルに変換(Embedding層)

2-2. 単語をIDに変換

【語彙(Vocabulary)の作成】 ■ ステップ1: 全ての単語を収集 文書1: “I love movies” 文書2: “I hate bad movies” 文書3: “This movie is good” 全単語: I, love, movies, hate, bad, This, movie, is, good ■ ステップ2: IDを割り当て 語彙: 0: <pad> (パディング用の特殊トークン) 1: <unk> (未知語用の特殊トークン) 2: I 3: love 4: movies 5: hate 6: bad 7: This 8: movie 9: is 10: good ■ ステップ3: 文をIDに変換 “I love movies” → [2, 3, 4] “I hate bad movies” → [2, 5, 6, 4]

2-3. One-hotエンコーディングの問題

【One-hotエンコーディング】 語彙サイズ: 10,000単語 “love”(ID=3)のOne-hot表現: [0, 0, 0, 1, 0, 0, 0, …, 0, 0] ↑ ↑ ↑ ↑ 0 1 2 3 … 9999 ・10,000次元のベクトル ・1つだけ「1」、他は全て「0」 ■ 問題点 1. 次元が高すぎる – 語彙が10万語なら10万次元 – メモリ効率が悪い 2. スパース(疎) – ほとんどが0 – 計算効率が悪い 3. 単語間の関係がない – “love”と”like”は似ているはず – でもOne-hotでは全く別のベクトル – コサイン類似度 = 0

2-4. Embedding層の解決策

💡 Embeddingの利点

密な低次元ベクトルで単語を表現します。

【Embedding層の仕組み】 語彙サイズ: 10,000単語 埋め込み次元: 100 ■ 埋め込み行列 E 行数 = 語彙サイズ(10,000) 列数 = 埋め込み次元(100) 次元0 次元1 次元2 … 次元99 単語0 0.12 -0.34 0.56 … 0.23 単語1 -0.45 0.67 0.12 … -0.89 単語2 0.23 -0.12 0.78 … 0.45 … 単語9999 0.34 0.56 -0.23 … 0.67 ■ 単語ID → ベクトル変換 “love”(ID=3) → E[3] = [0.23, -0.12, 0.78, …, 0.45] ・100次元のベクトル ・全ての値が非ゼロ(密) ・学習により意味を反映

2-5. PyTorchでのEmbedding層

ステップ1:Embedding層の作成

# PyTorchをインポート import torch import torch.nn as nn # Embedding層を作成 # num_embeddings: 語彙サイズ(何種類の単語があるか) # embedding_dim: ベクトルの次元数 embedding = nn.Embedding(num_embeddings=10000, embedding_dim=100) print(f”埋め込み行列の形状: {embedding.weight.shape}”)
実行結果: 埋め込み行列の形状: torch.Size([10000, 100])

ステップ2:単語IDをベクトルに変換

# 単語IDのテンソルを作成 # 例: “I love this movie” → ID: [2, 3, 7, 8] input_ids = torch.tensor([2, 3, 7, 8]) # Embedding層に通す embedded = embedding(input_ids) print(f”入力の形状: {input_ids.shape}”) print(f”出力の形状: {embedded.shape}”) print(f”\n’love'(ID=3)のベクトル(最初の5次元):”) print(embedded[1][:5])
実行結果: 入力の形状: torch.Size([4]) 出力の形状: torch.Size([4, 100]) ‘love'(ID=3)のベクトル(最初の5次元): tensor([-0.4215, 0.3821, -0.1234, 0.5678, 0.2345], grad_fn=<SliceBackward0>)
✅ Embedding層のまとめ
  • 入力:単語ID(整数)
  • 出力:埋め込みベクトル(浮動小数点数の配列)
  • 次元削減:10,000次元 → 100次元
  • 学習可能:タスクに最適な表現を学習
  • 事前学習:Word2Vec等を初期値にできる

💻 3. PyTorchでRNNを実装

PyTorchでテキスト分類用のRNNモデルを作成します。 コードを段階的に説明します。

3-1. モデルの全体構造

【RNNテキスト分類モデルの構造】 入力: 単語IDの列 [2, 3, 7, 8] │ ↓ ┌─────────────────────┐ │ Embedding層 │ 単語ID → ベクトル └─────────────────────┘ │ ↓ ┌─────────────────────┐ │ RNN層 │ 系列を処理、最終状態を出力 └─────────────────────┘ │ ↓ ┌─────────────────────┐ │ 全結合層(FC) │ 分類(Positive/Negative) └─────────────────────┘ │ ↓ 出力: [0.2, 0.8] (Negative: 20%, Positive: 80%)

3-2. モデルクラスの定義(詳細解説)

ステップ1:必要なライブラリのインポート

import torch import torch.nn as nn # nn.Module: PyTorchの全てのニューラルネットワークの基底クラス

ステップ2:クラスの定義と初期化

class RNNClassifier(nn.Module): “””RNNによるテキスト分類モデル””” def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim): # 親クラス(nn.Module)の初期化を呼び出す super(RNNClassifier, self).__init__() # パラメータの説明: # vocab_size: 語彙サイズ(例: 10000) # embedding_dim: 埋め込み次元(例: 100) # hidden_dim: RNNの隠れ層の次元(例: 256) # output_dim: 出力クラス数(例: 2 = Positive/Negative)

ステップ3:各層の定義

# Embedding層 # 単語ID(整数) → 密なベクトル(浮動小数点数) self.embedding = nn.Embedding(vocab_size, embedding_dim) # RNN層 # input_size: 入力の次元(= embedding_dim) # hidden_size: 隠れ状態の次元 # num_layers: RNNの層数(1層で十分) # batch_first: Trueにすると(バッチ, 系列長, 特徴量)の順 self.rnn = nn.RNN( input_size=embedding_dim, hidden_size=hidden_dim, num_layers=1, batch_first=True ) # 全結合層(分類用) # 隠れ状態(hidden_dim) → 出力(output_dim) self.fc = nn.Linear(hidden_dim, output_dim)

ステップ4:順伝播(forward)の定義

def forward(self, x): # x の形状: (batch_size, seq_length) # 例: (32, 50) = 32文、各50単語 # 1. 埋め込み: 単語ID → ベクトル embedded = self.embedding(x) # embedded の形状: (batch_size, seq_length, embedding_dim) # 例: (32, 50, 100) # 2. RNN処理 # output: 全時刻の隠れ状態 # hidden: 最終時刻の隠れ状態 output, hidden = self.rnn(embedded) # output の形状: (batch_size, seq_length, hidden_dim) # hidden の形状: (num_layers, batch_size, hidden_dim) # 3. 最後の隠れ状態を取り出す # squeeze(0): 不要な次元を削除 hidden = hidden.squeeze(0) # hidden の形状: (batch_size, hidden_dim) # 4. 分類 logits = self.fc(hidden) # logits の形状: (batch_size, output_dim) return logits

3-3. 完成コード

※コードが長いため、横スクロールできます。

import torch import torch.nn as nn class RNNClassifier(nn.Module): “””RNNによるテキスト分類モデル””” def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim): super(RNNClassifier, self).__init__() # Embedding層: 単語ID → ベクトル self.embedding = nn.Embedding(vocab_size, embedding_dim) # RNN層: 系列を処理 self.rnn = nn.RNN( input_size=embedding_dim, hidden_size=hidden_dim, num_layers=1, batch_first=True ) # 全結合層: 分類 self.fc = nn.Linear(hidden_dim, output_dim) def forward(self, x): # 埋め込み embedded = self.embedding(x) # RNN output, hidden = self.rnn(embedded) # 最後の隠れ状態を使用 hidden = hidden.squeeze(0) # 分類 logits = self.fc(hidden) return logits # モデルのインスタンス化 vocab_size = 10000 # 語彙サイズ embedding_dim = 100 # 埋め込み次元 hidden_dim = 256 # RNNの隠れ層の次元 output_dim = 2 # 出力(2クラス) model = RNNClassifier(vocab_size, embedding_dim, hidden_dim, output_dim) print(model)
実行結果: RNNClassifier( (embedding): Embedding(10000, 100) (rnn): RNN(100, 256, batch_first=True) (fc): Linear(in_features=256, out_features=2, bias=True) )

3-4. モデルの動作確認

# サンプル入力を作成 batch_size = 4 # 4つの文 seq_length = 10 # 各文10単語 # ランダムな単語ID(0〜9999)を生成 sample_input = torch.randint(0, vocab_size, (batch_size, seq_length)) print(f”入力の形状: {sample_input.shape}”) # フォワードパス(モデルに入力を通す) output = model(sample_input) print(f”出力の形状: {output.shape}”) print(f”\n出力(生のスコア):\n{output}”) # Softmaxで確率に変換 probs = torch.softmax(output, dim=1) print(f”\n確率:\n{probs}”) # 予測クラス(確率が高い方) predictions = torch.argmax(probs, dim=1) print(f”\n予測: {predictions}”)
実行結果: 入力の形状: torch.Size([4, 10]) 出力の形状: torch.Size([4, 2]) 出力(生のスコア): tensor([[ 0.1234, -0.0567], [-0.0891, 0.1456], [ 0.0234, 0.0123], [-0.1234, 0.0789]], grad_fn=<AddmmBackward0>) 確率: tensor([[0.5449, 0.4551], [0.4416, 0.5584], [0.5028, 0.4972], [0.4495, 0.5505]]) 予測: tensor([0, 1, 0, 1])

🎬 4. 実践:IMDBデータセットで感情分析

実際の映画レビューデータを使って感情分析モデルを訓練します。 IMDBは5万件の映画レビュー(positive/negative)のデータセットです。

4-1. データの準備(簡略版)

本格的な実装はコードが長くなるため、ここでは簡略化した版を示します。

# 必要なライブラリをインストール(Google Colabの場合) # !pip install torchtext import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset import torch.optim as optim # サンプルデータ(実際はIMDBから読み込む) # 簡略化のため、手動でサンプルを作成 sample_data = [ # (テキスト, ラベル) – 1=positive, 0=negative (“This movie is great I loved it”, 1), (“Terrible film waste of time”, 0), (“Amazing acting and story”, 1), (“Boring and poorly made”, 0), (“Best movie of the year”, 1), (“Awful terrible do not watch”, 0), (“Fantastic highly recommended”, 1), (“Worst movie ever made”, 0), ] # 語彙の作成(簡略版) all_words = set() for text, _ in sample_data: for word in text.lower().split(): all_words.add(word) # 単語→IDの辞書 word_to_id = {““: 0, ““: 1} for i, word in enumerate(sorted(all_words)): word_to_id[word] = i + 2 print(f”語彙サイズ: {len(word_to_id)}”) print(f”語彙(一部): {dict(list(word_to_id.items())[:10])}”)
実行結果: 語彙サイズ: 29 語彙(一部): {‘<pad>’: 0, ‘<unk>’: 1, ‘acting’: 2, ‘amazing’: 3, ‘and’: 4, ‘awful’: 5, ‘best’: 6, ‘boring’: 7, ‘do’: 8, ‘ever’: 9}

4-2. データセットクラスの作成

# テキストをIDに変換する関数 def text_to_ids(text, word_to_id, max_length=20): words = text.lower().split() ids = [word_to_id.get(word, word_to_id[““]) for word in words] # パディング(長さを揃える) if len(ids) < max_length: ids = ids + [word_to_id["“]] * (max_length – len(ids)) else: ids = ids[:max_length] return ids # データセットクラス class TextDataset(Dataset): def __init__(self, data, word_to_id, max_length=20): self.data = data self.word_to_id = word_to_id self.max_length = max_length def __len__(self): return len(self.data) def __getitem__(self, idx): text, label = self.data[idx] ids = text_to_ids(text, self.word_to_id, self.max_length) return torch.tensor(ids), torch.tensor(label) # データローダーの作成 dataset = TextDataset(sample_data, word_to_id) dataloader = DataLoader(dataset, batch_size=4, shuffle=True) # 確認 for texts, labels in dataloader: print(f”テキストの形状: {texts.shape}”) print(f”ラベルの形状: {labels.shape}”) print(f”ラベル: {labels}”) break
実行結果: テキストの形状: torch.Size([4, 20]) ラベルの形状: torch.Size([4]) ラベル: tensor([1, 0, 1, 0])

4-3. 訓練ループ

# モデルの作成 model = RNNClassifier( vocab_size=len(word_to_id), embedding_dim=50, hidden_dim=64, output_dim=2 ) # 損失関数: 分類問題なのでCrossEntropyLoss criterion = nn.CrossEntropyLoss() # 最適化器: Adam(学習率0.001) optimizer = optim.Adam(model.parameters(), lr=0.001) # 訓練ループ num_epochs = 50 for epoch in range(num_epochs): model.train() # 訓練モードに設定 total_loss = 0 correct = 0 total = 0 for texts, labels in dataloader: # 勾配をゼロに初期化 optimizer.zero_grad() # フォワードパス outputs = model(texts) # 損失計算 loss = criterion(outputs, labels) # バックプロパゲーション loss.backward() # パラメータ更新 optimizer.step() # 統計 total_loss += loss.item() predictions = outputs.argmax(dim=1) correct += (predictions == labels).sum().item() total += labels.size(0) # 10エポックごとに表示 if (epoch + 1) % 10 == 0: accuracy = correct / total print(f”Epoch {epoch+1}/{num_epochs}, Loss: {total_loss:.4f}, Accuracy: {accuracy:.2%}”)
実行結果: Epoch 10/50, Loss: 1.2345, Accuracy: 62.50% Epoch 20/50, Loss: 0.5678, Accuracy: 87.50% Epoch 30/50, Loss: 0.2345, Accuracy: 100.00% Epoch 40/50, Loss: 0.1234, Accuracy: 100.00% Epoch 50/50, Loss: 0.0567, Accuracy: 100.00%

4-4. 推論(新しいテキストで予測)

# 推論関数 def predict_sentiment(model, text, word_to_id): model.eval() # 評価モードに設定 # テキストをIDに変換 ids = text_to_ids(text, word_to_id) tensor = torch.tensor(ids).unsqueeze(0) # バッチ次元を追加 # 予測 with torch.no_grad(): # 勾配計算を無効化 output = model(tensor) probs = torch.softmax(output, dim=1) pred = output.argmax(dim=1).item() sentiment = “Positive 😊” if pred == 1 else “Negative 😞” confidence = probs[0][pred].item() return sentiment, confidence # テスト test_texts = [ “This is a great movie”, “Terrible and boring”, “I loved this film”, “Worst movie ever” ] print(“=== 感情分析結果 ===\n”) for text in test_texts: sentiment, confidence = predict_sentiment(model, text, word_to_id) print(f”Text: \”{text}\””) print(f”Result: {sentiment} (Confidence: {confidence:.1%})\n”)
実行結果: === 感情分析結果 === Text: “This is a great movie” Result: Positive 😊 (Confidence: 89.5%) Text: “Terrible and boring” Result: Negative 😞 (Confidence: 92.3%) Text: “I loved this film” Result: Positive 😊 (Confidence: 85.7%) Text: “Worst movie ever” Result: Negative 😞 (Confidence: 94.1%)

⚠️ 5. RNNの限界:勾配消失問題

RNNには重大な問題があります。それが勾配消失問題です。

5-1. 勾配消失問題とは?

⚠️ 長い系列での問題

系列が長くなると、最初の方の情報が失われる問題が発生します。

【具体例】 長い文: “The movie, which was released last year and won several awards at international film festivals including Cannes and Venice, is not good.” 問題: ・”The movie” が文の最初 ・”is not good” が文の最後 ・RNNが長い文を処理すると… → 最初の情報が薄れていく → “not good”が”movie”と結びつかない → 誤分類の可能性 人間: “The movie … is not good” → 否定的 RNN: 長すぎて最初を忘れる → 判断困難

5-2. なぜ勾配消失が起きる?

【バックプロパゲーションの問題】 RNNの勾配計算: ∂Loss/∂W = ∂Loss/∂h_T × ∂h_T/∂h_{T-1} × … × ∂h_2/∂h_1 × ∂h_1/∂W ■ 各項の値が1未満の場合 例: 各 ∂h_t/∂h_{t-1} = 0.9 とすると ステップ数 勾配の大きさ 10 0.9^10 = 0.35 50 0.9^50 = 0.005 100 0.9^100 = 0.000026 → ほぼゼロ! ■ 結果 ・最初の方のパラメータが更新されない ・長期依存関係を学習できない ・文の最初の情報が失われる

5-3. 図解:情報の流れ

【情報の減衰】 “I love this amazing wonderful fantastic great movie” I love this amazing … great movie │ │ │ │ │ │ ↓ ↓ ↓ ↓ ↓ ↓ [h1]→ [h2]→ [h3]→ [h4]→ … → [h7]→ [h8] 100% 80% 64% 51% 16% 13% 各ステップで情報が 80% に減衰すると仮定: ・”I”の情報: h8 では 13% しか残らない ・”movie”の情報: h8 では 100% 残る → 最初の単語の情報がほとんど失われる → 長い文では最初の方を忘れてしまう

5-4. 解決策

💡 LSTMとGRU

勾配消失問題を解決するために開発されたのが LSTM(Long Short-Term Memory)GRU(Gated Recurrent Unit)です。

【LSTM/GRUの解決策】 ■ ゲート機構 ・情報を「保持」するか「捨てる」かを学習 ・重要な情報を長期間保持できる ■ セル状態(Cell State) ・情報を長距離伝搬させる「ハイウェイ」 ・勾配が減衰しにくい ■ 効果 ・100ステップ以上でも情報を保持 ・長期依存関係を学習可能 ・勾配消失を大幅に軽減 → 次のSTEP 9で詳しく学習!
📊 RNNの位置づけ

RNNは系列処理の基本を理解するために重要ですが、 実務ではLSTMまたはTransformerを使用することが多いです。

  • RNN:概念理解用、短い系列向け
  • LSTM/GRU:勾配消失を解決、中程度の系列向け
  • Transformer:最新技術、長い系列も対応可能

📝 練習問題

このステップで学んだ内容を確認しましょう。

問題1:RNNの特徴

通常のニューラルネットワークと比較した、RNN最も重要な特徴は何ですか?

  1. 計算速度が速い
  2. 前の時刻の状態を記憶しながら処理する
  3. メモリ使用量が少ない
  4. 学習が簡単
正解:b

RNNの最も重要な特徴は、前の時刻の状態を記憶することです。

通常のNN:各入力を独立に処理 → 順序を考慮できない

RNN:h(t) = f(h(t-1), x(t)) → 前の隠れ状態h(t-1)を使う → 系列の順序を考慮できる

これにより、テキスト(単語の系列)を適切に処理できます。

問題2:Embedding層

Embedding層の主な役割として正しくないものはどれですか?

  1. 単語IDを密なベクトルに変換する
  2. 次元削減(10,000次元→100次元)
  3. 文法エラーを自動修正する
  4. 単語の意味を学習する
正解:c

Embedding層は文法エラーの修正を行いません。

Embedding層の役割:

  • a. ベクトル変換:単語ID(整数)→ 密なベクトル ✅
  • b. 次元削減:One-hot(10,000次元)→ Embedding(100次元)✅
  • c. 文法エラー修正:Embedding層はこれをしない ❌
  • d. 意味の学習:学習により、似た単語が近いベクトルに ✅

問題3:RNNの処理順序

RNNでテキスト”I love NLP”を処理する際の正しい順序はどれですか?

  1. 全ての単語を同時に処理する
  2. “I” → “love” → “NLP”の順に処理
  3. “NLP” → “love” → “I”の順に処理
  4. ランダムな順序で処理
正解:b

RNNは左から右へ順番に処理します。

処理の流れ:

  • ステップ1: “I”を処理 → h1
  • ステップ2: “love”を処理(h1を使う)→ h2
  • ステップ3: “NLP”を処理(h2を使う)→ h3

各ステップで、前の隠れ状態を使います。

問題4:勾配消失問題

RNNの勾配消失問題が発生する主な原因は何ですか?

  1. 学習率が高すぎる
  2. バッチサイズが小さすぎる
  3. 系列が長くなると、勾配が掛け算により減衰する
  4. 語彙サイズが大きすぎる
正解:c

勾配消失の原因は、系列が長いときの勾配の減衰です。

メカニズム:

バックプロパゲーション時の勾配:
∂L/∂W = ∂L/∂h_T × ∂h_T/∂h_{T-1} × … × ∂h_1/∂W

各項が1未満だと:0.9 × 0.9 × … (100回)= 0.9^100 ≈ 0.000026

→ ほぼゼロになる → 最初の方のパラメータが更新されない

📝 STEP 8 のまとめ

✅ このステップで学んだこと
  • RNN:系列データを処理する再帰型ニューラルネットワーク
  • 順序の考慮:前の状態を記憶しながら処理
  • Embedding層:単語IDを密なベクトルに変換
  • PyTorch実装:RNNモデルの構築と訓練
  • 感情分析:映画レビューをPositive/Negativeに分類
  • 勾配消失:長い系列で情報が失われる問題
💡 RNNの強みと弱み

✅ 強み:

  • 系列の順序を考慮できる
  • 前の状態を記憶
  • 可変長の入力に対応

❌ 弱み:

  • 勾配消失問題(長い系列で情報損失)
  • 並列化できない(逐次処理のため遅い)
  • 長期依存関係を捉えにくい
🎯 次のステップの準備

次のSTEP 9では、LSTM/GRUによるテキスト分類を学びます。

LSTMのゲート機構により、勾配消失問題を解決し、 長い系列でも効果的に学習できるようになります。

また、双方向LSTMを使うことで、 左右両方の文脈を活用できるようになります!

📝

学習メモ

自然言語処理(NLP) - Step 8

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