コンテンツにスキップ

推論:自己回帰生成・温度と top-p・KV キャッシュ・量子化

対象読者: 本テーマ第 1〜5 章の内容と、確率分布・エントロピーの基礎、行列計算の計算量の見積もりを学んだ人。サンプリングや KV キャッシュは仮定しません。

前提となる記事:言語モデルの学習:次トークン予測・パープレキシティ・AdamW・LoRA、自己注意:スケール付き内積注意・マルチヘッド・因果マスク、Transformer ブロック:残差接続・層正規化・MLP とパラメータ数

生 Markdown

ChatGPT のような言語モデルは、文章を丸ごと一度に作るのではなく、「次の 1 語(トークン)は何か」を毎回予想して、1 つ選んで付け足すことを繰り返しています。予想の仕方(重み)が同じでも、どう選ぶか、計算をどう節約するか、重みをどこまで粗く保存するかで、出力の内容も速さも変わります。この記事では、その「選び方」(温度・top-p など)、「計算の節約」(KV キャッシュ)、「重みの粗い保存」(量子化)が、それぞれ何を保証するのかを、数式と小さな数値例で確かめます。

  • 生成は「次のトークンの分布から 1 つ選び、入力の末尾に足す」ことの反復です。同じ重みでも、選び方(復号の方法)を変えると出力の分布が変わります。毎回いちばん確率の高いトークンを選ぶ貪欲復号は、確率最大の列を返すとは限りません(命題 3.3)。
  • 温度 τ\tau はロジット(softmax に入れる前の、各トークンのスコア)を τ\tau で割ってから softmax を取る操作です。τ→0\tau \to 0 で最大成分だけに集中し、τ→∞\tau \to \infty で一様分布になり、エントロピー(分布の散らばり具合を表す数)は τ\tau について単調に増えます。その導関数は Var(z)/τ3\mathrm{Var}(z) / \tau^3 です(定理 4.2)。
  • top-k と top-p は、ある集合 SS への条件付き分布を取る操作です(命題 5.2)。top-p 集合は並べ方を決めれば一意で、その大きさは「確率の和がしきい値以上になる集合の最小の大きさ」に等しくなります(定理 5.4)。
  • KV キャッシュは、因果マスク(各位置が自分より後ろのトークンを見ないようにする制限)のもとでは過去の位置のキーとバリューが後のトークンに依らないことを使います。出力は計算し直した場合と一致し(定理 7.2)、nn トークンの生成の計算量は 1 層あたり O(n3d+n2d2)O(n^3 d + n^2 d^2) から O(n2d+nd2)O(n^2 d + n d^2) に減ります(定理 7.3)。
  • 重みを bb ビットに丸める一様量子化の誤差は、1 成分あたり刻みの半分以下で、ビットを 1 つ増やすと上界はほぼ半分になります(命題 8.2)。

1. 動機:重みが決まっても、出力は決まらない

Section titled “1. 動機:重みが決まっても、出力は決まらない”

学習で決まるのは重み θ\theta、すなわち接頭辞から次のトークンの確率分布への写像 pθ(⋅∣x<t)p_\theta(\cdot \mid x_{<t}) です。これは文章そのものではありません。分布から実際の文章を作るには、次のことを決める必要があります。

  1. 分布からトークンをどう選ぶか。いちばん確率の高いものを取るのか、分布に従って乱数で選ぶのか、分布を加工してから選ぶのか。
  2. 1 トークン選ぶたびに、モデルの順伝播を最初からやり直すのか。
  3. 重みをどの精度で持つのか。

1 は出力の内容を、2 と 3 は計算の速さと記憶の量を左右します。この章では、それぞれについて厳密に言えることを命題にします。「どの温度が良い文章を出すか」「何ビットまで落としても品質が保たれるか」は経験的な問いで、この章の命題は答えません。命題が与えるのは、各操作が分布や計算量や誤差に対して確実に行うことです。

語彙を V={1,…,N}V = \{1, \ldots, N\}(N=∣V∣N = |V|)とし、トークンを添字で表します。モデルは接頭辞 x<tx_{<t} に対してロジット z∈RN\boldsymbol{z} \in \mathbb{R}^N(softmax に入れる前の、各トークンのスコア)を返し、p=softmax(z)p = \mathrm{softmax}(\boldsymbol{z}) が次のトークンの分布です。softmax の基本性質(成分が正で和が 11、定数を足しても変わらない、成分の大小を保つ)は 命題 3.1[自己注意] を使います。

確率分布 p=(p1,…,pN)p = (p_1, \ldots, p_N) と集合 S⊂VS \subset V に対して p(S)=∑i∈Spip(S) = \sum_{i \in S} p_i と書きます。エントロピーは H(p)=−∑ipilog⁡piH(p) = -\sum_i p_i \log p_i(pi=0p_i = 0 の項は 00)で、対数は自然対数です。モデルの次元を dd、層数を LL、MLP の幅を dffd_{\mathrm{ff}} と書きます。

定義 3.1(自己回帰生成)↗

プロンプト(与えられた接頭辞)x≤t0x_{\le t_0} から始めて、t=t0+1,t0+2,…t = t_0 + 1, t_0 + 2, \ldots について

  1. モデルで pθ(⋅∣x<t)p_\theta(\cdot \mid x_{<t}) を計算する、
  2. 復号規則に従って xt∈Vx_t \in V を 1 つ決める、
  3. xtx_t を列の末尾に足す、

を繰り返す手続きを自己回帰生成といいます。xtx_t が終端を表す特殊トークンになったとき、または列の長さがあらかじめ決めた最大長に達したときに止めます。最大長があるので、手続きは必ず止まります。

復号規則として、xtx_t を pθ(⋅∣x<t)p_\theta(\cdot \mid x_{<t}) に従う乱数で選ぶと(祖先サンプリング)、生成された列は前章の自己回帰の積 ∏tpθ(xt∣x<t)\prod_t p_\theta(x_t \mid x_{<t}) の分布(定理 3.2[言語モデルの学習])に従います。それ以外の規則では、列の分布は別のものになります。

定義 3.2(貪欲復号とビーム探索)↗

  • 貪欲復号: 各ステップで xt=arg max⁡vpθ(v∣x<t)x_t = \operatorname{arg\,max}_{v} p_\theta(v \mid x_{<t}) とします。最大が複数あるときは添字の最も小さいものを取ります。
  • ビーム探索(幅 B≥1B \ge 1、長さ nn): 長さ tt の接頭辞の集合 Bt\mathcal{B}_t を、B0={空列}\mathcal{B}_0 = \{\text{空列}\} から順に次で定めます。候補の集合を Ct={(y,v):y∈Bt−1, v∈V}C_t = \{ (y, v) : y \in \mathcal{B}_{t-1},\ v \in V \} とし、CtC_t の元を列の確率 pθ(y,v)=pθ(y) pθ(v∣y)p_\theta(y, v) = p_\theta(y)\, p_\theta(v \mid y) の大きい順(同じ値はあらかじめ決めた順)に並べて、上から min⁡(B,∣Ct∣)\min(B, |C_t|) 個を Bt\mathcal{B}_t とします。出力は Bn\mathcal{B}_n のうち確率が最大の列です。

次の命題の 1 は、二文字だけの小さな例で見ると分かりやすくなります。1 文字目で確率の高いほう(a)を選ぶと、そのあとに続く文字の確率が低くなり、列全体では損をすることがあります。証明の 1 で使う確率を木にすると次のようになります。

空列ab0.60.40.550.450.90.1aa : 0.33(貪欲復号の結果)ab : 0.27ba : 0.36(確率が最大)bb : 0.04
2 文字の列の確率の木。各枝の数は条件付き確率で、右端は列の確率(枝の数の積)。貪欲復号は色つきの道をたどって aa(0.33)に着くが、確率が最大なのは ba(0.36)である。

命題 3.3(貪欲復号とビーム探索は確率最大の列を保証しない)✓

長さ nn の列の上の自己回帰言語モデル pθp_\theta を考えます。

  1. 貪欲復号が返す列は、確率 pθ(x)p_\theta(x) が最大の列とは限りません。
  2. 幅 B=1B = 1 のビーム探索は貪欲復号と同じ列を返します(同じ値の扱いが同じなら)。
  3. B≥∣V∣n−1B \ge |V|^{n-1} なら、ビーム探索は確率最大の列を返します。
  4. 1<B<∣V∣n−11 < B < |V|^{n-1} では、確率最大の列を返すとは限りません。
  5. ビーム探索が計算する候補の確率の個数は nB∣V∣n B |V| 以下です。
証明(命題 3.3)

1. V={a,b}V = \{\mathrm{a}, \mathrm{b}\}、n=2n = 2 とし、

p(a)=0.6,p(b)=0.4,p(a∣a)=0.55,p(b∣a)=0.45,p(a∣b)=0.9,p(b∣b)=0.1p(\mathrm{a}) = 0.6,\quad p(\mathrm{b}) = 0.4,\qquad p(\mathrm{a} \mid \mathrm{a}) = 0.55,\quad p(\mathrm{b} \mid \mathrm{a}) = 0.45,\qquad p(\mathrm{a} \mid \mathrm{b}) = 0.9,\quad p(\mathrm{b} \mid \mathrm{b}) = 0.1

とします。4 つの列の確率は p(aa)=0.33p(\mathrm{aa}) = 0.33、p(ab)=0.27p(\mathrm{ab}) = 0.27、p(ba)=0.36p(\mathrm{ba}) = 0.36、p(bb)=0.04p(\mathrm{bb}) = 0.04 で、和は 11 です。貪欲復号は 1 文字目に a\mathrm{a}(0.6>0.40.6 > 0.4)、2 文字目に a\mathrm{a}(0.55>0.450.55 > 0.45)を選んで aa\mathrm{aa} を返しますが、最大は ba\mathrm{ba} の 0.360.36 です。

2. B=1B = 1 のとき Bt−1\mathcal{B}_{t-1} はただ 1 つの接頭辞 yy からなり、Ct={(y,v):v∈V}C_t = \{(y, v) : v \in V\} です。pθ(y,v)=pθ(y) pθ(v∣y)p_\theta(y, v) = p_\theta(y)\, p_\theta(v \mid y) で、pθ(y)p_\theta(y) は vv に依らないので、pθ(y)>0p_\theta(y) > 0 なら CtC_t の中で最大のものは pθ(v∣y)p_\theta(v \mid y) が最大の vv に対応します。これは貪欲復号の選び方です(pθ(y)=0p_\theta(y) = 0 となることは、softmax の出力が正なので起こりません)。

3. t≤n−1t \le n - 1 について Bt=Vt\mathcal{B}_t = V^t であることを帰納法で示します。B0\mathcal{B}_0 は空列だけで、V0V^0 です。Bt−1=Vt−1\mathcal{B}_{t-1} = V^{t-1} なら Ct=VtC_t = V^t で、∣Ct∣=∣V∣t≤∣V∣n−1≤B|C_t| = |V|^t \le |V|^{n-1} \le B なので、min⁡(B,∣Ct∣)=∣Ct∣\min(B, |C_t|) = |C_t| 個、つまり全部が残り、Bt=Vt\mathcal{B}_t = V^t です。したがって Cn=VnC_n = V^n で、Bn\mathcal{B}_n は VnV^n の確率の上位 min⁡(B,∣V∣n)≥1\min(B, |V|^n) \ge 1 個からなり、確率最大の列を含みます。出力はその中の最大なので、確率最大の列です。

4. V={a,b,c}V = \{\mathrm{a}, \mathrm{b}, \mathrm{c}\}、n=2n = 2、B=2B = 2(1<2<3=∣V∣n−11 < 2 < 3 = |V|^{n-1})とし、

