STEP 10:Seq2Seqモデル

🔄 STEP 10: Seq2Seqモデル

Encoder-Decoderアーキテクチャで系列から系列への変換を実現します

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

  • Seq2Seq(Sequence-to-Sequence)モデルの基本概念
  • Encoder-Decoderアーキテクチャの仕組み
  • Context Vector(コンテキストベクトル)の役割
  • Teacher Forcing(教師強制)
  • 推論時の生成手法(Greedy Search、Beam Search)
  • PyTorchでの実装
  • Seq2Seqの課題と限界

練習問題: 5問

💻 実行環境について

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

🔄 1. Seq2Seqモデルとは?

Seq2Seq(Sequence-to-Sequence)モデルは、 可変長の入力系列可変長の出力系列に変換するモデルです。 2014年にGoogleが発表し、機械翻訳の精度を大幅に向上させました。

1-1. 従来のモデルの問題

【従来のLSTMの制約】 ■ テキスト分類(STEP 8-9で学んだ内容) 入力: “This movie is great” (4単語) 出力: positive/negative (1つの値) → 入力は可変長OK → 出力は固定長(クラス数) ■ 問題となるタスク 機械翻訳: 入力: “I love you” (3単語) 出力: “私はあなたを愛しています” (7単語?) → 入力と出力の長さが違う! → 出力の長さが事前にわからない! → 従来のLSTMでは対応困難

1-2. Seq2Seqの解決策

💡 Seq2Seqの核心アイデア

「2つのLSTMを組み合わせる」

  • Encoder(エンコーダ):入力を理解して「意味」に変換
  • Decoder(デコーダ):「意味」から出力を生成
【Seq2Seqのイメージ】 入力: “I love you”(英語) │ ↓ ┌─────────────────┐ │ Encoder │ ← 英語を理解 │ (LSTM) │ └────────┬────────┘ │ 「愛の意味」(ベクトル) │ ↓ ┌─────────────────┐ │ Decoder │ ← 日本語で表現 │ (LSTM) │ └────────┬────────┘ │ ↓ 出力: “私はあなたを愛しています”(日本語) ポイント: ・入力の長さ(3単語)と出力の長さ(7単語)が異なる ・中間に「意味」を表すベクトルがある

1-3. Seq2Seqの応用タスク

タスク 入力例 出力例
機械翻訳 “Good morning” “おはようございます”
文章要約 長い記事(200語) 要約(30語)
チャットボット “How are you?” “I’m fine!”
質問応答 “日本の首都は?” “東京です”

🏗️ 2. Encoder-Decoderアーキテクチャ

Seq2Seqモデルの中核はEncoder(エンコーダ)Decoder(デコーダ)の2つの部分です。

2-1. 全体構造

【Encoder-Decoderの全体像】 入力: “I love you” ┌─────────────────────────────────────────────────┐ │ Seq2Seqモデル │ │ │ │ Encoder Decoder │ │ ┌───────┐ ┌───────┐ │ │ │ │ Context │ │ │ │ │ LSTM │────Vector───────→│ LSTM │ │ │ │ │ (意味) │ │ │ │ └───┬───┘ └───┬───┘ │ │ ↑ ↓ │ │ 入力系列 出力系列 │ │ “I love you” “私は…愛しています” │ └─────────────────────────────────────────────────┘ 処理の流れ: 1. Encoder: 入力系列を読み込み、最終状態を出力 2. Context Vector: Encoderの最終状態(入力の「意味」) 3. Decoder: Context Vectorを初期状態として、1単語ずつ生成

2-2. Encoder(エンコーダ)の仕組み

📥 Encoderの役割

「入力系列の意味を1つのベクトルに圧縮する」

【Encoderの処理(例: “I love you”)】 入力: [“I”, “love”, “you”] ■ ステップ1: “I”を処理 入力: “I”のベクトル [0.1, 0.2, -0.3, …] 前の隠れ状態: h0 = ゼロベクトル(初期状態) ↓ LSTM セル ↓ 出力: h1 = [-0.2, 0.5, 0.1, …] (”I”の情報を含む) ■ ステップ2: “love”を処理 入力: “love”のベクトル [0.8, -0.1, 0.5, …] 前の隠れ状態: h1 ↓ LSTM セル ↓ 出力: h2 = [0.3, 0.7, -0.2, …] (”I love”の情報を含む) ■ ステップ3: “you”を処理 入力: “you”のベクトル [-0.1, 0.3, 0.2, …] 前の隠れ状態: h2 ↓ LSTM セル ↓ 出力: h3 = [0.5, -0.3, 0.8, …] (”I love you”の情報を含む) ★ Context Vector = h3 → 文全体の意味を表すベクトル

