attention を勉強すると、Query・Key・Value という3人組と、softmax で重みを作る話までは何とかついていけます。ところが最後に出てくる context vector(文脈ベクトル) で、「結局これは何を表しているの?」と手が止まる人が多いはずです。重み付き和で計算できることはわかった。でも、それが「意味的に何なのか」がつかめない。
この記事は、その context vector を主役に据えます。attention の出力そのものである context vector が、「その位置のために、周りの情報を要約して作った専用のまとめベクトル」 であることを、図と数値でじっくり腹落ちさせるのがゴールです。

上の図が context vector の定義のすべてです。複数の value ベクトルに、attention weight(合計1の重み)を掛けて足し合わせる。それだけで context vector $\mathbf{c}$ ができます。式で書けば $\mathbf{c} = \sum_i a_i \mathbf{v}_i$。単純な足し算に見えますが、この記事を読み終える頃には、この一本のベクトルが持つ幾何的な意味と、なぜ深層モデルの表現力の源になるのかが見えているはずです。
なぜこれを学ぶ価値があるのでしょうか。第一に、context vector は attention の「出力」そのものだからです。あなたが attention の計算を追うとき、最後にたどり着く答えがこれです。第二に、context vector こそが「文脈依存表現(contextual embedding)」の正体だからです。BERT や GPT が「同じ単語でも文脈で意味が変わる」表現を作れるのは、各位置で context vector を作り直しているからにほかなりません。
本記事の内容
- context vector とは何か — value の重み付き和という定義と直感
- なぜ必要か — Seq2Seq の固定長ボトルネックをどう解くか
- 幾何的な意味 — context vector は必ず value の「凸包」の中にいる
- クエリごとに動的に作られること、静的埋め込みとの違い、self-attention と multi-head での姿
前提知識
この記事は context vector の意味に集中します。attention の全体像や QKV の役割は、次の記事を先に読むと理解がスムーズです。
context vector とは — 「重み付きのまとめ」
まず言葉のイメージから入りましょう。あなたが会議の議事録を要約するとき、全ての発言を平等に扱うわけではありません。重要な発言は厚く、雑談は薄く。「重要度に応じて配分を変えた要約」 を作りますよね。context vector はまさにこれです。
attention には3人組がいます。Query(問い合わせ)、Key(見出し)、Value(中身) です。Query が「今、私はこういう情報が欲しい」と問いかけ、各 Key との一致度から「どの Value をどれだけ見るか」の配分(attention weight)が決まります。そして最後に、その配分で Value を混ぜ合わせたものが context vector です。
ここで大事なのは、混ぜられるのは Value であって Key ではないという点です。Key は「見出し」として一致度の計算だけに使われ、実際に持ち帰る「中身」は Value から取ってきます。図書館で例えるなら、Key は本の背表紙(探すための手がかり)、Value は本の中身(実際に欲しい情報)です。context vector は、複数の本の中身を重要度に応じてブレンドした「あなた専用の要約ノート」なのです。
数式で書くと、$n$ 個の value $\mathbf{v}_1, \dots, \mathbf{v}_n$ と、合計1の重み $a_1, \dots, a_n$ に対して
$$ \mathbf{c} = \sum_{i=1}^{n} a_i \mathbf{v}_i, \qquad \sum_{i=1}^{n} a_i = 1, \quad a_i \geq 0 $$
となります。重みが合計1で全て非負、という条件がついていることに注目してください。この条件は後で「幾何的な意味」を考えるときに効いてきます。まずは、そもそもなぜこんなものが必要になったのかを見ましょう。
なぜ必要か — 固定長ボトルネックを解く
context vector が生まれた背景には、機械翻訳などで使われた Seq2Seq モデルの弱点があります。Seq2Seq は入力文を Encoder で読み込み、その内容を1本の固定長ベクトルに押し込めてから、Decoder で出力文を生成します。
問題は、この「1本に押し込める」部分です。10単語の文も100単語の文も、同じ長さのベクトル1本に詰め込まなければなりません。長い文になるほど情報が溢れ、最初のほうの単語は忘れられていきます。これが固定長ボトルネック問題です。

左の図が Seq2Seq です。入力の全単語が1本のベクトルに集約され、そこが情報の細い通り道(ボトルネック)になっています。右が attention の発想です。出力単語を1つ生成するたびに、その単語に必要な入力語だけに注目して、専用の context vector をその場で作り直す。「私」を出すときは “I” を、「犬」を出すときは “dog” を厚く見る、というように。
この違いは決定的です。Seq2Seq は「全部を1本にまとめてから使う」のに対し、attention は「使うたびに、必要なぶんだけまとめる」。context vector が動的に作られる、というのがポイントです。固定された1本ではなく、出力位置ごとに違う context vector が生まれます。
では、その context vector は具体的にどう作られるのでしょうか。3つのステップに分けて見ていきます。
3ステップで context vector ができる
context vector の作り方は、たった3ステップです。「犬が走る。」という文で、ある Query が各単語(Key/Value)をどう見るかを例にします。
- 一致度スコアを測る — Query と各 Key の内積 $q \cdot k_i$ を計算します。似ているほど大きな値になります。
- softmax で配分に変える — スコアを softmax に通し、合計1の重み $a_i$ にします。これが attention weight です。
- value を重み付きで合成する — 重み $a_i$ で value を混ぜ、$\mathbf{c} = \sum_i a_i \mathbf{v}_i$ を作ります。

