月影

日々の雑感

【初心者向け】Transformerの心臓部!アテンションの仕組みを「カクテル作り」で完全理解

AI、特にGPTやBERTといったモデルの話になると必ず登場する「アテンション(Attention)機構」。なんとなく「重要そうな単語に注目する仕組み」と分かってはいるものの、具体的に何をしているのか、いまいちピンとこない方も多いのではないでしょうか?

Transformerのアテンションについてわかりやすく説明します。

Transformerについては以下の記事をご覧ください。

現代AIの王様「Transformer」とは?RNNの時代を終わらせた革命的な仕組みの全て - 月影

この記事を読めば大丈夫!

専門用語や数式は最小限に、**「オリジナルカ-クテル作り」**という身近なたとえを使って、アテンションが何をしているのか、その計算の裏側までスッキリ理解できるようになります。


 

アテンションの3人の主役:Query, Key, Value

 

まず、アテンションの世界に登場する3人の主役を紹介します。彼らの役割をカクテル作りにたとえてみましょう。

Query (クエリ) = あなたの「注文」

「スッキリした柑橘系の味が飲みたいな」という、あなたが今求めている情報です。文脈を理解したい中心の単語が発する「質問」に相当します。

Key (キー) = 材料の「ラベル」

バーカウンターに並ぶお酒のボトルのラベルです。「ジン」「ウォッカ」など、それぞれの材料が「何であるか」を示しています。文中の各単語が持つ「検索用のキーワード」だと考えてください。

Value (バリュー) = 材料の「中身」

ボトルの中に入っている液体そのものです。その単語が持つ「意味」や「情報」の本体です。

アテンションの仕事とは、あなたの**注文(Query)に最も合うラベル(Key)を複数見つけ出し、それぞれの中身(Value)**を絶妙な割合で混ぜ合わせて、完璧な一杯を作り上げることなのです。


 

アテンションの計算を覗いてみよう【基本的な仕組み】

 

では、アテンションの計算を、架空の簡単な数値を使ってステップ・バイ・ステップで見ていきましょう。これはエンコーダーの自己アテンションを例にした、最も基本的な仕組みです。

状況: 文「猫がマットに座る」において、「座る」という単語の文脈をAIがどう理解するかを見ていきます。

 

Step 0: 単語のベクトル化(出発点)

 

各単語をAIが扱える数値(ベクトル)に変換します。(※本来は数百次元ですが、ここでは2次元で考えます)

  • vec_猫 = [1, 5] (「生き物らしさ」の次元が高いと仮定)

  • vec_マット = [6, 1] (「場所らしさ」の次元が高いと仮定)

  • vec_座る = [3, 3]

 

Step 1: 変換ルール(Wq, Wk, Wv)の用意

 

AIが事前学習で獲得した「変換ルール」である行列Wq, Wk, Wvを定義します。(※これらは説明のための仮の数値です。本来の数値は大規模学習ごとに決まります。同じ層なら異なる言葉でも同じ数字になります)

  • Wq = [[2, 0], [0, 2]] (単語を「質問者」に変えるメガネ)

  • Wk = [[1, 0], [0, 3]] (単語を「検索キーワード」に変えるメガネ)

  • Wv = [[1, 2], [3, 4]] (単語を「伝えるべき情報」に変えるメガネ)

 

Step 2: Query, Key, Valueの生成

 

ベクトルと行列を掛け算し、3人の主役を生成します。

  • Query (「座る」から)(行列の積の計算)

    q_座る = vec_座る × Wq = [3, 3] × [[2, 0], [0, 2]] = [6, 6]

  • Keys (文中の全単語から)

    • k_猫 = vec_猫 × Wk = [1, 5] × [[1, 0], [0, 3]] = [1, 15]

    • k_マット = vec_マット × Wk = [6, 1] × [[1, 0], [0, 3]] = [6, 3]

  • Values (文中の全単語から)

    • v_猫 = vec_猫 × Wv = [1, 5] × [[1, 2], [3, 4]] = [16, 22]

    • v_マット = vec_マット × Wv = [6, 1] × [[1, 2], [3, 4]] = [9, 16]

 

