Skip to content
第11回:感覚の統合 ~異種多様体の結婚~

第11回:感覚の統合 ~異種多様体の結婚~

注意事項

  • CLIPの「同じ空間に整列」は、テキスト・画像の両エンコーダ出力が L2 正規化されている場合に cos 類似度が角度として解釈できる。
  • 「統一多様体」は設計目標であり、実際に単一の滑らかな多様体になっている保証はない。
  • コントラスト学習の「引力・斥力」は比喩的表現。
  • ImageBindやONE-PEACEなどの最新手法も、「統一」の程度や質については議論の余地がある。

導入:異なる感覚器官を持つ知性

人間は、視覚、聴覚、触覚、言語といった複数の感覚を統合して世界を理解している。目の前のリンゴを見て、その名前を言い、手に取ったときの重さを感じる。これらの情報は、脳内で何らかの形で統合され、「リンゴ」という一貫した概念を形成する。

機械学習においても、この「感覚の統合」は長年の課題であった。テキスト、画像、音声、動画——それぞれのモダリティは、全く異なる形式でデータが表現されている。これらをどう接続し、統合するか。

本回では、マルチモーダル学習を幾何学的な視点から再検討する。特に、CLIPに代表される対照学習が「異なる多様体を同じ空間に整列させる」という操作を、球面幾何学の言葉で理解する。そして、この「統一」がもたらす利点と限界、さらには次世代への示唆を探る。

異種多様体:それぞれの「住む世界」

モダリティごとの構造的特性

各モダリティは、本質的に異なる構造を持っている。

テキスト は離散的なトークン列である。単語や文字という離散的な単位が、文法という規則に従って順序付けられる。「猫が魚を食べる」と「魚が猫を食べる」では、同じ単語を使っていても意味が全く異なる。順序と文法構造が意味を決定する。

画像 は連続的なピクセル配列である。隣接するピクセルは通常、類似した値を持つ(空間的連続性)。また、物体は局所的なパターン(エッジ、テクスチャ)の組み合わせとして認識される。画像の意味は、空間的な配置に強く依存する。

音声 は時間方向の連続信号である。周波数特性(どの音程が含まれるか)と時間的な変化(どう音が推移するか)の両方が意味を担う。音楽では和音構造、音声では音素の遷移パターンが重要になる。

モダリティ基本単位構造意味を担う要素
テキストトークン(離散)順序依存、文法構造単語の選択と配置
画像ピクセル(連続)空間依存、局所パターン形状、色、テクスチャ
音声波形サンプル(連続)時間依存、周波数特性音程、リズム、音色

多様体としての解釈

第0回で導入した多様体仮説を思い出そう。高次元空間に埋め込まれたデータは、実際にはより低次元の多様体上に集中している。

この視点に立つと、各モダリティのデータは異なる多様体に住んでいると考えられる。テキストの多様体は離散的な構造を反映し、画像の多様体は空間的な連続性を反映する。これらは、同じ高次元空間に埋め込まれていても、異なる「形」 を持っている。

問題は、これらの異なる多様体をどう接続するかである。

NOTE

「多様体」という言葉の使い方について: 厳密には、離散的なテキストデータが滑らかな多様体を成すわけではない。ここでの「多様体」は、各モダリティの表現が持つ低次元構造を指す比喩的な用法である。重要なのは、各モダリティが独自の内部構造を持っており、それらが互いに異なるという点である。

CLIPの革命:共有空間への整列

対照学習の基本アイデア

CLIP(Contrastive Language-Image Pre-training)(Radford et al., 2021)は、テキストと画像を同じ埋め込み空間に配置するという、シンプルだが強力なアイデアを実現した。

基本的な仕組みは以下の通りである:

  1. ペアデータの収集:インターネットから、画像とそれに付随するテキスト(キャプション、alt text等)のペアを大量に収集する。
  2. 独立したエンコーダ:テキストエンコーダ(Transformer)と画像エンコーダ(ViTやResNet)を用意する。
  3. 対照学習:正しいペアは近くに、誤ったペアは遠くに配置されるよう学習する。

損失関数の幾何学

CLIPの損失関数は、InfoNCE損失 の一種である。まず、テキストから画像への方向を考えると:

Lti=1Ni=1Nlogexp(sim(ti,ii)/τ)j=1Nexp(sim(ti,ij)/τ)

ここで:

  • ti はテキスト埋め込み、 ij は画像埋め込み
  • sim(t,i)=titi はコサイン類似度
  • τ は温度パラメータ
  • N はバッチサイズ

CLIPでは、これに加えて画像からテキストへの方向 Lit も計算し、両方向の平均 L=(Lti+Lit)/2 を最終的な損失とする(対称化)。

CLIPでは、テキストと画像の埋め込みは L2 正規化されるため、 sim(t,i)=cosθ となる。これにより、類似度は純粋に角度で測られる。

