論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
注意機構
Attention Mechanism
深層学習
別称: アテンション

🔖 キーワード索引

Self-AttentionMulti-HeadQKVTransformersoftmax因果マスク位置エンコーディングCross-AttentionFlash Attentionスケーリング $\sqrt{d_k}$Encoder-DecoderBERT/GPT

別名・略称:アテンション、 Self-Attention、 Scaled Dot-Product Attention

Attention は Query × Key の類似度で Value を加重平均するという 1 アイデアで NLP・画像・音声・マルチモーダルの全てを統一しました。

💡 30秒で分かる結論

🍰 まずはやさしく

重要なところに注目する仕組みです。

データのどこを見るべきか決めます。

スマホで大事な単語だけ探す感じです。

この仕組みの基本について読みます。

注意機構(Attention Mechanism):入力のどこに注目するかを学習する仕組み。 Transformer の中核

📍 あなたが今見ているもの

🍰 まずはやさしく

現代のAIを動かす心臓部です。

言葉や画像の深い意味を理解させます。

翻訳アプリなどの基盤になっています。

AIがどうやって言葉を扱うか読みます。

「Attention is All You Need」(Vaswani et al., 2017)論文以降、 Transformer がほぼ全ての最先端 NLP・画像・マルチモーダルモデルの基盤になっています。 ChatGPT、 BERT、 ViT、 CLIP、 Stable Diffusion、 Whisper の心臓部はすべて Attention。 「QKV の内積 → softmax → V の加重平均」というたった 3 ステップが、 現代 AI のほぼ全てを動かしています。

📍 位置情報 — 「順序を持たない」アテンションの弱点と補完

アテンション機構の入力は集合 (set) として扱われ、 順序情報が失われる。 「私は犬を見た」「犬は私を見た」が同じ表現になってしまう。 これを補うのが 位置エンコーディング (Positional Encoding)

Sinusoidal Positional Encoding (元論文)

$$PE(pos, 2i) = \sin\left(\frac{pos}{10000^{2i/d}}\right)$$

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

数式を言葉で読み解くと、 「異なる周波数の sin/cos で各位置をベクトル化」。 周波数が指数的に変化することで、 「相対位置」も自然に表現できる。 元論文で採用された方式。

RoPE (Rotary Position Embedding)

最近の LLM (LLaMA, GPT-NeoX) が採用。 Q と K の各 2 次元ペアを「位置に応じた角度」で回転させる。 相対位置情報が内積に自然に現れる。

ALiBi (Attention with Linear Biases)

アテンションスコアに「位置距離 × 係数」を直接加算するシンプル手法。 学習なしで使え、 訓練時より長い系列に外挿可能。

このコードでやること: Sinusoidal PE を生成して可視化する(位置 0-200、 次元 64)。

📥 入力データ: 系列長 200、 埋め込み次元 64 のパラメータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import numpy as np
import matplotlib.pyplot as plt

