Transformer 内部構造ガイド入力から出力までを図・形状・コードで追う

全体図での位置処理順 8 番目 / 全 20 ブロック全体図で確認する

Encoder抽象度: ベクトル難易度: 入門推定学習時間: 約10分

Encoder出力(文脈表現)Contextual Representation

30秒で分かる要約Encoderの最終層が出力する、入力文の各トークンに対する文脈込みのベクトル列です。1トークンにつき1本のベクトルが残り、DecoderがCross AttentionでKey・Valueとして参照します。

hidden_states[B, S, D]encoder_states[B, S, D]

Level 1概要役割と処理の流れ

何をする機能か

Encoder の N 層すべてを通過したあとに残る、[B, S, D] のベクトル列です。 新しい計算をする層ではなく、Encoder スタックの最終的な出力を指します。

入力トークン 1 個につき 1 本のベクトルが対応し、その本数は最初から最後まで変わりません。 変わったのは中身で、各ベクトルは「文全体を踏まえたうえでの、その位置の意味」を表すようになっています。

なぜ必要か

入力埋め込み の時点では、 同じトークンはどこに出てきても同じベクトルでした。 Encoder を通ることで、同じ語でも文脈によって異なるベクトルになります。

この表現は 2 通りに使われます。

  1. Decoder が Cross Attention で参照する Key・Value として
  2. 分類や検索など、下流タスクの入力特徴として(Encoder-only モデルの使い方)

全体の中でいつ呼ばれるか

Encoder の最終層の Add & Norm を終えた時点です。 以降、Encoder 側の計算は行われません。 推論時、この結果は1 回だけ計算して使い回します(Decoder が 1 トークン生成するたびに再計算はしません)。

Level 2内部処理Tensor形状・内部ステップ・設計上の意味

前段から受け取るもの

Encoder 最終層の 残差接続 + LayerNorm の出力 [B, S, D]。

後段へ渡すもの

encoder_states [B, S, D]。Decoder の各層の Cross Attention へ、Key と Value の材料として渡されます。 Decoder は N 層すべてで同じ encoder_states を参照します。

あわせて、入力側のパディング位置を示す encoder_mask [B, S] も渡します。 パディングを参照しないようにするためです。

例文での処理

共通例文

The keys on the table are lost.

概念上のトークン列(S = 8): [The, keys, on, the, table, are, lost, .]

  1. The
  2. keys
  3. on
  4. the
  5. table
  6. are
  7. lost
  8. .
位置1の keys のベクトルには、on the table(どこにあるか)と lost(どうなったか)の情報が織り込まれています。

Encoder 出力の段階で、各位置のベクトルはおおむね次のような情報を含みます。

位置トークン含まれるようになった情報の例
1keys複数形である/on the table に修飾されている/lost の主語である
4tableon に続く名詞で、keys の場所を説明する句の一部である
5are主語 keys に対応する be 動詞である

Embedding 直後

位置1の keys = 「keys という語」のベクトル(文脈なし)

Encoder 出力

位置1の keys = 「テーブルの上にあった、失くした複数の鍵」のベクトル

重要なのは、ベクトルの本数は S 本のままという点です。 文全体を 1 本のベクトルに要約するわけではありません。 文全体を 1 本で表したい場合は、平均を取る、[CLS] のような特別な位置を使う、 といった追加の操作が必要です。

EncoderとDecoderでの違い

これは Encoder 固有の出力です。Decoder 側の対応物は、 Decoder 最終層の出力 [B, T, D] で、そちらは Linear(語彙数へ変換) へ渡されます。

  • Encoder 出力 [B, S, D] → Cross Attention の Key・Value になる
  • Decoder 出力 [B, T, D] → 語彙上の確率へ変換される

Decoder-only の LLM には Encoder がないため、この表現自体が存在しません。 入力(プロンプト)も同じ 1 本の系列として Decoder が処理します。

入力と出力

入力

項目名データの意味データ型Tensor形状記号の意味具体例次の渡し先
hidden_statesEncoder 最終層の出力float32 Tensor[B, S, D]B = バッチサイズ(同時に処理する文の数) / S = 入力系列長(Encoder側のトークン数) / D = モデル内部のベクトル次元(d_model)[1, 8, 512]そのまま Encoder 出力になる

出力