IMPORTANT

正規化の重要性: CLIPが「角度ベースの類似度」を実現できるのは、両エンコーダの出力を L2 正規化しているからである。正規化なしでは、ベクトルのノルム(大きさ)が類似度に影響し、角度の解釈が成り立たなくなる。これは第3回・第6回で議論した正規化の設計原則と整合する。

球面上の「引力」と「斥力」

対照学習を幾何学的に解釈しよう。

正規化された埋め込みは、単位球面 Sd1 上の点として表現される。CLIPの学習は、この球面上で以下の操作を行っていると見なせる:

正例ペア(同じ画像-テキストペア):球面上で近づける。つまり、なす角 θ を小さくする。

負例ペア(異なる画像-テキストペア):球面上で遠ざける。つまり、なす角 θ を大きくする。

これは、球面上での引力と斥力のシミュレーションと読める。正例ペアには引力が働き、負例ペアには斥力が働く。学習が収束すると、意味的に関連するテキストと画像は球面上の近い位置に、無関係なものは遠い位置に配置される。

操作幾何学的効果物理的メタファー
正例を近づけるcosθ1 (角度を小さく)引力
負例との相対順位を下げる正例より cosθ が小さくなる相対的な斥力

NOTE

「引力・斥力」は比喩: この物理的メタファーは直感的な理解を助けるが、実際の最適化は勾配降下法で行われており、力学シミュレーションではない。また、InfoNCE損失は負例を「できるだけ cosθ=1 に追い込む」わけではなく、Softmax内での正例の相対的な順位を上げる圧力が中心である。負例の最終的な配置は、バッチ内の分布状況や温度パラメータに依存する。

温度パラメータの役割