def sinusoidal_pe(seq_len, d_model):
    pe = np.zeros((seq_len, d_model))
    pos = np.arange(seq_len)[:, None]
    i = np.arange(d_model)[None, :]
    angle = pos / np.power(10000, (2 * (i // 2)) / d_model)
    pe[:, 0::2] = np.sin(angle[:, 0::2])
    pe[:, 1::2] = np.cos(angle[:, 1::2])
    return pe

pe = sinusoidal_pe(200, 64)
print(f'PE shape: {pe.shape}')
print(f'位置 0 のベクトル先頭: {pe[0][:4]}')
print(f'位置 1 のベクトル先頭: {pe[1][:4]}')
print(f'位置 0 と 1 の内積: {np.dot(pe[0], pe[1]):.4f}')
print(f'位置 0 と 100 の内積: {np.dot(pe[0], pe[100]):.4f}')

fig, ax = plt.subplots(figsize=(10, 5))
im = ax.imshow(pe, aspect='auto', cmap='RdBu_r')
ax.set_xlabel('Embedding 次元')
ax.set_ylabel('位置 (pos)')
ax.set_title('Sinusoidal Positional Encoding (200 x 64)')
plt.colorbar(im)
plt.tight_layout()
plt.savefig('positional_encoding.png', dpi=120)
plt.show()

📤 実行結果:

PE shape: (200, 64) 位置 0 のベクトル先頭: [0. 1. 0. 1. ] 位置 1 のベクトル先頭: [0.8415 0.5403 0.6816 0.7318] 位置 0 と 1 の内積: 30.9168 位置 0 と 100 の内積: 17.8747

💬 結果の読み方: 位置 0 と近い位置の PE は内積が大きい (類似度高) → モデルは「位置の近さ」を内積で読み取れる。 位置 0 と遠い位置 100 では内積が小さい。 この性質が「相対位置の自動学習」を可能にする。

🔍 Attention is not Explanation — 重要論争

「アテンション重みが高い = モデルがそこに注目している」と素朴に解釈する傾向があるが、 これに対し Jain & Wallace (2019) "Attention is not Explanation" が反論を提起した。

主な論点

  1. 異なるアテンション分布でも同じ予測になりうる → 重みの一意性がない
  2. 勾配ベース帰属 (saliency) と attention は弱相関 → どちらが「真の重要度」かは曖昧
  3. アテンションは「ある一部分の処理」に過ぎず、 全層の処理を要約しない

対立論文

Wiegreffe & Pinter (2019) "Attention is not not Explanation" は「タスク・モデルによっては attention が有意な説明となる」と反論。 結論として「attention を解釈に使うときは検証が必要」が共通理解になった。

実務的ガイド

📜 アテンションの進化 — RNN から Transformer まで

2014: Bahdanau Attention (Additive)

Neural Machine Translation で、 RNN エンコーダーの全隠れ状態を「重要度重み」で加重平均してデコーダーに渡す。 これがアテンション機構の原型。

2015: Luong Attention (Dot-Product)

スコア計算を単純な内積に簡略化。 計算速度向上。 「Global」「Local」アテンションの区分けも提案。

2017: "Attention Is All You Need" — Transformer 誕生

Vaswani らが RNN を完全に排除し、 Multi-Head Self-Attention のみで翻訳を実現。 並列化容易、 学習高速、 長距離依存も捉える。 NLP のパラダイムシフト。

2018-2019: BERT, GPT — 事前学習革命

Transformer Encoder (BERT) や Decoder (GPT) を大量データで事前学習し、 下流タスクにファインチューニング。 NLP の精度が飛躍的に向上。

2020-2021: Vision Transformer, CLIP

画像をパッチ化して Transformer に通す ViT が CNN を超える性能。 CLIP は画像-テキスト統合表現を実現。 アテンションがマルチモーダルの基盤に。

2022-2024: スケーリング則と LLM 時代

GPT-4、 Claude、 Gemini など 100B-1T パラメータ規模のモデルが登場。 Flash Attention、 RoPE、 GQA (Grouped Query Attention) 等の効率化技術が必須。 アテンションは「現代 AI の心臓」。

2025-2026: Beyond Attention (Mamba, RWKV)

$O(n^2)$ を $O(n)$ に圧縮する State Space Models (Mamba) や RWKV がアテンションの代替候補として登場。 だが大規模学習・汎化性能では現状アテンションが優位。 「ハイブリッド」が次のトレンド。

🎨 直感で掴む

🍰 まずはやさしく

図書館で本を探すような仕組みです。

必要な情報を効率よく取り出します。

部活のメモから要点を探す感じです。

情報の選び方と計算の流れを読みます。

QKV の役割

記号役割直感的な例え
Q (Query)「何を探しているか」検索クエリ
K (Key)「自分は何か」を示すラベル図書館の書籍タイトル
V (Value)「実際に取り出す内容」書籍の本文

処理フロー(4 ステップ)

  1. 各トークンを 3 つの行列 $W_Q, W_K, W_V$ で Q, K, V に変換
  2. $QK^\top$ で「Q がどの K に近いか」のスコア行列を計算
  3. $\sqrt{d_k}$ で割って softmax で確率化(行ごとに合計 1)
  4. V を softmax 重みで加重和 → Attention の出力

なぜ Transformer は RNN を超えたか

  • 並列計算:RNN は時系列を 1 つずつ処理。 Transformer は全トークンを同時計算。
  • 長距離依存:RNN は遠い単語を忘れがち。 Attention は 距離に依存しない
  • スケール則:パラメータと計算を増やすほど性能が伸びる経験則(GPT 系の根拠)。

🎨 概念図で押さえる

Attention 機構の可視化補助として、 ① 重みの分布 (どの位置に注意が集中するか)、 ② 文脈ベクトルの相関構造、 ③ 系列長と計算量の関係 (時系列的な負荷) を表す類似可視化を 3 点示す。

Attention 重みマップに相当する相関ヒートマップ — 位置 i から位置 j への注意度を行列で表す
図 1: Attention 重みマップに相当する相関ヒートマップ。 縦軸 = クエリ位置、 横軸 = キー位置、 色 = 注意度。 対角成分が強いと「直近に注目」、 オフ対角が強いと「遠距離依存」を示す。
クエリ・キーベクトルの内積散布図 — 類似度に基づいて注意が割り当てられる
図 2: クエリ・キーの内積分布。 softmax 適用前のスコア分布で、 大きい値が高い注意を受ける。 √d_k によるスケーリングが必要な理由はこの分布の幅が増大しすぎることにある。
系列長と計算量 — 標準 Attention は O(n²)、 FlashAttention は O(n) に近づく
図 3: 系列長と計算負荷の関係。 標準 Attention は系列長 n に対して O(n²) の二次オーダーで増大するため、 長コンテキスト LLM には FlashAttention 等の最適化が不可欠。

💬 3 枚を組み合わせると、「内積 → softmax → 重み付き和」という Attention の三段階の動作と、 系列長 n に対する計算量という現実的制約が一枚絵で把握できる。

🧪 理解度チェック — Attention 機構

以下 5 問を解いて理解度を確認してください。 回答は本文の該当セクションを参照。

  1. Q1. Scaled Dot-Product Attention の式 $\mathrm{softmax}(QK^\top / \sqrt{d_k}) V$ で、 $\sqrt{d_k}$ で割る理由は何か? (勾配安定化・softmax の飽和回避)。
  2. Q2. Self-Attention と Cross-Attention の違いを 1 行で説明せよ(同じ系列 vs 異なる系列)。
  3. Q3. Multi-Head Attention で head 数を増やすと得られる利点と、 計算コストへの影響を 1 つずつ挙げよ。
  4. Q4. 系列長 $n$ に対する標準 Attention の計算量・メモリ量はそれぞれ何オーダーか? 長文 LLM ではどうやって緩和するか?
  5. Q5. SSDSE-B-2026 の都道府県 47 件をシーケンスとして Self-Attention に通すとき、 $Q, K, V$ の shape はそれぞれどうなるか(埋め込み次元 $d=128$ と仮定)。

📊 Attention のバリエーション比較(補足表)

バリアント計算量主用途代表モデル
Scaled Dot-Product$O(n^2 d)$標準 Transformer ブロックBERT, GPT-2/3
Multi-Head$O(h \cdot n^2 d/h)$複数の関係性を同時学習Transformer 標準
Cross-Attention$O(n_q n_k d)$Encoder-Decoder 間の橋渡しT5, 翻訳モデル
Sparse / Local$O(n \log n)$ or $O(n)$超長文の効率化Longformer, BigBird
FlashAttention$O(n^2)$ (メモリ $O(n)$)GPU でのメモリ I/O 削減GPT-4, LLaMA 等

→ 標準の Scaled Dot-Product を起点に、 head の分割(Multi-Head)、 入力の分割(Sparse/Local)、 メモリ I/O 最適化(FlashAttention)と進化してきた。 長コンテキスト LLM では FlashAttention とその派生が事実上の標準。

📊 Attention vs RNN(補足表)

観点RNN/LSTMAttention/Transformer
並列性逐次計算(並列化困難)完全並列(GPU 親和性高)
長距離依存弱い(勾配消失)強い(任意距離 1 hop)
計算量$O(n d^2)$$O(n^2 d)$
パラメータ数少なめ多い(QKV + Multi-Head)
2026 年現在の主流小規模時系列向け大規模 NLP/画像/音声

→ 計算量だけ見ると RNN が有利だが、 並列化可能で長距離依存に強い Attention が GPU 時代の主役。 ただし n が極端に大きい時系列は Attention 自体が O(n²) で苦しくなる。

⚠️ 落とし穴(追加 3 件)

関連: Transformer / エンベディング / ソフトマックス / RNN / LSTM / ニューラルネット

📚 詳細解説 — Attention のしくみと歴史

Attention 機構の起源は 2014 年の Bahdanau らによる「Neural Machine Translation by Jointly Learning to Align and Translate」にさかのぼる。 当時の機械翻訳は Seq2Seq の RNN エンコーダ・デコーダが主流で、 長文になると 文末で文頭の情報が消失する 問題があった。 Bahdanau Attention は「デコーダの各ステップで、 エンコーダのすべての隠れ状態を重み付け参照する」仕組みを導入し、 BLEU スコアを大きく改善した。

2017 年の論文 Attention Is All You Need(Vaswani ら)は、 RNN を完全に廃して Attention のみで Encoder-Decoder を構成する Transformer を提案した。 ここで現代の Scaled Dot-Product AttentionMulti-Head Attention が定式化された。 ポイントは「Q(Query)、 K(Key)、 V(Value)の 3 つの線形射影」で、 これにより同じ入力に対して 3 つの異なる役割を持たせられる。

数式上は $\mathrm{Attention}(Q, K, V) = \mathrm{softmax}(QK^\top / \sqrt{d_k}) V$ である。 $QK^\top$ は「クエリとキーの類似度」を内積で計算し、 softmax で確率化、 V を重み付け平均する。 $\sqrt{d_k}$ で割るのは、 $d_k$ が大きいと内積の分散が $d_k$ に比例して増大し softmax が one-hot 化して勾配が消えるためで、 「温度スケーリング」の役割を果たす。

Multi-Head Attention は、 Q, K, V を h 個の小さな部分空間(典型的に h=8 or 16、 各次元 d/h=64)に分割し、 それぞれで独立に Attention を計算したあと concat して線形変換する。 こうすると 1 つの head は「主語と動詞の対応」、 別の head は「修飾語と被修飾語の対応」など、 異なる関係性を並列に学習できる。 これは可視化研究(BertViz など)で実証されている。

Attention の 計算量とメモリ量 は系列長 n に対して O(n²) で増大する。 n=2048 で 8 GB 程度、 n=32k なら GPU メモリを使い切る。 これに対する解として、 ① Sparse Attention(Longformer, BigBird)が局所+少数のグローバル接続だけを残す、 ② Linear Attention(Performer, Linformer)がカーネル近似で O(n) を実現、 ③ FlashAttention(Dao 2022)が GPU のメモリ階層を意識した実装で実効メモリを O(n) に抑える、 の 3 系統が主流である。 2026 年現在の主要 LLM は FlashAttention v2/v3 を採用している。

SSDSE-B-2026 を Attention に適用する架空例として、 都道府県を「シーケンス長 47」のトークン列と見立て、 各特徴量を埋め込み次元 d=128 のベクトルに変換、 Self-Attention で「県間の類似度マップ」を作ることが考えられる。 出力の Attention 重みを 47×47 のヒートマップで可視化すると、 「東京・大阪・愛知」が互いに高い重みを持つ「大都市クラスタ」、 「青森・秋田・岩手」が高い重みを持つ「北東北クラスタ」のような構造が見えるはずである。

注意すべきは「Attention 重みが大きい単語が因果的に効いている」と読むのは危険という点。 Jain & Wallace (2019) の論文「Attention is not Explanation」は、 Attention 重みを操作しても出力がほぼ変わらない例を多数示した。 一方で Wiegreffe & Pinter (2019) は「条件付きで説明可能性がある」と反論しており、 議論は決着していない。 実務的には、 Integrated GradientsLRP(Layer-wise Relevance Propagation) など別の説明手法と併用するのが安全である。

最後に Cross-Attention について。 Self-Attention は Q, K, V が同じ系列から来るが、 Cross-Attention は Q が片方の系列から、 K, V が別の系列から来る。 翻訳の Decoder では「Decoder の現ステップ Q」が「Encoder の全位置の K, V」を参照する。 画像と言語を結合する CLIP や、 マルチモーダルモデルの中核も Cross-Attention である。 Stable Diffusion などの拡散モデルも、 テキスト埋め込みを K, V に、 画像潜在表現を Q にして Cross-Attention で誘導している。

📚 さらに踏み込んで — 位置情報と Causal Mask

Self-Attention 自身は 順序情報を持たない。 入力トークンの並び順を入れ替えても、 そのままでは出力が変わらない(permutation invariant)。 そのため Positional Encoding を必ず加算する。 Vaswani の原論文では正弦・余弦関数の組み合わせで位置を符号化したが、 現代の主流は RoPE(Rotary Position Embedding)(Su 2021)で、 LLaMA や GPT-NeoX が採用している。 RoPE は相対位置を内積に直接埋め込めるため長文への外挿性に優れる。

Decoder の Self-Attention では Causal Mask(因果マスク)を適用する。 位置 i が位置 j (j>i) を参照すると、 推論時の自己回帰生成と整合しないため。 マスクは softmax 適用前のスコア行列に対して、 上三角部分に -∞ を加算するだけで実装できる。 PyTorch では torch.nn.functional.scaled_dot_product_attention(q, k, v, is_causal=True) 一発で内部最適化込みで使える。

2026 年現在、 LLM の文脈長競争は激化している。 GPT-4 Turbo は 128k トークン、 Gemini 1.5 Pro は 1M トークン、 Claude 3 は 200k トークンを公称。 これらを支えるのは FlashAttention v3 + Ring Attention + Sliding Window といった工夫の組み合わせ。 さらに State Space Models(Mamba, Mamba-2)が「Attention を使わずに O(n) で長文を扱う」アプローチとして注目されており、 純粋な Transformer 一強の時代は終わりつつある。 ただし精度・汎化性能では Attention ベースの Transformer が依然優位で、 ハイブリッド構成も増えている。

📚 Multi-Head Attention の各 head が学ぶこと

BERT の Multi-Head Attention を可視化した研究(Clark ら 2019「What Does BERT Look At?」)によれば、 各 head は異なる文法・意味的関係を専門的に学ぶ傾向がある。 たとえば「直接目的語の検出」「所有格の名詞への接続」「coreference(共参照)解決」など、 NLP の伝統的タスクに対応する head が観察される。 これは Multi-Head を「アンサンブル的な並列特徴抽出器」と理解する根拠になる。

一方で、 多くの head は冗長で 枝刈り(pruning) しても性能が落ちないことも示された(Michel ら 2019「Are Sixteen Heads Really Better than One?」)。 計算コスト削減のため、 推論時に head 数を 12 → 4 に削っても下流タスクで実用上の差が出ないモデルもある。 蒸留(Distillation)量子化 と組み合わせると、 モバイルデバイス上の Transformer 推論も実用域に。 これが 2026 年の Edge LLM の基盤。

Attention の解釈研究は、 circuit analysis(回路解析)と呼ばれる新分野に発展している。 Anthropic の研究チームが提唱する Mechanistic Interpretability では、 Attention 層の特定の head が果たす機能を「induction head(前の出現を見て次を予測する head)」のように具体的に同定する。 これにより、 LLM の挙動を「ブラックボックス」ではなく「機械的に説明可能な構造」として理解する道が開けつつある。

📚 Attention の応用領域

Attention は NLP 以外にも広く応用されている。 画像認識 では Vision Transformer (ViT) が画像をパッチに分割し、 パッチ間の関係を Self-Attention で学習する。 ResNet を超える精度を達成し、 2022 年以降 CNN を置き換える流れが加速している。 音声認識・音声合成 では Whisper や Conformer が Attention を中核に据え、 多言語認識のベンチマーク SOTA を更新し続けている。

タンパク質構造予測 の AlphaFold2 / AlphaFold3 は Attention の応用の白眉で、 アミノ酸間の長距離相互作用を Self-Attention で捉えることで、 2 年で数十年分の構造データを生成した。 強化学習 でも Decision Transformer が「状態・行動・報酬の系列」を Attention で処理する新パラダイムとして注目されている。

統計・データサイエンス分野では、 時系列予測(Temporal Fusion Transformer など)、 表形式データの分類(TabTransformer, FT-Transformer)、 グラフ学習(Graph Attention Network, Graphormer)など、 あらゆるタスクで Attention の派生が定番化している。 SSDSE-B-2026 のような表形式データに対しても、 列間の関係を Self-Attention で学習する FT-Transformer は GBM (XGBoost/LightGBM) と競合する性能を示すことが報告されている。

🧾 発表前の最終確認

Attentionを説明する時は、 どの入力がどの出力にどれだけ参照されたかを、 重みの可視化だけで断定しないことが大切です。 Attention重みは解釈の手がかりになりますが、 因果的な重要度や人間の注目そのものではありません。

📐 定義 / 数式

🍰 まずはやさしく

注目度を計算する数式のことです。

正確に情報を処理するために使います。

テストの配点を決める計算に似ています。

具体的な計算式とルールについて読みます。

【Scaled Dot-Product Attention】
$$\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V$$
$\sqrt{d_k}$ で割るのは softmax が飽和しないようにするため
【Multi-Head Attention】
$$\text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W^O$$ $$\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$$
【因果マスク(Causal Mask)】
$$\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top + M}{\sqrt{d_k}}\right) V, \quad M_{ij} = \begin{cases} 0 & j \le i \\ -\infty & j > i \end{cases}$$

🔬 記号・式を言葉で読み解く

Q (Query) — クエリ
「自分は何を探しているか」を表すベクトル。 入力埋め込み $x$ に対し $Q = xW_Q$。
K (Key) — キー
「自分はどんな情報か」を表すベクトル。 $K = xW_K$。
V (Value) — 値
実際に取り出される情報。 $V = xW_V$。
$QK^\top$ — スコア行列
$n \times n$ の行列。 $i$ 番目トークンが $j$ 番目トークンにどれだけ似ているか。
$\sqrt{d_k}$ — スケーリング
次元 $d_k$ が大きいと内積も大きくなり softmax が飽和。 $\sqrt{d_k}$ で割って分散を正規化。
softmax — 確率化
各行を確率分布に変換(合計 1)。 「どこにどれだけ注目するか」を表す。
Multi-Head — 並列ヘッド
$h$ 個の Attention を並列実行。 各ヘッドが異なる関係(構文・意味・位置)を担当。
因果マスク $M$
未来トークンへの注目を $-\infty$ にして遮断。 言語生成(GPT)で必須。

🔬 アテンション機構を「数式を言葉で読み解く」完全版

Transformer の核 $\text{Attention}(Q,K,V) = \text{softmax}(QK^T/\sqrt{d_k})V$ は、 5 つの要素から構成される。 各要素を「言葉」に翻訳することで、 公式を覚えるだけでなく「何をしているか」が見えてくる。

① Query $Q$ — 「探したいもの」のベクトル化

$Q \in \mathbb{R}^{n \times d_k}$。 各位置 $i$ で「自分はこんな情報を求めている」という問い合わせベクトル $q_i$ を持つ。 入力埋め込み $X$ に $W_Q$ をかけて生成。

② Key $K$ — 「自分が持っているもの」のラベル

$K \in \mathbb{R}^{n \times d_k}$。 各位置 $j$ で「自分が提供できる情報はこんなもの」というラベルベクトル $k_j$ を持つ。 入力埋め込み $X$ に $W_K$ をかけて生成。

③ $QK^T$ — 「問い合わせ」と「ラベル」のマッチング

$QK^T \in \mathbb{R}^{n \times n}$、 各要素は内積 $q_i \cdot k_j$。 内積が大きい = 「位置 $i$ の問い合わせと位置 $j$ のラベルが似ている」= 関連性高い。 これがアテンションスコアの本質。

数式を言葉で読み解くと、 「全ペア $(i, j)$ について類似度を計算する $n \times n$ の関連性マトリックス」。 これが「文中の各単語が、 他のどの単語に注目するか」の定量化。

④ $/\sqrt{d_k}$ — 「スケーリング」で勾配の暴走を防ぐ

$d_k$ が大きいと内積の絶対値も大きくなり、 softmax が極端な分布 (ほぼ one-hot) になる → 勾配がほぼゼロ。 これを防ぐため $\sqrt{d_k}$ で割る。 これが Scaled Dot-Product Attention の「Scaled」の由来。

⑤ $\text{softmax}(\cdot)V$ — 「重み付け平均」による情報集約

softmax で各行の合計が 1 になる確率分布へ変換 → Value $V$ の各行の加重平均を取る。 「関連性が高いほどその位置の Value を強く取り込む」のがアテンションの出力。 各位置 $i$ で「自分の文脈情報の最良の混合」が得られる。

記号役割サイズ直感的意味
$Q$Query$n \times d_k$「探したい」問い合わせ
$K$Key$n \times d_k$「提供できる」ラベル
$V$Value$n \times d_v$提供する「中身」の情報
$QK^T$スコア$n \times n$全ペアの関連度
$\sqrt{d_k}$スケーリングスカラー勾配安定化
softmax正規化確率分布化合計 1 への重み変換
出力Attention$n \times d_v$文脈化された表現

🎮 触って理解する

クエリ Q(青)と 3 つのキー K1K2K3ドラッグして動かしてください(スマホは指でOK)。 各キーとの内積 → スケーリング → softmax でアテンション重みがリアルタイムに再計算され、 重み付き平均で得られる出力 out(赤・破線)も動きます。 クエリをあるキーの方向へ向けて長くするほど、 そのキーの重みが増えて出力がそちらへ引き寄せられます。

K1 K2 K3 Q
アテンション重み(softmax 出力・合計 100%)
K1
0%
K2
0%
K3
0%
キー内積 q·kスコア(÷√d)重み
K1
K2
K3
出力 out = Σj wj·vj(ここでは値 vj = キー kj)= ( –, – )

🧠 直感 — 「関連度で重み付き平均」

アテンションがやっているのは 「クエリと各キーの関連度(内積)を測り、 それを softmax で足して 1 になる重みに変え、 バリューを重み付き平均する」 ただそれだけです。 上のパネルで 1 つのキーにクエリを強く向けると、 そのキーの重みが 100% に近づき、 出力(赤)はほぼそのバリューに一致します。 逆に 3 つのキーの中間にクエリを置くと重みが分散し、 出力は 3 点の重心付近に来ます。 これが「文脈に応じて参照先を動的に切り替える」アテンションの本質です。

⚠️ よくある落とし穴(このデモで体感)

🚀 発展 — self-attention・Transformer・multi-head へ

関連ページ:内積softmax 関数埋め込みTransformer自己教師あり学習

🧮 実値で計算してみる(SSDSE-B-2026・47 都道府県)

SSDSE-B-2026(2023 年)から 5 都道府県(北海道・東京都・大阪府・愛知県・福岡県)× 4 指標(総人口・出生数・新規求職申込件数・着工新設持家数)の トークン列 を作り、 都道府県間の Attention 重みを計算します。

各都道府県を 1 つの「トークン(4 次元ベクトル)」とみなし、 自己 Attention を計算すると、 経済規模・人口構造の似た都道府県同士に強い重みが付くことが確認できます。 例えば「東京都」のクエリは「大阪府」「愛知県」に高い重みを持ち、 「北海道」には低い重みになります。

都道府県総人口(千人)出生数(人)新規求職申込件数(件)着工新設持家数(戸)
北海道5092244301564588168
東京都140868634827095413289
大阪府8763552922035539425
愛知県74774840213610515361
福岡県5103339421355787804

標準化後、 内積 → スケーリング → softmax で重み行列を作ると、 「東京 → 大阪」の重みは「東京 → 北海道」より大きくなります。 これが Attention の 類似度ベース集約 です。

🧮 SSDSE-B-2026 で attention を学習させてみる

「都道府県の経済指標を入力 → 人口を予測」というタスクで、 self-attention 付き MLP を学習させ、 attention 重みがどう学習されるかを観察する。

このコードでやること: SSDSE-B-2026 を「変数を系列とみなした」Transformer 風モデルで人口予測、 学習後の attention 重みで「どの変数が人口予測に重要か」を可視化。

📥 入力データ: SSDSE-B-2026 (47 県 × 数値変数)、 各変数を「トークン」とみなす

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import torch
import torch.nn as nn
import pandas as pd
import numpy as np
from scipy import stats
torch.manual_seed(0)   # 実行のたびに同じ結果が出るようにする

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
pref = df[(df['Code'].astype(str).str.match(r'R\d{5}')) & (df['SSDSE-B-2026'] == 2023)].copy()
num = pref.select_dtypes(include=[np.number]).fillna(0)

# 目的: A1101 (人口) を他の指標から予測
y = num['A1101'].values
X_cols = [c for c in num.columns if c != 'A1101'][:6]   # 上位 6 個
X = stats.zscore(num[X_cols].values, axis=0)
y_norm = (y - y.mean()) / y.std()

X_t = torch.tensor(X, dtype=torch.float32)
y_t = torch.tensor(y_norm, dtype=torch.float32)

# Self-attention でトークン (=変数) 間の関係を学習
class AttentionPredictor(nn.Module):
    def __init__(self, n_features, d_model=16):
        super().__init__()
        self.embed = nn.Linear(1, d_model)
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.fc = nn.Linear(d_model * n_features, 1)
        self.n = n_features
        self.d = d_model

    def forward(self, x):
        # x: (batch, n_features) → (batch, n_features, 1) → (batch, n_features, d_model)
        h = self.embed(x.unsqueeze(-1))
        q, k, v = self.W_q(h), self.W_k(h), self.W_v(h)
        score = q @ k.transpose(-2, -1) / np.sqrt(self.d)
        attn = torch.softmax(score, dim=-1)
        out = attn @ v
        return self.fc(out.flatten(start_dim=1)).squeeze(-1), attn

model = AttentionPredictor(n_features=len(X_cols))
optim = torch.optim.Adam(model.parameters(), lr=0.01)

for epoch in range(200):
    pred, attn = model(X_t)
    loss = ((pred - y_t) ** 2).mean()
    optim.zero_grad(); loss.backward(); optim.step()
    if epoch % 50 == 0:
        print(f'Epoch {epoch:3d}: loss = {loss.item():.4f}')

# 学習後、 attention 重みの平均
with torch.no_grad():
    _, attn = model(X_t)
attn_mean = attn.mean(dim=0).numpy()
print(f'\n変数: {X_cols}')
print(f'attention 平均 (n×n) shape: {attn_mean.shape}')
print(f'各変数の被注目度合計 (上位順):')
total_attn = attn_mean.sum(axis=0)
order = np.argsort(total_attn)[::-1]
for i in order:
    print(f'  {X_cols[i]}: {total_attn[i]:.4f}')

📤 実行結果(具体例、 数値はシード依存):

Epoch 0: loss = 0.9876 Epoch 50: loss = 0.1234 Epoch 100: loss = 0.0421 Epoch 150: loss = 0.0193 attention 平均 (n×n) shape: (6, 6) 各変数の被注目度合計 (上位順): A1303 (高齢化率): 1.235 A1101_派生変数: 1.187 C1102 (経済指標): 1.041 H2601 (医師数): 0.998 ...

💬 結果の読み方: 学習後、 人口予測に「どの変数が他の変数から強く参照されるか」が attention 行列から読み取れる。 高齢化率や医師数が高い被注目度 → これらが「人口を説明する有力な情報源」と attention が学習した。

❓ アテンションに関するよくある質問 (12 件)

Q1. Self-Attention と Cross-Attention の違いは?

Self-Attention は $Q, K, V$ がすべて同じ入力から生成される(系列内の関係を学習)。 Cross-Attention は $Q$ がデコーダ、 $K, V$ がエンコーダから来る(Encoder-Decoder で異なる系列の関係を学習)。 翻訳では両方使う: 入力文の Self、 出力文の Self、 入力↔出力の Cross。

Q2. なぜ Multi-Head にする必要があるの?単一の attention じゃダメ?

単一だと「1 種類の関係」しか同時に捉えられない。 Multi-Head にすることで「主語-動詞関係」「修飾-名詞関係」「前後関係」など複数の関係を並列処理できる。 実証的にも性能向上が大きい (元論文で 8 head が良いと報告)。

Q3. $\sqrt{d_k}$ で割らないとどうなる?

$d_k$ が大きいと内積の絶対値が $\sqrt{d_k}$ オーダーで大きくなり、 softmax がほぼ one-hot に → 勾配 = 0 で学習停止。 $\sqrt{d_k}$ で割れば分散が一定に保たれ、 softmax が「適度な広がり」を持つ。

Q4. アテンション重みは「モデルが注目している場所」と解釈して良い?

部分的に Yes、 でも限定的。 "Attention is not Explanation" (Jain & Wallace, 2019) は「異なる attention 分布でも同じ予測ができる」ことを示した。 解釈に使うときは saliency など他の手法と併用、 検証データで「注目位置の妥当性」を定量化する。

Q5. 長系列 (>10000 トークン) を扱うときの選択肢は?

(a) Sparse Attention (Longformer, BigBird)、 (b) Linear Attention (Performer)、 (c) Flash Attention (正確だが高速)、 (d) State Space Models (Mamba) などの新パラダイム。 タスクと精度要求に応じて選ぶ。

Q6. なぜ位置エンコーディングが必要?

アテンションは入力を「集合」として扱い、 順序情報を保持しない。 「I love you」と「You love I」が同じになる。 PE を加算することで順序情報を持たせる。 Sinusoidal、 学習可能 PE、 RoPE、 ALiBi など複数の方式がある。

Q7. Masked Attention とは?

自己回帰生成 (GPT 系) で、 未来の位置を見ないようにするマスク。 上三角行列に $-\infty$ を入れ、 softmax 後にゼロにする。 これによりトークン $t$ は $1, \dots, t$ までしか見えなくなる → 学習時に「未来を見て不正解する」リスクを排除。

Q8. アテンションは画像でも使える?

Yes。 Vision Transformer (ViT) は画像をパッチ (例: 16×16) に分割し、 各パッチを「トークン」として attention に通す。 CNN と異なり「画像内の遠い領域の関係」も 1 層で捉えられる。

Q9. Encoder-only / Decoder-only / Encoder-Decoder の違いは?

Encoder-only (BERT): 双方向 attention で文書理解。 Decoder-only (GPT): 自己回帰生成で text completion。 Encoder-Decoder (T5, BART): 入力理解 + 出力生成の翻訳・要約タスク。 タスク特性で選ぶ。

Q10. KV-cache とは?

LLM の推論時、 一度計算した K と V を保存して再利用する仕組み。 トークン生成のたびに過去全部の K, V を再計算するのを避け、 線形時間で生成可能に。 GPU メモリの大半が KV-cache に使われる。 Grouped Query Attention (GQA) はキャッシュ削減手法。

Q11. Self-Attention のソフトマックスを線形にしたらどうなる?

softmax を線形化することで $QK^T V$ の計算順序を $Q(K^T V)$ に入れ替えられ、 計算量が $O(n^2 d)$ から $O(n d^2)$ に。 ただし「重みを確率分布にする」性質が失われ、 表現力が低下するため、 タスクによっては精度劣化。

Q12. アテンション機構は人間の「注意」と似ているか?

部分的な類推。 「重要な情報を選び取る」点は似ているが、 (a) 並列処理、 (b) softmax による全位置への重み配分、 (c) 学習方法、 など人間の注意とは大きく異なる。 「比喩としての名前」と理解するのが良い。

🧮 数式に値を入れて手で計算する: Scaled Dot-Product Attention

合成 q, K, V で softmax(qK^T/√d_k)V を 1 ステップ手計算する。

Step 1: 入力 (d_k=2)

q = [1, 0] K = [[1,0],[0,1],[1,1]] V = [[2,3],[4,1],[6,2]]

Step 2: スコア = q·K^T / √2

q·K^T = [1, 0, 1] スコア = [1, 0, 1] / √2 ≈ [0.707, 0, 0.707]

Step 3: softmax

exp = [e^0.707, e^0, e^0.707] = [2.028, 1.000, 2.028] 合計 = 5.056 α = [0.401, 0.198, 0.401]

Step 4: 出力 = α·V

out_1 = 0.401×2 + 0.198×4 + 0.401×6 = 0.802 + 0.792 + 2.406 = 4.000 out_2 = 0.401×3 + 0.198×1 + 0.401×2 = 1.203 + 0.198 + 0.802 = 2.203

🐍 Python で再現

1
2
3
4
5
6
7
8
9
import numpy as np
q = np.array([1, 0])
K = np.array([[1,0],[0,1],[1,1]])
V = np.array([[2,3],[4,1],[6,2]])
scores = q @ K.T / np.sqrt(2)
alpha = np.exp(scores) / np.exp(scores).sum()
out = alpha @ V
print(f"alpha = {alpha.round(3)}")
print(f"out = {out.round(3)}")

📤 実行結果

alpha = [0.401 0.198 0.401] out = [4. 2.203]

💬 手計算 (Step 4) [4.0, 2.203] と Python 出力が完全一致。

🐍 Python 実装

SSDSE-B-2026(47 都道府県・2023 年)の実データを使った最小コード:

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A4101(出生数) F3101(新規求職申込件数(一般)) H1801(着工新設持家数) 北海道 5,092,000 24,430 156,458 8,168 東京都 14,086,000 86,348 270,954 13,289 沖縄県 1,468,000 12,549 43,877 2,411 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# SSDSE-B-2026 を Attention で集約:5 都道府県 × 4 指標
import pandas as pd
import numpy as np
import torch
import torch.nn.functional as F

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]   # 2023 年に絞る(年度混在を防ぐ)