2-3. Context Vector(コンテキストベクトル)

【Context Vectorとは?】 “I love you” → Encoder → Context Vector Context Vector = [0.5, -0.3, 0.8, 0.2, -0.1, …] (hidden_dim次元のベクトル、例: 512次元) このベクトルは何を表す? ・「愛の告白」という意味 ・主語が「私」 ・対象が「あなた」 ・感情が「ポジティブ」 …などの情報が詰まっている 比喩: ・英語の文を読んで、頭の中で「意味」を理解 ・その「理解」がContext Vector ・日本語に翻訳するとき、この「理解」を元に言葉を選ぶ
⚠️ Context Vectorの問題点

情報のボトルネック:

  • どんなに長い文も、1つのベクトルに圧縮される
  • 長い文では、最初の方の情報が失われる
  • 例: 100単語の文 → 512次元のベクトル(情報が失われる)

解決策:Attention(次のSTEP 11で学習)

2-4. Decoder(デコーダ)の仕組み

📤 Decoderの役割

「Context Vectorから出力系列を1単語ずつ生成する」

【Decoderの処理(例: “私はあなたを愛しています”を生成)】 初期状態 = Context Vector(Encoderの最終状態) ■ ステップ1: 最初の単語を生成 入力: <START>トークン(開始を示す特別なトークン) 隠れ状態: Context Vector ↓ LSTM セル ↓ 出力: 各単語の確率 “私”: 0.8 ← 最大 “あなた”: 0.1 “愛”: 0.05 … → “私”を選択 ■ ステップ2: 次の単語を生成 入力: “私”(前のステップで生成した単語) 隠れ状態: h1(ステップ1の出力) ↓ LSTM セル ↓ 出力: 各単語の確率 “は”: 0.7 ← 最大 “が”: 0.2 … → “は”を選択 ■ ステップ3〜7: 同様に続く “あなた” → “を” → “愛し” → “て” → “います” ■ ステップ8: 終了 入力: “います” 出力: <END>トークン(終了を示す特別なトークン) → 生成終了 最終出力: “私はあなたを愛しています”

2-5. 特別なトークン

【Seq2Seqで使う特別なトークン】 1. <START> または <BOS> (Beginning of Sentence) – Decoderの最初の入力 – 「ここから文を始める」という合図 2. <END> または <EOS> (End of Sentence) – 生成の終了を示す – このトークンが出力されたら生成を停止 3. <PAD> (Padding) – バッチ処理時に長さを揃えるための詰め物 4. <UNK> (Unknown) – 語彙にない未知語 例: 入力: “I love you” → [<START>, I, love, you, <END>, <PAD>, <PAD>] 出力: “私は愛しています” → [<START>, 私, は, 愛し, てい, ます, <END>]

👨‍🏫 3. Teacher Forcing(教師強制)

Seq2Seqモデルの訓練にはTeacher Forcingという特別な手法を使います。

3-1. 問題:訓練時の困難

【訓練時の問題】 正解: “私はあなたを愛しています” ■ 普通に訓練する場合(自己回帰) ステップ1: <START> → 予測: “私” ✅ ステップ2: “私” → 予測: “が” ❌(正解は”は”) ステップ3: “が” → 予測: “あなた” ↑ 間違った入力から予測することになる! 問題: ・ステップ2で間違えると、ステップ3以降も影響を受ける ・誤りが連鎖して、正しい出力を学習できない ・学習が不安定になる

3-2. Teacher Forcingの解決策

💡 Teacher Forcingのアイデア

「訓練時は、予測結果ではなく正解を次の入力にする」

