第7回:不確実性の復権 ~Variance Matters~
注意事項
(集中度)を「確信度」として解釈できるのは、埋め込みをvMF分布として明示的にモデル化した場合に限られる。 - 単に
正規化して 類似度を使うだけでは、 は自動的には得られない(点埋め込みに「霧」はない)。 - エントロピーの近似式
は、高次元・高 の条件下での近似であり、一般には成り立たない。 - 本回で扱う「分布埋め込み」は、標準的な深層学習ではまだ主流ではない。しかし、不確実性を扱う設計の重要性は増しており、将来の標準になる可能性がある。
導入:解像度を上げる
第3回で、表現空間を「プラネタリウム」として捉えた。単位球面上に配置された点が、意味の「星」として輝いている。これは計算効率の良い、優れた近似である。
しかし、望遠鏡の倍率を上げれば、新たな構造が見えてくる。肉眼では「光る点」に見えた星も、高性能な望遠鏡で観察すれば、激しく燃え盛るガスの「広がり(霧)」であることがわかる。シャープに見える星は確信度が高く、ぼやけて見える星は不確実性が高い。この「にじみ」には重要な情報が含まれている。
埋め込み空間でも同じことが言える。「りんご」という単語の表現は、文脈によってぶれるだろうか。「量子もつれ」という専門用語の表現は、学習データの量によって確信度が異なるだろうか。従来の点埋め込みは、この「ぶれ」や「確信度」という次元を持たなかった——分布埋め込みの視点から振り返れば、確信度を無限大に固定していたと解釈できる。
本回では、この固定を解放する。解像度を上げることで、概念を「点(Point Estimate)」としてだけでなく、不確実性を含んだ「分布(Distribution)」として捉え直す。これにより、今まで見えなかった「迷い」や「知らなさ」を可視化できる。これは、「分かりません」と言えるAIへの第一歩である。
ノルムの分離という思想
従来:混沌としたノルム
第2回で見たように、従来の埋め込みではベクトルの長さ(ノルム)が様々な意味を担っていた。
| 解釈 | 例 |
|---|---|
| 単語の頻度 | 高頻度語は長いベクトル |
| 意味の「強さ」 | 感情的な単語は長いベクトル |
| 学習の進行度 | よく学習された概念は長いベクトル |
| 数値的なアーティファクト | 初期化や最適化の偶然 |
これらの意味が混在しているため、ノルムを解釈することは困難だった。「このベクトルが長いのは、頻度が高いからか、意味が強いからか、それとも偶然か」を区別できない。
これから:意味と確信度の分離
本講義のアプローチは、この混沌を設計によって解消することである。
方向(direction):意味を表す。「りんご」と「みかん」は異なる方向を向く。
広がり(spread):確信度を表す。確信度が高い概念は鋭く局在し、低い概念はぼやけて広がる。
この分離を実現するのが、方向分布の導入である。特に、単位球面上の方向分布としてvon Mises-Fisher(vMF)分布が有力な選択肢となる。
重要なのは、従来の点埋め込みがこの枠組みから外れているわけではない、という点である。点埋め込みは、確信度パラメータを無限大に固定した特殊ケースと見なすことができる。分布表現は、この固定を解放し、確信度を学習可能なパラメータとして扱う一般化である。
IMPORTANT
設計としての分離: この「意味と確信度の分離」は、データから自動的に得られるものではない。vMF分布を使い、
VAEとガウス空間の重力
潜在空間を「押し込める」力
分布表現の先駆的な成功例として、変分オートエンコーダ(VAE) (Kingma & Welling, 2014) がある。VAEは、データを潜在空間上の分布として符号化し、そこからサンプリングして復元する。この枠組みは、「点ではなく分布を学ぶ」という本回のテーマの出発点として重要である。
VAEの学習目標には、KLダイバージェンス正則化が含まれる。潜在分布
この正則化項は、事後分布のパラメータを標準正規事前分布に合わせる圧力として働く。具体的には、平均
ユークリッド空間の不均一性
ここで問題になるのが、ガウス分布が生む空間の不均一性である。
標準正規分布
| 確率密度 | 確率質量(典型集合) | |
|---|---|---|
| 原点付近 | 最大 | ほぼゼロ(体積が微小) |
| 中程度 | ほぼ全質量が集中 | |
| 遠方 | 急激に減少 | ほぼゼロ(密度が微小) |
VAEの潜在空間では、正則化が事後分布をこの標準正規分布に合わせようとする。結果として、潜在表現は
TIP
密度と体積の綱引き:なぜ
ガウス分布の密度(高さ)は原点で最大だが、高次元空間ではそこにサンプルは集まらない。 これを理解するには、 「半径
(原点付近): 密度は最大だが、半径 が小さすぎて となり、確率はほぼゼロ(場所がない)。 (遠方): 場所は広いが、密度 が急激にゼロになり、確率もゼロ(空気がない)。
均衡点の導出: この確率
つまり、高次元のサンプルは原点にはおらず、この半径
球面への脱出:vMFという一般化
ガウス事前分布の根本的な制約は、半径方向の自由度を強く持つ一方で、角度(方向)主体の構造に不向きなことにある。潜在表現が意味する「何であるか」が主に方向で決まる場合、半径方向の変動はノイズでしかない。にもかかわらず、ガウス事前分布は半径方向にも広い自由度を許し、典型帯という制約をかける。
第3回で「プラネタリウム」として導入した球面表現は、この問題に対する幾何学的な回答である。単位球面
第2回、第3回で見た
さらに、球面上で一様分布を事前分布に置けば、ガウス空間にあった半径方向の典型帯のような偏りは生じない。ただし、学習された事後分布は当然偏る——それは意味の構造を反映した望ましい偏りである。重要なのは、空間の幾何そのものが半径方向の不均一性を持たないという点である。
球面上での分布表現としてvMF分布を選ぶことは、この設計思想の自然な帰結である。vMF分布は、従来の点埋め込み(
| VAE(ガウス) | vMF(球面) | 従来の点埋め込み | |
|---|---|---|---|
| 空間 | |||
| 正則化の方向 | 標準正規への引力( | 球面上の一様分布への引力 | (正則化なし) |
| 半径方向の偏り | あり(典型帯 | なし(半径の自由度が存在しない) | なし(ノルム1に固定) |
| 確信度の表現 | 分散 | 集中度 | |
| 意味と確信度の分離 | ノルムに意味が混入しうる | 方向=意味、 | 分離不可(確信度固定) |
Davidson et al. (2018) は、VAEの潜在空間にvMF分布を導入したHyperspherical VAEを提案し、潜在構造が球面的な場合にガウス事前分布より有利になりうることを実験的に示した。これは、データの潜在構造に合った幾何学を事前分布に採用する——すなわち「正則化の形を変える」——ことの重要性を示す事例である。
IMPORTANT
包含としての一般化: vMF分布は、従来の点埋め込みを否定するものではなく、それを
von Mises-Fisher分布:球面上のガウス分布
vMF分布とは何か
von Mises-Fisher(vMF)分布は、単位球面上の方向分布である。ユークリッド空間でのガウス分布の「球面版」と考えることができる。
ここで:
:観測される方向(単位ベクトル) :平均方向(分布の「中心」) :集中度パラメータ :正規化定数(Bessel関数を含む)
の直感的理解
| 分布の形状 | 直感的解釈 | |
|---|---|---|
| 球面上の一様分布 | 方向の情報なし、完全な不確実性 | |
| ぼやけた広い分布 | 低確信度、複数の可能性 | |
| 鋭く集中した分布 | 高確信度、ほぼ確定 | |
| 点(デルタ分布)に収束 | 完全な確信、従来の点埋め込み |
重要な認識:我々がこれまで使ってきた従来の点埋め込み(正規化して使う場合のWord2Vec、正規化されたTransformer埋め込みなど)は、この表の最後の行——すなわち
分布埋め込みとは、この
プラネタリウムのメタファーで言えば:
- 大きい
:「あの星座しか見えない」(晴れた夜空、高確信) - 小さい
:「複数の星座が重なって見える」(霧の夜、低確信) :「レーザーポインタで一点を指す」(従来の点埋め込み)
NOTE
vMF分布とガウス分布の関係: 高次元の単位球面上で
正規化定数の複雑さ
vMF分布の正規化定数
ここで
この複雑さが、vMF分布の実装上の困難の源である。特に:
- Bessel関数の数値計算は、
が大きいときにオーバーフローしやすい - 勾配計算には Bessel 関数の比が現れ、数値的に不安定になりうる
CAUTION
実装上の注意: vMF分布からのサンプリングや対数尤度の計算は、ナイーブな実装では数値的に不安定になりやすい。後述の実装ノートで、安定した計算方法を紹介する。
NOTE
Bessel関数
数式に現れる第一種修正Bessel関数
確率分布は、空間全体での積分値(合計)が必ず「1」でなければならない。 指数部
我々が必要とする正規化定数
のとき: - 指数部は定数となり、積分値
は球面の表面積(Surface Area)に一致する。結果として、正規化定数 は となり、これは一様分布を意味する。
- 指数部は定数となり、積分値
が大きいとき: - 分布が鋭くなり積分値
が小さくなるため、正規化定数 は大きくなり、釣じりを合わせる。
- 分布が鋭くなり積分値
つまりBessel関数項は、空間の広がりと山の鋭さに応じて、総和を1に保つための補正係数を計算しているのである。
不確実性の定量化
エントロピーとしての不確実性
エントロピーとは、分布という「霧」の体積である。
第4回で登場した情報量
(点埋め込みの極限):霧が凝縮してゼロ体積の点に収束。エントロピー最小。 (一様分布の極限):霧が球面全体に薄く広がる。エントロピー最大。
分布の「ぼやけ具合」を定量化する自然な方法は、エントロピーである。エントロピーが高いほど、分布は広がっており、不確実性が高い。
vMF分布のエントロピー
ここで
近似式の条件
文献やチュートリアルで見かける単純な近似式:
これは、高次元かつ高
| 条件 | 近似の妥当性 |
|---|---|
| 高次元( | 良い近似 |
| 低次元( | 近似が崩れる |
| 低 | 近似が崩れる |
IMPORTANT
教育的簡略化の注意: 「
NOTE
第9回への伏線: 第9回(拡散モデル)では、この「霧の体積」が事前分布(等方的なガウスノイズ)全体に向かって拡大していく過程、すなわちエントロピーが単調増大していく軌道を扱う。「データへの逆拡散」とは、エントロピーを減らして霧を凝縮させる操作に他ならない。
確信度としての
実用上、
- vMF分布を明示的にモデル化している場合:埋め込みを点ではなく分布として学習し、
をパラメータとして推定している の推定が安定している場合:学習データが十分にあり、 の推定値が信頼できる
単に
Out-of-Distribution(OOD)検知
問題:ドーム上の「盲点」
プラネタリウムのドーム(単位球面)には、星(学習された概念)が点在している。では、星のない領域に入力が来たとき、モデルはどうすべきか。
従来の点埋め込み(
NOTE
「確信度100%」の意味:ここでの「確信度100%」は、分布埋め込みの視点から従来の点埋め込みを振り返った際の比喩的表現である。従来の点埋め込みが明示的に「確信度」を計算しているわけではなく、単に「不確実性を表現する次元を持たない」だけである。vMF分布として再解釈した場合に、
幾何学的に言えば、点埋め込みは「場所(方向)」という一つの軸しか持たない。未知の入力が来たとき、その「場所」をどこかに配置せざるを得ないが、 「霧の濃さ」という第二の軸 がないため、「ここだけど自信はない」という状態を表現できない。
この構造が、Out-of-Distribution(OOD)入力に対する脆弱性の一因である。
NOTE
本回で扱う集中度
しかし、
分布表現による解決策
分布表現(
低
従来の点埋め込み(不確実性の次元を持たず、
- 未知の入力 → 「これは犬です(確信度100%)」という誤答(ハルシネーション)
分布埋め込み(
- 未知の入力 → 「場所は犬のあたりだが、霧のように薄くて自信がない(
小)」
この 「霧の濃さ(
密度による検出:vMF混合モデルを使えば、入力が高密度領域にあるか低密度領域にあるかを評価できる。低密度領域はOODの可能性が高い。
| 検出方法 | 利点 | 欠点 |
|---|---|---|
| シンプル、解釈しやすい | 閾値の設定が難しい | |
| 密度ベース | 理論的に正当化しやすい | 計算コストが高い |
| アンサンブル | 頑健性が高い | モデルを複数持つ必要がある |
NOTE
「分かりません」と言えるAI: OOD検知は、AIの信頼性にとって本質的に重要である。医療診断や自動運転など、高リスクなアプリケーションでは、「分かりません」と言えることが安全性の鍵となる。分布表現は、この能力を表現空間のレベルで実現する一つのアプローチである。
ハルシネーションの幾何学
ハルシネーションとは何か
大規模言語モデル(LLM)のハルシネーションは、モデルが事実と異なる情報を、あたかも確信を持っているかのように生成する現象である。
幾何学的に見ると、ハルシネーションは以下のように解釈できる:
ハルシネーション = 確信度(
)の情報がないまま、星座を強制的に結ぶ行為
星がまばらな領域(学習データが少ない、または概念が曖昧な領域)で、モデルはそれでも何らかの出力を生成しなければならない。従来の点埋め込み(不確実性の次元を持たないため、分布埋め込みの視点では
分布埋め込みの視点で言えば、ハルシネーションは「
幾何学的な対策
分布表現を採用すれば、ハルシネーションに対する幾何学的な対策が可能になる。
閾値ベースの抑制:
確信度の伝播:生成の各ステップで確信度を追跡し、累積的な不確実性が高まったら警告を出す。
サンプリングの調整:低確信度領域では、より多様なサンプリング(高温)を行い、単一の「でっち上げ」に固執しないようにする。
CAUTION
比喩の限界: 上記の「星座を結ぶ」という比喩は、ハルシネーションの直感的理解には有用だが、実際のLLMの動作を完全に説明するものではない。LLMのハルシネーションには、表現空間の問題だけでなく、自己回帰生成の性質、学習データのバイアス、デコーディング戦略など、複数の要因が絡んでいる。
整列(Alignment)からの解放
従来の問題:座標系の不一致
異なるモデルや異なる学習から得られた埋め込み空間を比較したい場面がある。例えば:
- 言語Aの埋め込みと言語Bの埋め込みを対応付けたい
- 時刻
の埋め込みと時刻 の埋め込みの変化を測りたい - モデルAとモデルBの表現を比較したい
従来のアプローチでは、Procrustes整列が必要だった。これは、一方の座標系を回転・反転して、もう一方に合わせる操作である。
この整列は、対応点のペアが必要であり、計算コストもかかる。
による座標フリーの比較
分布表現を採用し、
| 比較対象 | 座標依存 | |
|---|---|---|
| 2つの点の位置 | 座標系に依存 | - |
| 2つの点の距離 | 座標系に依存しない | - |
| 分布の集中度 | 座標系に依存しない |
具体例:「言語Aで『犬』の確信度」と「言語Bで『dog』の確信度」を比較したい場合、座標系を合わせなくても、それぞれの
NOTE
限定的な解放: これは万能の解決策ではない。意味的な対応関係(「犬」と「dog」が同じ概念を指す)を知るには、依然として何らかの整列が必要である。
分布埋め込みの学習
アーキテクチャの選択肢
分布埋め込みを学習するには、モデルが点ではなく分布のパラメータを出力する必要がある。
vMF出力層:通常の埋め込み層の代わりに、
ここで
損失関数の設計:分布間の距離を測る損失関数が必要。KLダイバージェンス、期待コサイン類似度、あるいは対照学習の変種が使われる。
学習の課題
分布埋め込みの学習には、点埋め込みにはない課題がある。
サンプリングの分散:損失関数の計算にサンプリングが必要な場合、勾配の分散が大きくなりやすい。Reparameterization Trickの球面版が必要。
計算コスト:Bessel関数の計算、サンプリング、分布間距離の計算など、点埋め込みより計算量が増える。
Visualization Break:Attentionの幾何学を見る
本回の最後に、Attentionと不確実性の関係を可視化するデモを示す。
デモ:確信度を持つAttention
コード例: 07_attention_uncertainty_viz.py
import matplotlib.pyplot as plt
import numpy as np
def visualize_attention_with_uncertainty(sentence, attention_weights, kappa_values):
"""確信度付きAttentionの可視化
Args:
sentence: 単語のリスト
attention_weights: Attention重み [seq_len, seq_len]
kappa_values: 各トークンのκ値 [seq_len]
"""
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 左:Attentionヒートマップ
ax1 = axes[0]
im = ax1.imshow(attention_weights, cmap="Blues")
ax1.set_xticks(range(len(sentence)))
ax1.set_yticks(range(len(sentence)))
ax1.set_xticklabels(sentence, rotation=45, ha="right")
ax1.set_yticklabels(sentence)
ax1.set_xlabel("Key")
ax1.set_ylabel("Query")
ax1.set_title("Attention Weights")
plt.colorbar(im, ax=ax1)
# 右:確信度バー
ax2 = axes[1]
colors = plt.cm.RdYlGn(kappa_values / kappa_values.max())
ax2.barh(range(len(sentence)), kappa_values, color=colors)
ax2.set_yticks(range(len(sentence)))
ax2.set_yticklabels(sentence)
ax2.set_xlabel("Confidence (κ)")
ax2.set_title("Per-token Confidence")
ax2.axvline(x=10, color="r", linestyle="--", label="OOD threshold")
ax2.legend()
plt.tight_layout()
plt.savefig("attention_with_uncertainty.png", dpi=150)
plt.close()
print("Saved: attention_with_uncertainty.png")
# サンプルデータで実行
sentence = ["The", "quantum", "cat", "sat", "sleepily"]
np.random.seed(42)
# Attentionは「cat」と「sat」に集中するパターン
attention = np.array(
[
[0.3, 0.1, 0.3, 0.2, 0.1],
[0.1, 0.4, 0.2, 0.2, 0.1],
[0.2, 0.1, 0.4, 0.2, 0.1],
[0.1, 0.1, 0.3, 0.4, 0.1],
[0.2, 0.1, 0.2, 0.2, 0.3],
]
)
# 確信度:一般的な単語は高κ、専門用語「quantum」は低κ
kappa = np.array([45.0, 8.0, 50.0, 55.0, 35.0])
visualize_attention_with_uncertainty(sentence, attention, kappa)この可視化は、以下を示している:
- Attentionの分布:どの単語がどの単語に注目しているか
- 確信度の違い:「quantum」のような専門用語は低い
(赤系)、「The」「sat」のような一般的な単語は高い (緑系)
NOTE
Multi-headでの拡張: 実際のTransformerでは、複数のヘッドがそれぞれ異なるAttentionパターンを学習する。各ヘッドに対応する「確信度」を可視化することで、どのヘッドがどの種類の関係を確信を持って捉えているかを分析できる。
まとめ
| 概念 | 定義 | 本回での役割 |
|---|---|---|
| VAE | 潜在空間を分布として学習する生成モデル | 分布表現の先駆、ガウス空間の限界の例示 |
| 典型集合 | 高次元ガウスで確率質量が集中する領域 | 潜在空間の不均一性の核心 |
| 典型帯 | 典型集合のうち半径 | ガウス潜在空間の実効的な居住領域 |
| vMF分布 | 単位球面上の方向分布 | 分布埋め込みの基礎 |
| 分布の集中の度合い | 確信度の定量化 | |
| 分布埋め込み | 点ではなく分布としての表現 | 不確実性の明示的モデル化 |
| OOD検知 | 分布外入力の検出 | 低 |
| ハルシネーション | 低確信度での誤った生成 | |
| 座標フリー比較 | 回転不変統計量による比較 | 整列なしの分布比較 |
本回のポイント
従来の点埋め込みから分布埋め込みへの移行は、単なる技術的な拡張ではない。「分かりません」と言える能力をモデルに与えるという、質的な変化である。
ただし、この能力は設計によって獲得されるものであり、自動的には得られない。
重要な認識:点埋め込みは分布埋め込みと対立するものではなく、
視点の階層:「点」という言葉の多義性
本回では、「点」から「分布」への移行を扱った。しかし、最後に一つ重要な注意がある。我々が学習した分布のパラメータ
これは混乱を招きやすいが、以下の3つの階層を区別すれば整理できる:
| 階層 | 実体 | 直感的イメージ | 不確実性の有無 |
|---|---|---|---|
| レベル1:表現空間の点 | プラネタリウムの星(単一の方向) | なし( | |
| レベル2:表現空間の分布 | 星の周りの霧(広がりを持つ分布) | あり( | |
| レベル3:統計多様体の点 | その霧の形を指定する座標 | (次の階層で議論) |
従来の点埋め込み(レベル1)を分布埋め込み(レベル2)に拡張したことで、解像度が上がった。しかし、その分布を指定するパラメータ
Appendix 4「空間の物差し再考」 では、この第3の階層を扱う。そこでは、パラメータ空間上の「点」が実は確率分布そのものを代表しており、点と点の間の「距離」(KLダイバージェンス、フィッシャー情報行列)が持つ深い意味を議論する。本回で得た直感が、より普遍的な情報幾何学の視点へと接続される。
プラネタリウムのメタファーで言えば:
点だけでなく、その周りの「霧」を見よ。そしてその霧を決める「設計図」にも注目せよ。
星の位置(点埋め込み)だけでなく、星の周りのにじみ具合(分布の広がり)にも情報がある。そして、そのにじみ方を決めるパラメータ(統計多様体の点)にも、また別の幾何学が宿っている。霧が濃い領域では慎重に、霧が晴れた領域では自信を持って。この使い分けが、信頼できるAIへの道を開く。
発展的トピック: Zipf則の幾何学的正体 ~なぜ「頻出語」は広がるのか~
「頻度が高い単語(例:'run', 'set', 'get')」は、なぜ埋め込み空間で扱いづらいのだろうか?
特に静的埋め込み(Word2Vec、GloVeなど)では 、頻度が高い単語はノルムが大きくなる傾向が観察されてきた(ただし、正規化や学習設定により変わる)。しかし、 近年の研究は、より本質的な視点を提供している 。
Nagata et al. (2023) は、埋め込みの 分散(Variance) が意味の違いを捉える重要な指標であることを実証した。さらに、Nagata et al. (2025) は、この現象の背後にある言語学的原理を明らかにした:
- Zipfの意味-頻度則:頻度が高い単語ほど、多くの意味を持つ(多義性が高い)。
- 文脈的多様性(Contextual Diversity)の本質:頻度が高いから意味が広いのではなく、「多様な文脈で使われる」から意味が広がるのである。
これを本講義の「プラネタリウム」のメタファーで捉え直すと、どうなるか?
多様な文脈 = 広い視野角:様々な文脈に出現する単語は、球面上の「一点」ではなく、 「広い領域」 を占有しなければならない。
幾何学的帰結:つまり、高頻度語(高文脈多様性)は、 集中度
この視点に立てば、「頻度」という統計量は、文脈的多様性を介して、幾何学的な「不確実性(領域の広さ)」へと翻訳される。vMF分布を用いた分布埋め込みは、Zipf則が要求するこの「意味の広がり」を、自然な形で空間に許容する枠組みなのである。ただし、この対応は単純化された直感であり、実際のモデルでは正則化の強さ、コーパスの性質、サブワード化などの影響を受ける。
NOTE
頻度 vs 文脈的多様性:伝統的な言語統計では「頻度」が重視されてきたが、Zipf則の真の駆動力は文脈的多様性であることが明らかになりつつある。実務的には、'the' のような機能語は高頻度だが統語的役割が限定的なため、意味的な揺らぎ(semantic spread)が内容語に比べて小さく見えることがある。一方、'run' のような動詞は頻度も高く文脈的多様性も高いため、広い領域に分散しやすい。
ただし、 多義性が明確に分離している場合 (例:'bank' の「銀行」と「土手」)、単一のvMF分布(単峰分布)で表現すると複数の意味が一つの霧に混ざってしまい、意味の分離(sense separation)が失われる。このような場合は vMF混合モデル(mixture of vMF) や、意味ごとの成分化(contextualized embeddingsでの動的分離など)が必要になる。本講義では単峰vMF分布を第一近似として用いる。
従来のアプローチとの接続:第2回で見た「頻度が高い単語は長いベクトル」という観察(主に静的埋め込みで見られる傾向)は、この文脈的多様性を「ノルム」という形で暗黙的に捉えようとしていたと解釈できる。しかし、ノルムは方向情報と混在するため解釈が困難だった。分布埋め込み(
これは、言語学的観察(Zipf則)と幾何学的設計(vMF分布)が、深いレベルで整合することを示している。頻出語が「扱いにくい」のは偶然ではなく、その語が担う多様な意味が、幾何学的には「広がり」として表現されるべきだからである。
次回予告
第8回「時間の発見」では、時間軸を持つ表現を議論する。
これまで、埋め込みは「一瞬のスナップショット」として扱ってきた。入力が与えられ、一撃で表現が計算され、出力が返される。しかし、意味の理解や生成は、本当に一瞬で完結するのだろうか。
拡散モデルは「ノイズから意味が徐々に立ち上がる」プロセスを明示的に扱う。Chain of Thoughtは「推論の軌跡」を言語化する。これらの手法は、時間という軸を表現学習に導入することの重要性を示唆している。次回は、この「時間の発見」を幾何学的に探求する。
実装ノート
NOTE
以下のコードは PyTorch >= 1.9 を前提とする。vMF関連の実装について:
- サンプリング:Wood's algorithmに基づく実装を示す
- KL・正規化定数:高
・高次元での漸近近似を使用。 が小さい領域では誤差が大きくなる可能性があるため、厳密計算が必要な場合はscipy.special.ive等を使用すること
vMF分布のパラメータ化
コード例: 07_vmf_layer.py
import torch
import torch.nn as nn
import torch.nn.functional as F
class vMFLayer(nn.Module):
"""vMF分布のパラメータを出力する層
入力から平均方向μと集中度κを推定する。
"""
def __init__(self, input_dim, output_dim, kappa_min=1.0, kappa_max=100.0):
super().__init__()
self.output_dim = output_dim
self.kappa_min = kappa_min
self.kappa_max = kappa_max
# μを出力する層(正規化前)
self.mu_layer = nn.Linear(input_dim, output_dim)
# log κを出力する層(スカラー)
self.kappa_layer = nn.Linear(input_dim, 1)
def forward(self, x):
"""
Args:
x: 入力テンソル [batch, input_dim]
Returns:
mu: 平均方向 [batch, output_dim](単位ベクトル)
kappa: 集中度 [batch, 1]
"""
# 平均方向(正規化して単位ベクトルに)
mu = self.mu_layer(x)
mu = F.normalize(mu, dim=-1)
# 集中度(正の値に制約)
log_kappa = self.kappa_layer(x)
# Softplusで正の値に、さらに範囲を制限
kappa = F.softplus(log_kappa)
kappa = self.kappa_min + (self.kappa_max - self.kappa_min) * torch.sigmoid(kappa - 5)
return mu, kappavMF分布からのサンプリング
vMF分布からのサンプリングは、rejection samplingやWood's algorithmを使う。以下は高次元で効率的な方法:
コード例: 07_vmf_sampling.py
import math
import torch
import torch.nn.functional as F
def sample_vmf(mu, kappa, num_samples=1):
"""vMF分布からサンプリング(Wood's algorithm)
Args:
mu: 平均方向 [batch, dim]
kappa: 集中度 [batch, 1]
num_samples: サンプル数
Returns:
samples: サンプル [batch, num_samples, dim]
"""
batch_size, dim = mu.shape
device = mu.device
# κが非常に小さい場合は一様分布からサンプル
if kappa.max() < 1e-6:
samples = torch.randn(batch_size, num_samples, dim, device=device)
return F.normalize(samples, dim=-1)
# Householder変換でμを北極に写す
# e1 = [1, 0, 0, ..., 0]
e1 = torch.zeros(dim, device=device)
e1[0] = 1.0
results = []
for _ in range(num_samples):
# wをサンプル(μ方向の成分)
w = _sample_w(kappa.squeeze(-1), dim) # [batch]
# 球面上の一様な方向をサンプル(μに直交する成分)
v = torch.randn(batch_size, dim - 1, device=device)
v = F.normalize(v, dim=-1)
# 球面座標からデカルト座標へ
sqrt_term = torch.sqrt(torch.clamp(1 - w**2, min=1e-10))
# 北極周りのサンプルを構成
sample_around_north = torch.zeros(batch_size, dim, device=device)
sample_around_north[:, 0] = w
sample_around_north[:, 1:] = sqrt_term.unsqueeze(-1) * v
# Householder変換でμ周りに回転
sample = _householder_rotation(sample_around_north, e1.expand(batch_size, -1), mu)
results.append(sample)
return torch.stack(results, dim=1)
def _sample_w(kappa, dim):
"""vMF分布のw成分をサンプル(rejection sampling)"""
device = kappa.device
batch_size = kappa.shape[0]
# 近似パラメータ
c = torch.sqrt(4 * kappa**2 + (dim - 1) ** 2)
b = (c - 2 * kappa) / (dim - 1)
a = ((dim - 1) + c) / (2 * kappa)
# Rejection sampling
w = torch.zeros(batch_size, device=device)
done = torch.zeros(batch_size, dtype=torch.bool, device=device)
max_iter = 1000
for _ in range(max_iter):
if done.all():
break
# 提案分布からサンプル
eps = torch.rand(batch_size, device=device)
u = torch.rand(batch_size, device=device)
z = torch.cos(math.pi * eps)
w_proposal = (1 + b * z) / (b + z)
# 受理確率
t = kappa * w_proposal + (dim - 1) * torch.log(1 - a * w_proposal)
accept = (dim - 1) * torch.log(1 - a * b) - 1 + torch.log(u) < t
w = torch.where(~done & accept, w_proposal, w)
done = done | accept
return w
def _householder_rotation(x, u, v):
"""Householder反射を用いてuをvに写す変換をxに適用
uとvが単位ベクトルのとき、w = normalize(v - u) に対する
Householder反射 H = I - 2ww^T は、uをvに写す。
注意:厳密には反射であり回転ではない(行列式が-1)。
vMFサンプリングの文脈では、北極周りの点をμ周りに移動させる
という目的は多くの場合達成できる。ただし、以下の場合は
2回の反射(=回転)やRodriguesの回転公式を検討すること:
- 時間方向の連続性・滑らかさが必要な場合
- 後段処理が「回転」としての性質(det=+1)を仮定する場合
"""
# u, vは単位ベクトル
# 反射軸: w = normalize(v - u)
w = v - u
w_norm = w.norm(dim=-1, keepdim=True)
# u ≈ v の場合(反射不要)
mask = (w_norm < 1e-6).squeeze(-1)
if mask.all().item():
return x
w = w / (w_norm + 1e-8)
# Householder反射: x' = x - 2(x·w)w
x_reflected = x - 2 * (x * w).sum(dim=-1, keepdim=True) * w
# u ≈ v の場合は元のxを返す
x_result = torch.where(mask.unsqueeze(-1), x, x_reflected)
return x_resultvMF間のKLダイバージェンス
CAUTION
以下の実装は高
コード例: 07_vmf_kl_divergence.py
import math
import torch
def kl_divergence_vmf_approx(mu1, kappa1, mu2, kappa2):
"""2つのvMF分布間のKLダイバージェンス【高κ近似版】
KL(vMF(μ1, κ1) || vMF(μ2, κ2))
WARNING: この実装は高κ・高次元での漸近近似を使用。
κ < 10 程度の領域では誤差が大きくなる可能性がある。
Args:
mu1, mu2: 平均方向 [batch, dim]
kappa1, kappa2: 集中度 [batch, 1]
Returns:
kl: KLダイバージェンス [batch](近似値)
"""
dim = mu1.shape[-1]
# コサイン類似度
cos_sim = (mu1 * mu2).sum(dim=-1, keepdim=True)
# Bessel関数の比(高κ近似)
A1 = _bessel_ratio_approx(kappa1, dim)
# 正規化定数の差(対数、高κ近似)
log_C1 = _log_normalizer_vmf_approx(kappa1, dim)
log_C2 = _log_normalizer_vmf_approx(kappa2, dim)
# KLダイバージェンス
kl = log_C2 - log_C1 + kappa1 * A1 - kappa2 * A1 * cos_sim
return kl.squeeze(-1)
def _bessel_ratio_approx(kappa, dim):
"""Bessel関数の比 I_{d/2}(κ) / I_{d/2-1}(κ) の高κ近似
WARNING: κが小さい(< 10程度)場合、この近似は不正確。
厳密計算には scipy.special.ive を使用すること。
"""
# 高κでの近似: A(κ) ≈ 1 - (d-1)/(2κ)
nu = dim / 2 - 1
return 1 - (2 * nu + 1) / (2 * kappa + 1e-8)
def _log_normalizer_vmf_approx(kappa, dim):
"""vMF分布の対数正規化定数 log C_d(κ) の高κ近似
WARNING: κが小さい(< 10程度)場合、この近似は不正確。
厳密計算には scipy.special.ive を使用すること。
近似式: log C ≈ (d/2 - 1) * log κ - d/2 * log(2π) - κ
(Stirling近似に基づく、高κ・高次元での漸近展開)
"""
nu = dim / 2 - 1
return nu * torch.log(kappa + 1e-8) - (dim / 2) * math.log(2 * math.pi) - kappa
# 参考:厳密計算が必要な場合のスケルトン
def _log_normalizer_vmf_exact(kappa, dim):
"""vMF分布の対数正規化定数(厳密版、要scipy)
log C_d(κ) = (d/2 - 1) * log κ - (d/2) * log(2π) - log I_{d/2-1}(κ)
数値安定性のため、スケール付きBessel関数 ive を使用:
I_ν(κ) = ive(ν, κ) * exp(κ)
よって log I_ν(κ) = log(ive(ν, κ)) + κ
WARNING: この関数はNumPy配列またはPython floatを想定。
PyTorch tensorを渡す場合は事前に変換すること:
kappa_np = kappa.detach().cpu().numpy()
result_np = _log_normalizer_vmf_exact(kappa_np, dim)
result = torch.from_numpy(result_np).to(kappa.device)
"""
# from scipy.special import ive
# import numpy as np
# nu = dim / 2 - 1
# # ive(nu, kappa) は exp(-kappa) * I_nu(kappa) を返す(オーバーフロー防止)
# log_ive = np.log(np.maximum(ive(nu, kappa), 1e-300))
# log_bessel = log_ive + kappa # log I_nu(kappa) を復元
# return nu * np.log(kappa) - (dim / 2) * np.log(2 * np.pi) - log_bessel
raise NotImplementedError("厳密計算にはscipyが必要。上記コメントを参照。")
# 互換性のためのエイリアス(旧名で呼び出すコードがある場合用)
kl_divergence_vmf = kl_divergence_vmf_approx確信度に基づくOOD検知
IMPORTANT
- 閾値の選定(Precision-Recallトレードオフの確認)
- 温度スケーリング等による
の校正 - 分布内/分布外の
分布の可視化
コード例: 07_ood_detector.py
import warnings
import torch
class OODDetector:
"""κに基づくOOD検知
WARNING: 閾値はデータセット・モデルに依存する。
必ず検証セットで校正すること。
"""
def __init__(self, threshold=10.0):
self.threshold = threshold
self._is_calibrated = False
def calibrate(self, kappa_in, kappa_out, target_fpr=0.05):
"""検証セットで閾値を校正
Args:
kappa_in: 分布内データのκ。1D tensor [n_in] を想定。
2D [n_in, 1] の場合は自動的にsqueezeされる。
kappa_out: 分布外データのκ。1D tensor [n_out] を想定。
2D [n_out, 1] の場合は自動的にsqueezeされる。
target_fpr: 目標偽陽性率(分布内をOODと誤判定する率)
NOTE: 本実装では「分布内サンプルを誤ってOODと判定する率」を
FPR(False Positive Rate)と定義している。
文献によっては「OODサンプルを誤って分布内と判定する率」を
FPRとする場合もあるため、比較時は定義に注意すること。
Returns:
calibrated_threshold: 校正された閾値
"""
# 形状を1Dに統一
kappa_in = kappa_in.squeeze()
kappa_out = kappa_out.squeeze()
# 分布内データのκ分位点から閾値を決定
# target_fpr = 0.05 なら、分布内の5%がOODと判定される閾値
self.threshold = torch.quantile(kappa_in, target_fpr).item()
self._is_calibrated = True
# 検出率(分布外をOODと正しく判定する率)を計算
tpr = (kappa_out < self.threshold).float().mean().item()
print(f"Calibrated threshold: {self.threshold:.2f}")
print(f" FPR (in-dist as OOD): {target_fpr:.1%}")
print(f" TPR (out-dist as OOD): {tpr:.1%}")
return self.threshold
def is_ood(self, kappa):
"""κが閾値以下ならOODと判定
Args:
kappa: 推定された集中度 [batch, 1] または [batch]
Returns:
ood_mask: OODフラグ [batch]
"""
if not self._is_calibrated:
warnings.warn(
"OODDetector is not calibrated. Results may be unreliable.",
stacklevel=2,
)
return kappa.squeeze(-1) < self.threshold
def get_confidence(self, kappa):
"""κを[0, 1]の確信度スコアに変換
Args:
kappa: 集中度 [batch, 1] または [batch]
Returns:
confidence: 確信度スコア [batch]
"""
# シグモイドで[0, 1]に変換
# threshold周りで0.5になるように調整
return torch.sigmoid((kappa.squeeze(-1) - self.threshold) / 5.0)
# 使用例
detector = OODDetector(threshold=10.0)
# 仮のκ値
kappa_in_distribution = torch.tensor([[50.0], [30.0], [25.0]])
kappa_out_of_distribution = torch.tensor([[5.0], [3.0], [1.0]])
print("In-distribution:")
print(f" OOD: {detector.is_ood(kappa_in_distribution)}")
print(f" Confidence: {detector.get_confidence(kappa_in_distribution)}")
print("Out-of-distribution:")
print(f" OOD: {detector.is_ood(kappa_out_of_distribution)}")
print(f" Confidence: {detector.get_confidence(kappa_out_of_distribution)}")座標フリーの分布比較
コード例: 07_coordinate_free_comparison.py
import torch
def compare_distributions_coordinate_free(kappa1, kappa2):
"""座標系に依存しない分布の比較
確信度(κ)のみを使った比較。
座標系の整列なしで、2つのモデルの「確信度」を比較できる。
Args:
kappa1, kappa2: 2つのモデルからのκ [batch, 1]
Returns:
comparison: 比較結果の辞書
"""
kappa1 = kappa1.squeeze(-1)
kappa2 = kappa2.squeeze(-1)
return {
"kappa1_mean": kappa1.mean().item(),
"kappa2_mean": kappa2.mean().item(),
"kappa_diff": (kappa1 - kappa2).mean().item(),
"kappa_ratio": (kappa1 / (kappa2 + 1e-8)).mean().item(),
"more_confident": "model1" if kappa1.mean() > kappa2.mean() else "model2",
"correlation": torch.corrcoef(torch.stack([kappa1, kappa2]))[0, 1].item(),
}
# 使用例:2つのモデルの確信度を比較
kappa_model_a = torch.tensor([50.0, 30.0, 45.0, 20.0])
kappa_model_b = torch.tensor([40.0, 35.0, 50.0, 15.0])
comparison = compare_distributions_coordinate_free(kappa_model_a.unsqueeze(-1), kappa_model_b.unsqueeze(-1))
print("Coordinate-free comparison:")
for k, v in comparison.items():
print(f" {k}: {v}")参考文献
分布埋め込みとvMF分布
- Kingma, D. P., & Welling, M. (2014). Auto-Encoding Variational Bayes. ICLR 2014. arXiv: arXiv:1312.6114.
- VAEの原論文。潜在空間をガウス分布として正則化する枠組みを提案。本回では、ガウス空間の不均一性と球面表現への動機付けの文脈で参照。
- Nagata et al. (2023). Variance Matters: Detecting Semantic Differences without Corpus/Word Alignment. EMNLP 2023.
- 本回の中心的な参考文献。埋め込みの分散が意味の違いを検出する上で重要であることを示した。
- Nagata et al. (2025). A New Formulation of Zipf's Meaning-Frequency Law through Contextual Diversity. ACL 2025.
- Zipfの意味-頻度則を文脈的多様性(Contextual Diversity)の観点から再定式化。頻出語が埋め込み空間で広い分散を持つ理論的根拠を提供。本回では、vMF分布における低
(広がり)の言語学的正当性を説明するコラムで言及。
- Zipfの意味-頻度則を文脈的多様性(Contextual Diversity)の観点から再定式化。頻出語が埋め込み空間で広い分散を持つ理論的根拠を提供。本回では、vMF分布における低
- Mardia, K. V., & Jupp, P. E. (2000). Directional Statistics. Wiley Series in Probability and Statistics. Wiley.
- 方向統計学の標準的教科書。vMF分布を含む球面上の分布理論を体系的に扱う。
- Davidson, T. R., Falorsi, L., De Cao, N., Kipf, T., & Tomczak, J. M. (2018). Hyperspherical Variational Auto-Encoders. UAI 2018. arXiv: arXiv:1804.00891.
- VAEの潜在空間にvMF分布を導入。球面上のサンプリングとreparameterization trickを扱う。
- Diethe, T. (2015). A Note on the Kullback-Leibler Divergence for the von Mises-Fisher distribution. arXiv:1502.07104. arXiv: arXiv:1502.07104.
- vMF分布間のKLダイバージェンスの厳密な導出。数値安定な計算方法についても議論。本回の実装ノートで近似を使う際の参照先。
不確実性の定量化
- Gal, Y., & Ghahramani, Z. (2016). Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning. ICML 2016. arXiv: arXiv:1506.02142.
- Dropoutによる不確実性推定の古典的論文。分布埋め込みとは異なるアプローチだが、不確実性の重要性を示した。
- Sensoy, M., Kaplan, L., & Kandemir, M. (2018). Evidential Deep Learning to Quantify Classification Uncertainty. NeurIPS 2018. arXiv: arXiv:1806.01768.
- 証拠理論に基づく不確実性の定量化。OOD検知への応用を扱う。
OOD検知
- Hendrycks, D., & Gimpel, K. (2017). A Baseline for Detecting Misclassified and Out-of-Distribution Examples in Neural Networks. ICLR 2017. arXiv: arXiv:1610.02136.
- OOD検知のベースライン手法。Softmax確率を使った単純だが効果的な方法を提案。
- Lee, K., Lee, K., Lee, H., & Shin, J. (2018). A Simple Unified Framework for Detecting Out-of-Distribution Samples and Adversarial Attacks. NeurIPS 2018. arXiv: arXiv:1807.03888.
- Mahalanobis距離に基づくOOD検知。特徴空間の幾何学を活用。
ハルシネーションと信頼性
- Ji, Z., Lee, N., Frieske, R., Yu, T., Su, D., Xu, Y., Ishii, E., Bang, Y., Madotto, A., & Fung, P. (2023). Survey of Hallucination in Natural Language Generation. ACM Computing Surveys, 55(12), 1-38. arXiv: arXiv:2202.03629.
- ハルシネーションの包括的サーベイ。原因、検出、緩和策を整理。
- 本回の不確実性推定(低
の検出)では対処できない、「高 だが誤った方向」を指すハルシネーションについては、Appendix 2: 多様体の純度問題で扱う。幾何学が「データの真偽」に対して原理的に中立である理由と、外部検証が必要となる構造を説明している。
球面上のサンプリング
- Wood, A. T. A. (1994). Simulation of the von Mises Fisher Distribution. Communications in Statistics - Simulation and Computation, 23(1), 157-164. DOI: 10.1080/03610919408813161.
- vMF分布からの効率的なサンプリングアルゴリズム。実装ノートで使用した方法の原典。