本文へスキップ
ブログ一覧へ

BLOG

Transformerの設計意図を直感的に理解する

「Attention Is All You Need」(Vaswani et al., 2017)を解説します。

読了目安: 約14分

この記事を共有

この記事の目的は、Transformerの設計意図を直感的に理解することです。数式やコードは必要最低限にとどめます。

1. Transformerとは?

2017年、Googleの研究者たちが Attention Is All You Need という論文を発表し、Transformerが誕生しました。

それ以前、自然言語処理の主役はRNNとそれをベースにしたエンコーダ-デコーダモデルでした。 しかし、RNNには根本的な欠点がありました。

RNNの問題点

逐次処理しかできません。 単語を1つずつ順番に処理するため、

  1. 文が長いほど訓練が遅くなる(GPUの並列計算をほとんど使えない)
  2. 先頭付近の情報が薄れていく長距離依存問題が生じる

といった問題がありました。

たとえば100単語の文で先頭の主語を参照しようとすると、RNNは100ステップ分の情報を引き継がなければなりません。

そこでTransformerは再帰も畳み込みも使わず、Attentionだけで系列変換を行うという大胆な設計を採用しました。 入力を一度に並列処理できるため、学習速度と精度が向上し、翻訳タスクで当時の最高精度を更新しました。 BERT・GPT・T5・ViTなど、現代の大型モデルの基盤にもなっています。

2. 全体のアーキテクチャ

TransformerはEncoder-Decoder構造を採用しています。全体の構成は次のとおりです。

Transformerのアーキテクチャ

大きく分けて左側がEncoder、右側がDecoderです。

  • Encoder:原文を受け取り、「文脈を考慮した単語ベクトル」に変換する
  • Decoder:Encoderの出力を参照しながら、翻訳文を1単語ずつ生成する

各ブロックが6層重なっており、層を通るほど抽象度の高い表現になっていきます。

3. 入力の前準備

3.1 単語埋め込み

まず「単語」という離散的な記号を、ニューラルネットが扱える数値のベクトルに変換する必要があります。

最もシンプルな方法は、語彙数分の次元を用意してその単語だけ1にするone-hotエンコーディングです。 しかしこれでは「cat」と「dog」の距離も「cat」と「Tokyo」の距離も同じになってしまい、単語間の意味的な近さが表現できません。

そこで使われるのが単語埋め込みです。

各単語をdmodel=512d_{\text{model}} = 512次元の実数ベクトルにマッピングします。

この単語埋め込みの重み行列WeW_eは、訓練を通じて学習されます。

3.2 位置エンコーディング

ここで問題があります。

Attentionは単語を「集合」として扱うため、単語の順序を考慮しません

つまり、"I love cats" と "cats love I" が区別できず、同じ入力として扱われてしまいます。

これを解決するため、各単語ベクトルに位置情報のベクトルを加算します。

入力pos=Embedding(wordpos)+PEpos\text{入力}{\text{pos}} = \text{Embedding}(\text{word}{\text{pos}}) + \text{PE}_{\text{pos}}

位置エンコーディングの計算式

では、位置情報のベクトルはどのように作るのでしょうか。

発想は時計のアナログ表示に似ています。

秒針(i = 0)は1分で一周する短い周期、分針(i = 1)は60分で一周する長い周期—— 複数の針を組み合わせることで、どの時刻かを一意に特定できます。

位置エンコーディングも同じ発想で、短い周期から長い周期まで複数のsin/cos波を重ねることで、各位置に一意なベクトルを生成します。

位置エンコーディングの数式(詳細)

位置エンコーディングPEpos\text{PE}_{\text{pos}}は以下の式で定義されます。

PE(pos,2i)=sin(pos100002i/dmodel)\text{PE}{(\text{pos},2i)}=\sin\left(\frac{\text{pos}}{10000^{2i/d{\text{model}}}}\right)

PE(pos,2i+1)=cos(pos100002i/dmodel)\text{PE}{(\text{pos},2i+1)}=\cos\left(\frac{\text{pos}}{10000^{2i/d{\text{model}}}}\right)

  • pos\text{pos}:文中の位置(0, 1, 2, …)
  • ii:512次元のうち何番目の次元か(0〜255)
  • dmodeld_{\text{model}}:ベクトルの次元数(= 512)

iiが大きくなるほど分母が大きくなり、波の周期が長くなります。

最終的に、単語埋め込みと位置エンコーディングを足し合わせたベクトルが Encoderへの入力として使われます。

4. Encoder