【Teacher Forcingの動作】 正解: “私はあなたを愛しています” ■ Teacher Forcingあり(訓練時) ステップ1: <START> → 予測: “私” ✅ ステップ2: “私”(正解)→ 予測: “が” ❌ ↑ 予測が間違っていても、正解の”私”を入力として使う ステップ3: “は”(正解)→ 予測: “あなた” ↑ 予測が間違っていても、正解の”は”を入力として使う … 効果: ・各ステップが独立に学習できる ・誤りが連鎖しない ・学習が安定して速い

3-3. 訓練と推論の違い

【訓練時 vs 推論時】 ■ 訓練時(Teacher Forcing) 入力: 正解の単語 目的: 正しい単語を予測する確率を上げる <START> → “私”を予測 “私”(正解)→ “は”を予測 “は”(正解)→ “あなた”を予測 … ■ 推論時(実際の使用時) 入力: 自分の予測結果 目的: 文を生成する <START> → “私”を予測 “私”(予測)→ “は”を予測 “は”(予測)→ “あなた”を予測 … 問題: 訓練と推論で動作が違う! → Exposure Bias問題

3-4. Exposure Bias問題と対策

⚠️ Exposure Bias問題

問題:

  • 訓練時: 常に正解を入力として使う
  • 推論時: 自分の予測(誤りの可能性あり)を使う
  • 訓練時に「誤った入力」を見たことがない
  • 推論時に誤りがあると、そこから回復できない
【対策: Scheduled Sampling】 アイデア: 訓練中にTeacher Forcingの確率を徐々に下げる ■ 訓練の初期(エポック1-5) Teacher Forcing確率: 100% → まずは正解を見ながら基本を学ぶ ■ 訓練の中期(エポック6-10) Teacher Forcing確率: 50% → 半分は正解、半分は自分の予測を使う ■ 訓練の後期(エポック11-15) Teacher Forcing確率: 20% → ほぼ推論時と同じ状況で訓練 効果: ・訓練と推論のギャップを縮める ・誤りから回復する能力が育つ

🔍 4. 推論時の生成手法

訓練が終わったら、実際に文を生成(推論)します。 生成方法にはいくつかの選択肢があります。

4-1. Greedy Search(貪欲法)

💡 Greedy Searchのアイデア

「各ステップで最も確率の高い単語を選ぶ」

【Greedy Searchの例】 入力: “I love you” → 翻訳 ■ ステップ1: <START> 各単語の予測確率: “私”: 0.60 ← 最大! “僕”: 0.25 “俺”: 0.10 その他: 0.05 → “私”を選択 ■ ステップ2: “私” 各単語の予測確率: “は”: 0.70 ← 最大! “が”: 0.20 “も”: 0.05 その他: 0.05 → “は”を選択 ■ ステップ3: “は” 各単語の予測確率: “あなた”: 0.65 ← 最大! “君”: 0.20 “彼”: 0.10 その他: 0.05 → “あなた”を選択 … 続く … 最終出力: “私はあなたを愛しています” 特徴: ✅ シンプルで実装が簡単 ✅ 計算が速い ❌ 局所最適解に陥る可能性 ❌ 最初の選択が間違うと全体が崩れる

4-2. Beam Search(ビームサーチ)

🔦 Beam Searchのアイデア

「複数の候補を保持しながら探索する」

【Beam Search(beam_size=3)の例】 入力: “I love you” → 翻訳 ■ ステップ1: <START> 上位3つを保持: 候補1: “私” (確率: 0.60) 候補2: “僕” (確率: 0.25) 候補3: “俺” (確率: 0.10) ■ ステップ2: 各候補から展開 候補1 “私” から: “私 は” (0.60 × 0.70 = 0.42) “私 が” (0.60 × 0.20 = 0.12) “私 も” (0.60 × 0.05 = 0.03) 候補2 “僕” から: “僕 は” (0.25 × 0.50 = 0.125) “僕 が” (0.25 × 0.30 = 0.075) “僕 も” (0.25 × 0.10 = 0.025) 候補3 “俺” から: “俺 は” (0.10 × 0.40 = 0.04) … 上位3つを選択: 候補1: “私 は” (0.420) 候補2: “僕 は” (0.125) 候補3: “私 が” (0.120) ■ ステップ3: 同様に続く … 最終的に最も確率が高い系列を選択 特徴: ✅ より良い解を見つけやすい ✅ 局所最適解を避けられる ❌ 計算量が増える(beam_size倍) ❌ 多様性が低い(似た候補が残りやすい)