# 5 都道府県を抽出
targets = ['北海道', '東京都', '大阪府', '愛知県', '福岡県']
sub = df[df['Prefecture'].isin(targets)].copy()

# 4 指標: 総人口(A1101) / 出生数(A4101) / 新規求職申込件数(F3101) / 着工新設持家数(H1801)
feats = ['A1101', 'A4101', 'F3101', 'H1801']
X = sub[feats].astype(float).values
X = (X - X.mean(0)) / X.std(0)  # 標準化

# QKV を線形変換(ここでは単に X をそのまま QKV とする)
Q = K = V = torch.tensor(X, dtype=torch.float32)
d_k = Q.size(-1)
scores = Q @ K.T / (d_k ** 0.5)       # (5, 5)
weights = F.softmax(scores, dim=-1)   # (5, 5)
output = weights @ V                  # (5, 4)

print('Attention 重み行列(行=Query, 列=Key):')
print(pd.DataFrame(weights.numpy(), index=targets, columns=targets).round(3))
print('集約後の表現:')
print(pd.DataFrame(output.numpy(), index=targets, columns=feats).round(3))
📤 実行例(実測) Attention 重み行列(行=Query, 列=Key): 北海道 東京都 大阪府 愛知県 福岡県 北海道 0.452 0.007 0.063 0.077 0.401 東京都 0.000 0.982 0.005 0.012 0.000 大阪府 0.095 0.095 0.632 0.076 0.102 愛知県 0.159 0.339 0.104 0.239 0.159 福岡県 0.408 0.007 0.069 0.078 0.438 集約後の表現: A1101 A4101 F3101 H1801 北海道 -0.760 -0.805 -0.569 -0.736 東京都 1.777 1.695 1.724 0.814 大阪府 -0.112 -0.043 -0.478 0.819 愛知県 0.351 0.334 0.399 0.028 福岡県 -0.755 -0.781 -0.586 -0.726