p(a)=0.4, p(b)=0.35, p(c)=0.25,p(⋅∣a)=p(⋅∣b)=(0.4,0.3,0.3),p(⋅∣c)=(0.9,0.05,0.05)p(\mathrm{a}) = 0.4,\ p(\mathrm{b}) = 0.35,\ p(\mathrm{c}) = 0.25, \qquad p(\cdot \mid \mathrm{a}) = p(\cdot \mid \mathrm{b}) = (0.4, 0.3, 0.3), \qquad p(\cdot \mid \mathrm{c}) = (0.9, 0.05, 0.05)

とします。B1={a,b}\mathcal{B}_1 = \{\mathrm{a}, \mathrm{b}\} で、c\mathrm{c} は捨てられます。C2C_2 の中の最大は p(aa)=0.16p(\mathrm{aa}) = 0.16(ほかは p(ba)=0.14p(\mathrm{ba}) = 0.14 など)なので、出力は aa\mathrm{aa} です。ところが p(ca)=0.25×0.9=0.225>0.16p(\mathrm{ca}) = 0.25 \times 0.9 = 0.225 > 0.16 です。

5. 各ステップで ∣Ct∣=∣Bt−1∣⋅∣V∣≤B∣V∣|C_t| = |\mathcal{B}_{t-1}| \cdot |V| \le B|V| で、ステップは nn 回です。

3 の条件 B≥∣V∣n−1B \ge |V|^{n-1} は、全部の列を調べるのと同じです。語彙が数万、長さが数十の列では現実的でなく、確率最大の列を厳密に求める方法は実用上ありません。一方で、確率最大の列が望ましい出力であるとも限りません。Holtzman らは、確率を最大化する復号が、繰り返しの多い不自然な文章を生みやすいことを報告し、次節以降の「分布を加工してから乱数で選ぶ」方法を提案しました。これは経験的な観察で、この章の命題の外にあります。

定義 4.1(温度つき softmax)↗

ロジット z∈RN\boldsymbol{z} \in \mathbb{R}^N と τ>0\tau > 0 に対して

pτ=softmax(z/τ),pτ,i=ezi/τ∑j=1Nezj/τp_\tau = \mathrm{softmax}(\boldsymbol{z} / \tau), \qquad p_{\tau, i} = \frac{e^{z_i / \tau}}{\sum_{j=1}^{N} e^{z_j / \tau}}

を温度 τ\tau の分布といいます。τ=1\tau = 1 が元の分布です。

定理 4.2(温度の極限・順位の保存・エントロピーの単調性)✓

z∈RN\boldsymbol{z} \in \mathbb{R}^N とし、最大値を zmax⁡=max⁡iziz_{\max} = \max_i z_i、それを取る添字の集合を I={i:zi=zmax⁡}I = \{ i : z_i = z_{\max} \} とします。

  1. τ→0+\tau \to 0+ のとき、pτ,i→1/∣I∣p_{\tau, i} \to 1 / |I|(i∈Ii \in I)、pτ,i→0p_{\tau, i} \to 0(i∉Ii \notin I)です。
  2. τ→∞\tau \to \infty のとき、すべての ii で pτ,i→1/Np_{\tau, i} \to 1 / N です。
  3. 任意の τ>0\tau > 0 について、zi>zjz_i > z_j なら pτ,i>pτ,jp_{\tau, i} > p_{\tau, j}、zi=zjz_i = z_j なら pτ,i=pτ,jp_{\tau, i} = p_{\tau, j} です。温度は成分の順位を変えません。
  4. h(τ)=H(pτ)h(\tau) = H(p_\tau) は τ>0\tau > 0 で微分可能で、
dhdτ=Varpτ(z)τ3 ≥ 0,Varpτ(z)=∑ipτ,izi2−(∑ipτ,izi)2\frac{dh}{d\tau} = \frac{\mathrm{Var}_{p_\tau}(z)}{\tau^3} \ \ge\ 0, \qquad \mathrm{Var}_{p_\tau}(z) = \sum_i p_{\tau, i} z_i^2 - \Bigl(\sum_i p_{\tau, i} z_i\Bigr)^2

です。したがって hh は広義単調増加で、zz の成分がすべて等しい場合を除いて狭義単調増加です。

証明の方針です。1〜3 は式を見直すだけです。4 では、温度の逆数 β=1/τ\beta = 1/\tau を変数にして、確率の変化の速さ、ロジットの平均、エントロピーの順に微分します。途中に現れる量は「分布のもとでの平均」だけで、最後に分散が現れます。分散は負にならないので、温度を上げてもエントロピーは減らない、という結論になります。

証明(定理 4.2)

1. 分子と分母を ezmax⁡/τe^{z_{\max} / \tau} で割ると

pτ,i=e(zi−zmax⁡)/τ∑je(zj−zmax⁡)/τp_{\tau, i} = \frac{e^{(z_i - z_{\max}) / \tau}}{\sum_{j} e^{(z_j - z_{\max}) / \tau}}

です。j∈Ij \in I なら指数は 00 で、その項は τ\tau に依らず 11 です。j∉Ij \notin I なら zj−zmax⁡<0z_j - z_{\max} < 0 で、τ→0+\tau \to 0+ のとき (zj−zmax⁡)/τ→−∞(z_j - z_{\max})/\tau \to -\infty、その項は 00 に収束します。したがって分母は ∣I∣|I| に、分子は i∈Ii \in I なら 11、i∉Ii \notin I なら 00 に収束します。

2. τ→∞\tau \to \infty のとき、各 jj で zj/τ→0z_j / \tau \to 0 なので ezj/τ→1e^{z_j / \tau} \to 1 です。分子は 11 に、分母は NN に収束します。

3. 分母は共通で正です。τ>0\tau > 0 なので zi>zjz_i > z_j は zi/τ>zj/τz_i / \tau > z_j / \tau と同値で、指数関数は狭義単調増加なので ezi/τ>ezj/τe^{z_i/\tau} > e^{z_j/\tau} です。等しい場合も同様です。

4. β=1/τ\beta = 1/\tau とおき、Z(β)=∑jeβzjZ(\beta) = \sum_j e^{\beta z_j}、pi=eβzi/Z(β)p_i = e^{\beta z_i} / Z(\beta)、μ=∑ipizi\mu = \sum_i p_i z_i と書きます。まず pip_i の β\beta についての導関数を計算します。Z′(β)=∑jzjeβzj=ZμZ'(\beta) = \sum_j z_j e^{\beta z_j} = Z \mu なので、商の微分により

dpidβ=zieβziZ−eβziZμZ2=pi(zi−μ)\frac{dp_i}{d\beta} = \frac{z_i e^{\beta z_i} Z - e^{\beta z_i} Z \mu}{Z^2} = p_i (z_i - \mu)

です。したがって

dμdβ=∑izidpidβ=∑ipizi(zi−μ)=∑ipizi2−μ2=Varp(z)\frac{d\mu}{d\beta} = \sum_i z_i \frac{dp_i}{d\beta} = \sum_i p_i z_i (z_i - \mu) = \sum_i p_i z_i^2 - \mu^2 = \mathrm{Var}_{p}(z)

です。次に、log⁡pi=βzi−log⁡Z\log p_i = \beta z_i - \log Z から、エントロピーは

H=−∑ipi(βzi−log⁡Z)=log⁡Z−βμH = -\sum_i p_i (\beta z_i - \log Z) = \log Z - \beta \mu

と書けます(∑ipi=1\sum_i p_i = 1 を使いました)。ddβlog⁡Z=Z′/Z=μ\frac{d}{d\beta} \log Z = Z'/Z = \mu なので

dHdβ=μ−μ−βdμdβ=−β Varp(z)\frac{dH}{d\beta} = \mu - \mu - \beta \frac{d\mu}{d\beta} = -\beta\, \mathrm{Var}_p(z)

です。β=1/τ\beta = 1/\tau で dβ/dτ=−1/τ2d\beta / d\tau = -1/\tau^2 なので、合成関数の微分により

dhdτ=dHdβ⋅dβdτ=(−1τVarpτ(z))(−1τ2)=Varpτ(z)τ3\frac{dh}{d\tau} = \frac{dH}{d\beta} \cdot \frac{d\beta}{d\tau} = \Bigl(-\frac{1}{\tau} \mathrm{Var}_{p_\tau}(z)\Bigr) \Bigl(-\frac{1}{\tau^2}\Bigr) = \frac{\mathrm{Var}_{p_\tau}(z)}{\tau^3}

です。分散は ∑ipi(zi−μ)2\sum_i p_i (z_i - \mu)^2 に等しいので非負です(命題 5.3[確率変数と期待値])。pi>0p_i > 0 なので、これが 00 になるのはすべての ii で zi=μz_i = \mu、すなわち zz の成分がすべて等しいときに限ります。導関数が非負なら広義単調増加、正なら狭義単調増加です(系 3.4[平均値の定理とテイラーの定理])。

1 は「温度 00 は貪欲復号」という言い方の正確な意味です。最大のロジットがただ 1 つなら、τ→0+\tau \to 0+ の極限はそのトークンに確率 11 を置く分布で、そこから標本を取ることは貪欲復号と同じです。τ=0\tau = 0 そのものは式の上で定義されないので、実装では別の分岐(最大成分を取る)として扱います。

4 は、温度が「分布の散らばり具合を 1 つのつまみで動かす」操作であることを定量的に言っています。温度を上げるとエントロピーは必ず増え、下げると必ず減ります。増え方は、ロジットの(その時点の分布での)分散が大きいほど速く、τ\tau が大きくなると τ−3\tau^{-3} で鈍ります。

例 4.3(ロジット (2, 1, 0) の温度による変化)

z=(2,1,0)\boldsymbol{z} = (2, 1, 0) とします。τ=1\tau = 1 では e2:e1:e0=7.389:2.718:1e^2 : e^1 : e^0 = 7.389 : 2.718 : 1 で、和は 11.10711.107、p1=(0.6652,0.2447,0.0900)p_1 = (0.6652, 0.2447, 0.0900) です。τ=0.5\tau = 0.5 ではロジットが (4,2,0)(4, 2, 0) になったのと同じで、τ=2\tau = 2 では (1,0.5,0)(1, 0.5, 0) と同じです。

τ\taupτp_\tauH(pτ)H(p_\tau)
0.10.1(1.0000, 0.0000, 0.0000)(1.0000,\ 0.0000,\ 0.0000)0.00050.0005
0.50.5(0.8668, 0.1173, 0.0159)(0.8668,\ 0.1173,\ 0.0159)0.44110.4411
11(0.6652, 0.2447, 0.0900)(0.6652,\ 0.2447,\ 0.0900)0.83240.8324
22(0.5065, 0.3072, 0.1863)(0.5065,\ 0.3072,\ 0.1863)1.02021.0202
100100(0.3367, 0.3333, 0.3300)(0.3367,\ 0.3333,\ 0.3300)1.09861.0986

(値は第 6 節のコードの出力です。)順位はどの行でも第 1・第 2・第 3 成分の順で、エントロピーは上から下へ増えています。上限は一様分布の log⁡3≈1.0986\log 3 \approx 1.0986 です。

温度を 0.10.1 から 100100 まで動かすと、棒グラフと右のエントロピーの点がどう動くかを見てください。

温度を 0.1 から 100 まで上げていくと、3 本の棒グラフが、第 1 成分だけが 1 の尖った形から、3 本がほぼ同じ高さの平らな形へ変わる。右のグラフではエントロピーの点が 0 から上限 log 3 へ単調に上がる。
ロジット (2, 1, 0) の温度つき softmax。温度が低いと最大成分に確率が集中し、高いと一様に近づく。右の点は対応するエントロピーで、上限 log 3 に向かって単調に増える。

5. 分布の打ち切り:top-k と top-p

Section titled “5. 分布の打ち切り:top-k と top-p”

温度を上げると、確率の小さいトークン(分布の裾)にも確率が回ります。裾には文脈に合わないトークンが多く含まれるので、裾を切り落としてから選ぶ方法が使われます。