4-3. Greedy vs Beam の比較

項目 Greedy Search Beam Search
保持する候補数 1つ k個(beam_size)
計算速度 速い k倍遅い
精度 やや低い 高い
推奨用途 高速化が必要な場合 精度が重要な場合
推奨値 beam_size = 5〜10

💻 5. PyTorchでのSeq2Seq実装

Seq2SeqモデルをPyTorchで実装します。 Encoder、Decoder、Seq2Seq全体を段階的に作成します。

5-1. Encoderの実装

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

import torch import torch.nn as nn class Encoder(nn.Module): “””Seq2SeqのEncoder(LSTM)””” def __init__(self, input_dim, embedding_dim, hidden_dim, n_layers=1, dropout=0.5): super(Encoder, self).__init__() # パラメータの意味: # input_dim: 入力語彙サイズ(例: 英語の単語数) # embedding_dim: 埋め込み次元(例: 256) # hidden_dim: LSTMの隠れ状態の次元(例: 512) # n_layers: LSTMの層数 # dropout: ドロップアウト率 self.hidden_dim = hidden_dim self.n_layers = n_layers # Embedding層: 単語ID → ベクトル self.embedding = nn.Embedding(input_dim, embedding_dim) # LSTM層: 系列を処理 self.lstm = nn.LSTM( embedding_dim, # 入力次元 hidden_dim, # 隠れ状態の次元 n_layers, # 層数 dropout=dropout if n_layers > 1 else 0, batch_first=True # (batch, seq, feature)の順 ) self.dropout = nn.Dropout(dropout)

ステップ2:forwardメソッド

def forward(self, src): “”” Args: src: 入力系列 (batch_size, src_length) 例: [[2, 5, 8, 3], [4, 6, 9, 1]] (バッチサイズ2、系列長4) Returns: hidden: 最終隠れ状態 (n_layers, batch_size, hidden_dim) cell: 最終セル状態 (n_layers, batch_size, hidden_dim) “”” # 1. 埋め込み: 単語ID → ベクトル embedded = self.dropout(self.embedding(src)) # embedded: (batch_size, src_length, embedding_dim) # 2. LSTM処理 # outputs: 全時刻の出力(今回は使わない) # hidden: 最終時刻の隠れ状態 → Context Vector # cell: 最終時刻のセル状態 outputs, (hidden, cell) = self.lstm(embedded) # Context Vector = hidden(Encoderの最終状態) return hidden, cell

5-2. Decoderの実装

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

class Decoder(nn.Module): “””Seq2SeqのDecoder(LSTM)””” def __init__(self, output_dim, embedding_dim, hidden_dim, n_layers=1, dropout=0.5): super(Decoder, self).__init__() # パラメータの意味: # output_dim: 出力語彙サイズ(例: 日本語の単語数) # その他はEncoderと同じ self.output_dim = output_dim self.hidden_dim = hidden_dim self.n_layers = n_layers # Embedding層 self.embedding = nn.Embedding(output_dim, embedding_dim) # LSTM層 self.lstm = nn.LSTM( embedding_dim, hidden_dim, n_layers, dropout=dropout if n_layers > 1 else 0, batch_first=True ) # 出力層: 隠れ状態 → 単語の確率分布 self.fc_out = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout)

ステップ2:forwardメソッド

def forward(self, input, hidden, cell): “”” Decoderは1単語ずつ生成する Args: input: 現在の入力単語 (batch_size, 1) hidden: 前の隠れ状態 (n_layers, batch_size, hidden_dim) cell: 前のセル状態 (n_layers, batch_size, hidden_dim) Returns: prediction: 次の単語の確率 (batch_size, output_dim) hidden: 更新された隠れ状態 cell: 更新されたセル状態 “”” # 1. 埋め込み embedded = self.dropout(self.embedding(input)) # embedded: (batch_size, 1, embedding_dim) # 2. LSTM(1ステップだけ) output, (hidden, cell) = self.lstm(embedded, (hidden, cell)) # output: (batch_size, 1, hidden_dim) # 3. 出力層で単語の確率を計算 # squeeze(1): 系列長の次元を削除 (batch_size, 1, hidden_dim) → (batch_size, hidden_dim) prediction = self.fc_out(output.squeeze(1)) # prediction: (batch_size, output_dim) return prediction, hidden, cell

