ハクソク

世界を動かす技術を、日本語で。

Q, K, V行列

概要

  • LLMのアテンション機構の中心はQuery、Key、Valueの3つの行列
  • Q、K、V行列の役割と構築方法を具体例とともに解説
  • TransformerがRNNと異なる点やアテンションの直感的理解
  • Q、K、V行列の重み行列の意味や次元選択の影響
  • 実際のアテンション計算の流れとQKV行列の役割を整理

LLMのアテンション機構とQ、K、V行列の基礎

  • Query、Key、Value行列は、Transformerが入力系列内の異なる単語間に注意を向けるための基盤
  • 人間が「The cat sat on the mat because it was comfortable.」の“it”が“the mat”を指すと理解するのと同様の文脈把握機構
  • 従来のRNNはトークンを一つずつ処理し、隠れ状態で情報を伝搬
    • 例:「The」→h1、「cat」→h2(h1とcatの情報)、…と逐次処理
  • Transformerはアテンションにより、全単語を同時に処理し、各単語が他の単語すべてを直接参照可能
    • 例:「sat」は「cat」に60%の強い注意、「on」に15%の注意など、並列的な関係把握
  • この仕組みにより、学習効率向上と遠距離依存関係の捕捉が可能

アテンションの直感とQ、K、Vの意味

  • アテンションはデータベース検索に例えられる
    • Query(Q): 何を探すか
    • Key(K): 何を持っているか
    • Value(V): 実際に保持する情報
  • 各入力位置ごとに「何に注意すべきか?」というクエリを作成し、全てのキーと比較、最適な値を取得

アテンション処理の全体フロー

  • 入力 → 線形変換 → Q、K、V生成 → アテンションスコア計算 → Softmax → 重み付き和 → 出力
  • これにより、各単語が系列内の重要な単語に動的に注意を向ける

Q、K、V行列の具体的な構築例

  • 例文:「Cat eats fish」

    • 各単語を4次元ベクトルで表現(実際は埋め込みベクトルを利用)
      • cat = [1.0, 0.0, 0.5, 0.2] など
    • 3単語をまとめて入力行列X(3, 4)を作成
  • Q、K、V行列の生成には重み行列Wq、Wk、Wv(各4×3)を使用

    • これらは学習により最適化されるパラメータ
    • Q = X @ Wq、K = X @ Wk、V = X @ Wv(各3×3行列)
  • 各行の意味

    • Qの各行:各単語が「何に注意すべきか?」というクエリ
    • Kの各行:各単語が「どんな情報を持っているか?」というキー
    • Vの各行:各単語が「実際に持つ情報」バリュー

コード例(擬似コード)

  • 入力ベクトルと重み行列からQ、K、Vを生成する関数
    • 入力:input_embeddings(seq_len, d_model)、d_k(出力次元)、seed
    • 出力:Q、K、V、重み行列
  • 例:「Cat eats fish」の3単語を使い、Q、K、Vを計算

Q、K、Vの重み行列を分ける理由

  • 各重み行列の役割が異なるため
    • Wq:クエリ(質問)生成
    • Wk:キー(検索インデックス)生成
    • Wv:バリュー(実際の内容)生成
  • もし同じ重みを使うと、機能的な分離が損なわれ、最適な学習ができない
  • 検索エンジンの「検索ワード」「インデックス」「本文」の違いに相当

投影次元(d_k)の影響

  • d_kが小さい場合
    • 計算・メモリ効率が高い
    • 複雑な関係性の把握が難しい
    • シンプルなタスクやマルチヘッドアテンションの一部として有用
  • d_kが大きい場合
    • 複雑な関係性も捉えやすい
    • パラメータ数・計算コスト増加
    • 実運用モデル(BERT等)ではd_k=64×12ヘッド=768次元などを採用

