行列演算と内積
概要
行列演算と内積は、機械学習・深層学習のほぼすべての計算の基盤となる道具である。 ニューラルネットワークの順伝播、注意機構のスコア計算、線形変換など、あらゆる操作が 行列の積と内積として表現される。本記事では、Transformerの理解に必要な範囲で これらの概念を定式化し、実装する。
直感・モチベーション
なぜ「行列」という形で数を扱うのか。
スカラー(単一の数)では「1つの量」しか表せない。ベクトルは「方向を持つ量」、 つまり複数の特徴を並べたものだ。行列はさらに一歩進んで、「ベクトルからベクトルへの 変換(線形写像)」を表す。
Transformerで言えば、トークン(単語)の意味を512次元のベクトルとして表し、 重み行列 を掛けることで「Query空間」「Key空間」へと写像する。 この「写像」こそが行列積の本質である。
内積(ドット積)は、「2つのベクトルがどれだけ同じ方向を向いているか」を1つの スカラーで表す。Attention機構では、QueryとKeyの内積がトークン間の関連度スコアになる。
数学的定式化
ベクトルと内積
次元列ベクトル の内積を以下で定義する:
これは (行ベクトルと列ベクトルの積)とも書ける。
幾何学的な意味:
は2ベクトル間の角度。内積が大きい ⟺ 方向が近い。
行列積
、 のとき、積 の 成分は:
つまり の 成分 = の第 行と の第 列の内積。
重要な制約: の列数と の行数が一致しなければならない( が共通)。
転置
行列 の転置 は行と列を入れ替えたもの:
Transformerでは (Query と Key の転置の積)として内積を一括計算するために使う。
ノルム(ベクトルの大きさ)
内積の幾何学的解釈の導出を見る
余弦定理より、 として:
一方、ノルムの定義から:
2式を等置すると:
重要な性質・注意点
- 非可換性:一般に (積の順序を変えると結果が変わる)
- 計算量: と の積は 。Transformerの系列長 が大きいと が となりボトルネックになる
- 分配法則は成立:
- 結合法則は成立:
- 転置の積:(順序が逆転することに注意)
アルゴリズムと実装例
pythonimport math def dot_product(a: list[float], b: list[float]) -> float: """ベクトルの内積""" assert len(a) == len(b), "ベクトルの次元が一致しません" return sum(x * y for x, y in zip(a, b)) def norm(a: list[float]) -> float: """ベクトルのL2ノルム""" return math.sqrt(dot_product(a, a)) def cosine_similarity(a: list[float], b: list[float]) -> float: """コサイン類似度:内積を両ノルムで割ったもの""" return dot_product(a, b) / (norm(a) * norm(b)) def matmul(A: list[list[float]], B: list[list[float]]) -> list[list[float]]: """行列積 C = AB""" m, k = len(A), len(A[0]) k2, n = len(B), len(B[0]) assert k == k2, f"次元不一致: A の列数={k}, B の行数={k2}" C = [[0.0] * n for _ in range(m)] for i in range(m): for j in range(n): for l in range(k): C[i][j] += A[i][l] * B[l][j] return C def transpose(A: list[list[float]]) -> list[list[float]]: """転置行列""" m, n = len(A), len(A[0]) return [[A[i][j] for i in range(m)] for j in range(n)] # --- 動作確認 --- if __name__ == "__main__": # 内積の例 a = [1.0, 2.0, 3.0] b = [4.0, 5.0, 6.0] print(f"内積: {dot_product(a, b)}") # 32.0 print(f"コサイン類似度: {cosine_similarity(a, b):.4f}") # 0.9746 # 行列積の例(Attention で使う QK^T を想定) Q = [[1.0, 0.0], [0.0, 1.0]] # 2x2 K = [[1.0, 2.0], [3.0, 4.0]] # 2x2 Kt = transpose(K) scores = matmul(Q, Kt) print(f"QK^T = {scores}") # [[1.0, 3.0], [2.0, 4.0]]
まとめ
- 内積はベクトル間の類似度を1つのスカラーで表す操作で、
- 行列積 の 成分は の第 行と の第 列の内積
- 転置 は積の順序が逆転する
- Transformerでは という行列積でトークン間の類似度を一括計算する
- 行列積の計算量は であり、系列長が長いほど高コストになる
関連記事
前提知識
- なし(本記事がシリーズの出発点)
派生技術
- ソフトマックス関数 — 内積スコアを確率分布に変換する
- 注意機構 (Attention Mechanism) — を使ってトークン間の重みを計算する
応用事例
- Transformer — として Scaled Dot-Product Attention に使用
用語解説
| 用語 | 説明 |
|---|---|
| スカラー | 単一の数値 |
| ベクトル | 複数の数値を順序付きに並べたもの。方向と大きさを持つ |
| 行列 | 数値を行と列の2次元に並べたもの。線形写像を表す |
| 内積 | 2つのベクトルの対応する成分を掛けて合計したスカラー値 |
| 転置 | 行列の行と列を入れ替える操作 |
| ノルム | ベクトルの大きさ(長さ)。L2ノルムは各成分の二乗和の平方根 |
| コサイン類似度 | 内積を両ベクトルのノルムで割った値。方向の一致度を −1〜1 で表す |
| 線形写像 | ベクトル空間の間の構造を保つ変換。行列積として表現できる |