5-3. Seq2Seq全体の実装

import random class Seq2Seq(nn.Module): “””Seq2Seqモデル(Encoder + Decoder)””” def __init__(self, encoder, decoder, device): super(Seq2Seq, self).__init__() self.encoder = encoder self.decoder = decoder self.device = device def forward(self, src, trg, teacher_forcing_ratio=0.5): “”” Args: src: 入力系列 (batch_size, src_length) trg: 正解系列 (batch_size, trg_length) teacher_forcing_ratio: Teacher Forcingを使う確率 Returns: outputs: 全時刻の予測 (batch_size, trg_length, output_dim) “”” batch_size = src.shape[0] trg_length = trg.shape[1] trg_vocab_size = self.decoder.output_dim # 出力を格納するテンソル outputs = torch.zeros(batch_size, trg_length, trg_vocab_size).to(self.device) # 1. Encoderで入力を処理 hidden, cell = self.encoder(src) # hidden, cell: Context Vector(入力の「意味」) # 2. Decoderの最初の入力は<START>トークン # trg[:, 0]: 正解系列の最初の要素(= <START>) input = trg[:, 0].unsqueeze(1) # (batch_size, 1) # 3. 1単語ずつ生成 for t in range(1, trg_length): # Decoderで1単語予測 output, hidden, cell = self.decoder(input, hidden, cell) # output: (batch_size, output_dim) # 予測を保存 outputs[:, t] = output # Teacher Forcingを使うか決定 teacher_force = random.random() < teacher_forcing_ratio # 最も確率の高い単語を取得 top1 = output.argmax(1).unsqueeze(1) # (batch_size, 1) # 次の入力を決定 # Teacher Forcing: 正解を使う # そうでなければ: 自分の予測を使う input = trg[:, t].unsqueeze(1) if teacher_force else top1 return outputs

5-4. モデルの作成と確認

# デバイスの設定 device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’) # パラメータ INPUT_DIM = 10000 # 入力語彙サイズ(英語) OUTPUT_DIM = 10000 # 出力語彙サイズ(日本語) ENC_EMB_DIM = 256 # Encoder埋め込み次元 DEC_EMB_DIM = 256 # Decoder埋め込み次元 HID_DIM = 512 # 隠れ状態の次元 N_LAYERS = 2 # LSTM層数 DROPOUT = 0.5 # ドロップアウト率 # Encoder, Decoder, Seq2Seqの作成 encoder = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, DROPOUT) decoder = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DROPOUT) model = Seq2Seq(encoder, decoder, device).to(device) print(model) print(f”\nパラメータ数: {sum(p.numel() for p in model.parameters()):,}”)
実行結果: Seq2Seq( (encoder): Encoder( (embedding): Embedding(10000, 256) (lstm): LSTM(256, 512, num_layers=2, batch_first=True, dropout=0.5) (dropout): Dropout(p=0.5, inplace=False) ) (decoder): Decoder( (embedding): Embedding(10000, 256) (lstm): LSTM(256, 512, num_layers=2, batch_first=True, dropout=0.5) (fc_out): Linear(in_features=512, out_features=10000, bias=True) (dropout): Dropout(p=0.5, inplace=False) ) ) パラメータ数: 25,684,000

🎯 6. 訓練と推論

6-1. 訓練関数