Step 3: レシピ(重み)を決める

 

q_座ると各Key内積を計算し、関連度スコアを出します。

  • 「座る」と「猫」の関連度: score_猫 = (6 * 1) + (6 * 15) = 96

  • 「座る」と「マット」の関連度: score_マット = (6 * 6) + (6 * 3) = 54

このスコアをソフトマックス関数に通し、「合計すると1になる割合」に変換します。

完成したレシピ (Attention Weight)

  • weight_猫0.985 (98.5%)

  • weight_マット0.015 (1.5%)

 

Step 4: 情報をブレンドして最終出力を得る

 

このレシピに従って全てのValueベクトルを混ぜ合わせ(加重平均し)ます

  • 最終的な出力ベクトル = (v_猫 × 0.985) + (v_マット × 0.015) = [15.895, 21.91]

この新しいベクトルは、v_猫の情報を色濃く受け継いでいます。これにより、「座る」という単語は、**「主に猫が、場所としてはマットの上で」**という豊かな文脈情報をその身にまとったベクトルへと進化したのです。


 

もう少し詳しく:デコーダーでのアテンションの応用

 

文章を生成するデコーダでは、アテンションがさらに2つの方法で巧みに使われます。

状況: 日本語「猫がマットに座る」を英語「The cat sits on the mat」に翻訳中。「The cat」まで生成し、次に来る3番目の単語を決めようとしている場面です。

 

1. マスク付き自己アテンション ✍️

 

目的: 今まさに書いている文章の文脈を整える。

デコーダーは、自分自身(これまで生成した単語)を振り返ります。「The cat」と書いたから次は何が自然か、と考えます。

  • Query: q_cat = [4, 8]

  • Keys: k_The = [3, 1], k_cat = [2, 6]

  • スコア計算: q_catと各Keyを比較。未来の単語「sits」はまだ知らないので、計算から**除外(マスク)**します。⛔

  • 結果: スコアから計算された重みに基づき、「cat」の情報を強く意識したベクトル [29.6, 39.6] が作られ、次の単語を生成する準備が整います。

 

2. クロスアテンション 🕵️‍♂️➡️✍️

 

目的: **原文(エンコーダーの情報)**を参照し、次に何を翻訳すべきか判断する。

準備を整えたデコーダーが、いよいよ原文(日本語)に目を向けます。

  • Query: [29.6, 39.6] (先ほどの自己アテンションの結果)

  • Keys & Values: エンコーダーが作った日本語文の読解メモk_猫, v_猫, k_マット, v_マット, k_座る, v_座る

  • スコア計算: デコーダーのQueryと、日本語文の各Keyを比較すると、「座る」のスコアが最も高くなります。

  • 結果: 「座る」のValueを色濃く反映したベクトル [45.92, 46.64] が作られます。デコーダーはこれを手がかりに、自身の語彙の中から「sits」を選んで生成するのです。


 

よくある質問(Q&A)

 

Q1. この賢い計算ルール(Wq, Wk行列)はどうやって決まるの?

A. 開発元が膨大なテキストデータでAIを事前学習させる際に、間違いを繰り返しながら最適なルール(行列の数値)を自動で学習します。一度学習が終われば、そのルールは固定され、どんな文章にも適用されます。

Q2. 単語ごとに違うルール(Wq, Wk)があるの?

A. いいえ。ルール(Wq, Wk行列)は、AIのある層において全単語で共通です。まるで「質問者メガネ」のように、どんな単語も同じメガネを通して見ることで、それぞれの役割に応じたベクトルに変換されます。これにより、未知の単語にも対応できる高い汎用性が生まれるのです。


 

まとめ

 

  • アテンションは**Query(注文), Key(ラベル), Value(中身)**の3役で成り立っている。

  • 計算は、以下のステップで行われる。

    1. QueryとKeyで関連度を測り、**レシピ(重み)**を決める。

    2. レシピ通りにValueを混ぜ合わせ、最終的な出力を得る。

  • この仕組みによって、AIは文脈に応じて「今、どの単語の情報が最も重要か」を動的に判断し、文章を深く理解することができるのです。

