Self-Attentionは語順を知らない — 置換同変性と位置エンコーディングの必然性

「私は犬を見た」と「犬は私を見た」。使われている単語は同じでも、語順が変われば意味はまるで違います。言語にとって語順は本質です。ところが、Transformerの心臓部である self-attention は、実は語順を一切見ていません。トークンの並び順をぐちゃぐちゃに入れ替えても、self-attention の計算結果は「同じ規則で並べ替わるだけ」で、中身は1ビットも変わらないのです。

この性質を置換同変性(permutation equivariance)と呼びます。本記事では、この性質を数式で証明し、Pythonで機械精度レベルの厳密さで実測し、そこから導かれる重要な帰結——位置エンコーディング(PE)は「飾り」ではなく、語順情報を注入する唯一の入口である——を掘り下げます。

置換同変性の概念図 入力を並べ替えると出力も同じ並べ替えで出る

上の図がこの記事の主役です。入力トークンを並べ替えて self-attention に通すと、出力も「同じ並べ替え」で出てくるだけで、各トークンに対応する出力ベクトルの中身は完全に同一です。つまりモデルは「どの順で並んでいたか」を原理的に区別できません。

なぜこれを学ぶ価値があるのでしょうか。第一に、位置エンコーディングの必然性が腹の底から理解できるからです。正弦波PE・RoPE・ALiBiといった手法の存在理由は、すべてこの同変性に帰着します。第二に、同変性は「欠点」であると同時に武器にもなるからです。点群や集合のように順序に意味がないデータでは、同変性はむしろ望ましい帰納バイアスであり、DeepSets や Set Transformer はこれを積極的に活用しています。

本記事の内容

  • 置換同変性の定義と、置換不変性との違い
  • self-attention が置換同変であることの証明(1行ずつ)
  • Pythonでの厳密な数値検証と、「PEなしでは解けないタスク」の学習実験
  • bag-of-words化・causal maskの効果・同変性を活かす応用

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

置換同変性とは — 「並べ替えが素通りする」性質

まず言葉の定義から入りますが、その前にイメージをつかみましょう。3人の学生のテストを採点する場面を考えてください。答案を採点する処理は、答案が提出された順番に依存しません。提出順を入れ替えれば、返却される採点結果も同じ順で入れ替わるだけで、各人の点数は変わらない。この「入力を並べ替えると、出力も同じように並べ替わるだけ」という性質が置換同変性です。

数式で書きましょう。$N$ 個のトークンを行に持つ行列 $X \in \mathbb{R}^{N \times d}$ と、行を並べ替える置換行列 $P$(各行・各列に1がちょうど1つある0-1行列)に対して、関数 $f$ が

$$ f(PX) = P\, f(X) $$

を満たすとき、$f$ は置換同変であると言います。よく似た概念に置換不変性(permutation invariance)があります。こちらは

$$ f(PX) = f(X) $$

で、並べ替えても出力がまったく変わらない性質です。総和や平均、最大値がその例です。

置換同変と置換不変の違い

図の左が同変(出力に $P$ が残る)、右が不変(出力から $P$ が消える)です。self-attention は左の同変に属します。「同変」は出力の順番は変わるが中身は変わらない、「不変」は順番も中身も変わらない、と覚えてください。

置換行列 $P$ の作用も確認しておきます。$PX$ は $X$ の行(トークン)の並べ替えで、各トークンのベクトルの中身には触れません。

置換行列Pは行の並べ替え

左の置換行列を掛けると、中央の入力行列の行が右のように並べ替わるだけです。色(=ベクトルの中身)は無傷なことがわかります。定義が押さえられたので、いよいよ本題——self-attention がこの性質を持つことを証明します。

証明: self-attention は置換同変である

証明のゴールを先に宣言します。self-attention を

$$ f(X) = \mathrm{softmax}\!\left(\frac{(XW_Q)(XW_K)^\top}{\sqrt{d_k}}\right) XW_V $$

とおき、任意の置換行列 $P$ に対して $f(PX) = P f(X)$ を示します。方針は「$P$ を入力に入れて、計算の各段でどう伝播するかを追いかける」ことです。

ステップ1: Q・K・V への射影。 $W_Q, W_K, W_V$ は各トークン(各行)に独立に作用する行列なので、

$$ (PX)W_Q = P(XW_Q) = PQ, \qquad (PX)W_K = PK, \qquad (PX)W_V = PV $$