import torch.optim as optim # 損失関数(パディングを無視) PAD_IDX = 0 # <PAD>のインデックス criterion = nn.CrossEntropyLoss(ignore_index=PAD_IDX) # 最適化器 optimizer = optim.Adam(model.parameters(), lr=0.001) def train_epoch(model, dataloader, optimizer, criterion, clip=1.0): “””1エポックの訓練””” model.train() total_loss = 0 for src, trg in dataloader: src, trg = src.to(device), trg.to(device) # 勾配をゼロに optimizer.zero_grad() # Forward pass(Teacher Forcing率50%) output = model(src, trg, teacher_forcing_ratio=0.5) # output: (batch_size, trg_length, output_dim) # 損失計算 # <START>を除く(最初のトークンは予測しない) output_dim = output.shape[-1] output = output[:, 1:].reshape(-1, output_dim) # (batch_size * (trg_len-1), output_dim) trg = trg[:, 1:].reshape(-1) # (batch_size * (trg_len-1)) loss = criterion(output, trg) # Backward pass loss.backward() # 勾配クリッピング(重要!) torch.nn.utils.clip_grad_norm_(model.parameters(), clip) # パラメータ更新 optimizer.step() total_loss += loss.item() return total_loss / len(dataloader)

6-2. 推論関数(翻訳)

def translate(model, src_sentence, src_vocab, trg_vocab, max_length=50): “”” 文を翻訳する(Greedy Search) Args: model: 訓練済みSeq2Seqモデル src_sentence: 入力文(単語のリスト) src_vocab: 入力語彙(単語→ID) trg_vocab: 出力語彙(ID→単語) max_length: 最大生成長 Returns: 翻訳結果(単語のリスト) “”” model.eval() # 1. 入力をIDに変換 src_ids = [src_vocab.get(word, src_vocab[‘<unk>’]) for word in src_sentence] src_tensor = torch.LongTensor(src_ids).unsqueeze(0).to(device) # src_tensor: (1, src_length) with torch.no_grad(): # 2. Encoderで入力を処理 hidden, cell = model.encoder(src_tensor) # 3. Decoderで1単語ずつ生成 trg_ids = [trg_vocab[‘<start>’]] for _ in range(max_length): # 現在の入力 input = torch.LongTensor([trg_ids[-1]]).unsqueeze(0).to(device) # Decoder output, hidden, cell = model.decoder(input, hidden, cell) # 最も確率が高い単語 pred_id = output.argmax(1).item() trg_ids.append(pred_id) # <END>が出たら終了 if pred_id == trg_vocab[‘<end>’]: break # 4. IDを単語に変換 id_to_word = {v: k for k, v in trg_vocab.items()} translation = [id_to_word[id] for id in trg_ids[1:-1]] # <START>と<END>を除く return translation

⚠️ 7. Seq2Seqの課題と限界

Seq2Seqは画期的なモデルでしたが、いくつかの重要な課題があります。

7-1. 情報のボトルネック

🔴 問題:Context Vectorに全てを詰め込む

入力文全体の意味を1つの固定長ベクトルに圧縮するため、 長い文では情報が失われます。

【情報のボトルネックの例】 ■ 短い文(問題なし) 入力: “I love you”(3単語) Context Vector: 512次元 → 十分に表現できる ■ 長い文(問題あり) 入力: “The cat, which was sitting on the mat near the window where the sunlight was streaming in, suddenly jumped up and ran away.”(30単語) Context Vector: 512次元(同じ!) → 情報が失われる 特に: ・文の最初の方の情報が薄れる ・細かいニュアンスが失われる ・固有名詞などが正しく翻訳されない

7-2. 長期依存関係の問題

【長期依存関係の例】 入力: “The keys, which were on the table next to the door where I left them yesterday morning, are missing.” 問題: ・”keys”と”are”が遠く離れている ・その間に多くの修飾語がある ・LSTMでも情報が薄れてしまう 結果: ・主語と動詞の一致が崩れる ・翻訳の品質が低下する

7-3. Seq2Seqの位置づけ

💡 Seq2Seqの歴史的な意義

2014年:Seq2Seq登場

  • 機械翻訳の精度が大幅に向上
  • End-to-End学習の可能性を示した
  • NLPに革命をもたらした

現在の位置づけ:

  • 基礎概念として重要(学習目的)
  • 実務ではTransformerが主流
  • 次のAttentionを理解するための前提知識
📊 Seq2Seqからの進化

2014年:Seq2Seq → 情報のボトルネック問題
2015年:Attention追加 → 問題を大幅に改善
2017年:Transformer → RNNを完全に置き換え
2018年〜:BERT, GPT → 現代のNLPの標準

📝 練習問題

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

問題1:Seq2Seqの構造