もうアテンションは怖くありませんね!この「カクテル作り」のイメージさえ持っていれば、AIが文章を読むときの頭の中を、より鮮明に想像できるようになったはずです。

 

追記:デコーダーでの計算例

1. マスク付き自己アテンション ✍️

 

目的: デコーダーが今まさに書いている文章の文脈を整える。

このアテンションは、デコーダーが自分自身(これまで生成した単語)を振り返る作業です。「The cat」と書いたから、次は何が自然か?と考えます。

 

Step 1: Q, K, V の生成

 

デコーダーが生成した「The」と「cat」からQuery, Key, Valueを作ります。(Wq, Wk, Wvによる変換は済んだものとします)

  • Query (現在の注目点): q_cat = [4, 8]
  • Keys (振り返る対象):
    • k_The = [3, 1]
    • k_cat = [2, 6]
  • Values (振り返る対象の情報):
    • v_The = [10, 20]
    • v_cat = [30, 40]

 

Step 2: スコア計算(マスク適用)

 

q_catと各Key内積を計算します。

  • q_catk_The = (4 * 3) + (8 * 1) = 20
  • q_catk_cat = (4 * 2) + (8 * 6) = 56
  • q_catk_sits = 計算不可

ここが最も重要です。デコーダーはまだ「sits」という単語を知らない(生成していない)ので、未来の単語との関連度を計算できません。これが「マスク」の役割です。

 

Step 3: 重みの計算と情報のブレンド

 

スコア[20, 56]をソフトマックス関数に通して重みを決めます。

  • weight_The 0.02
  • weight_cat 0.98

この重みでValueを混ぜ合わせます。

  • 出力 = (v_The × 0.02) + (v_cat × 0.98)
    = [0.2, 0.4] + [29.4, 39.2]
    = [29.6, 39.6]

この結果は、「catの情報を強く意識した次の単語を生成する準備ができた」ことを示すベクトルです。

 

 

2. クロスアテンション 🕵️‍♂️➡️✍️

 

目的: エンコーダーが作った読解メモを参照し、次に何を翻訳すべきか判断する。

マスク付き自己アテンションで準備を整えたデコーダーが、次はいよいよ原文(日本語)に目を向けます。

 

Step 1: Q, K, V の用意

 

Queryデコーダーから、KeyValueエンコーダーの読解メモから持ってきます。

  • Query (デコーダーの現在の状態):
    • q_decoder = [29.6, 39.6] (先ほどの自己アテンションの結果)
  • Keys (エンコーダーの読解メモ):
    • k_ = [1, 15]
    • k_マット = [6, 3]
    • k_座る = [12, 12]
  • Values (エンコーダーの読解メモの情報):
    • v_ = [16, 22]
    • v_マット = [9, 16]
    • v_座る = [50, 50]

 

Step 2: スコア計算

 

デコーダーのQueryと、エンコーダーの各Key内積を計算し、原文のどこに注目すべきか判断します。

  • q_decoderk_ = (29.6 * 1) + (39.6 * 15) = 623.6
  • q_decoderk_マット = (29.6 * 6) + (39.6 * 3) = 296.4
  • q_decoderk_座る = (29.6 * 12) + (39.6 * 12) = 830.4

スコアから、デコーダーは「座る」という単語に最も強く注目すべきだと判断しました。

 

Step 3: 重みの計算と情報のブレンド

 

スコア[623.6, 296.4, 830.4]をソフトマックス関数で重みにします。

  • weight_ 0.12
  • weight_マット 0.00
  • weight_座る 0.88

この重みでエンコーダーValueを混ぜ合わせます。

  • 出力 = (v_ × 0.12) + (v_マット × 0.00) + (v_座る × 0.88)
    = [1.92, 2.64] + [0, 0] + [44, 44]
    = [45.92, 46.64]

この最終的な出力ベクトルは、「座る」という情報を色濃く反映しています。デコーダーは、このベクトルを手がかりに、自身の語彙の中から最も確率の高い単語、つまり「sits」を選んで生成するのです。

2025年8月20日更新