高校数学Bの内積を思い出そう

高校数学Bで習った2つのベクトルの内積を覚えていますか? 2つの定義式があります。

定義1(成分表示):a = (a₁, a₂), b = (b₁, b₂) のとき

a · b = a₁b₁ + a₂b₂

定義2(幾何学的)

a · b = |a| |b| cosθ

|a|, |b| はベクトルの長さ、θは2つのベクトルがなす角

この2つは同じものを表しています。そして注目すべきは 定義2 です。

具体例で確認する

簡単な2次元ベクトルで内積を計算してみましょう。

ベクトル a ベクトル b 内積 a·b 関係
(1, 0) (1, 0) 1·1 + 0·0 = 1 完全に同じ方向 (cosθ=1)
(1, 0) (0, 1) 1·0 + 0·1 = 0 直交 (cosθ=0)
(1, 0) (-1, 0) 1·(-1) + 0·0 = -1 反対向き (cosθ=-1)
(2, 3) (1, 4) 2·1 + 3·4 = 14 向きが近い(大きい正の値)
(2, 3) (4, -2) 2·4 + 3·(-2) = 2 少し離れている(小さい正の値)

パターンが見えますね。内積が大きいほど、2つのベクトルは「同じ方向を向いている」。これがAttentionの第一の発見です。

Attentionへの橋渡し — 「似ている」を数値化する

前章で、単語の意味は Embeddingベクトル として表現されると学びました。「猫」「犬」「車」をベクトルにすると、こんなイメージです(実際は512次元などですが、ここでは2次元で例示)。

vec("猫") = (0.9, 0.4)   # 動物・ペット軸が強い
vec("犬") = (0.8, 0.5)   # 同じく動物・ペット
vec("車") = (-0.3, 0.7)  # 全く別の方向(乗り物)

# 内積を計算
猫 · 犬 = 0.9 * 0.8 + 0.4 * 0.5 = 0.72 + 0.20 = 0.92  ← 大きい
猫 · 車 = 0.9 * (-0.3) + 0.4 * 0.7 = -0.27 + 0.28 = 0.01  ← ほぼゼロ

「猫」と「犬」の内積は0.92と大きく、「猫」と「車」の内積はほぼゼロ。内積を使えば、単語の意味的な近さが数値で測れる のです。

graph TD
  A[2つのEmbeddingベクトル] --> B[内積を計算\nΣxi·yi]
  B --> C{値の大きさ}
  C -->|大| D[似ている\n注目すべき]
  C -->|ゼロ| E[無関係]
  C -->|負| F[反対方向\n相反する]

  style A fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style B fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style D fill:#14b8a6,stroke:#0d9488,color:#fff
  style E fill:#6b7280,stroke:#4b5563,color:#fff
  style F fill:#ef4444,stroke:#b91c1c,color:#fff
内積=単語の意味的な近さ。Attentionはこの値を「注目度」のスコアとして使う

コサイン類似度 — 長さの影響を消す

ところで、内積には1つ困った性質があります。ベクトルの長さに影響される のです。

たとえば (2, 0) と (3, 0) は完全に同じ方向ですが、内積は 2·3 + 0·0 = 6。一方、(1, 0) と (1, 0) も同じ方向ですが内積は1です。「同じ方向」を測りたいのに、長さで値が変わってしまいます。

そこで「長さの影響を消す」工夫として、内積をベクトルの長さで割る方法があります。

コサイン類似度

cos similarity(a, b) = (a · b) / (|a| · |b|) = cosθ

必ず -1 〜 1 の範囲に収まる

高次元でも式は同じ

ここまで2次元で説明してきましたが、実際のEmbeddingは512次元、4096次元、12288次元……と巨大です。視覚化はできませんが、計算規則は完全に同じ です。

n次元ベクトルの内積

a · b = Σ aᵢ bᵢ (i=1 〜 n)

= a₁b₁ + a₂b₂ + ... + aₙbₙ

# Python で512次元ベクトルの内積(NumPy使用)
import numpy as np

a = np.random.randn(512)  # 512次元のランダムベクトル
b = np.random.randn(512)

# 内積を計算(1行)
score = np.dot(a, b)
print(score)  # 例: -3.247...

# Σの式を手で書いてもいい
score_manual = sum(a[i] * b[i] for i in range(512))
print(score_manual)  # 上と同じ値

次章への布石 — Q · K というアイデア

Attentionの核心式 softmax(QK^T/√dk)V の中の QK^T の部分が、まさに「すべての(Query, Key)ペアの内積を計算する」操作です。

Qは「私はこの情報を探している」という質問ベクトル、Kは「私はこういう情報を持っている」という鍵ベクトル。その内積が大きい=QとKの相性が良い=注目すべき。これがAttentionの心臓部のロジックです。

graph LR
  Q[Query\n質問ベクトル\n何を探している?] --> DOT[内積\nQ · K]
  K[Key\n鍵ベクトル\n何を持っている?] --> DOT
  DOT --> S[相性スコア\n大きいほど\n注目すべき]

  style Q fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style K fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style DOT fill:#f97316,stroke:#ea580c,color:#fff
  style S fill:#14b8a6,stroke:#0d9488,color:#fff
Q(質問)とK(鍵)の内積で「相性」を計算する。これがAttentionの核心の半分

ただし、内積で得たスコアをそのまま使うわけではありません。「合計1の確率分布」に変換する必要があります。その魔法の道具が、次章で扱う softmax関数 です。

この章のまとめ

内積は高校数学Bで習う「ベクトルの向きの近さを測る道具」です。a · b = a₁b₁ + a₂b₂ + ... + aₙbₙ の式は次元が増えても変わらず、512次元でも12288次元でも同じ計算で動きます。

Attentionは、この内積を「Q(質問)とK(鍵)の相性スコア」として使います。内積が大きい単語ペアほど、注目すべき関係にある ——これが心臓部の半分です。残りの半分(softmaxで重みに変える、V でValueを集約する)は次章以降で扱います。

理解度チェック

問題 0 / 50%
Q1

高校数学Bで習う内積の定義 a · b = |a||b|cosθ から、内積の本質を最もよく表すのはどれですか?

キーボード: 1〜4 で選択、Enter で回答