Encoderブロックは以下の3つのコンポーネントで構成されています。

  1. Multi-Head Attention
  2. Position-wise Feed-Forward Network
  3. Add & Layer Normalization(Norm)

phase4-encoder

4.1 Attention

The animal didn't cross the street because it was too tired.

この文で "it" が何を指すか理解するには、"animal" に注目する必要があります。 RNNはこれを「情報を順番に引き継ぐ」ことで解決しようとしましたが、 文が長いと情報が薄れてしまいます。

Attentionは発想を変えます。すべての単語ペアの関連度を一度に計算するという考え方です。

Query・Key・Value(Q・K・V)

Attentionは以下の3種類のベクトルで計算されます。

Q・K・V

Query(Q):「私は何を探しているか」── 検索する側の表現

Key(K):「私はどんな情報を持っているか」── 検索される側の表現

Value(V):「実際に渡す情報の中身」── 検索がヒットしたときに渡すデータ

qkv

Q・K・Vの生成

入力埋め込み行列XXに対して、 学習可能な重み行列をかけることでQ・K・Vを生成します。

Q=XWQ,K=XWK,V=XWVQ = XW^Q,\quad K = XW^K,\quad V = XW^V

この線形変換が重要な意味を持ちます。 同じ入力ベクトルxitx_{\text{it}}("it"のベクトル)から出発しても、

  • WQW^Qをかけると「itが何かを探すときの表現」に変換される
  • WKW^Kをかけると「itが検索されたときにヒットしやすい表現」に変換される
  • WVW^Vをかけると「itが実際に渡す情報の表現」に変換される

つまり、3つの重み行列が「同じ単語の3つの異なる役割」を学習するということです。

Scaled Dot-Product Attention

Q・K・Vが揃ったところで、Attentionの計算式を見ていきましょう。

Attention(Q,K,V)=softmax(QKdk)V\text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V

行列の形を追いながら、4ステップで読み解きましょう。ここでも"I have cats"の例を使います。

Step 1:スコア行列の計算 QKQK^\top

S=QKTS = QK^T

SijS_{ij}は「単語iiが単語jjにどれだけ関連しているか」を表すスコアです。

"I have cats" ならこのようになります。(値は説明のためのイメージです)

Ihavecats
I24.13.20.8
have2.122.43.8
cats0.94.123.7

Step 2:スケーリング

dk=64d_k = 64次元の内積は、次元数が大きいほど値が大きくなる傾向があります。

内積の値が大きすぎるとsoftmaxへの入力が極端になり、出力が「0か1か」のような分布に飽和します。 すると勾配がほぼ0になり、学習が止まってしまいます。

そこでdk\sqrt{d_k}で割ることで正規化します。

S=SdkS^{\prime} = \frac{S}{\sqrt{d_k}}

Step 3:Softmaxで注意重みへ変換

A=softmax(S)A = \text{softmax}(S^{\prime})

各行に対してsoftmaxを適用します。これにより各行の和が1になり、「確率分布」として解釈できます。

Ihavecats傾向
I0.880.100.02ほぼ自分自身に注目
have0.080.800.12自分と "cats" に注目
cats0.030.140.83ほぼ自分自身に注目

この行列AAをAttention Mapといい、各行がその単語のどの単語への注目度を表します。

Step 4:Valueの加重和 V\cdot V

Output=AVRn×dk\text{Output} = AV \quad \in \mathbb{R}^{n \times d_k}

たとえば "have" の出力ベクトルは、

Output["have"] = 0.08 × V["I"] + 0.80 × V["have"] + 0.12 × V["cats"]

となり、"have" は自分自身のValueを80%、"cats" のValueを12%取り込んだ表現になります。

"have"の意味は"cats"との関係によって少し変わるという文脈情報が、この加重和に埋め込まれているわけです。

scaled-dot-product-attention

Multi-Head Attention

1組のQ,K,VQ,K,Vで計算するScaled Dot-Product Attentionは、ひとつの視点しか表現できません。しかし自然言語の単語間には同時に複数の関係が存在します。

"The animal didn't cross the street because it was too tired."

"it"と他の単語の間には、少なくとも以下の関係が同時に存在します。

  • 照応関係:it → animal (照応先)
  • 構文関係:it → was (主語-述語)
  • 意味関係:it → tired (状態の主体)

1ヘッドではこれらを1枚のAttentionマップに押し込む必要があり、どれかの関係が犠牲になります。

そこでMulti-Head Attentionは、Attention計算をhh個並列に走らせます

multi-head-attention

論文ではh=8h = 8ヘッドを使用しています。各ヘッドの次元を縮小することで合計の計算コストを維持しつつ、8つの独立した視点が得られます。