Seq2SeqモデルのContext Vectorとは何ですか?

  1. Decoderの最終状態
  2. Encoderの最終状態
  3. 入力文の単語ベクトルの平均
  4. 出力文の単語ベクトルの平均
正解:b

Context VectorはEncoderの最終状態です。

処理の流れ:

  1. Encoder: 入力系列を処理 → 最終状態
  2. Context Vector = Encoderの最終状態
  3. Decoder: Context Vectorを初期状態として使用

Context Vectorは入力文全体の「意味」を表すベクトルです。 これがSeq2Seqの「情報のボトルネック」の原因でもあります。

問題2:Teacher Forcing

Teacher Forcingを使用する主な理由は何ですか?

  1. 推論時の精度を向上させるため
  2. 訓練を高速化し、安定させるため
  3. メモリ使用量を削減するため
  4. モデルのパラメータ数を減らすため
正解:b

Teacher Forcingは訓練を高速化し、安定させるために使います。

仕組み:

  • 訓練時に正解の単語を次の入力として使用
  • 予測が間違っていても、正解から学習を続けられる
  • 誤りが連鎖しない

欠点:Exposure Bias問題(訓練と推論のギャップ)

問題3:Beam Search

Beam Search(beam_size=5)は、Greedy Searchと何が違いますか?

  1. 各ステップで1つの候補を保持
  2. 各ステップで5つの候補を保持
  3. 各ステップで全ての候補を保持
  4. ランダムに候補を選択
正解:b

Beam Searchは各ステップで複数(k個)の候補を保持します。

Greedy Search:各ステップで最良の1つだけを選択

Beam Search(k=5):各ステップで上位5つを保持し、最終的に最も確率が高い系列を選択

メリット:より良い解を見つけやすい
デメリット:計算量がk倍に増える

問題4:情報のボトルネック

Seq2Seqの情報のボトルネック問題とは何ですか?

  1. Decoderのメモリが不足する
  2. 入力文全体を1つのベクトルに圧縮するため情報が失われる
  3. LSTMの層数が多すぎる
  4. 語彙サイズが大きすぎる
正解:b

情報のボトルネックとは、入力文全体を1つの固定長ベクトル(Context Vector)に圧縮することで情報が失われる問題です。

例:

  • 短い文(3単語)→ 512次元ベクトル → OK
  • 長い文(100単語)→ 512次元ベクトル → 情報が失われる

解決策:Attention機構(次のSTEP 11)

問題5:Seq2Seqの応用

Seq2Seqモデルが適さないタスクはどれですか?

  1. 機械翻訳
  2. 文章要約
  3. テキスト分類(感情分析)
  4. チャットボット
正解:c

Seq2Seqはテキスト分類には適していません。

理由:

  • テキスト分類: 系列 → 固定長出力(1クラス)
  • Seq2Seq: 系列 → 系列(可変長出力)

テキスト分類には、単純なLSTM + 全結合層で十分です。

Seq2Seqが適するタスク:機械翻訳、文章要約、チャットボット、質問応答

📝 STEP 10 のまとめ

✅ このステップで学んだこと
  • Seq2Seq:可変長入力を可変長出力に変換するモデル
  • Encoder:入力を理解してContext Vectorに圧縮
  • Decoder:Context Vectorから1単語ずつ生成
  • Context Vector:入力文全体の「意味」を表すベクトル
  • Teacher Forcing:訓練時に正解を入力として使用
  • Greedy/Beam Search:推論時の生成手法
  • 課題:情報のボトルネック、Exposure Bias
💡 重要ポイント

Seq2Seqの意義:

  • 2014年にNLPに革命をもたらした
  • 可変長→可変長の変換を実現
  • 機械翻訳の精度を大幅に向上

現在の位置づけ:

  • 基礎概念として重要
  • 実務ではTransformerが主流
  • Attentionを理解するための前提知識
🎯 次のステップの準備

次のSTEP 11では、Attentionメカニズムを学びます。

Attentionとは?

  • Seq2Seqの情報のボトルネックを解決
  • Encoderの全ての状態を活用
  • 「どの入力単語に注目するか」を学習
  • 2017年のTransformerにつながる重要な概念

“Attention is All You Need”(2017年)
→ TransformerはAttentionだけで構築されます!

📝

学習メモ

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

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