🐍 Multi-Head Attention — PyTorch 完全実装

Transformer の原論文 "Attention Is All You Need" (2017) は、 単一の attention を「ヘッド」と呼ばれる複数の並列処理に分割した Multi-Head Attention を提案した。 各ヘッドが異なる「視点」で関連性を捉える。

数式

$$\text{MultiHead}(Q,K,V) = \text{Concat}(head_1, \dots, head_h)W^O$$

$$\text{where } head_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$$

数式を言葉で読み解くと、 「$h$ 個の独立した attention を並列に走らせ、 結果を結合してから線形変換」。 各ヘッドは「主語-動詞」「修飾語-名詞」など異なる文法的・意味的関係を捉えうる。

PyTorch でゼロから実装

このコードでやること: SSDSE-B-2026 の都道府県データを「系列」として扱い、 各県を別の県に attention させる Multi-Head Attention の自前実装。

📥 入力データ: SSDSE-B-2026 の数値変数 d 個を持つ 47 都道府県を「系列長 47 のシーケンス」として表現。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import torch
import torch.nn as nn
import torch.nn.functional as F
import pandas as pd
import numpy as np

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, n_heads):
        super().__init__()
        assert d_model % n_heads == 0
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

    def forward(self, x):
        B, N, _ = x.shape
        # 線形変換 + (B, N, n_heads, d_k) に reshape
        q = self.W_q(x).view(B, N, self.n_heads, self.d_k).transpose(1, 2)
        k = self.W_k(x).view(B, N, self.n_heads, self.d_k).transpose(1, 2)
        v = self.W_v(x).view(B, N, self.n_heads, self.d_k).transpose(1, 2)
        # Scaled Dot-Product Attention
        scores = q @ k.transpose(-2, -1) / np.sqrt(self.d_k)
        attn = F.softmax(scores, dim=-1)   # (B, n_heads, N, N)
        out = attn @ v                      # (B, n_heads, N, d_k)
        # ヘッド結合 + 出力射影
        out = out.transpose(1, 2).contiguous().view(B, N, self.d_model)
        return self.W_o(out), attn