dk=dv=dmodelh=5128=64d_k = d_v = \frac{d_{\text{model}}}{h} = \frac{512}{8} = 64

Concatと射影

それぞれのHeadでAttentionが終わったら、8つのヘッドの出力を次元方向に結合(Concat)します。

Concat(head1,...,head8):(3,64×8)=(3,512)\text{Concat}(\text{head}_1,...,\text{head}_8):(3,64 \times 8)=(3,512)

ここで512次元に戻りましたが、これは単なる「くっつけた」状態です。 重み行列WOW^Oをかけてヘッド間の情報を混合し、統合された表現に変換します。

MultiHead(Q,K,V)=Concat(head1,,head8),WO\text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_8),W^O

(3,512)×(512,512)=(3,512)(3,512) \times (512,512)=(3,512)

4.2 Position-wise Feed-Forward Network

なぜAttentionの後にFFNが必要か

Attentionは「単語間の情報のやり取り」ですが、本質的には加重和(線形変換)にすぎません。 深いネットワークの恩恵を受けるには非線形変換が必要であり、また文脈を取り込んだ表現を各単語の内部でさらに変換・整理する層も必要です。これがFFNの役割です。

Attentionが「単語間の情報交換」なら、FFNは**「各単語内での情報整理」**です。 重み行列は全単語で共有されますが、各単語に独立して適用されます。

FFNの計算式

FFN(x)=max(0,xW1+b1),W2+b2\text{FFN}(x) = \max(0, xW_1 + b_1),W_2 + b_2

2層の全結合層。max(0,)\max(0, \cdot)はReLU活性化関数で、非線形性を導入します。

4.3 Add & Layer Normalization(Norm)

残差接続

Encoderでは6層のブロックを重ねるため、そのままでは勾配消失が問題になります。

そこで、前の層からの入力xxを、処理ブロックを通すだけでなく、 処理をスキップするバイパスを作り、そのまま足し合わせるのが残差接続です。

output=x+Sublayer(x)\text{output} = x + \text{Sublayer}(x)

通常のネットワークがF(x)F(x)を学習するのに対し、 残差接続ではF(x)=Sublayer(x)F(x) = \text{Sublayer}(x)が「入力からの変化分」を学習します。

重要な性質として、逆伝播の際に勾配がxxのパスを通って そのまま(掛け算なしで)前の層まで届きます。 どれだけ層が深くても勾配が消えにくくなり、6層のブロックが安定して訓練できます。

Layer Normalization(Norm)

また、層を重ねるとデータのスケールがずれ、学習が不安定になります。Layer Normalizationはこれを抑えるため、各サンプルの全特徴量次元にわたって正規化します。

Layer Normalizationの数式

LayerNorm(x)=γxμσ+ϵ+β\text{LayerNorm}(x) = \gamma \cdot \frac{x - \mu}{\sigma + \epsilon} + \beta

  • μ,σ\mu, \sigma:そのサンプルの512次元にわたる平均・標準偏差
  • γ,β\gamma, \beta:スケールとシフトの学習パラメータ
  • ϵ\epsilon:ゼロ除算防止の小さな定数

5. Decoder

DecoderはEncoderと同様のブロックを持ちますが、2つの重要な追加要素があります。

decoder

推論時のDecoderは、1単語ずつ生成し、生成した単語を次のステップの入力に加えながら繰り返します。

この自己回帰的な生成は直感的ですが、訓練時には問題が生じます。

5.1 Masked Multi-Head Self-Attention

Teacher Forcing

誤った単語を生成するたびにその後の計算が全て狂うため、逐次生成で訓練するのは非効率です。 そこで訓練時はTeacher Forcingを使います。

「モデルが生成した単語」ではなく、正解の翻訳文をまとめてDecoderに渡し、 全ての位置を並列に予測させます。

役割トークン列説明
Encoder 入力"Yo tengo gatos"原文
Decoder 入力<start>, "I", "have", "cats"正解をまとめて渡す
Decoder 出力"I", "have", "cats", <end>全位置を一度に予測

しかし**"have"を予測するときに正解の"cats"が見えてしまいます**——これはカンニングです。

マスキングの仕組み

これを防ぐのがマスキングです。 スコア行列S=QKT/dkS = QK^T / \sqrt{d_k}を計算した後、 「現在の位置より右」の要素を-\inftyに置き換えます。

"I have cats"(4トークン)のスコア行列の変化を追います。(値はイメージ)