温度 τ は、第4回で議論したSoftmaxの温度と同じ役割を果たす。

  • 低温( τ0:分布が鋭くなり、最も類似度の高いペアに集中する。ハードな負例マイニングに近づく。
  • 高温( τ:分布が均一になり、すべてのペアが等しく扱われる。

多くのCLIP実装では、 τ は学習可能なパラメータとして扱われる。典型的には、 1/τ に相当する logit_scale をログ空間で学習する形が採られる(logit_scale = nn.Parameter(torch.log(torch.tensor(1/0.07)))のように初期化)。実際の計算では logits = logit_scale.exp() * (text_emb @ image_emb.T) のように、exp() を通して正のスケールとして類似度に掛けられる。適切な温度は、正例と負例の区別の「粒度」を制御する。

統一多様体の問題:「無理やり同じドームに押し込む」歪み

モダリティ固有の構造が取り出しにくくなる可能性

CLIPのアプローチには、根本的な問題がある。異なるモダリティを同じ空間に押し込むことで、各モダリティに固有の構造が最終表現から取り出しにくくなる可能性があるのだ。

画像の空間的隣接関係:画像では、「猫の顔」と「猫の尻尾」は空間的に離れているが、同じ「猫」という概念に属する。しかし、テキストでは「顔」と「尻尾」は別の単語であり、その空間的関係は表現されない。統一空間では、この画像固有の空間構造が明示的には保持されにくい。

テキストの構文構造:テキストでは、主語-動詞-目的語の関係や、修飾関係といった構文構造が意味を担う。画像にはこのような階層的な文法構造は存在しない。統一空間では、この構文的な情報が線形に取り出しにくくなる可能性がある。

取り出しにくくなりうる構造説明影響
画像の空間的関係ピクセル間の隣接関係、物体の配置最終表現から線形に取り出しにくい
テキストの構文構造文法的な依存関係、係り受け下流タスクで活用しにくくなりうる
音声の時間的連続性音の遷移パターン、リズム線形プローブで拾いにくい

NOTE

「失われる」ではなく「取り出しにくくなる」: ここで注意すべきは、画像エンコーダ(ViT/ResNet)は内部で空間的帰納バイアスを保持し、テキストエンコーダ(Transformer)も内部で構文的手がかりを保持しているという点である。最終的な共有埋め込みは「タスクに必要な情報を圧縮した結果」であり、モダリティ固有の構造が完全に失われるわけではない。ただし、その情報が最終表現から線形に取り出せるか下流タスクで活用しやすいかは別問題である。

モダリティギャップ

実際の学習済みCLIPモデルを調べると、テキスト埋め込みと画像埋め込みは、同じ空間内でも異なる領域に分布していることが観察されている(Liang et al., 2022)。これをモダリティギャップ(modality gap) と呼ぶ。

球面上で考えると、テキストの埋め込みが集まる領域と、画像の埋め込みが集まる領域が、ある程度分離しているのだ。これは、「統一」が完全ではないことを示唆している。

CAUTION

「統一多様体」は設計目標であり、達成された事実ではない: CLIPが「テキストと画像を同じ空間に埋め込んでいる」という表現は、厳密には「同じベクトル空間に射影している」という意味であり、それらが単一の滑らかな多様体を形成しているわけではない。モダリティギャップの存在は、この区別の重要性を示している。

ゼロショット転移の限界

CLIPの強力な能力の一つは、ゼロショット転移 である。学習時に見たことのないカテゴリでも、テキストプロンプト(例:「a photo of a dog」)との類似度を計算することで分類できる。

しかし、この能力にも限界がある:

  1. 細粒度の区別:「柴犬」と「秋田犬」のような細かい区別は、テキストプロンプトだけでは難しい。
  2. 構成的な理解:「赤いリンゴの上に青いボール」と「青いリンゴの上に赤いボール」の区別は、属性と物体の組み合わせ(構成性)の理解を必要とするが、CLIPはこれが苦手である(Yuksekgonul et al., 2023)。
  3. カウンティング:「3匹の猫」と「5匹の猫」の区別も困難である。

これらの限界は、「統一空間への埋め込み」というアプローチが、モダリティ間の構造的な対応関係を完全には捉えられていないことを示唆している。

歴史からの教訓:空間を「広げて」解決する

Frustratingly Easy Domain Adaptation (FEDA)

ここで、異なる「世界」を接続する最もシンプルな方法の一つを振り返ってみよう。

2007年、Hal Daumé IIIが提案した FEDA(Frustratingly Easy Domain Adaptation) は、ドメイン適応という課題に対して、驚くほど単純な「空間の拡張」で解決を図った。

当時、ドメイン適応の研究では、手の込んだ特徴設計や学習アルゴリズム側の工夫が多数提案されていた。しかしFEDAは、特徴量を3倍にコピーして繋げるだけという、たった数行で実装できる手法で、多くの設定で既存の強力なベースラインと競争できる性能を示したのである。

幾何学的な本質:次元の直交化

FEDAの核心は、元の d 次元の特徴量 x を、 3d 次元の拡張空間へ写像することである:

ソースドメイン(例:書籍レビュー)のデータ xs

ϕs(xs)=[xs;xs;0]R3d

ターゲットドメイン(例:映画レビュー)のデータ xt

ϕt(xt)=[xt;0;xt]R3d

ここで、3つのブロック(各 d 次元)はそれぞれ以下の役割を担う:

  1. 第1ブロック(共通):両ドメインが共有する情報を配置する軸
  2. 第2ブロック(ソース専用):ソース固有の性質を「逃がす」ための軸
  3. 第3ブロック(ターゲット専用):ターゲット固有の性質を「逃がす」ための軸

これは、共通の性質と個別の性質を幾何学的に分離するという、極めてクリアな設計指針である。ソース固有ブロックとターゲット固有ブロックは、構成上互いに干渉しない(ソースデータではターゲットブロックが0、ターゲットデータではソースブロックが0)という意味で「直交的」である。

「情報の棲み分け」という思想

この手法が「腹立たしいほど簡単(Frustratingly Easy)」と呼ばれつつも強力だったのは、複雑な非線形写像を学ぶ代わりに、空間の構造(直交性)をあらかじめ定義しておくことの威力を示したからである。

学習モデル(SVMなど)は、この拡張された空間で:

  • 第1ブロック(共通軸)の特徴を重視すれば、両ドメインで汎化する
  • 第2・第3ブロック(ドメイン固有軸)の特徴は、各ドメインに特化した調整に使える
アプローチ幾何学的操作利点課題
CLIP型(統一)異なる多様体を強引に重ね合わせる共通概念の抽出に強い固有構造が干渉しやすい(モダリティギャップ)
FEDA型(拡張)空間を広げ、固有構造を別次元へ分離情報の干渉を防げる次元数が増加し、疎性の問題が生じうる

NOTE

「外在的」アプローチとしてのFEDA: FEDAは、データが本来持つ構造を探るのではなく、「外から」次元を付け足すという「外在的」なアプローチである。対照的に、多様体学習は、データが内在的に持つ低次元構造を発見しようとする「内在的」アプローチと言える。

現代への遺産

FEDAの精神は、名前こそ表に出る機会は減ったが、類似の発想が現代の最先端技術の中に見られる:

  • LoRA(Low-Rank Adaptation):巨大な事前学習モデル(Frozen)の横に、小さな「差分空間(Adapter)」を並列に用意する。FEDAが特徴空間(Feature Space)を拡張するのに対し、LoRAはパラメータ空間(Parameter Space)における演算パスを拡張するという違いはあるが、「元の汎用的な知識(Common)」を壊さずに、「特定のタスク固有の知識(Specific)」を別の計算パスとして追加するという点で、幾何学的に類似した設計思想と言える。
  • Mixture of Experts(MoE):第13回で扱うこの手法も、「共有知識」と「専門知識」を分離するという点で、情報の棲み分けという考え方を共有している。
  • モダリティ専用トークン:ImageBindのような現代的なマルチモーダルモデルでも、「共有埋め込み」と「モダリティ専用の表現」を分離する設計が見られる。

NOTE

現代技術との関係: これらの手法がFEDAから直接的に影響を受けたわけではないが、「共通部分と固有部分を明示的に分離する」という幾何学的な設計思想は、時代を超えて繰り返し現れるパターンである。

IMPORTANT

「空間の作り方」の重要性: FEDAが2007年の論文でありながら、現在も引用され続けている(2026年2月時点で引用数は約2,200件)のは、 「モデルを複雑にするのではなく、特徴空間の設計を変えることで問題を解決する」 という普遍的な設計原理を示したからである。これは本講義が一貫して主張する「幾何学的視点」の原点とも言える。

CLIPとの対比:「統一」か「分離」か

第11回の文脈で見ると、CLIPとFEDAは対照的なアプローチを取っている:

  • CLIP:テキストと画像を「同じ場所」に押し込むことで、ゼロショット転移を実現。しかしモダリティギャップという代償を払う。
  • FEDA:ドメイン固有の情報を「別の場所」に逃がすことで、共通部分の純度を保つ。しかし次元数の増加という代償を払う。

どちらが優れているかは、タスクとデータ次第である。しかし重要なのは、「統一」と「分離」のバランスをどう取るかという問いが、マルチモーダル学習の根本的な課題であり続けているという点である。

次世代への示唆:翻訳か統一か

アプローチ1:モダリティ間の構造を保つ写像

「統一」の代わりに、「翻訳」 というアプローチがある。

完全に同じ空間に押し込むのではなく、各モダリティが独自の表現空間を持ちつつ、それらの間の構造をある程度保つ写像を学習する:

f:MtextMimage,g:MimageMtext

ここで M は厳密な多様体を仮定しない、各モダリティの表現空間を表す記号である。

この写像が「意味的に近いものは近くに写す」という性質を持つなら、各表現空間の固有の構造を維持しながら、モダリティ間の変換が可能になる。

NOTE

数学用語の使い方について: ここでの「構造を保つ写像」は、厳密な数学的意味での準同型写像(homomorphism)を指しているわけではない。設計原理としての比喩であり、「近さの関係がある程度保存される」「情報ボトルネックと復元のバランスが取れている」といった直感を表現している。

利点

  • 各モダリティの固有構造を保存しやすい
  • 写像の逆方向も学習可能(双方向の変換)
  • モダリティ固有のタスクと統合タスクを両立できる

課題

  • 写像の学習が複雑になる
  • 「どの程度の構造保存が必要か」の定義がタスク依存

アプローチ2:階層的な統合

もう一つのアプローチは、階層的な統合 である。

低レベル(具体的)では各モダリティの固有構造を保ちつつ、高レベル(抽象的)でのみ共有表現を持つ:

txt
高レベル:抽象的な共通表現(「猫」という概念)
    ↑               ↑
中間レベル:モダリティ依存の中間表現
    ↑               ↑
低レベル:画像の特徴  テキストの特徴

この設計では、「猫の画像」と「猫という単語」は高レベルでは近い表現を持つが、低レベルではそれぞれのモダリティに適した異なる表現を持つ。

NOTE

脳科学との類似: 人間の脳でも、感覚野(視覚野、聴覚野など)は各モダリティに特化しており、高次の連合野で情報が統合されると考えられている。階層的統合は、この生物学的な知見と整合する設計原則である。

アプローチ3:動的な統合

さらに進んだアプローチとして、入力に応じて統合の度合いを変えるという設計がある。

すべての入力に対して同じ「統合の仕方」を適用するのではなく、タスクや文脈に応じて、どのモダリティをどの程度重視するかを動的に決定する。これは第6回で見たAttention機構の精神と通じる。

具体例:ImageBindとその先

ImageBind:6モダリティの統合

ImageBind(Girdhar et al., 2023)は、6つのモダリティ(画像、テキスト、音声、深度、熱画像、IMU)を単一の埋め込み空間に統合することを試みた。

興味深い点は、画像を「アンカー」として使う設計である。すべてのモダリティを画像と対応付けることで、間接的にすべてのモダリティ間の対応が学習される。

モダリティAモダリティB直接のペアデータ
画像テキストあり(CLIP)
画像音声あり(動画から)
画像深度あり(RGB-Dセンサー)
テキスト音声なし(画像経由で接続)

この「画像を介した間接的な接続」により、直接のペアデータがないモダリティ間でも、意味的な対応が生まれる。

「統一」の質を問う

しかし、ImageBindのような手法が本当に「統一された表現」を実現しているかは、議論の余地がある。

疑問1: 6つのモダリティが本当に同じ意味空間に住んでいるのか、それとも単に同じベクトル空間に「押し込まれている」だけなのか。

疑問2: 画像を介した間接的な接続は、直接のペアデータと同じ質の対応を実現できるのか。

疑問3: モダリティ間の「距離」は、意味的な類似度を正しく反映しているのか。

疑問4(画像中心主義): ImageBindでは画像エンコーダが固定(Frozen)されており、他のモダリティのエンコーダが画像空間に「合わせにいく」設計になっている。これは画像中心主義(Visiocentrism) とも呼べるバイアスを生む。音声や深度の表現が、画像で表現しやすい概念に偏り、画像では捉えにくいが他のモダリティでは自然な概念(例:音声の韻律、触覚の質感)が適切に表現されない可能性がある。

これらの問いに対する明確な答えはまだない。マルチモーダル学習は、活発な研究領域であり続けている。

IMPORTANT

「統一」の程度と質: 複数のモダリティを「同じ空間に埋め込む」ことと、それらが「意味的に統一されている」ことは、異なる。前者は技術的に達成できるが、後者は評価が難しい。ベンチマークでの性能向上が、必ずしも「真の統一」を意味するわけではない。

まとめ

概念定義本回での役割
異種多様体各モダリティ固有の構造を持つ表現空間マルチモーダル学習の出発点
対照学習正例を近づけ、負例を遠ざける学習CLIPの基本原理
コサイン類似度正規化されたベクトル間の内積角度ベースの類似度測定
モダリティギャップ異なるモダリティ間の埋め込み領域の分離「統一」の不完全さの指標
FEDA空間を拡張し、共通/固有情報を直交化する手法「分離」による解決の古典的傑作
統一 vs 翻訳単一空間への埋め込み vs 多様体間の写像次世代設計の選択肢

本回のポイント

マルチモーダル学習は、「異なる感覚器官を持つ知性をどう統合するか」という根本的な問いに関わる。

CLIPは、テキストと画像を同じ埋め込み空間に整列させるという、シンプルだが強力なアプローチを示した。対照学習による「引力と斥力」は、球面上での配置問題として幾何学的に理解できる。

しかし、「統一多様体」は設計目標であり、達成された事実ではない。モダリティギャップの存在や、構成的理解の限界は、現在の手法がまだ「真の統一」には至っていないことを示唆している。

次世代への道筋として、「統一」ではなく「翻訳」や「階層的統合」といったアプローチも検討されている。各モダリティの固有構造を尊重しつつ、意味的な対応を実現する——この両立が、マルチモーダル学習の次の課題である。

問い

統一多様体は可能か、それとも複数の多様体を「橋渡し」すべきか?

この問いに対する答えは、まだ出ていない。しかし、幾何学的な視点を持つことで、「何が失われ、何が保存されているか」を明確に議論できるようになる。

次回予告

第12回「双曲幾何学 ~負の曲率の世界~」では、球面とは異なる「曲がった空間」を探る。

これまで見てきた球面は正の曲率を持つ空間だった。しかし、階層構造——木構造、系統樹、組織図——を表現するには、球面は不向きである。負の曲率を持つ双曲空間が、なぜ階層構造の表現に適しているのか。ポアンカレ円盤モデルを通じて、その直感を獲得する。

実装ノート:対照学習の基本

NOTE

以下のコードは PyTorch >= 1.9 を前提とする。

コサイン類似度と対照損失

NOTE

バッチサイズと負例の数: InfoNCE損失の性質上、バッチサイズ N が大きいほど負例(分母の和の項数)が増え、相互情報量の下界がタイトになるため学習効果が高まることが知られている(Oord et al., 2018)。以下のコード例では batch_size=32 としているが、これは教育目的の簡易例である。実際のCLIP学習では数万単位(元論文では32,768)のバッチサイズが重要であり、そのために分散学習や勾配キャッシュなどの技術が用いられる。

コード例: 11_contrastive_loss.py
python
import torch
import torch.nn.functional as F


def cosine_similarity_matrix(text_emb, image_emb):
    """テキストと画像の埋め込み間のコサイン類似度行列を計算

    Args:
        text_emb: テキスト埋め込み [batch_size, dim]
        image_emb: 画像埋め込み [batch_size, dim]

    Returns:
        類似度行列 [batch_size, batch_size]
    """
    # L2正規化
    text_emb = F.normalize(text_emb, dim=-1)
    image_emb = F.normalize(image_emb, dim=-1)

    # コサイン類似度行列(正規化後は内積=コサイン類似度)
    return text_emb @ image_emb.T


def clip_loss(text_emb, image_emb, temperature=0.07):
    """CLIP形式の対照学習損失

    Args:
        text_emb: テキスト埋め込み [batch_size, dim]
        image_emb: 画像埋め込み [batch_size, dim]
        temperature: 温度パラメータ

    Returns:
        損失値(スカラー)
    """
    # 類似度行列
    logits = cosine_similarity_matrix(text_emb, image_emb) / temperature

    # ラベル(対角成分が正例)
    batch_size = text_emb.size(0)
    labels = torch.arange(batch_size, device=text_emb.device)

    # 対称な損失(text→image と image→text の両方向)
    loss_t2i = F.cross_entropy(logits, labels)
    loss_i2t = F.cross_entropy(logits.T, labels)

    return (loss_t2i + loss_i2t) / 2


# 使用例
batch_size, dim = 32, 512
text_emb = torch.randn(batch_size, dim)
image_emb = torch.randn(batch_size, dim)

loss = clip_loss(text_emb, image_emb)
print(f"CLIP Loss: {loss.item():.4f}")

# 類似度行列の可視化用
sim_matrix = cosine_similarity_matrix(text_emb, image_emb)
print(f"Similarity matrix shape: {sim_matrix.shape}")
print(f"Diagonal (positive pairs) mean: {sim_matrix.diag().mean().item():.4f}")
print(
    "Off-diagonal (negative pairs) mean:"
    f" {(sim_matrix.sum() - sim_matrix.diag().sum()).item() / (batch_size * (batch_size - 1)):.4f}"
)

モダリティギャップの可視化

NOTE

簡易指標としての位置づけ: 以下のコードは、モダリティギャップを「重心間の差」「重心間の角度」で測る簡易的な実装例である。これは直感的な理解を助けるための一例であり、論文で用いられる評価指標(例:Liang et al., 2022 の手法)とは異なる場合がある。また、結果はデータ数、バッチング、正規化の有無、学習の進行度合いなどによって大きく変わりうる。

コード例: 11_modality_gap.py
python
import torch
import torch.nn.functional as F


def compute_modality_gap(text_emb, image_emb):
    """モダリティギャップを計算

    Args:
        text_emb: テキスト埋め込み [n_samples, dim]
        image_emb: 画像埋め込み [n_samples, dim]

    Returns:
        ギャップベクトルとその大きさ
    """
    # L2正規化
    text_emb = F.normalize(text_emb, dim=-1)
    image_emb = F.normalize(image_emb, dim=-1)

    # 各モダリティの重心
    text_centroid = text_emb.mean(dim=0)
    image_centroid = image_emb.mean(dim=0)

    # ギャップベクトル(重心間の差)
    gap_vector = text_centroid - image_centroid
    gap_magnitude = gap_vector.norm().item()

    # 重心を正規化して角度も計算
    text_centroid_norm = F.normalize(text_centroid, dim=0)
    image_centroid_norm = F.normalize(image_centroid, dim=0)
    cos_angle = (text_centroid_norm @ image_centroid_norm).item()
    angle_deg = torch.acos(torch.tensor(cos_angle)).item() * 180 / 3.14159

    return {
        "gap_vector": gap_vector,
        "gap_magnitude": gap_magnitude,
        "centroid_angle_deg": angle_deg,
    }


def analyze_intra_inter_similarity(text_emb, image_emb):
    """モダリティ内・モダリティ間の類似度を分析

    Args:
        text_emb: テキスト埋め込み [n_samples, dim]
        image_emb: 画像埋め込み [n_samples, dim]

    Returns:
        各種統計量
    """
    text_emb = F.normalize(text_emb, dim=-1)
    image_emb = F.normalize(image_emb, dim=-1)

    # モダリティ内類似度
    text_sim = text_emb @ text_emb.T
    image_sim = image_emb @ image_emb.T

    # 対角成分を除いた平均(自分自身との類似度を除く)
    n = text_emb.size(0)
    mask = ~torch.eye(n, dtype=torch.bool, device=text_emb.device)

    intra_text = text_sim[mask].mean().item()
    intra_image = image_sim[mask].mean().item()

    # モダリティ間類似度
    cross_sim = text_emb @ image_emb.T
    inter_matched = cross_sim.diag().mean().item()  # 対応するペア
    inter_unmatched = cross_sim[mask].mean().item()  # 対応しないペア

    return {
        "intra_text_similarity": intra_text,
        "intra_image_similarity": intra_image,
        "inter_matched_similarity": inter_matched,
        "inter_unmatched_similarity": inter_unmatched,
    }


# 使用例(擬似的なデータで)
n_samples, dim = 100, 512

# 実際のCLIPでは、テキストと画像は異なる領域に分布する
# ここでは、その様子を模擬的に再現
text_emb = torch.randn(n_samples, dim) + torch.tensor([1.0] + [0.0] * (dim - 1))
image_emb = torch.randn(n_samples, dim) + torch.tensor([-1.0] + [0.0] * (dim - 1))

gap_info = compute_modality_gap(text_emb, image_emb)
print(f"Modality gap magnitude: {gap_info['gap_magnitude']:.4f}")
print(f"Centroid angle: {gap_info['centroid_angle_deg']:.1f} degrees")

sim_info = analyze_intra_inter_similarity(text_emb, image_emb)
print(f"Intra-text similarity: {sim_info['intra_text_similarity']:.4f}")
print(f"Intra-image similarity: {sim_info['intra_image_similarity']:.4f}")
print(f"Inter-matched similarity: {sim_info['inter_matched_similarity']:.4f}")
print(f"Inter-unmatched similarity: {sim_info['inter_unmatched_similarity']:.4f}")

FEDA(空間の拡張)の実装

NOTE

シンプルさの美学: FEDAの実装は驚くほどシンプルである。以下のコードは、特徴量を3倍に拡張するだけの変換を示している。この「たった数行」で、複雑なカーネル法と競合できるのがFEDAの真骨頂である。

コード例: 11_feda.py
python
import torch


def feda_transform(features, domain_label):
    """FEDA変換を適用

    Args:
        features: 元の特徴量 [batch_size, dim]
        domain_label: ドメインラベル ('source' または 'target')

    Returns:
        拡張された特徴量 [batch_size, 3*dim]
    """
    batch_size, dim = features.shape

    # 3つのブロックを準備
    common = features  # 共通ブロック
    source_specific = torch.zeros_like(features)  # ソース専用
    target_specific = torch.zeros_like(features)  # ターゲット専用

    if domain_label == "source":
        source_specific = features
    elif domain_label == "target":
        target_specific = features

    # [共通; ソース専用; ターゲット専用] として結合
    return torch.cat([common, source_specific, target_specific], dim=-1)


def batch_feda_transform(features, domain_labels):
    """バッチ単位でFEDA変換を適用

    Args:
        features: 元の特徴量 [batch_size, dim]
        domain_labels: ドメインラベルのテンソル [batch_size]
                      (0=source, 1=target)

    Returns:
        拡張された特徴量 [batch_size, 3*dim]
    """
    batch_size, dim = features.shape
    expanded = torch.zeros(batch_size, 3 * dim, device=features.device)

    # 共通ブロック(全サンプル共通)
    expanded[:, :dim] = features

    # ソース専用ブロック
    source_mask = domain_labels == 0
    expanded[source_mask, dim : 2 * dim] = features[source_mask]

    # ターゲット専用ブロック
    target_mask = domain_labels == 1
    expanded[target_mask, 2 * dim :] = features[target_mask]

    return expanded


# 使用例
batch_size, dim = 32, 128

# ソースドメインのデータ
source_features = torch.randn(batch_size // 2, dim)
source_labels = torch.zeros(batch_size // 2, dtype=torch.long)

# ターゲットドメインのデータ
target_features = torch.randn(batch_size // 2, dim)
target_labels = torch.ones(batch_size // 2, dtype=torch.long)

# バッチとして結合
all_features = torch.cat([source_features, target_features], dim=0)
all_domain_labels = torch.cat([source_labels, target_labels], dim=0)

# FEDA変換
expanded_features = batch_feda_transform(all_features, all_domain_labels)

print(f"Original feature shape: {all_features.shape}")
print(f"Expanded feature shape: {expanded_features.shape}")

# ソース専用ブロックとターゲット専用ブロックの構造的な分離を確認
# 各サンプルで、ソースブロックとターゲットブロックの一方は常に0になる
source_block = expanded_features[:, dim : 2 * dim]
target_block = expanded_features[:, 2 * dim :]
# ソースサンプルではtarget_blockが0、ターゲットサンプルではsource_blockが0
# なので、要素ごとの積の和は理論的に0になる
element_wise_product = (source_block * target_block).sum()
print(f"Element-wise product sum (structural separation): {element_wise_product.item():.6f}")

# この拡張された特徴量は、通常の分類器(SVMなど)に渡せる
# 分類器は自動的に、共通の特徴と各ドメイン固有の特徴を使い分ける

簡易的なマルチモーダルエンコーダ

コード例: 11_simple_multimodal.py
python
import torch
import torch.nn as nn
import torch.nn.functional as F


class SimpleTextEncoder(nn.Module):
    """簡易的なテキストエンコーダ(教育目的)"""

    def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True, bidirectional=True)
        self.projection = nn.Linear(hidden_dim * 2, output_dim)

    def forward(self, x):
        # x: [batch, seq_len] のトークンID
        emb = self.embedding(x)  # [batch, seq_len, embed_dim]
        _, (h, _) = self.lstm(emb)  # h: [2, batch, hidden_dim]
        h = torch.cat([h[0], h[1]], dim=-1)  # [batch, hidden_dim * 2]
        out = self.projection(h)  # [batch, output_dim]
        return F.normalize(out, dim=-1)  # L2正規化


class SimpleImageEncoder(nn.Module):
    """簡易的な画像エンコーダ(教育目的)"""

    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, output_dim),
        )

    def forward(self, x):
        # x: [batch, input_dim] の画像特徴
        out = self.encoder(x)
        return F.normalize(out, dim=-1)  # L2正規化


class SimpleCLIP(nn.Module):
    """簡易的なCLIPモデル(教育目的)"""

    def __init__(self, vocab_size, text_embed_dim, text_hidden_dim, image_input_dim, image_hidden_dim, shared_dim):
        super().__init__()
        self.text_encoder = SimpleTextEncoder(vocab_size, text_embed_dim, text_hidden_dim, shared_dim)
        self.image_encoder = SimpleImageEncoder(image_input_dim, image_hidden_dim, shared_dim)
        # 学習可能な温度パラメータ(log scaleで初期化)
        self.log_temperature = nn.Parameter(torch.tensor([0.07]).log())

    def forward(self, text_tokens, image_features):
        text_emb = self.text_encoder(text_tokens)
        image_emb = self.image_encoder(image_features)
        return text_emb, image_emb

    def compute_loss(self, text_tokens, image_features):
        text_emb, image_emb = self.forward(text_tokens, image_features)
        temperature = self.log_temperature.exp()

        # 類似度行列
        logits = (text_emb @ image_emb.T) / temperature

        # ラベル
        batch_size = text_emb.size(0)
        labels = torch.arange(batch_size, device=text_emb.device)

        # 対称な損失
        loss_t2i = F.cross_entropy(logits, labels)
        loss_i2t = F.cross_entropy(logits.T, labels)

        return (loss_t2i + loss_i2t) / 2


# 使用例
model = SimpleCLIP(
    vocab_size=10000,
    text_embed_dim=128,
    text_hidden_dim=256,
    image_input_dim=2048,  # 例:ResNetの特徴
    image_hidden_dim=512,
    shared_dim=256,
)

# ダミーデータ
batch_size = 16
text_tokens = torch.randint(0, 10000, (batch_size, 20))  # [batch, seq_len]
image_features = torch.randn(batch_size, 2048)  # [batch, feature_dim]

loss = model.compute_loss(text_tokens, image_features)
print(f"Loss: {loss.item():.4f}")

# 推論時:テキストと画像の類似度を計算
text_emb, image_emb = model(text_tokens, image_features)
similarity = text_emb @ image_emb.T
print(f"Similarity matrix shape: {similarity.shape}")

参考文献

CLIPと対照学習

  • Radford, A., Kim, J. W., Hallacy, C., Ramesh, A., Goh, G., Agarwal, S., Sastry, G., Askell, A., Mishkin, P., Clark, J., Krueger, G., & Sutskever, I. (2021). Learning Transferable Visual Models From Natural Language Supervision. ICML 2021. arXiv: arXiv:2103.00020.
    • CLIPの原論文。対照学習によるテキスト-画像の統一空間を提案。
  • Oord, A. v. d., Li, Y., & Vinyals, O. (2018). Representation Learning with Contrastive Predictive Coding. arXiv:1807.03748.
    • InfoNCE損失を提案。対照学習の理論的基盤。

ドメイン適応と空間の拡張

  • Daumé III, H. (2007). Frustratingly Easy Domain Adaptation. ACL 2007. URL: https://aclanthology.org/P07-1033/.
    • 空間を拡張し、共通/固有情報を直交化する手法を提案。シンプルだが強力なドメイン適応の古典的傑作。

モダリティギャップ

  • Liang, V. W., Zhang, Y., Kwon, Y., Yeung, S., & Zou, J. Y. (2022). Mind the Gap: Understanding the Modality Gap in Multi-modal Contrastive Representation Learning. NeurIPS 2022. arXiv: arXiv:2203.02053.
    • モダリティギャップを発見・分析した論文。統一空間の限界を示す。

CLIPの限界と構成性

  • Yuksekgonul, M., Bianchi, F., Kalluri, P., Jurafsky, D., & Zou, J. (2023). When and Why Vision-Language Models Behave like Bags-of-Words, and What to Do About It? ICLR 2023. arXiv: arXiv:2210.01936.
    • CLIPの構成的理解の限界を分析。属性と物体の組み合わせにおける問題を指摘。

ImageBindと多モダリティ統合

  • Girdhar, R., El-Nouby, A., Liu, Z., Singh, M., Alwala, K. V., Joulin, A., & Misra, I. (2023). ImageBind: One Embedding Space To Bind Them All. CVPR 2023. arXiv: arXiv:2305.05665.
    • 6モダリティを単一空間に統合。画像をアンカーとした設計を提案。

マルチモーダル学習のサーベイ

  • Baltrusaitis, T., Ahuja, C., & Morency, L.-P. (2019). Multimodal Machine Learning: A Survey and Taxonomy. IEEE TPAMI, 41(2), 423-443. DOI: 10.1109/TPAMI.2018.2798607.
    • マルチモーダル学習の包括的なサーベイ。表現、融合、アライメントなどの観点から整理。