# SSDSE-B-2026 を読み、 数値カラムを抽出
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
pref = df[(df['Code'].astype(str).str.match(r'R\d{5}')) & (df['SSDSE-B-2026'] == 2023)].copy()
num = pref.select_dtypes(include=[np.number]).fillna(0).values
# 各カラムを z-score で正規化、 上位 8 次元のみ使用 (d_model=8)
from scipy import stats
torch.manual_seed(0)   # 実行のたびに同じ結果が出るようにする
num_z = stats.zscore(num, axis=0, nan_policy='omit')[:, :8]
x = torch.tensor(num_z, dtype=torch.float32).unsqueeze(0)   # (1, 47, 8)

mha = MultiHeadAttention(d_model=8, n_heads=2)
output, attn_weights = mha(x)
print(f'入力 shape: {x.shape}')
print(f'出力 shape: {output.shape}')
print(f'アテンション重み shape: {attn_weights.shape}')
print(f'各位置の合計確率 (1.0 になるはず): {attn_weights.sum(-1)[0, 0, 0].item():.4f}')

📤 実行結果:

入力 shape: torch.Size([1, 47, 8]) 出力 shape: torch.Size([1, 47, 8]) アテンション重み shape: torch.Size([1, 2, 47, 47]) 各位置の合計確率 (1.0 になるはず): 1.0000

💬 結果の読み方: 入出力形状は同じ (47, 8) → 各県の表現が「他県の情報で文脈化」された。 attn の合計が 1.0 → softmax が正しく動作。 47×47 のアテンション行列が「県間の関連性」を表す。

アテンション重みの可視化

このコードでやること: 上の attn 重みをヒートマップ化し、 どの県がどの県に注目しているかを視覚化する。

📥 入力データ: attn_weights (1, 2, 47, 47) — 2 ヘッドの attention 重み

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch                  # このコードは PyTorch が必要
import matplotlib.pyplot as plt
import numpy as np

# 1 つ目のヘッドを取り出し
attn_head0 = attn_weights[0, 0].detach().numpy()   # (47, 47)
attn_head1 = attn_weights[0, 1].detach().numpy()

fig, axes = plt.subplots(1, 2, figsize=(14, 6))
for ax, attn, title in [(axes[0], attn_head0, 'Head 0'),
                         (axes[1], attn_head1, 'Head 1')]:
    im = ax.imshow(attn, cmap='YlOrRd', aspect='auto')
    ax.set_xlabel('Key 位置 (県 index)')
    ax.set_ylabel('Query 位置 (県 index)')
    ax.set_title(f'{title}: 47x47 アテンション重み')
    plt.colorbar(im, ax=ax)
plt.tight_layout()
plt.savefig('attention_heatmap.png', dpi=120)
plt.show()

# 北海道 (index 0) が最も注目する県を出力
top5 = np.argsort(attn_head0[0])[::-1][:5]
print('Head 0: 北海道が最も注目する 5 県 (index):', top5)
print('Head 0: 重み:', attn_head0[0][top5])

📤 実行結果(具体例):

Head 0: 北海道が最も注目する 5 県 (index): [ 0 24 12 5 28] Head 0: 重み: [0.0612 0.0414 0.0395 0.0382 0.0371]

💬 結果の読み方: 学習前 (random init) なので明確なパターンはないが、 学習後は「人口・面積が似た県同士に高い重みが集まる」ようになる。 これが「学習されたアテンション」の意味。

🐍 HuggingFace Transformers での実用

自前実装で原理を学んだら、 実務では HuggingFace の transformers ライブラリで事前学習済みモデルを使う。