となり、$P$ はそのまま左に残ります。射影は「トークンごとの変換」なので、並べ替えと干渉しません。

ステップ2: スコア行列。 注意スコアは $A = QK^\top/\sqrt{d_k}$ です。置換後の入力では

$$ A’ = \frac{(PQ)(PK)^\top}{\sqrt{d_k}} = \frac{P Q K^\top P^\top}{\sqrt{d_k}} = P A P^\top $$

となります。ここで $(PK)^\top = K^\top P^\top$ を使いました。$PAP^\top$ は「行(クエリ側)も列(キー側)も同じ規則で並べ替えたスコア行列」です。

ステップ3: softmax と置換の可換性。 softmax は行ごとに独立に作用します。行の並べ替え $P$ は各行の中身を変えないので softmax と可換であり、列の並べ替え $P^\top$ は各行内の要素の順序を変えるだけで、softmax は要素ごとの指数関数と行内の正規化なのでこれとも可換です。したがって

$$ \mathrm{softmax}(PAP^\top) = P\,\mathrm{softmax}(A)\,P^\top $$

が成り立ちます。ここが証明の心臓部です。softmaxが「行ごとの操作」であることが効いています。

ステップ4: 出力。 最後に value を掛けると

$$ f(PX) = P\,\mathrm{softmax}(A)\,P^\top \cdot PV = P\,\mathrm{softmax}(A)\,V = P f(X) $$

となります。$P^\top P = I$(置換行列は直交行列)で $P^\top$ と $P$ が打ち消し合うのがポイントです。これで証明が完了しました。

置換Pがself-attentionを素通りする証明フロー

図は証明の流れをデータフローで表したものです。どの計算段でも $P$ は消えずに素通りし、最後まで「行の並べ替え」として残る——これが $f(PX) = Pf(X)$ の視覚的な意味です。

さらに重要なのは、この性質が attention 単体にとどまらないことです。FFN は位置ごとに独立な変換、LayerNorm も各トークン内の正規化、残差接続は同変な関数の和なので、すべて置換同変です。つまり、位置エンコーディングを入れない限り、Transformer 全体が置換同変になります。理屈はわかりました。次は、この主張を数値で厳密に確かめましょう。

Pythonで厳密に検証する — 残差は機械精度

証明が正しければ、$\|f(PX) – Pf(X)\|$ は浮動小数点の丸め誤差レベル($10^{-15}$ 前後)になるはずです。NumPyで確かめます。

import numpy as np

rng = np.random.default_rng(42)
N, d = 8, 16

def softmax_rows(A):
    A = A - A.max(axis=-1, keepdims=True)
    E = np.exp(A)
    return E / E.sum(axis=-1, keepdims=True)

def self_attention(X, WQ, WK, WV):
    A = softmax_rows(X @ WQ @ WK.T @ X.T / np.sqrt(WQ.shape[1]))
    return A @ (X @ WV)

WQ = rng.standard_normal((d, d)) / np.sqrt(d)
WK = rng.standard_normal((d, d)) / np.sqrt(d)
WV = rng.standard_normal((d, d)) / np.sqrt(d)
X = rng.standard_normal((N, d))

perm = rng.permutation(N)
P = np.eye(N)[perm]

resid = np.linalg.norm(self_attention(P @ X, WQ, WK, WV)
                       - P @ self_attention(X, WQ, WK, WV))
print(f"同変性の残差: {resid:.3e}")
print(f"出力自体の大きさ: {np.linalg.norm(self_attention(X, WQ, WK, WV)):.3f}")

実行すると、残差は 1.062e-15 になります。出力自体の大きさが 8.373 あるのに対し、残差は15桁小さい——これは float64 の丸め誤差そのものであり、同変性が厳密に成立していることを意味します。

では、位置エンコーディングを足すとどうなるでしょうか。正弦波PEを加算してから同じ検証をします。