<start>Ihavecats
<start>3.21.10.82.4
I2.14.51.30.9
have0.82.33.71.2
cats1.40.62.14.8

未来の単語にマスクを適用すると、次のようになります。

<start>Ihavecats
<start>3.2−∞−∞−∞
I2.14.5−∞−∞
have0.82.33.7−∞
cats1.40.62.14.8

Softmaxを適用すると-\inftyの部分はe=0e^{-\infty} = 0になるため、 未来の単語へのAttention重みは0になります。

以下はSoftmax後のAttention Mapのイメージです。

<start>Ihavecats備考
<start>1.000.000.000.00<start> しか参照できない
I0.190.810.000.00<start> と I だけ参照
have0.080.320.600.00have まで参照
cats0.050.070.200.68全て参照可

これにより訓練時でも「未来の単語は見えない」という推論時と同じ制約を保ち、 かつ全位置を並列に計算できます。

5.2 Cross-Attention

なぜCross-Attentionが必要か

Masked Self-Attentionを経たDecoderは「訳語の文脈表現」を持っていますが、原文のどの部分に対応する翻訳を生成すべきかはまだわかりません。Cross-Attentionがその橋渡しをします。

Q・K・Vの出所

Cross-AttentionのQ・K・V
  • Query(Q):Decoderの前層出力(「今、何を生成しようとしているか」)
  • Key(K):Encoderの最終出力(「原文の各単語がどんな内容を持っているか」)
  • Value(V):Encoderの最終出力(「原文の各単語から実際に取り出す情報」)

QだけDecoderから、K・VはEncoderから来ます。 Self-Attentionとの違いはここです。

行列の形で確認しましょう。"Yo tengo gatos"(3単語)→ "I have cats"(3単語)の例:

テンソル形状説明
Encoder 最終出力(3, 512)"Yo", "tengo", "gatos" の文脈表現
Decoder 前層出力(3, 512)"I", "have", "cats" の途中表現
Q = Decoder × W^Q(3, 64)「何を生成しようとしているか」
K = Encoder × W^K(3, 64)「原文の各単語のキー」
V = Encoder × W^V(3, 64)「原文の各単語の内容」
Attention(Q, K, V)(3, 64)「各訳語が原文のどこを参照したか」

Attentionスコア行列のイメージ:

Yotengogatos参照先
I0.850.100.05"Yo" を強く参照
have0.070.880.05"tengo" を強く参照
cats0.040.080.88"gatos" を強く参照

DecoderのQueryが対応する原文単語のKeyと一致することで、そのValueから情報を引き出す——これが翻訳のアライメント(原文と訳文の単語対応関係)です。

なおCross-AttentionにはMaskはありません。 訳語を生成するとき、原文全体を参照するのは正当だからです。

EncoderとDecoderのデータフロー(まとめ)

Encoder–Decoder データフロー
原文 Yo tengo gatos Encoder × 6層 文脈ベクトル (3, 512) Cross-Attention K, V: Encoder出力 / Q: Decoder前層 Decoder × 6層 Masked Self-Attention + Cross-Attention 翻訳文 I have cats

5.3 最終出力

Decoderの最終層の出力を、Linear層で語彙サイズに射影し、Softmaxで確率分布に変換します。 確率が最も高い単語をその時刻の出力とし、end\langle\text{end}\rangleが出るまで繰り返します。

出力確率の計算式

y^t=softmax(htWout+b)\hat{y}t = \text{softmax}(h_t W{\text{out}} + b)

hth_tはDecoderの最終層出力(Rdmodel\in \mathbb{R}^{d_{\text{model}}})、WoutW_{\text{out}}は語彙サイズへの射影行列です。

phase6-predict

6. まとめ

Transformerが革命的だった理由は、

「RNNもCNNも使わず、Attentionだけで、より速く・より精度高く・より汎用的に系列変換を解いた」

ことです。要点を整理すると、

  • Multi-Head Self-Attentionで単語間の関係を並列に・多角的に捉える
  • 位置エンコーディングでAttentionの「順序盲点」を補う
  • 残差接続+Layer Normで深いネットワークを安定訓練
  • 任意の2単語間がO(1)O(1)ステップで繋がり、長距離依存を学習しやすい

この設計のシンプルさと汎用性が、NLPを超えて画像・音声・マルチモーダルへと広がった理由です。 BERT・GPT・T5・ViTなど、多くの現代AIモデルの起点がここにあります。

「Attentionだけで十分だ」という発想が、系列モデルの設計を大きく変えました。

コメント

GitHub Discussions のコメント欄は、開いたときだけ読み込みます。