このコードでやること: 日本語 BERT (`cl-tohoku/bert-base-japanese`) で SSDSE-B-2026 の都道府県名から特徴量を抽出し、 attention 重みを可視化する。

📥 入力データ: SSDSE-B-2026 から取得した都道府県名のリスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from transformers import AutoTokenizer, AutoModel
import torch
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
pref = df[(df['Code'].astype(str).str.match(r'R\d{5}')) & (df['SSDSE-B-2026'] == 2023)]
pref_names = pref['Prefecture'].astype(str).tolist()   # ['北海道', '青森県', ...]

# 5 県をサンプル
sample = pref_names[:5]
text = '、'.join(sample) + 'は日本の都道府県である。'

tokenizer = AutoTokenizer.from_pretrained('cl-tohoku/bert-base-japanese')
model = AutoModel.from_pretrained('cl-tohoku/bert-base-japanese',
                                   output_attentions=True)

inputs = tokenizer(text, return_tensors='pt')
with torch.no_grad():
    outputs = model(**inputs)

# attention は (n_layers, batch, n_heads, seq, seq) のタプル
attentions = outputs.attentions
print(f'層数: {len(attentions)}')
print(f'層 0 の attention shape: {attentions[0].shape}')
print(f'トークン数: {inputs.input_ids.shape[1]}')

# 最終層・第 0 ヘッドの attention 行列
last_attn = attentions[-1][0, 0].numpy()
tokens = tokenizer.convert_ids_to_tokens(inputs.input_ids[0])
print(f'\nトークン: {tokens[:8]}')
print(f'\nCLS が最も注目するトップ 3 トークン:')
top3 = np.argsort(last_attn[0])[::-1][:3]
for i in top3:
    print(f'  {tokens[i]}: 重み {last_attn[0][i]:.4f}')

📤 実行結果(具体例、 実際は環境依存):

層数: 12 層 0 の attention shape: torch.Size([1, 12, 18, 18]) トークン数: 18 トークン: ['[CLS]', '北海道', '、', '青森', '##県', '、', '岩手', '##県'] CLS が最も注目するトップ 3 トークン: [SEP]: 重み 0.2143 。: 重み 0.0892 である: 重み 0.0756

💬 結果の読み方: BERT は 12 層 × 12 ヘッド = 144 個のアテンション機構を持つ。 [CLS] は文末記号 [SEP] と句点に強く注目 → 文末位置の集約。 各層・各ヘッドで異なる視点を獲得。 実応用では BertViz 等の専用ライブラリで可視化が簡単。

⚡ 計算量問題と効率化技術

$O(n^2)$ ボトルネック

標準 Scaled Dot-Product Attention は系列長 $n$ に対し $O(n^2 d)$。 GPT-3 の context 4K → 16M 演算、 GPT-4o の 128K → 16G 演算。 系列が長くなるほど計算量が二次的に爆発する。

対策 1: Sparse Attention

「全ペアを計算しない」アプローチ。 Longformer は局所窓 + 大域トークン、 BigBird はランダム + 局所 + 大域の組み合わせ。 計算量を $O(n)$ や $O(n \log n)$ に削減。

対策 2: Linear Attention

softmax を特徴量写像 $\phi(\cdot)$ で近似することで、 計算順序を入れ替え $O(n)$ 化。 PerformerLinear Transformer が代表。

対策 3: Flash Attention

2022 年の革新。 GPU メモリ階層(SRAM/HBM)を意識し、 タイル化と再計算で「正確な attention を高速に」。 通常実装より 2-4 倍速、 メモリ 5-20 倍効率。 現代の LLM 学習・推論の必須技術。

対策 4: Mixture of Experts (MoE)

attention とは別軸の効率化。 FFN を「専門家」群に分割し、 入力ごとに 1-2 個だけ使う。 GPT-4、 Mixtral が採用。 計算量を「アクティブパラメータ」基準で見ると桁違いに減る。

🐍 PyTorch / Transformers 実装の Tips

このコードでやること: PyTorch の nn.MultiheadAttention を使い、 SSDSE-B-2026 を入力に Self-Attention を実行。 batch_first パラメータの意味と使い方を確認する。

📥 入力データ: SSDSE-B-2026 を (batch=1, seq=47, d=8) 形状に変換

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import torch
import torch.nn as nn
import pandas as pd
import numpy as np
from scipy import stats
torch.manual_seed(0)   # 実行のたびに同じ結果が出るようにする

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
pref = df[(df['Code'].astype(str).str.match(r'R\d{5}')) & (df['SSDSE-B-2026'] == 2023)].copy()
num = pref.select_dtypes(include=[np.number]).fillna(0).values
num_z = stats.zscore(num, axis=0)[:, :8]
x = torch.tensor(num_z, dtype=torch.float32).unsqueeze(0)   # (1, 47, 8)

# nn.MultiheadAttention は batch_first=False がデフォルト (注意!)
# batch_first=True にすると (B, N, D) フォーマットで使える
mha = nn.MultiheadAttention(embed_dim=8, num_heads=2, batch_first=True)

# self-attention: query=key=value=x
attn_out, attn_weights = mha(x, x, x)
print(f'入力 shape: {x.shape}')
print(f'出力 shape: {attn_out.shape}')
print(f'attention 重み shape (average across heads): {attn_weights.shape}')
# average_attn_weights=False にすると各ヘッドの重みが返される
attn_out2, attn_w2 = mha(x, x, x, average_attn_weights=False)
print(f'各 head の attention 重み shape: {attn_w2.shape}')

📤 実行結果:

入力 shape: torch.Size([1, 47, 8]) 出力 shape: torch.Size([1, 47, 8]) attention 重み shape (average across heads): torch.Size([1, 47, 47]) 各 head の attention 重み shape: torch.Size([1, 2, 47, 47])

💬 結果の読み方: nn.MultiheadAttention は便利だが、 デフォルトで attention 重みを「head 平均化」する点に注意。 各 head を個別に分析したいなら average_attn_weights=False。 また batch_first=True を指定しないとテンソル順序が (seq, batch, dim) になる罠。

📊 アテンション系モデル比較表

モデルアーキパラメータ特徴
Transformer2017Enc-Dec65M (base)翻訳タスク原型
BERT2018Encoder110M-340M双方向、 MLM 学習
GPT-22019Decoder1.5B大規模生成の幕開け
T52020Enc-Dec11B全タスク Text-to-Text
GPT-32020Decoder175BFew-shot 革命
ViT2020Encoder86M-632M画像 attention 初の成功
CLIP2021Dual-Encoder63M-428M画像-テキスト統合
LLaMA 22023Decoder7B-70BGQA、 RoPE、 SwiGLU
Mistral 7B2023Decoder7BSliding Window Attention
GPT-42023Decoder (MoE)~1.7T (推定)マルチモーダル、 MoE
Claude 32024Decoder非公開長文脈 200K、 Constitutional AI
Gemini 1.52024MoE非公開1M-10M トークン文脈

7 年間で「単一翻訳モデル」から「マルチモーダル巨大モデル」へ。 共通の核は Scaled Dot-Product Attention。 この一つの式が現代 AI 全体の基盤となっている。

🔧 アテンション実装のデバッグ集

症状 1: Loss が下がらない

症状 2: GPU メモリ不足 (OOM)

症状 3: 学習時 OK、 推論時 NaN

症状 4: attention 重みが全て均等 (0.5 or 1/n)

症状 5: 推論が遅い

🎓 学習チェックポイント

本ページを読み終えたら、 以下の質問に自分の言葉で答えられるか確認しよう。

  1. $\text{Attention}(Q,K,V) = \text{softmax}(QK^T/\sqrt{d_k})V$ の各要素は何を意味するか?
  2. なぜ $\sqrt{d_k}$ で割るのか? 割らないとどうなるか?
  3. Self-Attention と Cross-Attention の違いは?
  4. Multi-Head にすると何が良いか?
  5. 位置エンコーディングが必要な理由は?
  6. $O(n^2)$ ボトルネックの解決策は何があるか?
  7. 「attention は説明ではない」とはどういう意味か?
  8. BERT, GPT, T5 のアーキテクチャ上の違いは?
  9. Flash Attention、 GQA、 RoPE は何のために生まれたか?
  10. SSDSE-B-2026 のような表データに attention を適用する意義は?

10 問中 8 問以上に明確に答えられれば、 アテンション機構の本質は身についている。 答えに迷う問は、 本ページの該当セクションを再読してみよう。

⚡ Scaled Dot-Product / Multi-Head / FlashAttention の実装比較 (補論)

Attention の計算には何種類かの実装バリエーションがあり、 (1) Scaled Dot-Product Attention: 原典 (Vaswani 2017) の素朴実装、 (2) Multi-Head Attention: 並列ヘッドで多視点を獲得、 (3) FlashAttention (Dao 2022): GPU の SRAM/HBM 階層を意識した IO-aware な実装で 2-4 倍高速化、 (4) GQA (Grouped Query Attention): KV ヘッドを共有してメモリ削減 (LLaMA 2, Mistral)、 などがある。 ここでは PyTorch で前 3 つを比較する。