図の左でスコアを見ると「犬」が飛び抜けて高く、softmax を通した中央では「犬」の重みが約 0.75 に集中しています(残りは「走る」約 0.17、「が」約 0.05、「。」約 0.04)。右のように、この配分で value を混ぜると、context vector は「犬」の value を主成分としつつ、少しだけ「走る」を混ぜた要約になります。スコアが高い value ほど、できあがる context vector に強く反映される——これが3ステップの帰結です。
計算方法はわかりました。では、こうしてできた context vector は「どこに」生まれるのでしょうか。ここから、この記事の目玉である幾何的な視点に入ります。
幾何的な意味 — context vector は value の「凸包」の中にいる
context vector の定義 $\mathbf{c} = \sum_i a_i \mathbf{v}_i$ を、幾何の言葉で読み直してみましょう。重みが「非負」で「合計1」という条件は、数学では凸結合(convex combination)と呼ばれる特別な足し合わせです。そして凸結合には、美しい性質があります。凸結合で作られる点は、必ず元の点たちの凸包(convex hull)の内側に入るのです。
凸包とは、ばらまいた点を輪ゴムでぐるっと囲んだときにできる、いちばん外側の多角形(とその内部)のことです。context vector は value たちの凸結合なので、value がどんな配置でも、どんな重みを選んでも、必ずこの輪ゴムの内側に生まれます。

図は2次元の value を4つ置き、重み $(0.55, 0.10, 0.25, 0.10)$ で context vector(赤い星)を作ったものです。星は4つの value を頂点とする水色の凸包の内側にあります。重みが最も大きい $v_1$(大きい丸)に引き寄せられているのが見て取れます。context vector は「最も注目した value」の方向に寄った、凸包内の代表点なのです。
この幾何的な見方は、attention weight の「尖り具合」が context vector の位置をどう動かすかも教えてくれます。softmax に温度パラメータを入れて、重みを平坦にしたり尖らせたりしてみましょう。

重みが平坦(高温)だと context vector はほぼ全 value の単純平均、つまり凸包の重心近くに来ます。重みが尖る(低温)ほど、context vector は最も注目する value の1点に近づいていきます。「広く薄く見る」と context vector は真ん中に、「一点集中で見る」と context vector はその value に張り付く。attention の鋭さが、要約の性格をそのまま決めているわけです。
「凸包の内側」という制約は、本当にいつでも成り立つのでしょうか。多数の重みを試して確かめます。

6つの value に対し、ランダムな重みを400通り試して context vector を打った図です。紫の点(context vector)はすべて value の凸包(水色)の内側に収まり、一つも外に出ていません。これは偶然ではなく、凸結合の数学的な帰結です。この事実は「attention は value の外挿はできない — あくまで既存の value の内側で混ぜるだけ」という、context vector の能力の範囲も教えてくれます。
幾何的な意味がつかめたところで、context vector の「動的さ」をもう一歩深めます。同じ value 集合でも、問いかける Query が変われば答えは変わるはずです。
クエリごとに動的に作られる
context vector の最大の特徴は、Query が変われば、同じ value 集合からでも別の context vector が生まれることです。value(材料)は同じでも、問い方(Query)次第でまったく違う要約ができます。

図は、同じ4つの value に対して3つの異なる Query で context vector を作ったものです。Query A・B・C はそれぞれ凸包内の別の位置に context vector を生みます。同じ材料を使っているのに、問いかけ方だけで答えが移動する。この柔軟さこそが、固定長の1本ベクトルには決してできなかったことです。
この「Query ごとに違う要約」という性質を、機械翻訳の注意重み行列で見ると直感的です。

縦が出力語、横が入力語で、各マスが attention weight です。各行(各出力語)が違う配分になっていることに注目してください。「私」「は」を出すときは入力の “I” を、「犬」「を」を出すときは “dog” を厚く見ています。行ごとに違う重み = 出力語ごとに違う context vector。これが「必要な入力に注目して訳す」の実体です。
こうして Query ごとに変わる context vector は、実は「文脈依存表現」という重要な概念に直結しています。
静的な埋め込みとの違い — 文脈で変わる表現
古典的な単語埋め込み(word2vec など)では、1つの単語に1つの固定ベクトルが割り当てられます。「bank」は文脈に関係なく、いつも同じ点です。でも「川の bank(土手)」と「お金の bank(銀行)」は意味が違うのに、同じベクトルで表すのは無理があります。

