LLMへ文章を渡してから、次の一トークンが選ばれるまでには、種類の違う数値が何段階も登場します。トークンID、埋め込み、各層の表現、Attentionの重み、logit、確率は、すべて数値ですが役割は同じではありません。
この記事では、自己回帰型Transformerの推論の流れを追います。文字列をID列へ変え、各位置の表現を更新し、処理済みのKとVを再利用して、次のIDを選ぶまでを説明します。モデルごとの差がある箇所は、共通する範囲に絞ります。
対応するショート「LLMのトークンIDは、意味の近さを表す番号ではない」では、数値を混同しないための入口を短く整理しました。この記事は、同じ流れを図と架空例まで広げて説明します。
まず全体像
文章はモデル固有のID列になる
トークナイザーは文字列をモデルが扱う単位へ分け、各トークンを語彙表のIDへ変換します。トークンは単語一つとは限りません。単語の一部、記号、バイト列、文頭・文末などを示す特殊トークンも含まれます。
たとえば、次の対応は仕組みを説明するための架空例です。
| 段階 | 説明用の値 |
|---|---|
| 入力文字列 | 雨が降る |
| トークン列 | [雨] [が] [降] [る] |
| ID列 | [81, 204, 57, 19] |
実際の分割とIDは、使用するモデルとトークナイザーによって変わります。この例のIDは実在するモデルの出力ではありません。
IDの役割は、語彙表のどの項目かを指定することです。ID 81と82が近い番号でも、二つのトークンの意味が近いとは限りません。モデルはIDを使って埋め込み層を参照し、トークンごとの初期ベクトルを得ます。
ここでいうトークン埋め込みと、意味検索で使う文章埋め込みも別物です。前者はモデル内部の処理を始める各位置の表現です。後者は、文章や段落を一つのベクトルとして比較する用途があります。
同じ「埋め込み」という名前だけで、数値の単位や目的を同一視できません。
参考:Tokenizer — Hugging Face Transformers、Semantic Textual Similarity — Sentence Transformers
各トークンのベクトルは層ごとに更新される
モデルは位置情報を計算のどこかへ組み込みます。埋め込みへ加算する方式もあれば、Attention内のQとKへ位置情報を組み込む方式もあります。
Transformerのブロックは、Attentionだけで構成されるわけではありません。代表的には、次の処理を組み合わせます。
- Self-Attention:その位置自身を含む、参照可能な位置から情報を集める
- Feed Forward Network:各位置の表現を個別に変換する
- 残差接続:ブロックへ入った表現と処理結果を組み合わせる
- 正規化:層を重ねた計算を扱いやすくする
これらの処理を通るたび、各位置のベクトルは周囲の文脈を反映した表現へ更新されます。正規化をAttentionの前後どちらへ置くか、どのAttention方式を使うかなど、細かな構成はモデルごとに確認が必要です。
したがって、一つのトークンに対応する数値を追うときも、「埋め込み層から取り出した直後」なのか「何層目かを通った後」なのかを区別します。同じ位置を表すベクトルでも、層が違えば中身は変わります。
参考:Attention Is All You Need、RoFormer: Enhanced Transformer with Rotary Position Embedding
AttentionはQとKで重みを作り、Vを混ぜる
Self-Attentionは、トークンIDの大小を比べて参照先を決めているわけではありません。各位置の現在の表現を別々の重みで変換し、Query(Q)、Key(K)、Value(V)を作ります。
Scaled Dot-Product Attentionの基本形は、次の順序です。
- 各位置のQと、参照候補のKの内積を計算する
- ベクトルの次元に応じてスコアを調整する
- 参照できない位置をマスクする
- softmaxで参照先ごとの重みへ変換する
- その重みでVを混ぜる
QとKは、どの位置をどれだけ参照するかを決める側です。Vは、参照先から取り込む情報を担います。
自己回帰型の生成では、未来の位置を参照しないように因果マスクを使います。その位置自身は参照できます。
実際のLLMでは、この計算を複数のヘッドに分けるほか、KとVのヘッドを共有する構成などもあります。それでも、IDそのものではなく、層の途中にある表現からQ、K、Vを作るという区別が重要です。
生成では処理済みのKとVを再利用する
自己回帰型のLLMは、入力プロンプトを処理したあと、原則として次のトークンを一つずつ生成します。新しいトークンが増えるたびに過去の全位置のKとVを計算し直すと、同じ計算が繰り返されます。
KVキャッシュでは、入力プロンプトを含む処理済みの位置のKとVを、層ごとに保存します。次のトークンでは新しいQ、K、Vを計算し、保存済みのK、Vと合わせます。新しいKとVもキャッシュへ追加します。
KVキャッシュが保存するのは、文章そのものの代わりになるデータではありません。すでに処理した位置の表現から各層で作ったKとVです。トークンID列や入力文字列をシステムが別に保持することとは、役割を分けて考えます。
再計算を減らせる一方で、キャッシュはトークン数や層数などに応じてメモリを使います。モデルによっては参照範囲を制限するため、すべての位置を保持し続けません。
キャッシュを固定長にする、圧縮する、CPUへ移すといった方式でも、速度とメモリの関係が変わります。
参考:Caching — Hugging Face Transformers、Cache strategies — Hugging Face Transformers
logitと生成設定から次のIDを選ぶ
Transformerの最後の表現から、語彙にある各トークン候補のlogitを計算します。logitは確率へ変換する前のスコアです。ここからどのIDを選ぶかは、生成方式と設定によって変わります。
| 設定・方式 | 何をするか | 混同しやすい点 |
|---|---|---|
| greedy decoding | 最も高いスコアの候補を選ぶ | ランダムな抽選ではない |
| temperature | サンプリングに使う確率分布の集中度を変える | 候補を選ぶ方式そのものではない |
| top-k | 上位k個の候補を残す | k個すべてを出力するわけではない |
| top-p | 累積確率が指定値へ達する最小の候補集合を残す | 残る候補数は毎回一定ではない |
サンプリングでは、temperatureで調整したlogitを確率へ変えます。必要に応じてtop-kやtop-pで候補を絞り、その分布から次のトークンを選びます。
実装によって処理順や同時に使える設定は異なります。具体的な挙動を調べるときは、実行環境の仕様も確認します。
temperatureを低くすると、高いスコアの候補へ確率が集まりやすくなります。高くすると、確率が広がりやすくなります。
temperatureはモデルの知識を増やしません。値を下げても、回答が必ず正確になるわけではありません。
選ばれたIDを入力列へ追加し、次のlogitを計算します。このループは、文末などの停止トークン、最大生成長、実行環境が定めた停止条件のいずれかに達するまで続きます。
参考:Generation — Hugging Face Transformers
数値を混同しないための確認順
モデルの説明、デバッグ出力、実行ログを読むときは、数値を次の順で切り分けると混同を減らせます。
- トークナイザーの出力:文字列がどのトークンへ分かれ、どのIDになったか
- モデルへ入る表現:IDから得た埋め込みへ、位置情報をどの段階・形状で組み込むか
- 層の途中の表現:何層目の中間表現か、Q、K、Vのどれか、どのマスクを使うか
- キャッシュ:どの層・位置のKとVを保持し、どこまで再利用するか
- 生成処理:語彙全体のlogitへ、どの方式と設定を適用して次のIDを選ぶか
IDの差を意味の距離として読まないことが重要です。Attentionの重みを、トークンIDの直接比較だと思わないことも重要です。
temperatureをモデル自体の能力変更だと思わず、これらを別物として扱えば、数値を読み違えにくくなります。
まとめ
LLMの推論は、文字列をモデル固有のトークンID列へ変えるところから始まります。IDを使って初期ベクトルを取り出し、Transformerの層で文脈を反映した表現へ更新します。
Attentionは中間表現から参照先の重みを求め、KVキャッシュは処理済みの計算を再利用します。最後に語彙全体のlogitから次のIDを選び、同じ流れを繰り返します。
「いま見ている数値は、どの段階の何を表すのか」を先に確かめれば、トークン、埋め込み、Attention、キャッシュ、生成設定を一つの意味へまとめずに読めます。