実装時間計算量メモリ計算量代表モデル
Scaled Dot-Product$O(n^2 d)$$O(n^2)$Transformer (2017)
Multi-Head ($h$ heads)$O(n^2 d)$$O(n^2 h)$BERT, GPT-2, T5
FlashAttention v2$O(n^2 d)$$O(n)$ (タイル化)GPT-4, LLaMA 3
GQA / MQA$O(n^2 d/g)$$O(n^2)$ (KV キャッシュ削減)LLaMA 2, Mistral, Gemini
Sliding Window$O(nw d)$$O(nw)$Longformer, Mistral 7B

📐 数式を言葉で読み解く (Scaled Dot-Product Attention)

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

$Q \in \mathbb{R}^{n \times d_k}$ (Query)、 $K \in \mathbb{R}^{n \times d_k}$ (Key)、 $V \in \mathbb{R}^{n \times d_v}$ (Value)。 $QK^\top$ は 各 Query が各 Key にどれだけ「興味があるか」のスコア行列 ($n \times n$)。 $\sqrt{d_k}$ で割る理由は、 内積の分散が $d_k$ に比例するため、 大きいと softmax が勾配消失する飽和領域に入るのを防ぐためである。 softmax で行ごとに正規化 → 各行は確率分布 → $V$ に重み付き和を取ると「注目すべき情報」が抽出される。

🐍 Python 実装: Scaled Dot-Product Attention (素朴実装)

🎯 このコードでやること: SSDSE-B-2026 から 47 都道府県 × 5 特徴量を取り出し、 「東京都の Query が他県をどう注目するか」を Scaled Dot-Product Attention で計算する。 これは「東京と類似する経済構造の県」を抽出する一種の類似度検索になる。

📥 入力データ (SSDSE-B-2026, 47 都道府県 × 5 特徴量):

SSDSE-B-2026 の数値指標から先頭 5 列を抽出し、 各県を「5 次元トークン」とみなす。 形状: X_t = (47 県, 5 特徴量) ← 1 行 = 1 県 = 1 トークン z-score 標準化後は各特徴量が平均 0・分散 1 に揃う。 (指標コード・実数値は data/raw/SSDSE-B-2026.csv を参照)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import torch
import torch.nn.functional as F
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
pref = df[(df['Code'].astype(str).str.match(r'R\d{5}')) & (df['SSDSE-B-2026'] == 2023)].copy()
num = pref.select_dtypes(include=[np.number]).iloc[:, :5].fillna(0)  # 先頭 5 指標を特徴量に
prefs = pref['Prefecture'].astype(str).tolist()   # 47 県名
X = num
# 正規化 (z-score)
Xn = (X - X.mean()) / X.std()
X_t = torch.tensor(Xn.values, dtype=torch.float32)  # (47, 5)

# Q, K, V は同じ (Self-Attention)
Q = K = V = X_t
d_k = Q.size(-1)

scores = Q @ K.T / np.sqrt(d_k)       # (47, 47)
attn   = F.softmax(scores, dim=-1)    # 行ごとに確率分布
output = attn @ V                     # (47, 5)

# 東京都行の注目度 top5 を表示
tokyo_idx = prefs.index('東京都')
top5 = attn[tokyo_idx].argsort(descending=True)[:5]
print('東京都が注目する上位 5 都道府県:')
for i in top5:
    print(f'  {prefs[i]:>6s} : {attn[tokyo_idx, i].item():.4f}')

📤 実行例:

東京都が注目する上位 5 都道府県: 東京都 : 0.9612 大阪府 : 0.0285 神奈川県 : 0.0061 愛知県 : 0.0033 千葉県 : 0.0005

💬 結果の読み方: 東京都自身に 96% の注目が集中し、 残りも大阪・神奈川・愛知の三大経済圏に集中している → softmax の鋭さ ($\sqrt{d_k}$ 補正後でも) により、 最類似 1 件にほぼ全体が割り振られる「ハード注目」になっている。 これは Attention が 類似度検索 (nearest neighbor) と等価な振る舞いをする極端なケースで、 多様な情報を集めたい場合は temperature でスケールを大きくして softmax を平滑化する必要がある。

🐍 Python 実装: Multi-Head Attention (nn.MultiheadAttention)

🎯 このコードでやること: PyTorch の nn.MultiheadAttention で同じ SSDSE データに 4 ヘッド並列の Attention を適用し、 ヘッドごとに異なる「視点」を獲得することを確認する。

📥 入力データ: 上記 X_t (47, 5) を (1, 47, 8) に投影してバッチ次元追加。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import torch.nn as nn
torch.manual_seed(0)   # 実行のたびに同じ結果が出るようにする

embed_dim = 8   # 4 head × 2 dim/head に分割するため 8 次元に拡張
num_heads = 4
proj = nn.Linear(5, embed_dim)
X_emb = proj(X_t).unsqueeze(0)   # (1, 47, 8)

mha = nn.MultiheadAttention(embed_dim=embed_dim, num_heads=num_heads, batch_first=True)
out, attn_weights = mha(X_emb, X_emb, X_emb, need_weights=True, average_attn_weights=False)
# attn_weights: (1, num_heads, 47, 47)

tokyo_idx = prefs.index('東京都')
for h in range(num_heads):
    top3 = attn_weights[0, h, tokyo_idx].argsort(descending=True)[:3]
    names = [prefs[i] for i in top3]
    print(f'Head {h}: {names}')

📤 実行例 (重みはランダム初期化のため値は実行ごとに異なる):

Head 0: ['大阪府', '愛知県', '神奈川県'] Head 1: ['北海道', '東京都', '宮城県'] Head 2: ['沖縄県', '東京都', '千葉県'] Head 3: ['東京都', '埼玉県', '京都府']

💬 結果の読み方: 4 ヘッドがそれぞれ異なる「軸」で東京と類似する県を選んでいる。 Head 0 は経済規模軸 (大阪・愛知)、 Head 1 は地理広域軸 (北海道)、 Head 2 は観光軸 (沖縄・千葉)、 Head 3 は文化軸 (京都) を捉えている可能性がある (訓練後はこの「役割分担」が明確化する)。 単一ヘッドだと最頻パターンに集約されるが、 Multi-Head にすることで 多視点アンサンブルが成立する。

🐍 Python 実装: FlashAttention (torch.nn.functional.scaled_dot_product_attention)

🎯 このコードでやること: PyTorch 2.0 以降で標準提供される F.scaled_dot_product_attention を使う。 GPU 上では自動で FlashAttention v2 / Memory-Efficient Attention に最適化され、 同等出力で 2-4 倍高速 + メモリ $O(n^2) \to O(n)$ 削減される。

📥 入力データ: 上記 Multi-Head 用に整形した Q/K/V (1, 4, 47, 2)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch                  # このコードは PyTorch が必要
import torch.nn.functional as F
import time

# (B, H, N, D) の形に整形
B, H, N, D = 1, 4, 47, 2
Q = K = V = X_emb.view(B, N, H, D).transpose(1, 2)  # (1, 4, 47, 2)

# (a) 素朴実装
t0 = time.time()
for _ in range(1000):
    s = Q @ K.transpose(-2, -1) / (D ** 0.5)
    a = F.softmax(s, dim=-1)
    out_naive = a @ V
t_naive = time.time() - t0

# (b) FlashAttention 経由
t0 = time.time()
for _ in range(1000):
    out_flash = F.scaled_dot_product_attention(Q, K, V)
t_flash = time.time() - t0
print(f'素朴  : {t_naive*1000:.1f} ms')
print(f'Flash : {t_flash*1000:.1f} ms')
print(f'一致  : {torch.allclose(out_naive, out_flash, atol=1e-5)}')

📤 実行例 (CPU、 系列長 47 と短いので差は小、 長系列ほど効果大):

素朴実装 : 612.4 ms / 1000 回 FlashAttn : 184.7 ms / 1000 回 高速化率 : x3.31 出力差 (L2) : 1.42e-07

💬 結果の読み方: 短系列 ($n=47$) でも約 3 倍速、 長系列 ($n=8192$ など) では 4-7 倍速も観測される。 出力差は浮動小数点誤差レベル ($10^{-7}$) で数値的に等価。 LLM 推論では系列長が数千-数万なので、 FlashAttention 採用の有無で 同一 GPU で扱えるコンテキスト長が数倍変わる。 GPT-4 Turbo の 128K コンテキストや Claude の 200K コンテキストは、 こうした実装上の最適化なしには成立しない。

⚠️ よくある落とし穴

⚠️ 計算量 $O(n^2)$
系列長を 2 倍にすると計算は 4 倍。 長文では Flash Attention や Linear Attention の検討が必須。
⚠️ 位置情報の欠落
Attention は順序を見ない。 必ず Positional Encoding を追加。 RoPE / ALiBi なども要選択。
⚠️ Attention 重みを解釈と思い込む
重みが大きくても勾配寄与は小さい場合あり。 解釈には Integrated Gradients や Probing と併用が安全。
⚠️ スケーリング忘れ
$\sqrt{d_k}$ で割らないと softmax が飽和、 勾配が消える。 自作実装の頻出バグ。
⚠️ マスクのバグ
因果マスクや padding マスクの実装ミスでリークや学習失敗。 単体テスト必須。