# 正弦波位置エンコーディングを作る
pos = np.arange(N)[:, None]
i_idx = np.arange(d)[None, :]
angle = pos / (10000 ** (2 * (i_idx // 2) / d))
PE = np.where(i_idx % 2 == 0, np.sin(angle), np.cos(angle))

def attn_with_pe(Z):
    return self_attention(Z + PE, WQ, WK, WV)

resid_pe = np.linalg.norm(attn_with_pe(P @ X) - P @ attn_with_pe(X))
print(f"PEあり残差: {resid_pe:.3e}")

こちらの残差は 2.944e+00。出力の大きさ(約8.4)と同じオーダーで、同変性は完全に壊れています。PEは同変性を壊すために入れている——この一言の意味が、数値ではっきり見えました。

同変性の数値検証 PEなし機械精度 PEありで破れ

対数軸の棒グラフで見ると差は歴然です。PEなし(左)は $10^{-15}$ で機械精度、PEあり(右)は $10^0$ オーダー。同変性の成立と破れが15桁の差として現れています。

注意行列そのものの振る舞いも見ておきましょう。証明のステップ2〜3で、置換後の注意行列は $P\,\mathrm{softmax}(A)\,P^\top$ になるはずでした。

注意行列は行列とも同じ規則で並べ替わる実測

左が元の注意行列、中央が並べ替えた入力から実測した注意行列、右が理論値 $P\,\mathrm{softmax}(A)\,P^\top$ です。中央と右は最大差 $10^{-16}$ オーダーで完全に一致します。注意パターンは「行と列が同じ規則で並べ替わるだけ」で、新しい情報は何も生まれていません。

数値検証で同変性は確認できました。しかし「語順が見えない」ことが実際のタスクで何を引き起こすのか。次は学習実験で確かめます。

「ソート済みか判定」タスク — PEなしは原理的に解けない

置換同変性の恐ろしさは、順序が本質のタスクを原理的に解けなくすることです。これを直接示す実験をします。

タスクは「長さ10の整数列がソート済み(昇順)かどうかの2値分類」。ソート済みかどうかは順序そのものの性質なので、語順が見えないモデルには絶対に解けないはずです。PEなし/PEありの小型Transformer(2層・平均プーリングで分類)を同一条件で訓練します。

import torch
import torch.nn as nn

L, VOCAB, D = 10, 20, 32

def make_sort_data(n_pairs, seed):
    g = np.random.default_rng(seed)
    xs, ys = [], []
    for _ in range(n_pairs):
        v = g.integers(0, VOCAB, size=L)
        xs.append(np.sort(v)); ys.append(1)        # ソート済み → 1
        u = v.copy()
        while True:
            g.shuffle(u)
            if not np.all(u[:-1] <= u[1:]):
                break
        xs.append(u.copy()); ys.append(0)          # 非ソート → 0
    return torch.tensor(np.array(xs)), torch.tensor(ys)

class TinyTransformer(nn.Module):
    def __init__(self, use_pe):
        super().__init__()
        self.emb = nn.Embedding(VOCAB, D)
        self.pe = nn.Parameter(torch.randn(L, D) * 0.1) if use_pe else None
        layer = nn.TransformerEncoderLayer(D, 4, 64, batch_first=True, dropout=0.0)
        self.enc = nn.TransformerEncoder(layer, 2)
        self.head = nn.Linear(D, 2)

    def forward(self, x):
        h = self.emb(x)
        if self.pe is not None:
            h = h + self.pe
        h = self.enc(h)
        return self.head(h.mean(dim=1))   # 平均プーリング → 置換不変になる

PEなしモデルは self-attention(同変)+ 平均プーリング(不変化)の構成なので、モデル全体が置換不変になります。「ソート済みの列」と「それをシャッフルした列」はトークンの中身が同じなので、モデルには同一の入力に見え、ラベルだけが異なる——つまり学習不可能なはずです。

ソート判定タスク PEなしは0.5に張り付く

結果は理論どおりです。PEなし(赤)は10エポック回しても精度が 0.500 から1ミリも動きません。当てずっぽうと同じです。一方PEあり(緑)は3エポックで0.97近くまで急上昇し、最終的に 0.997 に達します。PEの有無だけで「原理的に不可能」と「ほぼ完璧」が分かれました。

ここで大事な対照実験があります。PEなしモデルは「何もできない」わけではありません。順序に依存しないタスクなら解けるはずです。「列の合計がしきい値を超えるか」という集合的なタスクで確かめます。

合計しきい値タスクはPEなしでも解ける

同じPEなしモデルが、合計しきい値タスクでは最終精度 0.979 まで学習できました(水色)。合計は並べ替えても変わらない集合の性質だからです。同じモデルがソート判定(赤)では0.5に張り付いたままなのと鮮やかな対照をなします。

タスク性質×PE有無の最終精度まとめ

まとめの棒グラフです。「ソート判定・PEなし= 0.500 / ソート判定・PEあり= 0.997 / 合計・PEなし= 0.979」。モデルの能力はタスクの性質×同変性の扱いで決まることが、この3本の棒に凝縮されています。

「PEなしだと語順が消える」ことを、もう少し違う角度からも見ておきましょう。

bag-of-words 化 — 袋に入れたら順序は消える

PEなしのTransformerに平均プーリングをつけた構成は、古典的なbag-of-words(単語の袋)と本質的に同じです。文を「単語の集合」として袋に放り込むと、語順の情報はどこにも残りません。

PEなし平均プーリングはbag-of-words

「私は犬を見た」と「犬は私を見た」は、袋に入れた瞬間に区別がつかなくなり、平均プーリング後のベクトルは完全に同一になります。self-attention がどれだけ洗練された文脈混合をしても、順序を注入しない限りこの限界は超えられません。これは context vector の記事 で見た「valueの凸結合」という描像とも整合します——混ぜ方(重み)は中身で決まり、位置では決まらないのです。

ところで、GPTのようなdecoderモデルには因果マスク(causal mask)が入っています。実はこのマスクが、同変性の話に面白いひねりを加えます。

causal mask は置換対称性を壊す

causal mask は「位置 $i$ のクエリは位置 $j \le i$ のキーしか見られない」という制約です。このマスク $M$ はトークンの中身ではなく位置に固定で付くため、トークンを並べ替えてもマスクは動きません。つまりマスク付き attention では $f(PX) \ne Pf(X)$ となり、置換同変性が(部分的に)壊れます。

causal maskは位置に固定で付き置換対称性を壊す

図の右を見てください。位置0は1トークン、位置5は6トークンと、見えるトークン数が位置ごとに違います。この非対称性が位置の手がかりになるため、causal mask 付きのdecoderは明示的なPEなしでもある程度位置情報を学習できることが知られています(いわゆるNoPE)。「マスクも暗黙の位置情報である」という視点は、PEの設計を考えるうえで見逃せません。

ここまで同変性を「壊すべきもの」として扱ってきました。しかし冒頭で述べたとおり、同変性が望ましい場面もあります。最後にその世界を見て締めくくりましょう。

同変性を「活かす」— 集合・点群のためのattention

順序に意味がないデータもたくさんあります。3D点群の点の格納順、推薦候補の集合、分子中の原子リスト——これらは「たまたまその順で格納されているだけ」で、並べ替えても対象は同じです。こうしたデータでは、モデルの出力が格納順に依存しないことがむしろ正しい帰納バイアスです。

同変性を壊すか活かすかの応用マップ

図の左が「順序が本質 → PEで同変性を壊す」世界(自然言語・時系列・音声)、右が「順序が無意味 → 同変性を活かす」世界(点群・集合入力・物体検出クエリ)です。右の世界の代表が DeepSets(総和プーリングで置換不変な集合関数を構成)や Set Transformer(attentionで要素間相互作用を入れつつ同変性を保つ)です。PEを入れない self-attention は、集合を扱う天然の同変レイヤーなのです。同じ数学的性質が、言語では「克服すべき制約」、点群では「設計の武器」になる——この対称性が、置換同変性という概念の美しいところです。

まとめ

self-attention が語順を知らないという事実を、証明・数値検証・学習実験の3段構えで確かめました。

  • 置換同変性 $f(PX) = Pf(X)$:入力を並べ替えると出力も同じ規則で並べ替わるだけ。射影は行ごと・softmaxは行ごとの操作なので $P$ が素通りする、というのが証明の骨子
  • 数値検証:同変性の残差は 1.06e-15(機械精度)で厳密に成立。正弦波PEを足すと残差 2.94(出力と同オーダー)で完全に破れる
  • 学習実験:順序が本質の「ソート判定」はPEなしだと精度 0.500 に張り付き原理的に解けない。PEありなら 0.997。順序不要の「合計しきい値」ならPEなしでも 0.979
  • 帰結:PEなしTransformer + 平均プーリング = bag-of-words。causal maskは位置に固定なので同変性を部分的に壊す(NoPEの直感)。点群・集合では同変性はむしろ武器(DeepSets / Set Transformer)

位置エンコーディングは「とりあえず足すもの」ではなく、置換同変という数学的性質を破って語順を注入する、理論的に必然の部品です。次のステップとして、以下の記事も参考にしてください。