定義 5.1(top-k と top-p(nucleus)サンプリング)↗

pp を V={1,…,N}V = \{1, \ldots, N\} 上の確率分布とします。添字を確率の降順に、同じ値は添字の昇順に並べたものを π(1),π(2),…,π(N)\pi(1), \pi(2), \ldots, \pi(N) とし(pπ(1)≥pπ(2)≥⋯p_{\pi(1)} \ge p_{\pi(2)} \ge \cdots)、累積を cj=∑i=1jpπ(i)c_j = \sum_{i=1}^{j} p_{\pi(i)} とします。

  • top-k 集合(1≤k≤N1 \le k \le N): S(k)={π(1),…,π(k)}S^{(k)} = \{\pi(1), \ldots, \pi(k)\}。
  • top-p 集合(しきい値 0<ρ≤10 < \rho \le 1): k(ρ)=min⁡{j:cj≥ρ}k(\rho) = \min\{ j : c_j \ge \rho \} とし、Sρ={π(1),…,π(k(ρ))}S_\rho = \{\pi(1), \ldots, \pi(k(\rho))\}。
  • 集合 SS(p(S)>0p(S) > 0)への制限: pS(i)=pi/p(S)p_S(i) = p_i / p(S)(i∈Si \in S)、pS(i)=0p_S(i) = 0(i∉Si \notin S)。

pS(k)p_{S^{(k)}} から標本を取ることを top-k サンプリング、pSρp_{S_\rho} から標本を取ることを top-p サンプリング(nucleus サンプリング)といいます。しきい値 ρ\rho が、通称の「top-p の p」です(分布の記号 pp と区別するため、ここでは ρ\rho と書きます)。

命題 5.2(打ち切りは条件付き分布である)✓

pp を VV 上の確率分布、S⊂VS \subset V を p(S)>0p(S) > 0 である集合とします。

  1. pSp_S は VV 上の確率分布で、pp に従う確率変数 XX の、事象 {X∈S}\{X \in S\} のもとでの条件付き分布に一致します: pS(i)=P(X=i∣X∈S)p_S(i) = P(X = i \mid X \in S)。
  2. i,j∈Si, j \in S、pj>0p_j > 0 なら pS(i)/pS(j)=pi/pjp_S(i) / p_S(j) = p_i / p_j です。SS の中の確率の比は変わりません。
  3. pp と pSp_S の全変動距離は 12∑i∣pi−pS(i)∣=1−p(S)\frac{1}{2} \sum_i |p_i - p_S(i)| = 1 - p(S) です。
証明(命題 5.2)

1. 条件付き確率の定義(定義 5.1[確率])から、i∈Si \in S なら P(X=i∣X∈S)=P(X=i)/P(X∈S)=pi/p(S)P(X = i \mid X \in S) = P(X = i) / P(X \in S) = p_i / p(S)、i∉Si \notin S なら {X=i}∩{X∈S}\{X = i\} \cap \{X \in S\} が空なので 00 です。これは pSp_S の定義と同じです。条件付き確率が確率分布であることは 命題 5.2[確率] です。

2. pS(i)/pS(j)=(pi/p(S))/(pj/p(S))=pi/pjp_S(i) / p_S(j) = (p_i / p(S)) / (p_j / p(S)) = p_i / p_j です。

3. i∈Si \in S では pS(i)−pi=pi(1/p(S)−1)≥0p_S(i) - p_i = p_i (1/p(S) - 1) \ge 0、i∉Si \notin S では pi−pS(i)=pip_i - p_S(i) = p_i です。したがって

∑i∣pi−pS(i)∣=(1p(S)−1)∑i∈Spi+∑i∉Spi=(1−p(S))+(1−p(S))\sum_i |p_i - p_S(i)| = \Bigl(\frac{1}{p(S)} - 1\Bigr) \sum_{i \in S} p_i + \sum_{i \notin S} p_i = \bigl(1 - p(S)\bigr) + \bigl(1 - p(S)\bigr)

で、12\frac{1}{2} を掛けると 1−p(S)1 - p(S) です。

3 から、top-p サンプリングの意味が読み取れます。p(Sρ)≥ρp(S_\rho) \ge \rho なので、元の分布からのずれ(全変動距離。2 つの分布の各成分の差の絶対値を足して半分にした量)は 1−ρ1 - \rho 以下です。ρ=0.9\rho = 0.9 なら、元の分布を高々 0.10.1 だけ動かす操作です。top-k にはこのような保証はなく、分布が平らなときには確率の大部分を捨てることがあります。

top-p 集合の定義は、並べ方 π\pi を固定したうえでの「累積がしきい値に届く最小の接頭辞」でした。これが「確率の和がしきい値以上の最小の集合」という言い方とどう対応するかを確定させます。まず補題を置きます。中身は、同じ個数だけ選ぶなら確率の大きいものから順に取るのが和をいちばん大きくする、という事実で、定理の 2 と 3 の証明で使います。

補題 5.3(上位 j 個は、大きさ j の集合のうち確率が最大)✓

定義 5.1 の記号のもとで、∣T∣=j|T| = j である任意の T⊂VT \subset V について p(T)≤cj=p(S(j))p(T) \le c_j = p(S^{(j)}) です。p1,…,pNp_1, \ldots, p_N がすべて異なるなら、等号は T=S(j)T = S^{(j)} のときに限ります。

証明(補題 5.3)

S=S(j)S = S^{(j)} と書きます。∣T∣=∣S∣=j|T| = |S| = j なので ∣S∖T∣=∣T∖S∣|S \setminus T| = |T \setminus S| です。この個数を mm とし、S∖T={a1,…,am}S \setminus T = \{a_1, \ldots, a_m\}、T∖S={b1,…,bm}T \setminus S = \{b_1, \ldots, b_m\} と番号を付けます。al∈Sa_l \in S は並び π\pi の初めの jj 個に入り、bl∉Sb_l \notin S は入らないので、ala_l は blb_l より前に並んでいます。並びは確率の降順なので pal≥pblp_{a_l} \ge p_{b_l} です。共通部分 S∩TS \cap T の寄与は打ち消し合うので

p(S)−p(T)=∑l=1m(pal−pbl)≥0p(S) - p(T) = \sum_{l=1}^{m} \bigl(p_{a_l} - p_{b_l}\bigr) \ge 0

です。確率がすべて異なるなら各項は正で、p(S)=p(T)p(S) = p(T) となるのは m=0m = 0、すなわち T=ST = S のときに限ります。

次の定理は、top-p が「確率の大きい順に取っていき、確率の和がしきい値に届いたところで止める」という操作であり、その結果が 1 通りに決まることを確かめます。たとえば確率が (0.5,0.3,0.2)(0.5, 0.3, 0.2)、しきい値が 0.60.6 なら、0.50.5 だけでは足りず、0.5+0.3=0.80.5 + 0.3 = 0.8 で届くので上位 2 個が選ばれます。

定理 5.4(top-p 集合の一意性・最小性・単調性)✓