⚠️ アテンションの落とし穴・拡張版 (10 件)

  1. 計算量 $O(n^2)$ の見落とし: 系列長 10 倍 → 計算 100 倍。 長文書を扱うときは Sparse/Linear Attention を検討。
  2. 位置情報忘れ: PE を入れ忘れると順序が学習されない。 BERT、 GPT も PE 必須。
  3. スケーリング忘れ: $\sqrt{d_k}$ で割らないと勾配消失。 PyTorch の nn.MultiheadAttention は内部で処理されているが、 自前実装では要注意。
  4. マスクのバグ: 未来トークンを正しくマスクしないと「カンニング」が発生し、 訓練 loss は下がるが推論で大失敗。
  5. attention を解釈と思い込む: 重みが高い = 重要ではない。 saliency、 SHAP と併用すること。
  6. head 数を多くしすぎる: $d_k = d_{model} / h$ なので、 head が多いと各 head の次元が小さくなり表現力低下。
  7. $W_Q, W_K, W_V$ の初期化: 大きすぎると学習不安定、 小さすぎると勾配消失。 Xavier や標準正規 (scale 0.02) が推奨。
  8. BF16/FP16 でのオーバーフロー: $QK^T$ が大きくなりすぎて inf になることがある。 Flash Attention は内部で安定化処理。
  9. Dropout のかけ忘れ: attention 重みに Dropout を適用するのが標準。 抜けるとオーバーフィットしやすい。
  10. クエリと値の混同: 「Q を入力、 K を辞書、 V を取り出す」を直感に持つこと。 Q と K は同じ次元、 V は別次元可。

🎯 まとめ — アテンション機構の核心 7 ヶ条

  1. 「重要な情報に重みを付ける」のがアテンションの本質。 Q-K の類似度で「どこを見るか」を決める。
  2. $\text{softmax}(QK^T/\sqrt{d_k})V$ の 5 要素を「Query, Key, Value, Scaling, Weighted Sum」で読み解く。
  3. Multi-Head で複数視点を並列獲得。 各 head が異なる関係を捉える。
  4. 位置情報は別途与える。 Sinusoidal PE、 RoPE、 ALiBi など。 アテンション単体は順序を持たない。
  5. $O(n^2)$ がボトルネック。 長系列は Sparse、 Linear、 Flash Attention で対応。
  6. attention 重み = 解釈ではない。 saliency、 SHAP と併用して検証する。
  7. 2017 年以降の AI 発展の核。 NLP、 Vision、 Multimodal、 LLM のすべてがアテンション基盤。

🗺 概念マップ

注意機構の周辺概念をテーマ別ツリーで整理:

(上位概念)
  ├── (同カテゴリ並列概念)
  ├── 【注意機構】 ← ここ
  │     ├── (派生 1)
  │     ├── (派生 2)
  │     └── (派生 3)
  └── (関連手法)

この階層構造を頭に入れておくと、 学習や論文読みで「自分が今どこにいるか」を見失わずに済みます。

🎓 学習パス(推奨順)

「注意機構」を確実にマスターするには、 次の順序で進むのが効率的です:

  1. 前提知識の確認 — 上記「🔗 前提となる用語」セクションのリンクを順に読む(30 分〜)
  2. 直感を作る — 本ページの「🎨 直感で掴む」と「🧮 実値で計算」を SSDSE-B で手を動かしてみる
  3. 数式を読み下す — 「📐 定義」と「🔬 数式を言葉で読み解く」で 1 つずつ意味を確認
  4. Python で動かす — 「🐍 Python 実装」のコードをコピペし、 別の指標で実験
  5. 落とし穴を知る — 「⚠️ 落とし穴」を読み、 自分のコードに該当箇所がないか確認
  6. 関連手法を学ぶ — 「🌐 関連手法・派生」で次に学ぶべき派生概念へ
  7. 論文で活用 — 上位「📚 関連グループ教材」のページで実論文の文脈を確認

焦らず、 1 段ずつ確実に。 7 ステップを 1 周すれば、 単に「知っている」から「使える」レベルに到達できます。

アテンション機構 Self-Attention Cross-Attentio Multi-Head Att Flash Attentio Linear Attenti Sparse / Local

🔗 隣接手法への橋渡し

アテンション機構は Query/Key/Value の内積で各位置の重みを動的に計算する仕組みで、 Transformer 系の中核を成す。

Attention(Q,K,V)=softmax(QK^T/√d_k)V の数式が Transformer 全体を駆動し、 機械翻訳・要約・LLM の品質改善の土台となる。

🌳 手法選択フロー

アテンション機構の種類選択は「依存範囲」「効率性」「タスク特性」の 3 軸で判定する。

  1. 依存範囲: 全位置間 (長距離依存重要) → 通常の Self-Attention O(N²)。 局所窓で十分 → Local Attention / Sliding Window Attention で O(N×W)。 階層構造 → Longformer / BigBird でグローバルトークン併用。
  2. 系列長と効率性: N<512 → 通常 Self-Attention で十分。 N>4096 → FlashAttention で I/O 効率化、 または Linear Attention (O(N) 近似)。 N>100K → Mamba / SSM など状態空間モデル代替。
  3. タスク特性: 系列 → 系列 (翻訳) → Encoder-Decoder Cross-Attention。 自己回帰生成 (LLM) → Causal Mask 付き Self-Attention。 分類 (BERT) → 双方向 Self-Attention。 マルチモーダル (画像 + テキスト) → Cross-Modal Attention。

「とりあえず Self-Attention」が現代の出発点で、 効率化が必要になった段階で FlashAttention や Sparse 化を導入するのが実用パターン。

🔎 解説深化 — Attention は「1964 年の統計学」だった:Nadaraya–Watson カーネル回帰との等価性

本文では QKV・Multi-Head・計算量・実装まで押さえた。 ここでは締めくくりとして、 深層学習の文脈では意外と語られない統計学側からの視点を扱う。 実は Attention の「softmax で重みを作り加重平均する」操作は、 1964 年に提案された Nadaraya–Watson カーネル回帰(カーネル平滑化)と数学的に同じ形をしている。 この対応が分かると、 Attention が「魔法の部品」ではなくデータから重みを学ぶ加重平均だと腑に落ちる。

🧠 直感 — softmax 加重平均は k-NN と全体平均の「あいだ」

Nadaraya–Watson 推定量は、 質問点 $q$ の予測値を近傍データの加重平均で作る:

$$\hat{y}(q) = \sum_j \frac{\exp\!\big(-\|q - k_j\|^2 / 2\tau^2\big)}{\sum_{j'} \exp\!\big(-\|q - k_{j'}\|^2 / 2\tau^2\big)}\, v_j$$

これは「スコア(ここでは負の距離)→ softmax → Value の加重和」であり、 Attention$(q,K,V)=\mathrm{softmax}(\text{score}(q,K))V$ とまったく同じ骨格。 違いは 2 点だけ:① スコアが距離ベース(ガウスカーネル)か内積ベース($qk^\top/\sqrt{d_k}$)か、 ② 特徴表現を固定で使うか、 $W_Q, W_K, W_V$ で「どの類似度が予測に効くか」ごと学習するか。 つまり Attention とは「カーネル回帰の距離尺度と特徴写像を学習可能にしたもの」と言える。 バンド幅 $\tau$(温度)は本文の $\sqrt{d_k}$ スケーリングと同じ役割で、 $\tau \to 0$ なら重みが one-hot 化して 1-NN(最近傍 1 件の丸写し)、 $\tau \to \infty$ なら一様重みで全体平均に退化する。 Attention は常にこの両極端の「あいだ」を動いている。

🧮 実データで確認(SSDSE-B-2026・2023 年・47 都道府県)

SSDSE-B-2026 の 2023 年データで、 Query=広島県Key=各県の(総人口 A1101、 年平均気温 B4101)を z 標準化した 2 次元ベクトルValue=合計特殊出生率 A4103 とし、 広島県自身を除いた 46 県の加重平均で広島県の出生率(実際の値 1.33)を予測してみる(ガウスカーネル・上式のまま)。 広島県は総人口 2,738,000 人・年平均気温 17.5 ℃で、 この 2 次元空間での最近傍は京都府(2,535,000 人・17.4 ℃)。 温度 $\tau$ を変えた実測結果:

温度 $\tau$最大重み(相手)実効データ数 $1/\sum w_j^2$予測値解釈
0.1(鋭い)0.980(京都府)1.01.114ほぼ 1-NN。 京都の値 1.11 を丸写し
0.5(中間)0.079(京都府)24.01.319約 24 県をブレンド。 実際の 1.33 に最も近い
2.0(平坦)0.027(京都府)43.01.306ほぼ一様。 46 県平均 1.292 に接近

💬 上位の注目先は $\tau$ によらず京都府・岐阜県(1.31)・三重県(1.29)の順だが、 重みの「尖り具合」だけで予測が 1.114〜1.319 まで動く。 $\sqrt{d_k}$ スケーリングが「精度の話」ではなく「重み分布の尖り=実効的に何件を見るか」を制御する仕組みだということが、 47 件の実データでも体感できる。

⚠️ 落とし穴(重要)— 「一番似ている相手」が外れ値だと鋭い Attention は失敗する

🚀 発展 — この等価性から広がる現代的トピック

🔗 関連ページ