項目名データの意味データ型Tensor形状記号の意味具体例次の渡し先
encoder_states入力トークンごとの文脈込みベクトルfloat32 Tensor[B, S, D]B = バッチサイズ(同時に処理する文の数) / S = 入力系列長(Encoder側のトークン数) / D = モデル内部のベクトル次元(d_model)[1, 8, 512]Decoder 各層の Cross Attention(Key・Value)
encoder_mask入力側のパディング位置(参照させない位置)bool / int64 Tensor[B, S]B = バッチサイズ(同時に処理する文の数) / S = 入力系列長(Encoder側のトークン数)[[1, 1, 1, 1, 1, 1, 1, 1]]Cross Attention のマスク
B
バッチサイズ(同時に処理する文の数)
S
入力系列長(Encoder側のトークン数)
D
モデル内部のベクトル次元(d_model)

このサイトでは Tensor 形状を PyTorch の `batch_first=True` 相当、つまり `[B, S, D]`(バッチ次元が先頭)で統一しています。実装によっては `[S, B, D]` を採用するものもあります。

よくある誤解

Level 3数式・Python数式・疑似実装・計算量・実装差

Pythonで表したインターフェース

from dataclasses import dataclass
from typing import Optional
import torch
from torch import Tensor, nn
 
 
@dataclass
class EncoderOutput:
    encoder_states: Tensor            # [B, S, D] 文脈込みの表現
    encoder_mask: Optional[Tensor]    # [B, S]    パディング位置
 
 
class TransformerEncoder(nn.Module):
    """Encoder 層を N 個積み重ねたスタック。"""
 
    def __init__(self, layers: nn.ModuleList) -> None:
        super().__init__()
        # 各層は別々のパラメータを持つ。同じ層を N 回ループするのではない。
        self.layers = layers
 
    def forward(
        self,
        hidden_states: Tensor,
        encoder_mask: Optional[Tensor] = None,
    ) -> EncoderOutput:
        """
        Args:
            hidden_states: [B, S, D]。位置情報を加算済みの埋め込み。
            encoder_mask: [B, S]。1 が実トークン、0 がパディング。
 
        Returns:
            encoder_states [B, S, D]。Decoder が Key/Value として参照する。
        """
        for layer in self.layers:
            hidden_states = layer(hidden_states, encoder_mask)  # 形は [B, S, D] のまま
        return EncoderOutput(encoder_states=hidden_states, encoder_mask=encoder_mask)
 
 
# 最小使用例(層の中身はダミー)
B, S, D = 1, 8, 512
identity_layers = nn.ModuleList([nn.Identity() for _ in range(6)])
 
 
class _DummyLayer(nn.Module):
    def forward(self, x: Tensor, mask: Optional[Tensor] = None) -> Tensor:
        return x
 
 
encoder = TransformerEncoder(nn.ModuleList([_DummyLayer() for _ in range(6)]))
out = encoder(torch.randn(B, S, D), torch.ones(B, S, dtype=torch.long))
 
print(out.encoder_states.shape)   # torch.Size([1, 8, 512]) == [B, S, D]
print(out.encoder_mask.shape)     # torch.Size([1, 8])      == [B, S]

この例で単純化している点

  • Encoder 層の中身(Attention・FFN)は既出のため省略し、スタックの入出力だけを示しています。
  • Post-Norm 構成を前提にしています(Pre-Norm では最後にもう一度 LayerNorm が入ります)。
  • パディングマスクの生成は呼び出し側の責務としています。

型と Tensor 形状の見え方を掴むための擬似実装です。そのまま学習・推論に使えるものではありません。

「N回反復」の意味

図に描かれた「N回反復」は、同じ重みの層を N 回ループするという意味ではありません。 通常は、それぞれ異なるパラメータを持つ層を N 個積み重ねることを指します (原典 base モデルでは N = 6)。

  • 1 層目は表層的な特徴(隣接関係、品詞など)を扱う傾向
  • 上の層ほど、構文や意味に関わる抽象的な特徴を扱う傾向

が観察されることがありますが、層ごとの役割が設計で決められているわけではありません。

下流での使われ方

  • Cross Attention の Key・Value: 原典 Transformer の用法
  • 文分類: [CLS] 位置のベクトル、または全位置の平均に分類ヘッドを付ける(BERT 系)
  • 系列ラベリング: 各位置のベクトルにタグ分類ヘッドを付ける(固有表現抽出など)
  • 埋め込み検索: 平均プーリングして 1 本のベクトルにし、 ベクトル DB に格納する(RAG の検索側)

この記事の位置づけ

このページ

Encoder出力(文脈表現)

次に読むとよい記事

Encoder–Decoder Attention

関連記事