アテンション計算におけるQ、K、Vの役割

  • アテンションスコアの計算
    • attention_scores = Q @ K^T / sqrt(d_k)
    • 各行:単語iが単語jにどれだけ注意を向けるかを示す
  • スコアをsoftmaxで正規化→Vの重み付き和を計算→出力ベクトルへ
  • Q、K、Vはアテンション処理の最初の一歩
    • 以降、スコア計算、softmax、重み付き和、出力投影と続く

まとめ:Q、K、V行列の意義

  • Query、Key、Value行列はTransformerの文脈理解の核
  • 入力埋め込みを3種の重みで別々に射影し、検索・被検索・内容伝達の役割を分担
  • この設計により、モデルは入力内の関連部分に動的に注意を向け、高度な言語理解を実現

Hackerたちの意見

これ、悪くはないけど(図があったらもっと良いかも!)、初めてこれを見た人がLLMのアテンションメカニズムを自分で学ぶのは難しいと思う。かなり難しいトピックだし、ちゃんと理解したいなら、少なくとも2、3章は必要だよ!この分野を本気で理解したい人には、セバスチャン・ラシュカの素晴らしい本『Build a Large Language Model (From Scratch)』を強くおすすめするよ。最近読み終わったばかりなんだけど、わかりやすくて詳細もちゃんとしてる。ところで、QKVの「データベースルックアップ」っていう動機付け、みんな混乱しない?(記事の中で、「クエリ(Q):何を探しているの?キー(K):何を持っているの?バリュー(V):実際にどんな情報を持っているの?」って書いてある)。正直、よくわからなくて、QKVをトークン埋め込みベクトルxの入力に対する一般的な線形代数の変換を構成する方法として考えるように切り替えたんだ。xに対して二次的で、すべてのトークンがNxNアテンションマトリックスで他のトークンと関連できるようにするためにね。実際、QKVの内容や「意味」はかなり不透明で、構成に使われる重みはトレーニング中に学習されるものだから。さらに、代数の中でQとKの間にはたくさんの対称性があって、それは因果マスクによってのみ壊れるんだ。みんなこの動機付けを深い意味で役立つと思ってるのかな?何か見落としてる?[編集: この最後の質問に関して、roadside_picnicが下に投稿した「Attention is just Kernel Smoothing」の記事が、これに対するクリーンで一般的な数学的アプローチを提供していて、手を振るような「データベースルックアップ」のクエリ/キー/バリューの解釈について少し疑問を持つのは間違ってないって確認してくれそうで、すごく興味深いよ。]
その本、理解するために何か技術的な前提が必要なの?
確か、QとKの対称性はソフトマックスの方向によっても壊れるんじゃなかったっけ?行ごとと列ごとの適用で解釈が違うよね。
QKVのプロジェクションについての考え方: Qはトークンiの特徴が他のトークンとの類似性を計算する際の感度を定義する。Kはトークンjの特徴が他のトークンに選ばれたときの可視性を定義する。Vは全トークンの加重和を計算する際に重要な特徴を定義する。
俺もすごく混乱してる。アナロジーは、Q[K] = Vみたいな感じを示唆してるよね。一つには、これがアテンションスコアを計算する数学的操作、ソフトマックスを適用してからV行列とのドット積を取ることにどう関係しているのか全くわからない。二つ目は、概念的に「単語が他の単語にどれだけ関連しているかを調べる」っていうのがどう関係しているのか理解できない。例えば「猫がスープを食べる」という文で、「彼の」は猫に対してどれだけ重要かを問いかけてる。だから、Vはその重要性の数値的な結果、例えば0.99みたいなものなの?俺はそんなにバカじゃないと思うけど、これを何度も見ているうちに、誰かがこの概念を本当に理解しているのか疑問に思い始めてる。
> 自分はあんまり理解できてなくて、QKVをトークン埋め込みベクトルxの一般的な線形代数変換の系列を構築する方法として考えるように切り替えたんだ。それはxに対して二次的で、すべてのトークンがNxNの注意行列で他のトークンと関係できることを保証する。ここで言ってることは正しい理解だと思う。ルックアップの話はナンセンスだよ。「クエリ」と「バリュー」という用語は実際にはほとんど任意で意味がない。PyTorchでこれを実装する方法を見れば、これらはただの重み行列で、ある種の射影を実装しているだけだとわかるし、自己注意は常に自己注意(x, x, x)か、場合によっては自己注意(x, x, y)(例えばクロスアテンション)で、xとyは前の層からの出力なんだ。さらに、マージドアテンションのような異なる形式の注意や、注意メカニズムが実際にどのように機能しているのかの研究が進む中で、「彼らはキー・バリュー・ストアに動機付けられている」という考え方は本当に怪しく見えてくる。実際には、注意層は相関や類似性、または次元削減された表現の間の乗法的相互作用をモデル化することを可能にしている。編集:あるいは、あなたが言うように、カーネルスムージングと見なすこともできる。
自分もデータベースのルックアップの類推は好きじゃないな。注意を教えるときに好む類推は天体力学だよ。トークンは(潜在的な)空間の惑星みたいなもので、注意メカニズムは一種の「重力」のようなもので、各トークンが互いに影響を与え合い、(潜在的な)空間で意味を洗練させるために押し合ったり引き合ったりしている。だけど「距離」や「質量」の代わりに、この重力は意味的な相互関連性に比例していて、物理的な空間の代わりに潜在空間で起こっているんだ。 https://www.youtube.com/watch?v=ZuiJjkbX0Og&t=3569s
「Attention is a reinvention of Kernel Smoothing」っていうのを広めるために、しつこく言い続けるよ。今はコスマ・シャリジの素晴らしいウェブサイトがダウンしてるみたいだから、彼のこのトピックに関する重要な読み物へのアーカイブリンクを貼っておくね。[0] 機械学習に少しでも興味があって、カーネル法についてあまり詳しくないなら、ぜひ深く掘り下げてみてほしい。機械学習の多くはカーネル法の視点から考えられるし、ガウス過程みたいなものもずっと理解しやすくなるよ。0. https://web.archive.org/web/20250820184917/http://bactra.org...
これ、ほんとに役立つね、ありがとう。他の(トップレベルの)コメントでも、アテンションの説明でQ、K、Vの行列がいつも手を振るような比喩的な方法で出てくることに対する漠然とした不満を言ったんだけど、カーネル法の扱いはもっと数学的に一般的でクリーンに見えるね。ただ、そのせいで数学のバックグラウンドがないとちょっと取っ付きにくいかも。でも、応用数学をやってた身としては、「これが一般的な形だ、さあ具体的にするための明確な仮定をしよう」っていうのが、「人間の注意やデータベースに対する曖昧なアナロジーで特定の方法で組み合わせる必要があるランダムな行列を見せる」よりもずっと好きだな。カーネルについてもっと読むようにメモしておくよ。他におすすめの読み物ある?
ガウス過程に関する最先端の機械学習研究が、深層学習を通じてカーネルを推定することにもっと注目されていないのが全く理解できない。これは、現代のAIのあらゆる側面を支配している原始的で硬直したドット積アテンションよりも、ずっと柔軟なように思える。
おお、これに対して一つ以上のアップボートをあげたいくらいだ!
上のアーカイブリンクは壊れてるね。これがそのページの以前のアーカイブコピーで、内容はそのまま残ってるよ。
サイトはまだ大丈夫だよ(でも、ずっとhttpのみだね)。
w1とw2の必要性が何から来ているのか理解できないな。クエリとキーの空間でアテンションをやっているという前提を受け入れない限り… でも、それは著者の主張じゃないし。何を見落としてるんだろう?意外にも、この記事を読むことでクエリとキーのメタファーがより理解できたよ。
> こんなに大量の機械学習はカーネル法の観点から考えられるけど、どれもカーネル法の再発明じゃないよね。ナダラヤとワトソンのアイデアと、実際に動いているアテンションモデルの間には大きなギャップがあるから、再発明って言うのはちょっと無理があると思う。勾配降下法で訓練されたニューラルネットワークが、関数近似の数値的手法の再発明だって言うのと同じくらい無理があるよ。
物理学ではこういうのを「二重性」って呼ぶんだよね。問題によって、異なる視点を選ぶことができる。ある領域で証明されたことは、二重性のつながりの矢印に沿って他の領域に引き戻すことができるんだ。
これまで読んだ中で、内容とスタイルの両方において最高のブログ記事かもしれない。みんなも読んでみて、最後まで読んでね。最後の段落は本当に貴重だよ。
いいね、数日前にLLMの簡単な説明を書こうとしたんだ @ https://kaamvaam.com/machine-learning-ai/llm-attention-expla... ちょっと悩んだのは、行列Vが必要な理由だった。
この記事(および「Attention is all you need」という有名な論文)で混乱するのは、自己注意にかなり重点が置かれていることだね。自己注意では、Q/K/Vがすべて同じ入力トークンから導出されるから、それぞれの役割を区別するのが難しい。機械翻訳のためのクロスアテンションに焦点を当てている元の注意論文[0]の方が、注意の理解がずっと簡単だと思う。翻訳では、翻訳される入力文がベクトル {x_1...x_n} にトークン化される。翻訳された文は、自動回帰的にトークン {y_1...y_m} に生成される。y_jを生成するために、モデルは以前に生成されたトークンy_{j-1}とすべてのx_iとの類似度スコアをドット積を使って計算するんだ。具体的には、s_{i,j} = x_i*K*y_{j-1}で、Key行列によって変換される。これをソフトマックスして重みベクトルa_j = softmax_i(s_{i,j})を作る。X = [x_1|...|x_n]の加重平均をa_jに基づいて取り、Value行列で変換する。つまり、c_j = V*X*a_jになる。c_jはさらにネットワークの層に渡されて出力トークンy_jが生成される。要するに、前の出力トークンを考慮して、各入力トークンとの類似度を計算し(Kを使って)、その類似度スコアを使ってすべての入力トークンの加重平均を計算し、その加重平均を使って次の出力トークンを生成する(Vを介して)。この論文では、Query行列は明示的には使われていないことに注意。これはトークンの前処理として考えられる。s_{i,j} = x_i*K*y_{j-1}を計算する代わりに、各x_iはまず何らかの行列Qによって線形変換される。この記事ではRNN(特にLSTM)を使ってトークンをエンコードしているので、入力トークンに対するそのような変換は各LSTMモジュールに暗黙的に含まれている。[0] https://arxiv.org/pdf/1508.04025(「Attention is all you need」の3年前のもの)
まさにその通り。クロスアテンションとx, yの表記法は、類似度/共分散行列をずっと明確で直感的にしてくれる。あと、「クエリ」、「キー」、「バリュー」っていう用語や、キー・バリュー・ストアへの曖昧な類推は忘れた方がいいと思う。あれは個人的にはかなり誤った類推だし、実際に何が起こっているのかを理解するのには役立たない。
バハダナウのアテンションってもっと前のものじゃない?[0] https://arxiv.org/abs/1409.0473
自分は情報検索(つまり検索)の観点から考えることが多いかな。入力テキストを全インターネットだと想像して、各ページが1トークンだとしたら、あなたの仕事はそのミニインターネットのトークンのためにニューラルネットワークのGoogle結果ページを構築することだよ。従来の検索では、検索クエリが与えられ、その中間検索結果ページを通じて10個の青いリンクのウェブページを見つけたい。基本的に、何かをグーグルしているときは、「この検索クエリに関連するウェブページはどれ?」と知りたいし、そのリンクを見て「そのウェブページは実際に何を言っているのか?」と問い、リンクをクリックして質問に答えるわけだ。この場合、「クエリ」は明らかにユーザーの検索クエリで、「キー」は10個の青いリンクの1つ(通常はページのタイトル)で、「バリュー」はそのリンクが指すウェブページの内容だ。注意メカニズムでは、トークンが与えられ、他のトークンと文脈化したときの意味を見つけたい。基本的には、「このトークンに関連する他のトークンはどれ?」という質問に答えようとして、その答えをもとに「これらの他の関連トークンを考慮したとき、元のトークンの意味は何?」と問いかける。つまり、「クエリ」は入力テキストの与えられたトークンで、「キー」は入力テキストの別のトークンで、「バリュー」はその他のトークンの文脈における元のトークンの最終的な意味(埋め込みの形で)だ。与えられたトークンについては、注意メカニズムが他の最も関連性の高いトークンの「10個の青いリンクをクリックした」ようなもので、何らかの方法でそれらを組み合わせて元のクエリトークンの意味を理解することを想像できる(また、入力テキスト内のすべてのトークンに対して同時にそのようなクエリを実行したと考えることもできる)。だから、自己注意メカニズムは基本的にGoogle検索みたいなもので、ユーザーのクエリの代わりに入力のトークンがあり、青いリンクの代わりに別のトークンがあり、ウェブページの代わりに意味があるんだ。
このスレッドで自分のコメントや他の人のコメントを読んでみて、あなたの考え方は比喩的で、実際の数学からかなり切り離されているから役に立たないよ。比喩を使って深層ネットワークを意味のある理解を得ることはできない。非常に基本的な線形代数を学ぶ必要があるんだ。実際、注意層はトークンを見たことがない。最初の自己注意層ですら位置埋め込みを見ているけど、その後の注意層はすべて、前の層の埋め込みが混ざり合った複雑な埋め込みを見ているだけなんだ。
注意メカニズムの大きな問題の一つは、クエリがすべてのキーを見なければならないことで、長いコンテキストでは非常にコストがかかることだ。自分が取り組んでいる小さなサイドプロジェクトは、LLMの上にモデルをトレーニングして、各キーを見て、一定の寿命を過ぎた後に必要かどうかを判断し、可能であれば排除するというものだ(寿命が切れた後に)。まだ作業中だけど、最初のテストでは90%のキーを削減できたよ! https://github.com/enjeyw/smartkv
QKVアテンションは、QKVが入力/出力の次元を調整してNNブロックにフィットさせる確率的なルックアップテーブルに過ぎないよ。もしQがトレーニングからの既知のKと完璧に一致すれば、正確なVが得られるけど、そうでなければ、アテンションで重み付けされたすべてのVの線形結合が得られるんだ。
それは違うよ、上のスレッドを読んでみて。
こういうメタファー的なデータベースのアナロジーにはイライラするし、コメントを見る限り他の人たちも同じみたいだね!今のところ、トレーニングのダイナミクスを考慮した一番合理的な説明はLenka Zdeborovaの研究室から見つけたよ(おもちゃのような線形アテンション設定だけど、実際のものに一般化される理由は簡単にわかる)。例えば、これが素晴らしい論文だよ。
投稿と説明ありがとう!このプロンプトキャッシングに関する関連する記事がすごく楽しめたよ。著者が同じ原則を説明して、追加のビジュアルも使ってたけど、主なポイントはKVキャッシュヒットがLLM APIの使用をかなり安くする理由だったんだ。
自己注意とマルチヘッドアテンションを別の方法で説明した動画を公開したよ。直感から数学、コードに進んで、最終結果から実際の手法に遡る形で解説してる。これが他のアプローチとは違った形で、トランスフォーマーアーキテクチャを理解するための明確さを提供できればいいなと思ってる。動画の41:22から始まるよ。 https://youtu.be/6jyL6NB3_LI?t=2482