context vector はここを解決します。各位置の Query が周りの語(=文脈)に注目して要約を作るので、「川の bank」なら “river” を厚く見た context vector に、「お金の bank」なら “money” を厚く見た context vector になります。同じ単語でも、文脈が違えば別の context vector になる。これが文脈依存表現(contextual embedding)の正体であり、BERT や GPT が古典的埋め込みを圧倒した核心です。より詳しくは 文脈依存表現(Contextual Embeddings) を参照してください。
Query が周りを見て context vector を作る、という発想を「文中の全単語」に一斉に適用したのが self-attention です。
self-attention と multi-head での context vector
Seq2Seq の attention では、Decoder 側の Query が Encoder 側の value を見ていました。self-attention では、これを1つの文の中で完結させます。文中の各トークンが自分自身の Query になり、同じ文の全トークンの value を集めて、自分専用の context vector を作ります。

図のように、「犬」というトークンは自分を Query として文中の全語を見渡し、必要な語(この例では自分自身や周辺語)を重く見て context vector $c_3$ を作ります。同時に「私」も「見た」も、それぞれ自分用の context vector を作ります。n 個のトークンがあれば、n 個の context vector が同時に生まれる。これが Transformer の1層がやっていることの本質です。そして層を重ねるたびに context vector はさらに文脈を取り込み、洗練されていきます。
さらに Transformer は、1つの観点だけで context vector を作ることに満足しません。multi-head attention は、複数の「注目の仕方」で並行して context vector を作り、それらを結合します。

あるヘッドは文法的な係り受けに、別のヘッドは意味的な近さに、また別のヘッドは位置的な近さに注目する、といった具合です。各ヘッドが作った context vector を結合して線形変換することで、多面的な要約が1つのベクトルにまとまります。1つの観点に絞らないことで、豊かな表現が得られるわけです。
理論を追ってきたので、最後に手を動かして context vector を実際に計算してみましょう。
Python で context vector を計算する
小さな例で、context vector が本当に「重み付き和」として計算できることを確かめます。「私・犬・見た」の3トークンがあり、クエリ「見た」が「何を見たか」を探す、という設定です。
import numpy as np
def softmax(z):
z = z - z.max()
e = np.exp(z)
return e / e.sum()
tokens = ["私", "犬", "見た"]
# value: 各トークンの「中身」(ここでは one-hot で見やすく)
V = np.array([[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]])
# key: 各トークンの「見出し」
K = np.array([[1.2, 0.1, 0.0],
[0.0, 1.3, 0.2],
[0.1, 0.2, 1.1]])
# query: 「見た」が「犬」を強く探すような問い合わせ
q = np.array([0.1, 1.4, 0.3])
scores = K @ q # ① 一致度スコア
a = softmax(scores) # ② 配分(合計1)
c = a @ V # ③ value の重み付き和 = context vector
print("attention weight:", np.round(a, 3))
print("context vector :", np.round(c, 3))
実行すると、attention weight は [0.134, 0.675, 0.191]、context vector は [0.134, 0.675, 0.191] になります。
# 検算: context vector は本当に value の凸結合か?
print("重みの合計:", round(a.sum(), 6)) # 1.0
recon = sum(w * v for w, v in zip(a, V))
print("Σ a_i v_i と一致:", np.allclose(recon, c)) # True
この結果から、context vector の性質がはっきり読み取れます。第一に、クエリ「見た」が「犬」に最も強い重み 0.675 を配り、context vector の「犬」成分が最も大きくなりました。「何を見たか → 犬」という関係が、context vector の中身にそのまま表れています。第二に、重みの合計は厳密に 1.0 で、context vector は value の凸結合になっています(検算も True)。value が one-hot なので、この例では context vector の成分がそのまま attention weight と一致し、「context vector = 重みの配分そのもの」という関係が目に見える形になりました。

図の左が各語への重み、右ができあがった context vector の中身です。「犬」の成分が突出した、しかし「見た」「私」も少し混ざったベクトルになっているのがわかります。これが「犬を主成分としつつ、周辺情報も薄く含んだ要約」という context vector の姿です。
まとめ
context vector(文脈ベクトル)は、attention の出力そのものであり、その正体は value の重み付き和による『動的なまとめ』 です。本記事のポイントを整理します。
- 定義:$\mathbf{c} = \sum_i a_i \mathbf{v}_i$。混ぜるのは value で、Key は一致度の計算にだけ使う
- なぜ必要か:Seq2Seq の固定長ボトルネックを、出力位置ごとに context vector を作り直すことで解消した
- 幾何的な意味:重みが非負・合計1なので、context vector は必ず value の凸包の内側に生まれる。重みが尖るほど最注目 value に近づく
- 動的さ:Query が変われば、同じ value からでも別の context vector ができる。これが「文脈で変わる表現」の源
- self-attention / multi-head:全トークンが自分用の context vector を持ち、複数の観点の context vector を束ねて豊かな表現を作る
context vector を「value の凸包内に生まれる、問いかけ次第で動く要約点」としてイメージできれば、attention のあらゆる場面が見通しよくなります。次のステップとして、以下の記事も参考にしてください。