自己注意:スケール付き内積注意・マルチヘッド・因果マスク
対象読者: 本テーマ第 1〜2 章の内容と、行列と連立一次方程式、確率変数の期待値・分散を学んだ人。Transformer や注意機構は仮定しません。
前提となる記事:埋め込みと位置符号化:正弦波と回転位置埋め込み(RoPE)、行列と連立一次方程式:線形写像の座標表示と解の構造、確率変数と期待値:可測関数としての確率変数、ルベーグ積分としての期待値
0. この記事の要点
Section titled “0. この記事の要点”文章を読むとき、私たちは「それ」や「かける」の意味を、文のほかの場所を見て決めています。自己注意は、計算機が同じことをするための部品です。列の中の各語について、どの語をどれだけ参考にするかを数で決め、その割合で情報を混ぜ合わせます。この記事では、この演算がどんな範囲の値を出すか、語順をどう扱うか、未来の語を見ないようにするにはどうするかを、式で確かめます。
- 自己注意は、列の各位置のベクトルを、ほかの位置のベクトルの重みつき平均で置き換える演算です。重みは内積を softmax に通して作るので、非負で和が 1 です。出力の各行は値ベクトルの凸結合(重みが非負で和が 1 の重みつき平均)になります(命題 4.2)。
- softmax は平行移動で変わらず、大小を保ち、置換と交換します(命題 3.1)。ヤコビ行列(入力を少し動かしたとき出力がどう動くかを表す行列)は で、出力が 1 点に集中するほど小さくなります(命題 3.2)。内積を で割るのは、この集中を次元に依らず抑えるためです(命題 4.4)。
- 位置情報もマスクもない自己注意は、入力の行を並べ替えると出力の行が同じように並べ替わるだけです(定理 5.2)。語順を区別できないので、前章の位置符号化が必要になります。
- 因果マスクを入れると、出力の第 行は だけの関数になります(定理 6.3)。これにより、長さ の列に対する 1 回の計算で、 個の「接頭辞から次のトークン」の予測が同時に得られます(系 6.4)。
- 1 層の乗算の回数は 、パラメータ数は で、どちらもヘッド数に依りません(命題 7.2、命題 7.1)。
1. 動機:位置どうしで情報をやり取りする
Section titled “1. 動機:位置どうしで情報をやり取りする”前章までで、トークン列は の行列 になりました。第 行 は第 トークンを表すベクトルです。この時点では、各行はそのトークン 1 個の情報しか持っていません。「それ」が何を指すか、「かける」が電話なのか橋なのかを決めるには、ほかの位置の情報を取り込む必要があります。
取り込み方として、どの位置からどれだけ取り込むかを入力に応じて決めるのが注意です。位置 が「こういう情報が欲しい」というベクトル(クエリ)を出し、各位置 が「自分はこういう情報を持っている」というベクトル(キー)と、渡す中身(バリュー)を出します。クエリとキーの内積が大きい位置ほど大きな重みを付けて、バリューを平均します。注意の仕組みは Bahdanau らが機械翻訳で導入し([2])、Vaswani らは再帰も畳み込みも使わず注意だけでモデルを組みました([1])。
この章では、定義のあとで次の 3 つの問いに命題として答えます。
- 注意の出力はどんな範囲に収まるか(凸結合)。
- 入力の順番を入れ替えると出力はどうなるか(同変性)。これが前章の位置符号化が必要な理由です。
- 「未来を見ない」という制約はどう入れ、それで何が保証されるか(因果マスク)。これが言語モデルの学習を並列にできる理由で、第 6 章の KV キャッシュの正しさの根拠にもなります。
2. 準備:記号・置換行列・softmax
Section titled “2. 準備:記号・置換行列・softmax”行列 の第 行を列ベクトルとみなしたものを と書きます。全成分が 1 のベクトルを と書きます。行列の積(定義 4.1[行列と連立一次方程式])について、 の第 行は です。
の置換 (定義 2.1[行列式とその性質])に対し、( のとき)、(それ以外)で定まる 次の正方行列 を置換行列という。
写像 が、すべての置換行列 とすべての について を満たすとき置換同変、 を満たすとき置換不変という。
関数 に対し、各行に を施す写像 を行ごとに働く写像という( は の第 行)。
イメージをつかむために小さい例を置きます。 で、、、(1 番目と 2 番目の入れ替え)とすると、 の行は上から順に の第 2 行、第 1 行、第 3 行になります。置換行列は「行を並べ替える操作」を行列で書いたものです。
置換行列について、定義から直接出る事実を 3 つ確認しておきます。
- 。つまり の第 行は の第 行で、 を左から掛けると行が並べ替わります。ベクトルなら です。
- 。右から転置を掛けると列が並べ替わります。
- で、 となるのは のときだけです。 は全単射なので、 ならそのような がちょうど 1 つあり、 なら 1 つもありません。よって 。また各行に 1 がちょうど 1 個あるので です。
定義 2.2(softmax とマスクつき softmax)↗
に対し
で定まる写像 を softmax 関数という。行列に対しては行ごとに施す。
空でない部分集合 に対し、マスクつき softmax を
で定める。 に入らない添字を「マスクされた」成分という。「マスクされた成分に を足してから softmax を取る」という書き方は、 のことを指すものとする。
は実数ではないので、「足す」という書き方はそのままでは定義になりません。上では を直接定義し、それが極限として正当化できることを 命題 3.3 で示します。
3. softmax の性質
Section titled “3. softmax の性質”とする。
- すべての で であり、。
- (平行移動不変)任意の について 。
- (大小を保つ) ならば 、 ならば 。
- (置換同変)任意の置換行列 について 。
証明(命題 3.1)
と置きます。指数関数は正の値を取り、狭義単調増加で、 を満たします(定理 3.3[指数・対数・三角関数をきちんと定義する] の 2 と 4)。
- 、 より 。和は 。
- 。
- なら で、同じ正の数 で割っても不等号は変わりません。等しい場合も同様です。
- とすると です。 は全単射なので (和の順番を入れ替えただけ)。よって 。
2 は実装で重要です。 が大きいと は浮動小数点数の範囲を超えますが、最大値を引いてから指数を取れば、すべての指数が 1 以下になり、結果は変わりません。8 節のコードもそうしています。
次の命題のねらいは、softmax に勾配がどれだけ流れるかを調べることです。証明の 1 では、 が「 を確率とみなしたときの の平均から、 の平均の 2 乗を引いたもの」、つまり分散の形になることを使い、それが 0 以上であることをコーシー・シュワルツの不等式で示します。
と書く。softmax は 上で微分可能で、
である( は のとき 1、それ以外 0)。さらに次が成り立つ。
- は対称で半正定値である。
- 。
- すべての で 。
証明(命題 3.2)
とすると 、 です。商の微分より
行列で書くと、 が 、 が の 成分です。
- は と を入れ替えても同じなので対称です。任意の について
です。、 にコーシー・シュワルツの不等式(定理 4.2[内積空間とグラム・シュミット直交化])を使うと (命題 3.1 の 1 で )。よって で、半正定値です(定義 6.2[スペクトル定理])。
-
第 成分は 。
-
が最大になる添字の 1 つを とします。 のとき、 の少なくとも一方は ではありません。 としてよく( は対称)、。 のとき で、 なら 、 なら です。
2 は平行移動不変性(命題 3.1 の 2)の微分形です。 の向きに動かしても出力が変わらないので、その向きの微分は 0 になります。3 は、softmax の出力がほぼ 1 点に集中している( が 1 に近い)と、ヤコビ行列の全成分が 0 に近くなることを言っています。そうなると softmax を通る勾配がほとんど流れません。交差エントロピー(予測した確率が正解からどれだけ外れているかを測る損失)と組み合わせたときの勾配 (命題 7.1[ニューラルネットワークと逆伝播])は、このヤコビ行列に損失の勾配を掛けた結果です(ヤコビ行列の式 そのものは同じ命題にも述べられています。ここで新しく示したのは 1〜3 の性質です)。
証明(命題 3.3)
( は空でない)、 と置きます。 の成分は、 で 、 で なので、分母は です。
のとき 。 で (。定理 3.3[指数・対数・三角関数をきちんと定義する] の 4)なので、分母は に収束し、値は に収束します。
のとき で、右辺は 0 に収束します。正であることは 命題 3.1 の 1 です。
実装では、マスクされた成分に十分大きな負の数(または浮動小数点の )を足します。上の評価から、誤差は に比例して小さくなります。
4. スケール付き内積注意とマルチヘッド
Section titled “4. スケール付き内積注意とマルチヘッド”定義 4.1(スケール付き内積注意・自己注意・マルチヘッド・因果マスク)↗
(注意) 、、 に対し
をスケール付き内積注意、 を注意の重み行列という( は行ごと)。 の行をそれぞれクエリ、キー、バリューという。成分で書けば、、 で、出力の第 行は である。
(自己注意) 入力 と、パラメータ 、、、 に対し
として を計算することを(1 ヘッドの)自己注意という。クエリ・キー・バリューがすべて同じ入力 から作られる。
(マルチヘッド) を の約数とし、 とする。 について別々のパラメータで 1 ヘッドの自己注意の出力 を計算し、列方向に連結した に、パラメータ 、 を使って
と定める。これをマルチヘッド自己注意、 をヘッド数という。
(因果マスク) 自己注意()で、重みの第 行をマスクつき softmax 、 で計算すること、すなわち の成分に を足すことを因果マスクという。このとき ()である。
Vaswani らの式では射影は行列を掛けるだけですが([1] 3.2.2 節)、ここではバイアスも含めて定義しました。バイアスを付けない場合は以下の命題で を 0 と置けばよく、パラメータ数だけが変わります。ヘッドを複数にするのは、「主語を探すヘッド」「直前の語を見るヘッド」のように、違う基準の重みを同時に持てるようにするためです。 と取るので、ヘッドを増やしても全体の大きさは変わりません(命題 7.1、命題 7.2)。
証明(命題 4.2)
マスクなしのとき、 の第 行は で、命題 3.1 の 1 より成分は正で和は 1 です。因果マスクつきのとき、第 行は で、 の成分は正、 の成分は 0、和は です。
ノルムについて、三角不等式(系 4.3[内積空間とグラム・シュミット直交化])と (定義 4.1[内積空間とグラム・シュミット直交化])より
成分については、 として 。上からも同様です。
注意は、バリューの集まりの「内側」しか出力できません。新しい方向を作るのは、前後の線形変換と、次章の MLP の役目です。
例 4.3(n = 3, d = 2 の手計算)
、1 ヘッド、、バイアス 0 とし、
とします。 で、 は
です。、 なので、第 1 行の重みは 、第 3 行は です。
出力の第 1 行は で、3 つの行ベクトルが作る三角形の内側の点です(命題 4.2)。
行の入れ替え。 第 1 行と第 2 行を入れ替えた入力 で同じ計算をすると、出力は になります。もとの出力の第 1 行と第 2 行が入れ替わっただけで、第 3 行は変わりません。これが 5 節の同変性です。
因果マスク。 マスクを入れると、第 1 行は自分だけを見るので重みは 、第 2 行は と 0、第 3 行は変わりません。出力は です。ここで第 3 行を に変えると、出力は小数第 4 位まででは になり、第 1・2 行は変わりません(第 3 行は自分自身との内積 が大きく、重みがほぼ になります)。マスクなしで同じ変更をすると第 1 行は に変わります。これが 6 節の因果性です。
4.1. なぜ で割るのか
Section titled “4.1. なぜ dk\sqrt{d_k}dk で割るのか”Vaswani らは、内積を で割る理由を脚注で説明しています。クエリとキーの成分が独立で平均 0・分散 1 なら、内積の分散は になり、次元が大きいほど softmax の入力が散らばる、というものです([1] 3.2.1 節)。この主張を証明します。本筋は、独立な項の分散は足し合わせられるので、 個の項の合計の分散が になる、という一点です。証明の中の「 と も独立」といった確認は、その足し算を使ってよいことの裏づけなので、初めは結論だけ追っても構いません。
証明(命題 4.4)
独立な族の一部を取り出したものも独立です(定義 2.3[確率変数と期待値] で、取り出さない変数に対応するボレル集合を に取る)。分散が有限なので各変数は 2 乗可積分で、したがって可積分です。
平均。 と は独立で可積分なので、命題 7.5[確率変数と期待値] より 。期待値の線形性より 。
各項の分散。 と も独立です。実際、ボレル集合 に対し ()で、 は連続なので はボレル集合であり、独立性の定義の式がそのまま使えます。(命題 5.3[確率変数と期待値] の 1)で、 も同様なので、再び 命題 7.5[確率変数と期待値] より 。よって は 2 乗可積分で、。
共分散。 のとき、 は独立な 4 個の可積分な確率変数なので、補題 10.5(Appendix)より 。よって 。
合計。 命題 5.3[確率変数と期待値] の 4 より
同じ命題の 2 より です。
例 4.5(割らないと重みが 1 点に集中する)
標準正規分布から成分を引いて確かめます(コードは 8 節)。左の 2 列は 20,000 組の での標本分散、右の 2 列は、1 個のクエリと 8 個のキーで作った重みの最大値の平均(2,000 回)です。
| の分散 | で割ったあとの分散 | 最大の重み(割らない) | 最大の重み(割る) | |
|---|---|---|---|---|
| 4 | 4.00 | 1.001 | 0.532 | 0.347 |
| 16 | 16.18 | 1.011 | 0.743 | 0.353 |
| 64 | 62.92 | 0.983 | 0.878 | 0.361 |
| 256 | 255.84 | 0.999 | 0.939 | 0.366 |
| 1024 | 1036.38 | 1.012 | 0.971 | 0.361 |
分散は 命題 4.4 のとおり に比例します。割らないと、次元が大きいほど 8 個のうち 1 個に重みが集中し、 では最大の重みが平均 0.97 です。命題 3.2 の 3 より、そのときヤコビ行列の成分は 程度以下で、勾配が流れにくくなります。 で割ると、最大の重みは次元に依らず 0.35 前後に保たれます。
なお、ここでの「成分が独立で分散 1」は初期化の直後を想定した模型で、学習が進んだあとのクエリとキーがこの仮定を満たすわけではありません。単位球面上の一様な方向どうしの内積の分散が になること(命題 3.2[数学を学び直す意義])は、長さを 1 にそろえた場合の同じ現象です。
5. 置換同変性:自己注意は語順を知らない
Section titled “5. 置換同変性:自己注意は語順を知らない”この節では、「入力の行を並べ替えてから自己注意に通しても、通してから出力の行を並べ替えても同じ」ことを示します。2 節の例でいえば、1 番目と 2 番目の語を入れ替えて計算しても、出力の 1 番目と 2 番目が入れ替わるだけです。つまり自己注意は語がどの順に並んでいるかを知りません。まず、この性質を保ったまま部品を組み立てられることを補題で確かめ、そのあとで自己注意そのものを調べます。
- 行ごとに働く写像は置換同変である。とくに は置換同変である。
- が置換同変ならば、合成 、和 、列方向の連結 も置換同変である。とくに が置換同変ならば も置換同変である。
証明(補題 5.1)
とします。 の第 行は です。
- 。 の第 行は で、 を各行に施したものです。
- 。。連結は、 を左から掛けることが行の並べ替えで、連結した行列の第 行は と の第 行を並べたものなので、。最後の主張は、恒等写像が置換同変であることと和の場合から従います。
位置情報を加えておらず、マスクもないマルチヘッド自己注意 は置換同変である。すなわち任意の置換行列 と任意の について
さらに、マスクのない自己注意、行ごとに働く写像(MLP・正規化など)、それらの合成・和(残差接続)だけから組み立てた写像は、すべて置換同変である。
証明(定理 5.2)
とし、1 つのヘッドについて、入力を に替えたときの量にダッシュを付けます。
クエリ・キー・バリュー。 積の結合法則(系 4.3[行列と連立一次方程式])と より
で、同様に 、 です。
点数。 と置くと、。2 節の事実より です。
重み。 の第 行は、 の第 行 の成分を で並べ替えたベクトル です。softmax の置換同変性(命題 3.1 の 4)より で、その第 成分は 。よって 、すなわち です。
出力。 より
よって各ヘッドの出力は で、1 ヘッドの自己注意は置換同変です。
マルチヘッド。 は、置換同変な を連結し、 を合成したものなので、補題 5.1 より置換同変です。後半の主張も同じ補題から、組み立ての段数についての帰納法で従います。
証明の要点は、点数の行列が と「行と列を同時に」並べ替わり、バリューの並べ替え と で打ち消し合うことです。この定式化は、集合を入力とするネットワークの文脈で Lee らが整理しています([3])。
を置換同変な写像とする(定理 5.2 より、位置情報もマスクもない Transformer の層の重ね合わせはこれにあたる)。
- 置換 が を満たすならば 。すなわち出力の第 行は、 と、ほかの行の多重集合(順序を忘れ、重複は数える集まり)だけで決まる。
- とくに最後の位置 の出力は、それより前のトークンをどう並べ替えても変わらない。
証明(系 5.3)
- 同変性より 。 以外の行の並べ方が違う 2 つの入力は、 を動かさない置換で移り合うので、第 行の出力は等しくなります。2 は 1 で とした場合です。
次のトークンの予測は最後の位置の出力から作るので、2 は「位置情報のないモデルは、『犬が猫を追う』と『猫が犬を追う』の続きについて同じ予測をする」ことを意味します(トークン化して最後のトークンが同じなら)。前章の位置符号化を入れると、 の各行に位置ごとに違うベクトルが足されるので、行を入れ替えた入力はもはや「同じ行の並べ替え」ではなくなり、この系の仮定が外れます。RoPE(回転位置埋め込み。前章で扱いました)の場合は点数 が に依るので が成り立たなくなります。
注意 5.4(因果マスクつきの場合)
因果マスクは「 だけを見る」という形で位置の添字を使うので、因果マスクつきの自己注意は置換同変ではありません(8 節の数値実験で、 と が大きく違うことを確かめます)。ただし、マスクが位置の情報を十分に伝えるかどうかは別の問題です。演習 10.4 では、因果マスクつきの注意 1 層の最後の行が、前の行の並べ替えで変わらないことを示します。層を重ねた場合にどこまで語順を使えるかは、この章では扱いません。
6. 因果マスク:未来に依存しない
Section titled “6. 因果マスク:未来に依存しない”言語モデルは「これまでのトークンから次のトークンを予測する」関数です。位置 の出力が より後ろのトークンに依存してしまうと、学習のときに答えを見て予測することになります。因果マスクはそれを防ぎます。入力の長さ を変えたときの振る舞いまで含めて述べるために、次の定義を置きます。
次の定義の式 は、「長さ の文全体を入れて第 行を見ても、最初の 語だけを入れて最後の行を見ても、答えは同じ」と読んでください。たとえば 、 なら、5 語を入れたときの 3 行目は、3 語だけを入れたときの 3 行目(最後の行)と等しい、ということです。
各 に対して写像 が与えられているとする。族 が因果的であるとは、すべての 、すべての 、すべての について
が成り立つことをいう。ここで は の最初の 行からなる行列である。
因果的ならば、 の第 行は だけの関数です(右辺が にしか依らないため)。それに加えて、「長さ の列の第 行の出力」と「最初の 個だけを入力したときの最後の行の出力」が一致することも言っています。自己注意は同じパラメータで任意の長さの列に適用できるので、族 が自然に定まります。
- 関数 ( に依らない)に対し、 で定まる族は因果的である。とくに、行ごとに働く写像(すべての が同じ場合)と、位置 に依る位置ベクトルを足す写像 は因果的である。
- が因果的ならば、合成 、和 、列方向の連結も因果的である。とくに が因果的ならば も因果的である。
- が因果的ならば、 について 。すなわち 。
証明(補題 6.2)
-
で、 の第 行も なので 。両者は等しい。
-
とします。定義を に使うと 。定義を と入力 に使うと 。よって両者は等しい。
-
合成について。3 より なので、 の因果性と合わせて
右辺は合成の族を に施したものの第 行です。和と連結は、第 行がそれぞれの第 行の和・連結なので、 と の因果性からただちに従います。最後の主張は、恒等写像が 1 の形( が恒等写像)で因果的であることと和の場合からです。
定理 6.3(因果マスクつきの自己注意は未来に依存しない)✓
因果マスクつきのマルチヘッド自己注意は因果的である。したがって出力の第 行は だけの関数である。さらに、因果マスクつきの自己注意、補題 6.2 の 1 の形の写像(行ごとの MLP・正規化、位置ベクトルの加算)、それらの合成・和(残差接続)を何層重ねた写像も因果的である。
証明(定理 6.3)
を因果的な族とする(定理 6.3 の形のモデル)。長さ の列 に対する 1 回の計算 の第 行は、接頭辞 だけを入力したときの最後の行に等しい:
したがって、 個の「接頭辞 から次のトークンを予測する」計算の結果が、1 回の順伝播で同時に、別々に計算したときと同じ値で得られる。
この系が、言語モデルの学習を効率よくしている理由です。長さ の文 1 つから、 個の予測問題の損失とその勾配が 1 回の順伝播・逆伝播で得られます。接頭辞ごとに別々に計算すれば、長さ の列を 回処理することになります。生成のときには逆に、補題 6.2 の 3()が効きます。トークンを 1 個足しても、それまでの位置の計算結果は変わらないので、使い回せます。第 6 章の KV キャッシュはこの事実に基づきます。
7. パラメータ数と計算量
Section titled “7. パラメータ数と計算量”証明(命題 7.1)
1 つのヘッドは と を持つので 個。 ヘッドで 個()。これに と の 個を加えて 個です。バイアスを除けば です。
たとえば Vaswani らの基本の構成 、、([1])なら、 個(バイアスなしなら 個)です。
長さ 、次元 、ヘッド数 ()のマルチヘッド自己注意 1 層を定義の式どおりに計算するとき、スカラーの乗算の回数は
で、ヘッド数 に依らない。このほかに指数関数の評価と除算が 回ある。注意の重みを保持するのに必要な記憶は 個の数である。 なので、時間計算量は であり、 のときは である。 を 2 倍にすると、 の項は 4 倍、 の項は 2 倍になる。
証明(命題 7.2)
行列と 行列の積の乗算の回数は です(定義 5.1[NumPy で書く配列計算])。
- 射影 、、:1 ヘッドあたり 、 ヘッドで 。
- 点数 :1 ヘッドあたり 、 ヘッドで 。
- 重みつき和 :1 ヘッドあたり 、 ヘッドで 。
- 出力の射影(連結したものに を掛ける):。
合計は です。 での除算、指数関数、正規化の除算は、 の成分 1 個につき定数回で、 は 個の 行列なので 回です。 より で、全体は (定義 3.1[計算量と O 記法])。 なら なので です。記憶は の成分数 です。
2 倍にしたときの比は、 が の 2 次、 が の 1 次の単項式であることから、それぞれ 、 です(命題 5.1[計算量と O 記法] の 3)。
Vaswani らの表 1 は自己注意の 1 層あたりの計算量を としています([1])。上の命題の の項がそれにあたります。 が より小さいあいだは射影の のほうが大きく、列が長くなると の 2 乗の項が支配的になります。 のときの回数は次のとおりです(8 節のコードの出力)。
| 合計 | の前の行との比 | 合計の前の行との比 | |||
|---|---|---|---|---|---|
| 64 | 1,048,576 | 524,288 | 1,572,864 | ||
| 128 | 2,097,152 | 2,097,152 | 4,194,304 | 4.00 | 2.67 |
| 256 | 4,194,304 | 8,388,608 | 12,582,912 | 4.00 | 3.00 |
| 512 | 8,388,608 | 33,554,432 | 41,943,040 | 4.00 | 3.33 |
| 1024 | 16,777,216 | 134,217,728 | 150,994,944 | 4.00 | 3.60 |
合計の比は、 が大きくなるにつれて 4 に近づきます。 で 2 つの項が等しくなります。
注意 7.3(交差注意)
クエリを一方の列から、キーとバリューを別の列から作る注意を交差注意といいます。Vaswani らのエンコーダ・デコーダ型のモデルでは、デコーダの各層が、エンコーダの出力をキーとバリューにした交差注意を持ちます([1] 3.2.3 節)。命題 4.2 はそのまま成り立ちます。このテーマで扱うデコーダのみのモデルには交差注意はありません。
8. 最小実装と数値検証
Section titled “8. 最小実装と数値検証”マルチヘッド自己注意を NumPy で実装します。ヘッドの軸を先頭に持つ 3 次元配列でパラメータを持ち、積は einsum(定義 5.1[NumPy で書く配列計算])で書きます。バイアスの加算と での除算はブロードキャスト(定義 3.1[NumPy で書く配列計算])です。
einsum は、添字の名前で「どの軸をかけて、どの軸で足すか」を指定する記法です。たとえば "nd,hdk->hnk" は、 の軸を n(位置)と d(次元)、W の軸を h(ヘッド)と d と k として、共通の d について積の和を取り、軸が h, n, k の配列を作る、という意味です。矢印の右に残らない添字は足し合わされます。
# Python 3.12.14, NumPy 2.5.2import numpy as np
def softmax(z): """最後の軸に沿った softmax。最大値を引いてから指数を取る(平行移動不変性)。""" e = np.exp(z - z.max(axis=-1, keepdims=True)) return e / e.sum(axis=-1, keepdims=True)
def init_params(d, h, rng): dk = d // h p = {name: rng.standard_normal((h, d, dk)) / np.sqrt(d) for name in ("WQ", "WK", "WV")} p.update({name: 0.1 * rng.standard_normal((h, dk)) for name in ("bQ", "bK", "bV")}) p["WO"] = rng.standard_normal((d, d)) / np.sqrt(d) p["bO"] = 0.1 * rng.standard_normal(d) return p
def self_attention(X, p, causal=False): """マルチヘッド自己注意。X は (n, d)。出力 (n, d) と重み (h, n, n) を返す。""" n, d = X.shape h, _, dk = p["WQ"].shape Q = np.einsum("nd,hdk->hnk", X, p["WQ"]) + p["bQ"][:, None, :] K = np.einsum("nd,hdk->hnk", X, p["WK"]) + p["bK"][:, None, :] V = np.einsum("nd,hdk->hnk", X, p["WV"]) + p["bV"][:, None, :] S = np.einsum("hik,hjk->hij", Q, K) / np.sqrt(dk) if causal: S = np.where(np.tril(np.ones((n, n), dtype=bool)), S, -np.inf) A = softmax(S) H = np.einsum("hij,hjk->hik", A, V) # (h, n, dk) Hcat = H.transpose(1, 0, 2).reshape(n, h * dk) # ヘッドの出力を連結 return Hcat @ p["WO"] + p["bO"], A
if __name__ == "__main__": rng = np.random.default_rng(0) n, d, h = 6, 8, 2 p = init_params(d, h, rng) X = rng.standard_normal((n, d)) print("params:", sum(a.size for a in p.values()), "= 4d^2+4d =", 4 * d * d + 4 * d)
perm = rng.permutation(n) Y, A = self_attention(X, p) Yp, _ = self_attention(X[perm], p) print("equivariance max|f(PX) - P f(X)| = %.1e" % np.abs(Yp - Y[perm]).max()) Yc, Ac = self_attention(X, p, causal=True) Ycp, _ = self_attention(X[perm], p, causal=True) print("causal, permuted max|f(PX) - P f(X)| = %.1e" % np.abs(Ycp - Yc[perm]).max())
X2 = X.copy(); X2[4:] = rng.standard_normal((2, d)) # 5・6 番目のトークンを変える Yc2, _ = self_attention(X2, p, causal=True) Y2, _ = self_attention(X2, p) print("causal rows 1-4 change: %.1e" % np.abs(Yc2[:4] - Yc[:4]).max()) print("no mask rows 1-4 change: %.1e" % np.abs(Y2[:4] - Y[:4]).max()) pre = max(np.abs(self_attention(X[:t], p, causal=True)[0][t - 1] - Yc[t - 1]).max() for t in range(1, n + 1)) print("prefix consistency: %.1e" % pre)
Vh = np.einsum("nd,hdk->hnk", X, p["WV"]) + p["bV"][:, None, :] Hh = np.einsum("hij,hjk->hik", Ac, Vh) print("weights >= 0:", bool((Ac >= 0).all()), " row sums - 1: %.1e" % np.abs(Ac.sum(-1) - 1).max(), " upper triangle max: %.1e" % np.abs(np.triu(Ac, 1)).max()) print("max row norm of head output %.4f <= max row norm of V %.4f" % (np.linalg.norm(Hh, axis=-1).max(), np.linalg.norm(Vh, axis=-1).max()))params: 288 = 4d^2+4d = 288equivariance max|f(PX) - P f(X)| = 2.2e-16causal, permuted max|f(PX) - P f(X)| = 2.6e+00causal rows 1-4 change: 0.0e+00no mask rows 1-4 change: 1.5e+00prefix consistency: 1.1e-16weights >= 0: True row sums - 1: 1.1e-16 upper triangle max: 0.0e+00max row norm of head output 2.3391 <= max row norm of V 3.5719出力を上から読みます。
- 1 行目:パラメータの総数が 命題 7.1 の に一致。
- 2 行目:マスクなしでは が丸め誤差の範囲で成り立つ(定理 5.2)。
- 3 行目:因果マスクつきでは成り立たない(注意 5.4)。
- 4・5 行目:5・6 番目の入力を変えても、因果マスクつきなら 1〜4 番目の出力はまったく変わらず、マスクなしでは変わる(定理 6.3)。
- 6 行目:接頭辞だけを入力したときの最後の行が、全体を入力したときの対応する行に一致(系 6.4)。
- 7・8 行目:重みが非負で行の和が 1、上三角が 0、ヘッドの出力の行のノルムがバリューの行のノルムの最大値以下(命題 4.2)。
例 4.5 の表と 7 節の回数の表は、次のコードの出力です。
# Python 3.12.14, NumPy 2.5.2。attention.py は前のコードimport numpy as npfrom attention import softmax
rng = np.random.default_rng(0)print(" d_k Var(q.k) Var(q.k/sqrt(d_k)) max weight: raw scaled")for dk in (4, 16, 64, 256, 1024): q, k = rng.standard_normal((20000, dk)), rng.standard_normal((20000, dk)) s = (q * k).sum(axis=1) q1, k8 = rng.standard_normal((2000, 1, dk)), rng.standard_normal((2000, 8, dk)) scores = (q1 * k8).sum(axis=-1) # 1 個のクエリと 8 個のキー raw = softmax(scores).max(axis=-1).mean() scaled = softmax(scores / np.sqrt(dk)).max(axis=-1).mean() print("%5d %9.2f %12.3f %18.3f %7.3f" % (dk, s.var(), (s / np.sqrt(dk)).var(), raw, scaled))
d = 64print(" n 4nd^2 2n^2d total ratio(2n^2d) ratio(total)")prev = Nonefor n in (64, 128, 256, 512, 1024): proj, attn = 4 * n * d * d, 2 * n * n * d if prev is None: print("%5d %8d %10d %10d" % (n, proj, attn, proj + attn)) else: print("%5d %8d %10d %10d %10.2f %12.2f" % (n, proj, attn, proj + attn, attn / prev[0], (proj + attn) / prev[1])) prev = (attn, proj + attn) d_k Var(q.k) Var(q.k/sqrt(d_k)) max weight: raw scaled 4 4.00 1.001 0.532 0.347 16 16.18 1.011 0.743 0.353 64 62.92 0.983 0.878 0.361 256 255.84 0.999 0.939 0.366 1024 1036.38 1.012 0.971 0.361 n 4nd^2 2n^2d total ratio(2n^2d) ratio(total) 64 1048576 524288 1572864 128 2097152 2097152 4194304 4.00 2.67 256 4194304 8388608 12582912 4.00 3.00 512 8388608 33554432 41943040 4.00 3.33 1024 16777216 134217728 150994944 4.00 3.609. 次章へ
Section titled “9. 次章へ”この章で確定したことは 3 つです。自己注意の出力はバリューの凸結合であること、位置情報がなければ置換同変で語順を区別できないこと、因果マスクを入れれば各位置の出力が未来に依存しないこと。次章の Transformer ブロックでは、自己注意に残差接続(入力に層の出力を足す接続)・層正規化・行ごとの MLP を組み合わせて 1 つの層にし、それを重ねてモデル全体を作ります。補題 5.1 と 補題 6.2 は「行ごとに働く写像との合成と和で性質が保たれる」ことを言っているので、同変性と因果性はブロック全体にそのまま引き継がれます。
10. 演習
Section titled “10. 演習”について を求めよ。また について を求めよ。
解答
、、 で和は 6 なので です。 なので、平行移動不変性(命題 3.1 の 2)より です。定義どおりに を計算する必要はありません。
演習 10.2標準
のとき、 と書く。ヤコビ行列を で表し、固有値を求めよ。固有値の最大値が最も大きくなるのは がいくつのときか。
解答
命題 3.2 より
は を に、 を に写すので、固有値は 0 と 2 です。よって の固有値は (固有ベクトル 。命題の 2)と です。 なので、 のとき最大値 を取り、 が 0 か 1 に近づくと 0 に近づきます。出力が一方に偏るほど勾配が流れにくくなることが、この場合は式で見えます。
、 とする。 を求めよ。また、第 3 成分から を引いて普通の softmax を取ったとき、第 3 成分の値はどれだけ以下か。
解答
、 で和は なので、 です。命題 3.3 の評価より、第 3 成分は 以下です。
演習 10.4標準
位置情報のない、因果マスクつきの自己注意 1 層(1 ヘッド)を とする。 が を満たす置換のとき、 を示せ。2 層重ねたときにも同じことが成り立つか、数値実験の結果から答えよ。
解答
定理 6.3 の証明の式で とすると、最後の行の出力は
で、 は と だけ、 は だけで決まります。入力を に替えると、第 行は 、最後の行は のままなので、和の第 項がもとの和の第 項になります。 は全単射なので、分母の和も全体の和も、項の順番が入れ替わるだけで値は同じです。
2 層では成り立つとは限りません。1 層目の第 行()の出力は に依るので、前の行を並べ替えると、2 層目に入る行の集まりそのものが変わるからです。8 節の attention.py を使った次の実験では、1 番目と 2 番目の行を入れ替えたとき、1 層では最後の行が変わらず、2 層では変わりました。
# Python 3.12.14, NumPy 2.5.2。attention.py は前のコードimport numpy as npfrom attention import init_params, self_attention
rng = np.random.default_rng(0)n, d, h = 6, 8, 2p1, p2 = init_params(d, h, rng), init_params(d, h, rng)X = rng.standard_normal((n, d))Xs = X.copy(); Xs[[0, 1]] = X[[1, 0]] # 1 番目と 2 番目を入れ替える(最後の行は動かさない)
def one(X): return self_attention(X, p1, causal=True)[0]
def two(X): return self_attention(one(X), p2, causal=True)[0]
print("1 layer, last row change: %.1e" % np.abs(one(Xs)[-1] - one(X)[-1]).max())print("2 layers, last row change: %.1e" % np.abs(two(Xs)[-1] - two(X)[-1]).max())1 layer, last row change: 0.0e+002 layers, last row change: 5.1e-01- [1] A. Vaswani, N. Shazeer, N. Parmar, J. Uszkoreit, L. Jones, A. N. Gomez, Ł. Kaiser, I. Polosukhin, “Attention Is All You Need”, 2017. arXiv:1706.03762 — 3.2 節(スケール付き内積注意、マルチヘッド、因果マスク。 で割る理由は 3.2.1 節の脚注)、表 1(層の種類ごとの計算量)。
- [2] D. Bahdanau, K. Cho, Y. Bengio, “Neural Machine Translation by Jointly Learning to Align and Translate”, ICLR 2015. arXiv:1409.0473 — 注意機構を機械翻訳に導入した論文。
- [3] J. Lee, Y. Lee, J. Kim, A. R. Kosiorek, S. Choi, Y. W. Teh, “Set Transformer: A Framework for Attention-based Permutation-Invariant Neural Networks”, ICML 2019. arXiv:1810.00825 — 注意に基づく置換同変・置換不変なネットワークの定式化。
- [4] 本サイト「確率変数と期待値:可測関数としての確率変数、ルベーグ積分としての期待値」 — 独立性、分散の性質、独立な確率変数の積の期待値。
Appendix: 独立な確率変数の積の期待値
Section titled “Appendix: 独立な確率変数の積の期待値”命題 4.4 の証明で使った、3 個以上の積についての補題を示します。 2 個の場合は既出の命題で、ここではそれを個数についての帰納法で延長します。
証明(補題 10.5)
についての帰納法です。 は 命題 7.5[確率変数と期待値] です。 とし、 個の場合を仮定します。
の積。 は独立です(独立性の定義で と取る)。帰納法の仮定より は可積分で です。 が確率変数であることは 命題 3.4[確率変数と期待値] です。
と の独立性。 ボレル集合 を固定し、 のボレル集合 に対して
と置きます。これが定義できること、すなわち任意のボレル集合 について が事象であることを先に確かめます。この性質を持つ の全体は、逆像が補集合と可算和を保つので σ-加法族で、長方形 を含みます(逆像は事象 の共通部分)。長方形は を生成するので(下で使うのと同じ 命題 2.3[直積測度と Fubini–Tonelli の定理])、すべてのボレル集合がこの性質を持ちます。 はどちらも 上の有限測度です( の可算加法性から)。長方形 (各 はボレル集合)の全体を とすると、2 つの長方形の共通部分は長方形なので は π-系で、 であり、 は を生成します(命題 2.3[直積測度と Fubini–Tonelli の定理])。長方形の上では、 の独立性と の独立性から
です。測度の一意性(定理 4.5[測度空間と Carathéodory の拡張定理])より、 の全体で です。
ボレル集合 に対し と置くと、積 は連続なので はボレル集合で、 です。よって
で、 と は独立です。
結論。 と は独立で可積分なので、命題 7.5[確率変数と期待値] より は可積分で です。
執筆: Claude Code(Opus 5.5)、Claude Code(Sonnet 5.5)・監査 2 回(Claude Code)・最終 2026-10-12
この記事の誤りを報告する ・運営: 夢現技研合同会社 ・料金 ・利用条件 ・特定商取引法に基づく表記
© 2026 夢現技研合同会社 ・コード例は MIT ライセンスです。