pp を V={1,…,N}V = \{1, \ldots, N\} 上の確率分布、0<ρ≤10 < \rho \le 1 とします。

  1. (一意性)k(ρ)k(\rho) と SρS_\rho は一意に定まります。
  2. (最小性)k(ρ)=min⁡{∣T∣:T⊂V, p(T)≥ρ}k(\rho) = \min\{ |T| : T \subset V,\ p(T) \ge \rho \} です。すなわち SρS_\rho は、確率の和が ρ\rho 以上である集合のうち、大きさが最小のものの 1 つです。
  3. (その大きさの中での最大性)大きさ k(ρ)k(\rho) の集合のうち、SρS_\rho は確率の和が最大です。p1,…,pNp_1, \ldots, p_N がすべて異なるなら、最大を与える集合は SρS_\rho だけです。
  4. (単調性)ρ≤ρ′\rho \le \rho' なら k(ρ)≤k(ρ′)k(\rho) \le k(\rho') で、Sρ⊂Sρ′S_\rho \subset S_{\rho'} です。
  5. (両端)ρ≤pπ(1)\rho \le p_{\pi(1)} なら Sρ={π(1)}S_\rho = \{\pi(1)\} で、これは貪欲復号が選ぶトークンです。ρ=1\rho = 1 なら S1={i:pi>0}S_1 = \{ i : p_i > 0 \} です。
証明(定理 5.4)

1. 「確率の降順、同じ値は添字の昇順」は添字の全順序なので、並び π\pi はただ 1 通りに決まり、c1≤c2≤⋯≤cN=1c_1 \le c_2 \le \cdots \le c_N = 1 も決まります。cN=1≥ρc_N = 1 \ge \rho なので集合 {j:cj≥ρ}\{ j : c_j \ge \rho \} は空でなく、自然数の空でない集合には最小元がただ 1 つあります。したがって k(ρ)k(\rho) が、ひいては SρS_\rho が一意に決まります。

2. SρS_\rho は大きさ k(ρ)k(\rho) で p(Sρ)=ck(ρ)≥ρp(S_\rho) = c_{k(\rho)} \ge \rho なので、右辺の最小値は k(ρ)k(\rho) 以下です。逆に p(T)≥ρp(T) \ge \rho である TT を取り、j=∣T∣j = |T| とすると、補題 5.3 により cj≥p(T)≥ρc_j \ge p(T) \ge \rho です。k(ρ)k(\rho) は cj≥ρc_j \ge \rho となる最小の jj なので k(ρ)≤j=∣T∣k(\rho) \le j = |T| です。したがって最小値は k(ρ)k(\rho) 以上です。

3. 補題 5.3 を j=k(ρ)j = k(\rho) で使ったものです。

4. ρ≤ρ′\rho \le \rho' なら cj≥ρ′c_j \ge \rho' は cj≥ρc_j \ge \rho を含意するので、{j:cj≥ρ′}⊂{j:cj≥ρ}\{ j : c_j \ge \rho' \} \subset \{ j : c_j \ge \rho \} です。小さい集合の最小元は、大きい集合の最小元以上なので k(ρ′)≥k(ρ)k(\rho') \ge k(\rho) です。SρS_\rho と Sρ′S_{\rho'} はどちらも同じ並び π\pi の接頭辞なので、長いほうが短いほうを含みます。

5. c1=pπ(1)≥ρc_1 = p_{\pi(1)} \ge \rho なら k(ρ)=1k(\rho) = 1 です。π(1)\pi(1) は確率が最大の添字のうち最も小さいもので、定義 3.2 の貪欲復号の選び方と同じです。ρ=1\rho = 1 のとき、正の確率を持つ添字の個数を ss とすると、降順の並びでは正の確率のものが初めの ss 個を占めます。j<sj < s では cj=1−∑i>jpπ(i)≤1−pπ(s)<1c_j = 1 - \sum_{i > j} p_{\pi(i)} \le 1 - p_{\pi(s)} < 1、j=sj = s では cs=1c_s = 1 なので k(1)=sk(1) = s で、S1S_1 は正の確率を持つ添字の全体です。

注意 5.5

2 と 3 を合わせても、「大きさが最小で、和が ρ\rho 以上の集合は SρS_\rho だけ」とは言えません。確率がすべて異なっていても成り立ちません。p=(0.5,0.3,0.2)p = (0.5, 0.3, 0.2)、ρ=0.6\rho = 0.6 では k(ρ)=2k(\rho) = 2、Sρ={1,2}S_\rho = \{1, 2\}(和 0.80.8)ですが、{1,3}\{1, 3\} も大きさ 22 で和が 0.7≥0.60.7 \ge 0.6 です。Holtzman らの原論文は top-p の語彙を「和がしきい値以上になる最小の集合」と述べていますが、この条件だけでは集合が 1 つに決まらないことがあり、「確率の大きい順に取る」という規則を合わせて初めて一意になります。実装は、並べ替えて累積を取る 定義 5.1 の形で書くのがふつうです(しきい値ちょうどの扱いや同じ値の並べ方は実装によって違いえます)。

例 5.6(確率 (0.5, 0.2, 0.2, 0.1) の top-p 集合)

p=(0.5,0.2,0.2,0.1)p = (0.5, 0.2, 0.2, 0.1) とします。第 2・第 3 成分が同じ値なので、添字の昇順で π=(1,2,3,4)\pi = (1, 2, 3, 4)、累積は c=(0.5,0.7,0.9,1.0)c = (0.5, 0.7, 0.9, 1.0) です。

  • ρ=0.6\rho = 0.6: c1=0.5<0.6≤c2=0.7c_1 = 0.5 < 0.6 \le c_2 = 0.7 なので k=2k = 2、Sρ={1,2}S_\rho = \{1, 2\}。制限した分布は (0.5,0.2)/0.7=(0.714,0.286)(0.5, 0.2)/0.7 = (0.714, 0.286) です。同じ確率の第 3 成分は、添字が大きいというだけの理由で外れます。{1,3}\{1, 3\} も大きさ 22 で和が 0.70.7 なので、定理 5.4 の 3 の「最大を与える集合はただ 1 つ」は、同じ値があると成り立ちません。
  • ρ=0.9\rho = 0.9: c2=0.7<0.9≤c3=0.9c_2 = 0.7 < 0.9 \le c_3 = 0.9 なので k=3k = 3、Sρ={1,2,3}S_\rho = \{1, 2, 3\}。

top-k で k=2k = 2 とすれば、分布がどうであっても 2 個です。top-p では、分布が (0.97,0.01,0.01,0.01)(0.97, 0.01, 0.01, 0.01) なら ρ=0.9\rho = 0.9 でも 1 個、一様分布 (0.25,0.25,0.25,0.25)(0.25, 0.25, 0.25, 0.25) なら ρ=0.9\rho = 0.9 で 4 個と、分布の形に応じて大きさが変わります。

なお、ρ=0.9\rho = 0.9 の場合は浮動小数点数では別の結果になります。倍精度では 0.5+0.2+0.20.5 + 0.2 + 0.2 が 0.89999999999999990.8999999999999999 と計算され、0.90.9 に届かないので、4 個目まで取られます(次節のコードの出力を見てください)。しきい値ちょうどの場合の集合は、丸め誤差で変わることがあります。

6. 分布から 1 つ選ぶ:標本抽出と決定性

Section titled “6. 分布から 1 つ選ぶ:標本抽出と決定性”

加工した分布 qq(温度を掛け、SS に制限したもの)から実際に 1 つのトークンを選ぶには、一様乱数を 1 つ使います。

命題 6.1(累積和による標本抽出の正しさ)✓

qq を V={1,…,N}V = \{1, \ldots, N\} 上の確率分布、Cj=∑i≤jqiC_j = \sum_{i \le j} q_i(C0=0C_0 = 0、CN=1C_N = 1)とします。UU を区間 (0,1)(0, 1) 上の一様分布に従う確率変数とし、

X=min⁡{j∈V:Cj≥U}X = \min\{ j \in V : C_j \ge U \}

とおくと、すべての jj で P(X=j)=qjP(X = j) = q_j です。計算に必要な比較と加算は O(N)O(N) 回です。

証明(命題 6.1)

CN=1≥UC_N = 1 \ge U なので、最小を取る集合は空でなく、XX は定義されます。X=jX = j であることは、Cj≥UC_j \ge U かつ Cj−1<UC_{j-1} < U(j=1j = 1 のときは C0=0<UC_0 = 0 < U でつねに成立)と同値です。CC は単調非減少なので、i<ji < j のすべてで Ci<UC_i < U であることは Cj−1<UC_{j-1} < U と同じだからです。したがって

P(X=j)=P(Cj−1<U≤Cj)=Cj−Cj−1=qjP(X = j) = P(C_{j-1} < U \le C_j) = C_j - C_{j-1} = q_j

です(一様分布では、区間 (a,b](a, b] に入る確率は長さ b−ab - a です)。

これは逆関数法(定理 3.3[分布からの標本抽出])の離散の場合です。qq の分布関数 F(x)=∑i≤xqiF(x) = \sum_{i \le x} q_i の一般化逆関数(定義 3.1[分布からの標本抽出])は F−(u)=inf⁡{x:F(x)≥u}=min⁡{j:Cj≥u}F^{-}(u) = \inf\{x : F(x) \ge u\} = \min\{ j : C_j \ge u \} で、X=F−(U)X = F^{-}(U) です。累積和の計算に N−1N - 1 回の加算、最小の jj の探索に高々 NN 回の比較を使います。

注意 6.2

同じ分布から何度も標本を取るなら、O(N)O(N) の前処理のあと 1 回あたり O(1)O(1) で取れる別名法(定理 6.2[分布からの標本抽出])があります。しかし言語モデルの生成では、分布は 1 ステップごとに変わり、同じ分布から取る標本は 1 個だけです。前処理が毎回必要になるので、別名法の利点は生きません。そもそも分布を作る softmax の計算が O(N)O(N) で、top-p の並べ替えは O(Nlog⁡N)O(N \log N) なので、標本抽出の O(N)O(N) は全体の中で支配的ではありません。

次のコードは、温度・top-k・top-p・制限・標本抽出をそれぞれ数行で実装し、例 4.3 と 例 5.6 の値、および標本の経験分布が 命題 5.2 の条件付き分布に近づくことを確かめます。

# Python 3.12.14, NumPy 2.5.2
import numpy as np
def softmax(z, tau=1.0):
z = np.asarray(z, dtype=float) / tau
e = np.exp(z - z.max()); return e / e.sum()
def top_k_set(p, k):
return np.argsort(-p, kind="stable")[:k] # 降順、同じ値は添字の昇順
def top_p_set(p, top_p):
order = np.argsort(-p, kind="stable")
c = np.cumsum(p[order])
return order[: int(np.searchsorted(c, top_p, side="left")) + 1] # c_j >= top_p となる最小の j
def restrict(p, S): # S に制限して正規化
q = np.zeros_like(p); q[S] = p[S] / p[S].sum(); return q
def sample(p, rng): # 累積和と一様乱数
return int(np.searchsorted(np.cumsum(p), rng.random(), side="right"))
H = lambda p: float(-(p[p > 0] * np.log(p[p > 0])).sum())
for tau in (0.1, 0.5, 1.0, 2.0, 100.0):
p = softmax([2.0, 1.0, 0.0], tau)
print(f"tau={tau:6.1f} p={np.round(p, 4)} H={H(p):.4f}")
print(f"log 3 = {np.log(3):.4f}")
p = np.array([0.5, 0.2, 0.2, 0.1])
for tp in (0.3, 0.6, 0.9, 1.0):
print(f"top-p={tp}: set={top_p_set(p, tp).tolist()}", end=" ")
print()
print("cumsum:", np.cumsum(p).tolist())
print("top-k=2:", top_k_set(p, 2).tolist())
z = np.array([3.0, 2.5, 1.0, 0.2, -1.0, -2.0]); p = softmax(z, 0.8)
S = top_p_set(p, 0.95); q = restrict(p, S)
rng = np.random.default_rng(20261010); N = 200000
counts = np.bincount([sample(q, rng) for _ in range(N)], minlength=len(p))
print("p :", np.round(p, 4))
print("top-p set:", S.tolist(), " mass:", round(float(p[S].sum()), 4))
print("target q :", np.round(q, 4))
print("empirical:", np.round(counts / N, 4))
print("TV(p, q) :", round(0.5 * float(np.abs(p - q).sum()), 4), " 1 - p(S):", round(1 - float(p[S].sum()), 4))
tau= 0.1 p=[1. 0. 0.] H=0.0005
tau= 0.5 p=[0.8668 0.1173 0.0159] H=0.4411
tau= 1.0 p=[0.6652 0.2447 0.09 ] H=0.8324
tau= 2.0 p=[0.5065 0.3072 0.1863] H=1.0202
tau= 100.0 p=[0.3367 0.3333 0.33 ] H=1.0986
log 3 = 1.0986
top-p=0.3: set=[0] top-p=0.6: set=[0, 1] top-p=0.9: set=[0, 1, 2, 3] top-p=1.0: set=[0, 1, 2, 3]
cumsum: [0.5, 0.7, 0.8999999999999999, 0.9999999999999999]
top-k=2: [0, 1]
p : [0.6038 0.3232 0.0496 0.0182 0.0041 0.0012]
top-p set: [0, 1, 2] mass: 0.9765
target q : [0.6183 0.331 0.0508 0. 0. 0. ]
empirical: [0.6173 0.3322 0.0505 0. 0. 0. ]
TV(p, q) : 0.0235 1 - p(S): 0.0235

コードの添字は 00 始まりです。sample は Cj>UC_j > U となる最小の jj を返す実装で、命題 6.1 の Cj≥UC_j \ge U とは UU がちょうど CjC_j に等しい場合だけ違いますが、その確率は 00 です。2020 万個の標本の経験分布は目標の条件付き分布と小数第 3 位まで合い、全変動距離は 1−p(S)1 - p(S) に一致しています。top-p=0.9 の行は、例 5.6 で述べた丸め誤差の例です。

この最後の点は、生成の再現性にかかわります。次の命題は、乱数の種を固定すれば出力が決まること(1)と、それでも実行環境によって結果が変わりうる理由(2、3)を述べます。3 に出てくる uu は 1 回の演算で生じる誤差の割合の上限(単位丸め)、γk\gamma_k は kk 回の演算を重ねたときの誤差の割合の上限を表す記号です。3 の内容は、足し算の誤差の幅より大きい差がついていれば、足す順序を変えても大小関係は入れ替わらない、ということです。

命題 6.3(生成の決定性と、浮動小数点演算の順序)✓

  1. 重み、プロンプト、復号の設定(温度、kk、ρ\rho、最大長)、一様乱数の列 u1,u2,…u_1, u_2, \ldots を固定し、ロジットの計算が入力の決定的な関数であるとします。このとき自己回帰生成(定義 3.1)の出力は一意に決まります。擬似乱数生成器は種の決定的な関数なので、種を固定すれば出力は再現されます。
  2. 浮動小数点数の加算は結合法則を満たしません。倍精度で (0.1+0.2)+0.3(0.1 + 0.2) + 0.3 は 0.60000000000000010.6000000000000001、0.1+(0.2+0.3)0.1 + (0.2 + 0.3) は 0.60.6 と計算されます。したがって、和を取る順序が変わると、同じ重みと同じ入力でもロジットの値が変わりえます。
  3. あるトークンのロジットが nn 個の浮動小数点数 x1,…,xnx_1, \ldots, x_n の逐次和として計算され、比べる相手のロジット z′z' は固定されているとします。ある順序での計算値 s^\hat{s} が ∣s^−z′∣>2γn−1∑i∣xi∣|\hat{s} - z'| > 2\gamma_{n-1} \sum_i |x_i| を満たすなら、x1,…,xnx_1, \ldots, x_n をどの順序に並べ替えて逐次和を取っても z′z' との大小は変わりません(γk=ku/(1−ku)\gamma_k = ku/(1 - ku)、uu は単位丸め、(n−1)u<1(n-1)u < 1 で、オーバーフローとアンダーフローは起きないとします)。
証明(命題 6.3)

1. ステップ数についての帰納法です。x<tx_{<t} が決まっていれば、ロジット zt\boldsymbol{z}_t はその決定的な関数、加工した分布 qtq_t は zt\boldsymbol{z}_t と設定の関数(定義 4.1、定義 5.1。定理 5.4 の 1 により top-p 集合も一意)、xtx_t は qtq_t と utu_t の関数(命題 6.1 の XX の定義)です。したがって x≤tx_{\le t} が決まります。停止の条件も x≤tx_{\le t} だけで決まります。

2. 倍精度の 0.10.1、0.20.2、0.30.3 はどれも 2 進で有限桁に表せない数を丸めたもので、加算のたびに結果が最も近い浮動小数点数に丸められます(定義 2.2[浮動小数点数と丸め誤差])。丸めが入る位置が 2 つの順序で違うので、結果が違いえます。実際の値は Python で (0.1 + 0.2) + 0.3 と 0.1 + (0.2 + 0.3) を評価して確かめられ、前者は 0.6000000000000001、後者は 0.6 です。

3. s=∑ixis = \sum_i x_i を真の和とします。逐次和の誤差の定理(定理 5.1[浮動小数点数と丸め誤差])は、足す順序によらず、計算値と ss の差が γn−1∑i∣xi∣\gamma_{n-1} \sum_i |x_i| 以下であることを与えます(定理を並べ替えた列に使います。∑i∣xi∣\sum_i |x_i| は順序に依りません)。別の順序での計算値を s^′\hat{s}' とすると、三角不等式から ∣s^−s^′∣≤∣s^−s∣+∣s−s^′∣≤2γn−1∑i∣xi∣|\hat{s} - \hat{s}'| \le |\hat{s} - s| + |s - \hat{s}'| \le 2\gamma_{n-1} \sum_i |x_i| です。s^−z′>2γn−1∑i∣xi∣\hat{s} - z' > 2\gamma_{n-1}\sum_i |x_i| なら s^′−z′≥(s^−z′)−∣s^−s^′∣>0\hat{s}' - z' \ge (\hat{s} - z') - |\hat{s} - \hat{s}'| > 0 で、符号は変わりません。s^−z′\hat{s} - z' が負の場合も同様です。

例 6.4(和の順序で最大成分が入れ替わる)

トークン A のロジットが 0.1,0.2,0.30.1, 0.2, 0.3 の和として計算され、トークン B のロジットがちょうど 0.60.6(倍精度の値)で、B のほうが添字が小さいとします。

  • (0.1+0.2)+0.3(0.1 + 0.2) + 0.3 の順に足すと A は 0.60000000000000010.6000000000000001 で、B の 0.60.6 より大きく、貪欲復号は A を選びます。
  • 0.1+(0.2+0.3)0.1 + (0.2 + 0.3) の順に足すと A は 0.60.6 で B と同じ値になり、同じ値は添字の小さいほうを取る規則により B が選ばれます。

2 つの計算値の差は約 1.1×10−161.1 \times 10^{-16} で、命題 6.3 の 3 の幅 2γ2×0.6≈2.7×10−162\gamma_2 \times 0.6 \approx 2.7 \times 10^{-16} に収まっています。差がこの幅より大きければ入れ替わりは起きません。入れ替わるのは、上位の 2 つがほぼ同じ値のときだけです。ただし自己回帰生成では、1 か所でトークンが変わると、それ以降の入力が変わり、列全体が別のものになりえます。

和の順序は、並列計算のスレッド数、バッチの中での位置、使うハードウェアやライブラリの版によって変わりえます。したがって「種を固定したのに出力が再現しない」ことは、1 の仮定(ロジットの計算が決定的)が実行環境をまたいでは成り立たない、ということで説明がつきます。

定義 3.1 をそのまま実装すると、1 トークン足すたびに、列全体をモデルに入れ直すことになります。因果マスクつきの注意では、その大部分が前のステップと同じ計算の繰り返しです。

この節では、デコーダの 1 層を次の形に書きます(1 ヘッドの場合。マルチヘッドは同じものをヘッドごとに並べるだけです)。位置 tt の層 ℓ\ell の出力を ht(ℓ)∈Rd\boldsymbol{h}^{(\ell)}_t \in \mathbb{R}^d とし、ht(0)\boldsymbol{h}^{(0)}_t はトークン xtx_t の埋め込みと位置 tt の符号化から決まるベクトルとします。層 ℓ\ell は、行ごとに働く写像 κℓ,νℓ,χℓ\kappa_\ell, \nu_\ell, \chi_\ell(層正規化のあとに WK,WV,WQW_K, W_V, W_Q を掛ける)と GℓG_\ell(出力の射影、残差の和、MLP)によって

ks(ℓ)=κℓ(hs(ℓ−1)),vs(ℓ)=νℓ(hs(ℓ−1)),qt(ℓ)=χℓ(ht(ℓ−1)),\boldsymbol{k}^{(\ell)}_s = \kappa_\ell\bigl(\boldsymbol{h}^{(\ell-1)}_s\bigr), \quad \boldsymbol{v}^{(\ell)}_s = \nu_\ell\bigl(\boldsymbol{h}^{(\ell-1)}_s\bigr), \quad \boldsymbol{q}^{(\ell)}_t = \chi_\ell\bigl(\boldsymbol{h}^{(\ell-1)}_t\bigr), ht(ℓ)=Gℓ(ht(ℓ−1), ∑s=1tαts(ℓ) vs(ℓ)),αts(ℓ)=exp⁡(⟨qt(ℓ),ks(ℓ)⟩/d)∑s′=1texp⁡(⟨qt(ℓ),ks′(ℓ)⟩/d)\boldsymbol{h}^{(\ell)}_t = G_\ell\Bigl(\boldsymbol{h}^{(\ell-1)}_t,\ \sum_{s=1}^{t} \alpha^{(\ell)}_{ts}\, \boldsymbol{v}^{(\ell)}_s\Bigr), \qquad \alpha^{(\ell)}_{ts} = \frac{\exp\bigl(\langle \boldsymbol{q}^{(\ell)}_t, \boldsymbol{k}^{(\ell)}_s \rangle / \sqrt{d}\bigr)}{\sum_{s'=1}^{t} \exp\bigl(\langle \boldsymbol{q}^{(\ell)}_t, \boldsymbol{k}^{(\ell)}_{s'} \rangle / \sqrt{d}\bigr)}

と定まります。和が s≤ts \le t だけにわたることが因果マスクです(命題 3.3[自己注意])。これは前章の Pre-LN のブロックを位置ごとに書き下したものです。

記号が多いですが、1 層でしていることは 3 つです。(1) 各位置の入力 h\boldsymbol{h} から、キー・バリュー・クエリを作ります(κℓ,νℓ,χℓ\kappa_\ell, \nu_\ell, \chi_\ell)。(2) 位置 tt のクエリと、位置 tt 以前のキーの内積から重み α\alpha を作り、バリューを重みつきで足します。(3) その結果を元の h\boldsymbol{h} と合わせ、出力の射影・残差・MLP を通して次の層への入力にします(GℓG_\ell)。

定義 7.1(KV キャッシュ)↗

各層 ℓ=1,…,L\ell = 1, \ldots, L について、これまでに処理した位置のキーとバリューの列 (ks(ℓ),vs(ℓ))s≤t\bigl(\boldsymbol{k}^{(\ell)}_s, \boldsymbol{v}^{(\ell)}_s\bigr)_{s \le t} を保存したものを KV キャッシュといいます。キャッシュつきの生成は、新しいトークン xtx_t が決まるたびに、ℓ=1,…,L\ell = 1, \ldots, L の順に次を行います。

  1. ht(ℓ−1)\boldsymbol{h}^{(\ell-1)}_t から kt(ℓ),vt(ℓ),qt(ℓ)\boldsymbol{k}^{(\ell)}_t, \boldsymbol{v}^{(\ell)}_t, \boldsymbol{q}^{(\ell)}_t を計算し、kt(ℓ),vt(ℓ)\boldsymbol{k}^{(\ell)}_t, \boldsymbol{v}^{(\ell)}_t を層 ℓ\ell のキャッシュの末尾に足す。
  2. キャッシュにある s≤ts \le t のキーとバリューを使って αts(ℓ)\alpha^{(\ell)}_{ts} と ht(ℓ)\boldsymbol{h}^{(\ell)}_t を計算する。

位置 tt の 1 行だけを計算し、過去の位置の hs(ℓ)\boldsymbol{h}^{(\ell)}_s(s<ts < t)は計算し直しません。

注意の重み(下三角)キーのキャッシュ(t 行)バリューのキャッシュ(t 行)過去の行は保存済み過去の行は保存済み位置 t で追加位置 t で追加t1
位置 t のトークンを処理するとき、新しく計算するのは注意の重みの第 t 行(色つき)だけである。それより上の行は過去のステップで計算済みで、キーとバリューだけがキャッシュに残っている。

次の定理は、キャッシュを使っても答えが変わらないことを保証します。方針は、因果マスクのおかげで位置 tt の値は tt 以前のトークンだけで決まる、つまり過去の位置の値は新しいトークンが来ても変わらないので、保存したものを使い回せる、というものです。証明では、層の番号と位置の番号についての帰納法でこれを確かめます。

定理 7.2(KV キャッシュの正しさ)✓

上の形の層を LL 個重ねたモデルを考えます。

  1. (因果性)各 ℓ\ell と tt について、ht(ℓ)\boldsymbol{h}^{(\ell)}_t、kt(ℓ)\boldsymbol{k}^{(\ell)}_t、vt(ℓ)\boldsymbol{v}^{(\ell)}_t は x1,…,xtx_1, \ldots, x_t だけの関数です。tt より後のトークンにも、列の全体の長さにも依りません。
  2. (一致)キャッシュつきの生成が位置 tt で計算する ht(ℓ)\boldsymbol{h}^{(\ell)}_t(ℓ=0,…,L\ell = 0, \ldots, L)は、列 x≤tx_{\le t} の全体を入力して計算し直したときの第 tt 行と一致します。したがって位置 tt のロジットと次のトークンの分布も一致します。
証明(定理 7.2)

1. ℓ\ell についての帰納法で、「すべての tt で ht(ℓ)\boldsymbol{h}^{(\ell)}_t は x≤tx_{\le t} の関数である」ことを示します。ℓ=0\ell = 0 では、ht(0)\boldsymbol{h}^{(0)}_t は xtx_t と tt だけで決まります。ℓ−1\ell - 1 で成り立つとします。ks(ℓ),vs(ℓ)\boldsymbol{k}^{(\ell)}_s, \boldsymbol{v}^{(\ell)}_s は hs(ℓ−1)\boldsymbol{h}^{(\ell-1)}_s の関数なので x≤sx_{\le s} の関数です。層の定義の式で ht(ℓ)\boldsymbol{h}^{(\ell)}_t を与える右辺に現れるのは、ht(ℓ−1)\boldsymbol{h}^{(\ell-1)}_t と、s≤ts \le t についての ks(ℓ),vs(ℓ)\boldsymbol{k}^{(\ell)}_s, \boldsymbol{v}^{(\ell)}_s だけです。これらはすべて x≤tx_{\le t} の関数なので、ht(ℓ)\boldsymbol{h}^{(\ell)}_t もそうです。式に tt より大きい添字も列の長さも現れないので、後のトークンにも長さにも依りません。これは因果マスクの定理(定理 6.3[自己注意])と、それがブロック全体で保たれること(命題 7.2[Transformer ブロック])を、位置ごとの式で言い直したものです。

2. tt についての帰納法で示します。位置 tt より前のすべての位置 s<ts < t について、キャッシュに保存された ks(ℓ),vs(ℓ)\boldsymbol{k}^{(\ell)}_s, \boldsymbol{v}^{(\ell)}_s が、列 x≤sx_{\le s} を入力して計算し直したときの値と一致すると仮定します(t=1t = 1 ではキャッシュは空で、仮定は自明に成り立ちます)。1 により、それらは列 x≤tx_{\le t} を入力して計算し直したときの第 ss 行のキーとバリューとも一致します。

位置 tt について、ℓ\ell についての帰納法を使います。ht(0)\boldsymbol{h}^{(0)}_t はどちらの計算でも同じ式(xtx_t の埋め込みと位置 tt の符号化)です。ht(ℓ−1)\boldsymbol{h}^{(\ell-1)}_t が一致するなら、それから計算する kt(ℓ),vt(ℓ),qt(ℓ)\boldsymbol{k}^{(\ell)}_t, \boldsymbol{v}^{(\ell)}_t, \boldsymbol{q}^{(\ell)}_t も一致します。キャッシュの s<ts < t の成分は上の仮定により一致しているので、αts(ℓ)\alpha^{(\ell)}_{ts}(s≤ts \le t)と ∑s≤tαts(ℓ)vs(ℓ)\sum_{s \le t} \alpha^{(\ell)}_{ts} \boldsymbol{v}^{(\ell)}_s が一致し、GℓG_\ell を通した ht(ℓ)\boldsymbol{h}^{(\ell)}_t も一致します。同時に、位置 tt で新しくキャッシュに足した kt(ℓ),vt(ℓ)\boldsymbol{k}^{(\ell)}_t, \boldsymbol{v}^{(\ell)}_t も計算し直した値と一致するので、帰納法の仮定が t+1t + 1 に引き継がれます。ロジットは ht(L)\boldsymbol{h}^{(L)}_t の関数なので、一致します。

証明が使ったのは「層の式に tt より後の添字が現れない」ことだけです。逆に、これが崩れるとキャッシュは使えません。双方向の注意(各位置が後ろも見るもの)では、トークンを足すたびに過去の位置の出力がすべて変わります。また、プロンプトの途中のトークンを 1 つ書き換えると、その位置以降のキャッシュはすべて無効になります。有効なまま残るのは、書き換えた位置より前の部分だけです。

次の定理では、スカラーの乗算の回数を数えます。数え方は、a×ba \times b 行列と b×cb \times c 行列の積が abcabc 回、という 1 つの規則だけです。たとえば位置 tt の 1 行(1×d1 \times d)に d×dd \times d の行列 WQ,WK,WV,WOW_Q, W_K, W_V, W_O を掛けると、1 つあたり d2d^2 回で、4 つ合わせて 4d24d^2 回になります。これが式に出てくる 4d24d^2 の由来です。

定理 7.3(KV キャッシュの計算量と記憶量)✓

1 ヘッドの層(WQ,WK,WV,WOW_Q, W_K, W_V, W_O は d×dd \times d、MLP は d→dff→dd \to d_{\mathrm{ff}} \to d)で、スカラーの乗算の回数を数えます(層正規化、活性化関数、softmax の指数は数えません)。nn 個の位置 t=1,…,nt = 1, \ldots, n を順に処理するとします。

  1. キャッシュつきでは、位置 tt の 1 層の乗算は 2td+4d2+2d dff2td + 4d^2 + 2d\, d_{\mathrm{ff}} 回で、nn 個の合計は
Ccache(n)=d n(n+1)+n (4d2+2d dff)C_{\mathrm{cache}}(n) = d\, n(n+1) + n\,(4d^2 + 2d\, d_{\mathrm{ff}})

です。 2. キャッシュなしで、位置 tt のたびに長さ tt の列全体を計算し直すと、1 層の乗算は 2t2d+t(4d2+2d dff)2t^2 d + t(4d^2 + 2d\, d_{\mathrm{ff}}) 回で、合計は

Cfull(n)=d n(n+1)(2n+1)3+n(n+1)2(4d2+2d dff)C_{\mathrm{full}}(n) = \frac{d\, n(n+1)(2n+1)}{3} + \frac{n(n+1)}{2}(4d^2 + 2d\, d_{\mathrm{ff}})

です。 3. dff=4dd_{\mathrm{ff}} = 4d のとき、Ccache(n)=d n(n+1)+12nd2=O(n2d+nd2)C_{\mathrm{cache}}(n) = d\,n(n+1) + 12 n d^2 = O(n^2 d + n d^2)、Cfull(n)=13d n(n+1)(2n+1)+6d2n(n+1)=O(n3d+n2d2)C_{\mathrm{full}}(n) = \frac{1}{3} d\,n(n+1)(2n+1) + 6 d^2 n(n+1) = O(n^3 d + n^2 d^2) です。 4. キャッシュが保存する数の個数は、LL 層・nn 位置で 2Lnd2 L n d です。

証明(定理 7.3)

a×ba \times b 行列と b×cb \times c 行列の積は abcabc 回の乗算を使います。

1. 位置 tt の 1 行(1×d1 \times d)について、WQ,WK,WVW_Q, W_K, W_V を掛けるのに 3d23d^2 回、qt\boldsymbol{q}_t とキャッシュの tt 個のキーとの内積に tdtd 回、重み αts\alpha_{ts} と tt 個のバリューの積の和に tdtd 回、WOW_O に d2d^2 回、MLP の 2 つの行列に d dff+dff dd\,d_{\mathrm{ff}} + d_{\mathrm{ff}}\,d 回です。合計は 2td+4d2+2d dff2td + 4d^2 + 2d\,d_{\mathrm{ff}} です。t=1,…,nt = 1, \ldots, n について足すと、∑t=1nt=n(n+1)/2\sum_{t=1}^{n} t = n(n+1)/2 から 2d⋅n(n+1)/2+n(4d2+2d dff)2d \cdot n(n+1)/2 + n(4d^2 + 2d\,d_{\mathrm{ff}}) です。

2. 長さ tt の列全体(t×dt \times d)では、WQ,WK,WVW_Q, W_K, W_V に 3td23td^2 回、t×tt \times t の内積の行列に t2dt^2 d 回、重みの行列(t×tt \times t)とバリュー(t×dt \times d)の積に t2dt^2 d 回、WOW_O に td2td^2 回、MLP に 2td dff2td\,d_{\mathrm{ff}} 回で、合計 2t2d+t(4d2+2d dff)2t^2 d + t(4d^2 + 2d\,d_{\mathrm{ff}}) です。∑t=1nt2=n(n+1)(2n+1)/6\sum_{t=1}^{n} t^2 = n(n+1)(2n+1)/6 と ∑t=1nt=n(n+1)/2\sum_{t=1}^{n} t = n(n+1)/2 を使うと主張の式になります。

2 つの和の公式は nn についての帰納法で確かめられます。n=1n = 1 ではどちらも 11 です。nn で成り立つとすると、n(n+1)2+(n+1)=(n+1)(n+2)2\frac{n(n+1)}{2} + (n+1) = \frac{(n+1)(n+2)}{2}、また

n(n+1)(2n+1)6+(n+1)2=(n+1)(2n2+n+6n+6)6=(n+1)(n+2)(2n+3)6\frac{n(n+1)(2n+1)}{6} + (n+1)^2 = \frac{(n+1)\bigl(2n^2 + n + 6n + 6\bigr)}{6} = \frac{(n+1)(n+2)(2n+3)}{6}

で、n+1n + 1 でも成り立ちます。

3. dff=4dd_{\mathrm{ff}} = 4d を入れると 4d2+2d dff=12d24d^2 + 2d\,d_{\mathrm{ff}} = 12d^2 です。n(n+1)≤2n2n(n+1) \le 2n^2、n(n+1)(2n+1)≤6n3n(n+1)(2n+1) \le 6n^3 なので、Ccache(n)≤2n2d+12nd2C_{\mathrm{cache}}(n) \le 2n^2 d + 12nd^2、Cfull(n)≤2n3d+12n2d2C_{\mathrm{full}}(n) \le 2n^3 d + 12 n^2 d^2 で、OO 記法の定義(定義 3.1[計算量と O 記法])と和の規則(命題 3.4[計算量と O 記法])から主張が従います。

4. 各層は位置ごとにキー dd 個とバリュー dd 個の数を保存するので、1 層・1 位置あたり 2d2d 個、全体で 2Lnd2Lnd 個です。

マルチヘッド(hh ヘッド、ヘッドあたりの次元 d/hd/h)でも、内積と重みつき和の乗算はヘッドごとに t⋅d/ht \cdot d/h 回、合わせて tdtd 回ずつで、同じ数になります。

例 7.4(n = 1000, d = 1000 での演算回数)

n=d=1000n = d = 1000、dff=4dd_{\mathrm{ff}} = 4d とします。1 層あたり

Ccache=1000×1000×1001+12×1000×106=1.001×109+1.2×1010≈1.30×1010,C_{\mathrm{cache}} = 1000 \times 1000 \times 1001 + 12 \times 1000 \times 10^6 = 1.001 \times 10^9 + 1.2 \times 10^{10} \approx 1.30 \times 10^{10},Cfull=1000×1000×1001×20013+6×106×1000×1001≈6.68×1011+6.01×1012≈6.67×1012C_{\mathrm{full}} = \frac{1000 \times 1000 \times 1001 \times 2001}{3} + 6 \times 10^6 \times 1000 \times 1001 \approx 6.68 \times 10^{11} + 6.01 \times 10^{12} \approx 6.67 \times 10^{12}

で、比は約 513513 です。キャッシュつきの場合、n=dn = d では注意の項(1.0×1091.0 \times 10^9)は線形写像と MLP の項(1.2×10101.2 \times 10^{10})の 1/121/12 程度にすぎません。nn が 12d12d を超えたあたりで、注意の項のほうが大きくなります。

記憶量は 1 層あたり 2nd=2×1062nd = 2 \times 10^6 個で、LL 層なら 2L×1062L \times 10^6 個です。文脈長 nn に比例して増えます。

Ccache(n)=d n(n+1)+12nd2C_{\mathrm{cache}}(n) = d\,n(n+1) + 12nd^2 は、長さ nn の列を 1 回だけ順伝播する回数 2n2d+12nd22n^2 d + 12 n d^2(2 の t=nt = n の場合)と同じオーダーです(線形写像と MLP の項は同じで、注意の項は約半分です。2 の数え方は因果マスクで捨てる上三角の対も計算しているためです)。キャッシュつきの生成全体の計算量は、できあがった列を 1 回読むのと同じ程度だということになります。プロンプトの部分は、実際には 1 回の順伝播でまとめて処理し、その過程でキャッシュを満たします。

次のコードは、小さなモデル(乱数の重み、L=2L = 2、d=32d = 32)で貪欲復号を 2 通りに実行し、ロジットが一致することと、乗算の回数が 定理 7.3 の式に一致することを確かめます。

# Python 3.12.14, NumPy 2.5.2
import numpy as np
rng = np.random.default_rng(20261010)
V, d, dff, L, n_max = 50, 32, 128, 2, 64
E = rng.normal(0, 0.5, (V, d)); pos = rng.normal(0, 0.5, (n_max, d))
W = [{k: rng.normal(0, d ** -0.5, s) for k, s in
[("q", (d, d)), ("k", (d, d)), ("v", (d, d)), ("o", (d, d)), ("1", (d, dff)), ("2", (dff, d))]}
for _ in range(L)]
count = 0
def mm(a, b): # 行列積。スカラーの乗算の回数を数える
global count
count += a.shape[0] * a.shape[1] * b.shape[1]
return a @ b
def ln(h):
return (h - h.mean(axis=1, keepdims=True)) / np.sqrt(h.var(axis=1, keepdims=True) + 1e-5)
def softmax_rows(S):
A = np.exp(S - S.max(axis=1, keepdims=True)); return A / A.sum(axis=1, keepdims=True)
def forward_full(ids): # キャッシュなし: t 個の位置を全部計算し直す
t = len(ids); h = E[ids] + pos[:t]
mask = np.triu(np.full((t, t), -np.inf), 1)
for w in W:
a = ln(h); q, k, v = mm(a, w["q"]), mm(a, w["k"]), mm(a, w["v"])
A = softmax_rows(mm(q, k.T) / np.sqrt(d) + mask)
h = h + mm(mm(A, v), w["o"])
h = h + mm(np.maximum(mm(ln(h), w["1"]), 0), w["2"])
return ln(h)[-1] @ E.T # 最後の位置のロジット
def forward_cached(tok, t, cache): # キャッシュあり: 位置 t の 1 行だけ計算する
h = (E[tok] + pos[t])[None, :]
for w, c in zip(W, cache):
a = ln(h); q = mm(a, w["q"])
c["k"].append(mm(a, w["k"])[0]); c["v"].append(mm(a, w["v"])[0])
K, Vm = np.array(c["k"]), np.array(c["v"])
A = softmax_rows(mm(q, K.T) / np.sqrt(d)) # 過去と自分だけ。マスクは不要
h = h + mm(mm(A, Vm), w["o"])
h = h + mm(np.maximum(mm(ln(h), w["1"]), 0), w["2"])
return ln(h)[0] @ E.T
for n in (8, 16, 32, 64):
ids = [7]; count = 0; logits_full = []
for t in range(n): # 貪欲復号で n 個の位置を処理
z = forward_full(np.array(ids)); logits_full.append(z); ids.append(int(z.argmax()))
c_full = count
ids2 = [7]; count = 0; cache = [{"k": [], "v": []} for _ in range(L)]; diff = 0.0
for t in range(n):
z = forward_cached(ids2[-1], t, cache); diff = max(diff, float(np.abs(z - logits_full[t]).max()))
ids2.append(int(z.argmax()))
c_cache = count
f_cache = L * (d * n * (n + 1) + 12 * n * d * d)
f_full = L * (d * n * (n + 1) * (2 * n + 1) // 3 + 6 * d * d * n * (n + 1))
print(f"n={n:3d} same tokens={ids == ids2} max|dlogit|={diff:.1e} "
f"mults full={c_full:>10,} cached={c_cache:>9,} ratio={c_full / c_cache:6.2f} "
f"formula ok={c_full == f_full and c_cache == f_cache}")
print("cache size (numbers):", sum(len(c["k"]) * d + len(c["v"]) * d for c in cache), "= 2*L*n*d =", 2 * L * 64 * d)
n= 8 same tokens=True max|dlogit|=8.9e-15 mults full= 910,848 cached= 201,216 ratio= 4.53 formula ok=True
n= 16 same tokens=True max|dlogit|=8.9e-15 mults full= 3,533,824 cached= 410,624 ratio= 8.61 formula ok=True
n= 32 same tokens=True max|dlogit|=8.9e-15 mults full=14,440,448 cached= 854,016 ratio= 16.91 formula ok=True
n= 64 same tokens=True max|dlogit|=8.9e-15 mults full=62,566,400 cached=1,839,104 ratio= 34.02 formula ok=True
cache size (numbers): 8192 = 2*L*n*d = 8192

生成されたトークンは 2 通りで同じで、ロジットの差は 10−1410^{-14} 程度です。数学的には一致する(定理 7.2)2 つの計算が、ぴったり 00 の差にならないのは、行列全体で計算するときと 1 行ずつ計算するときとで、浮動小数点演算の順序が違うからです(命題 6.3 の 2)。乗算の回数は式と完全に一致し、比は nn にほぼ比例して大きくなっています。

学習済みの重みは、ふつう 32 ビットか 16 ビットの浮動小数点数で保存されます。これをより少ないビット数の整数に丸めて、記憶量と計算量を減らすのが量子化です。

定義 8.1(一様量子化)↗

a>0a > 0、整数 b≥1b \ge 1 に対して、刻みを Δ=2a2b−1\Delta = \dfrac{2a}{2^b - 1} とし、区間 [−a,a][-a, a] の上の 2b2^b 個の水準 ℓj=−a+jΔ\ell_j = -a + j\Delta(j=0,1,…,2b−1j = 0, 1, \ldots, 2^b - 1)を取ります。w∈[−a,a]w \in [-a, a] を、最も近い水準(同じ距離のものが 2 つあるときはどちらか)に移す写像 QQ を bb ビットの一様量子化、w−Q(w)w - Q(w) を量子化誤差といいます。行列には成分ごとに適用します。保存するのは番号 jj(bb ビットの整数)と、行列ごとの aa だけです。

次の命題は、重みを丸めたときの誤差がどれだけになりうるかの最悪値を与えます。2 に出てくるフロベニウスノルム ∥W∥F\|W\|_F は、行列の全成分の二乗和の平方根のことです。2 の 2 番目の不等式は、丸めた行列を掛けたときの出力ベクトルのずれも、同じ量で上から押さえられることを言っています。

命題 8.2(一様量子化の誤差の上界)✓

定義 8.1 の記号のもとで、次が成り立ちます。

  1. すべての w∈[−a,a]w \in [-a, a] で ∣w−Q(w)∣≤Δ/2|w - Q(w)| \le \Delta / 2 です。
  2. 成分がすべて [−a,a][-a, a] に入る W∈Rm×nW \in \mathbb{R}^{m \times n} について ∥W−Q(W)∥F≤Δ2mn\|W - Q(W)\|_F \le \dfrac{\Delta}{2} \sqrt{mn} で、任意の x∈Rn\boldsymbol{x} \in \mathbb{R}^n について ∥(W−Q(W))x∥≤Δ2mn ∥x∥\|(W - Q(W))\boldsymbol{x}\| \le \dfrac{\Delta}{2} \sqrt{mn}\, \|\boldsymbol{x}\| です。
  3. bb ビットの刻みを Δb\Delta_b と書くと、Δb+1Δb=2b−12b+1−1<12\dfrac{\Delta_{b+1}}{\Delta_b} = \dfrac{2^b - 1}{2^{b+1} - 1} < \dfrac{1}{2} で、b→∞b \to \infty のとき 12\dfrac{1}{2} に収束します。
  4. 量子化誤差 ee が区間 [−Δ/2,Δ/2][-\Delta/2, \Delta/2] 上の一様分布に従うという模型のもとでは、E[e]=0\mathbb{E}[e] = 0、Var(e)=Δ2/12\mathrm{Var}(e) = \Delta^2 / 12 です。
証明(命題 8.2)

1. ℓ0=−a\ell_0 = -a、ℓ2b−1=−a+(2b−1)Δ=a\ell_{2^b - 1} = -a + (2^b - 1)\Delta = a なので、水準は [−a,a][-a, a] を長さ Δ\Delta の 2b−12^b - 1 個の小区間 [ℓj,ℓj+1][\ell_j, \ell_{j+1}] に分けます。ww はそのどれかに入ります。w−ℓjw - \ell_j と ℓj+1−w\ell_{j+1} - w は非負で和が Δ\Delta なので、小さいほうは Δ/2\Delta/2 以下です。Q(w)Q(w) は最も近い水準なので、∣w−Q(w)∣≤min⁡(w−ℓj,ℓj+1−w)≤Δ/2|w - Q(w)| \le \min(w - \ell_j, \ell_{j+1} - w) \le \Delta/2 です。

2. E=W−Q(W)E = W - Q(W) とおくと、1 から各成分は ∣Eij∣≤Δ/2|E_{ij}| \le \Delta/2 です。∥E∥F2=∑i,jEij2≤mn Δ2/4\|E\|_F^2 = \sum_{i,j} E_{ij}^2 \le mn\, \Delta^2 / 4 で、平方根を取れば最初の不等式です。EE の第 ii 行を ei\boldsymbol{e}_i とすると、(Ex)i=⟨ei,x⟩(E\boldsymbol{x})_i = \langle \boldsymbol{e}_i, \boldsymbol{x} \rangle で、コーシー・シュワルツの不等式(定理 4.2[内積空間とグラム・シュミット直交化])から (Ex)i2≤∥ei∥2∥x∥2(E\boldsymbol{x})_i^2 \le \|\boldsymbol{e}_i\|^2 \|\boldsymbol{x}\|^2 です。ii について足すと ∥Ex∥2≤∑i∥ei∥2 ∥x∥2=∥E∥F2∥x∥2\|E\boldsymbol{x}\|^2 \le \sum_i \|\boldsymbol{e}_i\|^2\, \|\boldsymbol{x}\|^2 = \|E\|_F^2 \|\boldsymbol{x}\|^2 で、最初の不等式と合わせて 2 番目の不等式です。

3. Δb+1/Δb=2a2b+1−1⋅2b−12a=2b−12b+1−1\Delta_{b+1} / \Delta_b = \dfrac{2a}{2^{b+1} - 1} \cdot \dfrac{2^b - 1}{2a} = \dfrac{2^b - 1}{2^{b+1} - 1} です。2(2b−1)=2b+1−2<2b+1−12(2^b - 1) = 2^{b+1} - 2 < 2^{b+1} - 1 なので、この比は 1/21/2 より小さくなります。分子と分母を 2b2^b で割ると 1−2−b2−2−b\dfrac{1 - 2^{-b}}{2 - 2^{-b}} で、b→∞b \to \infty のとき 1/21/2 に収束します。

4. 一様分布の密度は 1/Δ1/\Delta です。密度が原点について対称なので E[e]=∫−Δ/2Δ/2eΔ de=0\mathbb{E}[e] = \int_{-\Delta/2}^{\Delta/2} \frac{e}{\Delta}\, de = 0 で、

Var(e)=E[e2]=∫−Δ/2Δ/2e2Δ de=1Δ⋅23(Δ2)3=Δ212\mathrm{Var}(e) = \mathbb{E}[e^2] = \int_{-\Delta/2}^{\Delta/2} \frac{e^2}{\Delta}\, de = \frac{1}{\Delta} \cdot \frac{2}{3} \Bigl(\frac{\Delta}{2}\Bigr)^3 = \frac{\Delta^2}{12}

です(分散の定義は 定義 5.1[確率変数と期待値])。

1〜3 は仮定のない上界です。4 は模型の中での計算で、誤差が一様に分布するという仮定は、重みの分布が刻みに比べてなだらかなときの近似です。この模型では E∥W−Q(W)∥F2=mnΔ2/12\mathbb{E}\|W - Q(W)\|_F^2 = mn\Delta^2/12 となり、典型的な誤差 Δmn/12\Delta\sqrt{mn/12} は 2 の上界の 1/3≈0.581/\sqrt{3} \approx 0.58 倍です。

例 8.3(8 ビットと 4 ビットの誤差の上界)

a=1a = 1 とします。

  • b=8b = 8: 水準は 256256 個、Δ=2/255≈0.00784\Delta = 2/255 \approx 0.00784、1 成分の誤差は Δ/2≈0.0039\Delta/2 \approx 0.0039 以下。
  • b=4b = 4: 水準は 1616 個、Δ=2/15≈0.133\Delta = 2/15 \approx 0.133、誤差は 0.0670.067 以下。
  • b=2b = 2: 水準は 44 個(−1,−1/3,1/3,1-1, -1/3, 1/3, 1)、Δ=2/3\Delta = 2/3、誤差は 0.330.33 以下。

ビット数を半分にすると、上界は 22 分の 11 ではなく、8→48 \to 4 で 1717 倍、4→24 \to 2 で 55 倍になります。1 ビット減らすごとに約 22 倍なので、4 ビット減らせば約 242^4 倍です。

水準の数 2b2^b は偶数で、水準は原点について対称に並ぶので、00 は水準になりません(−a+jΔ=0-a + j\Delta = 0 は j=(2b−1)/2j = (2^b - 1)/2 を要求しますが、これは整数ではありません)。00 に最も近い水準は ±Δ/2\pm\Delta/2 です。実際の方式には、00 を正確に表せるように水準をずらすもの(Jacob らの方式はその 1 つです)があります。

# Python 3.12.14, NumPy 2.5.2
import numpy as np
rng = np.random.default_rng(20261010)
def quantize(W, a, b):
"""[-a, a] を 2^b 個の等間隔の水準に分け、最も近い水準に丸める。"""
delta = 2 * a / (2 ** b - 1)
j = np.clip(np.round((W + a) / delta), 0, 2 ** b - 1) # 水準の番号(b ビットの整数)
return -a + j * delta, delta
m, n = 64, 48
W = rng.normal(0, 0.05, (m, n)); x = rng.normal(size=n)
a = float(np.abs(W).max())
print(f"a = max|W| = {a:.4f}")
print(" b delta max|err| delta/2 ||W-Q||_F bound delta*sqrt(mn/12) ||(W-Q)x|| bound")
for b in (8, 4, 2):
Q, delta = quantize(W, a, b); Err = W - Q
print(f"{b:2d} {delta:8.5f} {np.abs(Err).max():8.5f} {delta/2:8.5f} {np.linalg.norm(Err):9.5f} "
f"{delta/2*np.sqrt(m*n):8.5f} {delta*np.sqrt(m*n/12):12.5f} {np.linalg.norm(Err@x):12.5f} "
f"{delta/2*np.sqrt(m*n)*np.linalg.norm(x):8.5f}")
# 外れ値が 1 つあると、範囲 a が広がって刻みが粗くなる
W2 = W.copy(); W2[0, 0] = 1.0
for a2 in (float(np.abs(W2).max()), a):
Q2, delta2 = quantize(W2, a2, 4); Err2 = W2 - Q2
print(f"b=4, a={a2:.4f}: delta={delta2:.5f} ||W-Q||_F={np.linalg.norm(Err2):.5f} "
f"distinct levels used={len(np.unique(Q2))} error at outlier={abs(Err2[0, 0]):.4f}")
a = max|W| = 0.1753
b delta max|err| delta/2 ||W-Q||_F bound delta*sqrt(mn/12) ||(W-Q)x|| bound
8 0.00137 0.00069 0.00069 0.02211 0.03810 0.02200 0.02166 0.28016
4 0.02337 0.01168 0.01169 0.37493 0.64773 0.37397 0.41510 4.76279
2 0.11687 0.05842 0.05843 1.90140 3.23866 1.86984 2.34504 23.81393
b=4, a=1.0000: delta=0.13333 ||W-Q||_F=2.21452 distinct levels used=5 error at outlier=0.0000
b=4, a=0.1753: delta=0.02337 ||W-Q||_F=0.90588 distinct levels used=16 error at outlier=0.8247

読み取れることは次のとおりです。

  • 1 成分の誤差の最大値は、どのビット数でも Δ/2\Delta/2 にほぼ届いていて、命題 8.2 の 1 の上界はこれ以上改善できません。
  • フロベニウスノルムの実測値は、上界 Δ2mn\frac{\Delta}{2}\sqrt{mn} の約 0.580.58 倍で、一様分布の模型の値 Δmn/12\Delta\sqrt{mn/12} とよく合っています。
  • ∥(W−Q)x∥\|(W - Q)\boldsymbol{x}\| の上界は実測の 1010 倍以上で、かなり緩い評価です。上界は誤差の符号がすべて x\boldsymbol{x} と揃う最悪の場合を想定していますが、実際の誤差は符号がばらばらで、打ち消し合うからです。
  • 最後の 2 行は範囲 aa の選び方の例です。1.01.0 という外れ値が 1 つ入った行列を、a=max⁡∣W∣=1a = \max |W| = 1 で 4 ビットに量子化すると、1616 個の水準のうち 55 個しか使われず、誤差は 2.212.21 になります。aa を外れ値を除いた最大値 0.1750.175 にして外れ値を切り詰めると、外れ値 1 つに 0.820.82 の誤差が出る代わりに、全体の誤差は 0.910.91 に減ります。範囲の決め方は誤差に大きく効きますが、どの決め方が良いかは重みの分布に依ります。

量子化したモデルの出力がどれだけ変わるかは、この上界を層の数だけ重ねても良い評価になりません(誤差が非線形の層を通って伝わるため)。何ビットまで落として実用になるかは、モデルと課題ごとに測るしかない経験的な問いです。

9. この章で扱わなかった復号の工夫

Section titled “9. この章で扱わなかった復号の工夫”

注意 9.1

実際の生成では、ここまでの操作のほかに次のようなものが使われます。いずれも「ロジットか候補の集合を加工してから選ぶ」という同じ枠の中にあります。

  • 繰り返しへのペナルティ: すでに出力したトークンのロジットを下げます。定理 4.2 の 3 と違い、成分の順位を変える操作です。
  • 長さの正規化: ビーム探索で、列の確率の対数を長さで割って比べます。確率は因子を掛けるほど小さくなるので、正規化しないと短い列が有利になります。
  • 制約つき復号: 出力が決まった書式(たとえばある文法)に従うように、その時点で文法上許されるトークンの集合 SS に分布を制限します。命題 5.2 がそのまま当てはまり、SS の中の確率の比は保たれます。
  • 投機的復号: 小さなモデルで数トークン先まで下書きし、大きなモデルで検証して受け入れるか決める方法です。

これらの既定値や組み合わせは実装ごとに違い、変わりうるので、ここでは挙げません。

演習 10.1易

ロジットが z=(1,0)\boldsymbol{z} = (1, 0) の 2 トークンの分布を考えます。温度 τ\tau の分布で第 1 成分の確率がちょうど 0.90.9 になる τ\tau を求めてください。また τ=1\tau = 1 のときの確率とエントロピーを求め、求めた τ\tau でのエントロピーと比べてください。

解答

pτ,1=e1/τe1/τ+1=0.9p_{\tau,1} = \dfrac{e^{1/\tau}}{e^{1/\tau} + 1} = 0.9 から e1/τ=9e^{1/\tau} = 9、τ=1/log⁡9≈0.455\tau = 1/\log 9 \approx 0.455 です。

τ=1\tau = 1 では p=(e/(e+1),1/(e+1))≈(0.731,0.269)p = (e/(e+1), 1/(e+1)) \approx (0.731, 0.269) で、H=−0.731log⁡0.731−0.269log⁡0.269≈0.229+0.353=0.582H = -0.731 \log 0.731 - 0.269 \log 0.269 \approx 0.229 + 0.353 = 0.582 です。τ=0.455\tau = 0.455 では p=(0.9,0.1)p = (0.9, 0.1) で、H=−0.9log⁡0.9−0.1log⁡0.1≈0.095+0.230=0.325H = -0.9 \log 0.9 - 0.1 \log 0.1 \approx 0.095 + 0.230 = 0.325 です。温度を下げたのでエントロピーは減っていて、定理 4.2 の 4 と合います。

演習 10.2標準

p=(0.4,0.3,0.15,0.1,0.05)p = (0.4, 0.3, 0.15, 0.1, 0.05) とします。ρ=0.5,0.8,0.95\rho = 0.5, 0.8, 0.95 のそれぞれについて top-p 集合 SρS_\rho を求めてください。ρ=0.8\rho = 0.8 について、制限した分布と、元の分布との全変動距離を求めてください。

解答

確率はすでに降順で、累積は c=(0.4,0.7,0.85,0.95,1.0)c = (0.4, 0.7, 0.85, 0.95, 1.0) です。

  • ρ=0.5\rho = 0.5: c1=0.4<0.5≤c2c_1 = 0.4 < 0.5 \le c_2 なので Sρ={1,2}S_\rho = \{1, 2\}。
  • ρ=0.8\rho = 0.8: c2=0.7<0.8≤c3=0.85c_2 = 0.7 < 0.8 \le c_3 = 0.85 なので Sρ={1,2,3}S_\rho = \{1, 2, 3\}。
  • ρ=0.95\rho = 0.95: c3=0.85<0.95≤c4=0.95c_3 = 0.85 < 0.95 \le c_4 = 0.95 なので Sρ={1,2,3,4}S_\rho = \{1, 2, 3, 4\}。

ρ=0.8\rho = 0.8 では p(Sρ)=0.85p(S_\rho) = 0.85 で、制限した分布は (0.4,0.3,0.15)/0.85≈(0.471,0.353,0.176)(0.4, 0.3, 0.15)/0.85 \approx (0.471, 0.353, 0.176)、残りは 00 です。全変動距離は 命題 5.2 の 3 から 1−0.85=0.151 - 0.85 = 0.15 で、1−ρ=0.21 - \rho = 0.2 以下です。

演習 10.3標準

L=12L = 12、d=768d = 768、dff=4dd_{\mathrm{ff}} = 4d のモデルで、n=1024n = 1024 個の位置を処理したとします。(1) KV キャッシュが保存する数の個数と、1 個を 4 バイトで持つときのバイト数を求めてください。(2) キャッシュつきで t=1024t = 1024 番目の位置を処理するときの 1 層の乗算の回数を求め、そのうち注意(内積と重みつき和)が占める割合を答えてください。

解答

(1) 定理 7.3 の 4 から 2Lnd=2×12×1024×768=18,874,3682Lnd = 2 \times 12 \times 1024 \times 768 = 18{,}874{,}368 個で、4 バイトずつなら 75,497,47275{,}497{,}472 バイト(約 75.575.5 MB)です。

(2) 定理 7.3 の 1 から 2td+12d2=2×1024×768+12×7682=1,572,864+7,077,888=8,650,7522td + 12d^2 = 2 \times 1024 \times 768 + 12 \times 768^2 = 1{,}572{,}864 + 7{,}077{,}888 = 8{,}650{,}752 回です。注意の部分は 1,572,8641{,}572{,}864 回で、約 18%18\% です。この大きさの nn と dd では、1 ステップの計算の大部分は線形写像と MLP です。

演習 10.4標準

a=1a = 1、b=3b = 3 の一様量子化の水準をすべて書き、Q(0.2)Q(0.2) と Q(0.5)Q(0.5) を求めてください。また、∣w−Q(w)∣=Δ/2|w - Q(w)| = \Delta/2 となる ww を 1 つ挙げ、命題 8.2 の 1 の上界が達成されることを確かめてください。

解答

Δ=2/7\Delta = 2/7 で、水準は −1,−5/7,−3/7,−1/7,1/7,3/7,5/7,1-1, -5/7, -3/7, -1/7, 1/7, 3/7, 5/7, 1 の 88 個です。

0.20.2 は 1/7≈0.1431/7 \approx 0.143 と 3/7≈0.4293/7 \approx 0.429 の間にあり、1/71/7 までの距離は 0.0570.057、3/73/7 までは 0.2290.229 なので Q(0.2)=1/7Q(0.2) = 1/7 です。0.50.5 は 3/7≈0.4293/7 \approx 0.429 と 5/7≈0.7145/7 \approx 0.714 の間で、距離は 0.0710.071 と 0.2140.214 なので Q(0.5)=3/7Q(0.5) = 3/7 です。

w=0w = 0 は −1/7-1/7 と 1/71/7 のちょうど中間で、どちらに丸めても ∣w−Q(w)∣=1/7=Δ/2|w - Q(w)| = 1/7 = \Delta/2 です。例 8.3 で見たとおり 00 は水準でなく、上界がちょうど達成される点になっています。

  • A. Holtzman, J. Buys, L. Du, M. Forbes, Y. Choi, “The Curious Case of Neural Text Degeneration”, ICLR 2020, arXiv:1904.09751 — nucleus(top-p)サンプリングの定義と、確率を最大化する復号についての観察。
  • A. Fan, M. Lewis, Y. Dauphin, “Hierarchical Neural Story Generation” (2018), arXiv:1805.04833 — top-k サンプリングを使った生成。
  • I. Sutskever, O. Vinyals, Q. V. Le, “Sequence to Sequence Learning with Neural Networks” (2014), arXiv:1409.3215 — ビーム探索による復号。
  • 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 — 因果マスクつきのデコーダ。
  • B. Jacob, S. Kligys, B. Chen, M. Zhu, M. Tang, A. Howard, H. Adam, D. Kalenichenko, “Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference” (2017), arXiv:1712.05877 — 整数演算だけで推論するための量子化。

このテーマの 100 本ノック(50 問)

執筆: Claude Code(Opus 5.5)、Claude Code(Sonnet 5.5)・監査 2 回(Claude Code)・最終 2026-10-12

この記事の誤りを報告する ・運営: 夢現技研合同会社 ・料金 ・利用条件 ・特定商取引法に基づく表記

© 2026 夢現技研合同会社 ・コード例は MIT ライセンスです。