Masato Izumi Portfolio

ViT(Vision Transformer)画像埋め込み解説

  • Transformer
  • 機械学習
  • ViT
  • 画像処理

本記事では、Vision Transformer(ViT)がどのように画像をベクトル化するかを解説します。テキストの埋め込みと対比しながら、画像特有の処理を理解していきます。

テキストと画像の対比

テキスト:
  "今日は晴れ" → トークン化 → ["今日", "は", "晴れ"] → 埋め込み層 → ベクトル列

画像:
  [画像データ] → パッチ分割 → [パッチ1, パッチ2, ...] → 線形投影 → ベクトル列

画像では「パッチ」がトークンに相当します。

画像のパッチ分割

ステップ1: 画像をグリッド状に分割

元の画像 (224×224ピクセル)
┌────┬────┬────┬────┬────┬────┬────┐
│    │    │    │    │    │    │    │  ...
├────┼────┼────┼────┼────┼────┼────┤
│    │    │    │    │    │    │    │  ...
├────┼────┼────┼────┼────┼────┼────┤
...

16×16ピクセルのパッチに分割
→ 224 ÷ 16 = 14
→ 14 × 14 = 196パッチ

ステップ2: 各パッチをフラット化

1つのパッチ (16×16ピクセル、RGB 3チャンネル)
  → 16 × 16 × 3 = 768個の数値

パッチのピクセル値:
┌─────────────────┐
│ R G B R G B ... │  ← 1行目のピクセル
│ R G B R G B ... │  ← 2行目のピクセル
│ ...             │
└─────────────────┘
  ↓ フラット化
[r₀, g₀, b₀, r₁, g₁, b₁, ..., r₂₅₅, g₂₅₅, b₂₅₅]  ← 768次元ベクトル

線形投影(Patch Embedding)

テキストとの違い

テキスト:
  トークンID → 埋め込み層(テーブル参照)→ ベクトル
  ※ 離散的なID → ルックアップ

画像:
  パッチ(768次元)→ 線形投影(行列積)→ ベクトル(768次元など)
  ※ 連続的な数値 → 行列演算

線形投影の仕組み

$$ \text{出力} = \text{パッチベクトル} \times W + b $$
パッチベクトル (768次元)     投影行列 W (768×768)      出力 (768次元)
[r₀, g₀, b₀, ..., b₂₅₅]  ×  [学習されるパラメータ]  =  [x₀, x₁, ..., x₇₆₇]

入力:  生のピクセル値(意味を持たない数値の羅列)
出力:  意味的な特徴を捉えたベクトル

なぜテーブル参照ではなく行列積か

テキスト 画像
入力の性質離散的("猫" or "犬"、中間はない)連続的(0〜255の任意の値)
パターン数有限(語彙5万語など)無限(パッチのパターンは無限)
埋め込み方法テーブルで全パターンを持てる関数(行列積)で変換する必要がある

全体の流れ

画像 (224×224×3)
    ↓ パッチ分割 (16×16)
196個のパッチ (各16×16×3 = 768ピクセル)
    ↓ フラット化
196個のベクトル (各768次元)
    ↓ 線形投影 (学習パラメータ)
196個の埋め込みベクトル (各768次元)
    ↓ [CLS]トークンを先頭に追加
197個のベクトル
    ↓ 位置エンコーディング追加
197個の位置情報付きベクトル
    ↓ Transformer Encoder
197個の出力ベクトル
    ↓ [CLS]トークンの出力を使用
1つの画像埋め込み (768次元)

[CLS]トークンとは

画像全体を代表するための特別なトークンです。

入力:
  [CLS] [パッチ1] [パッチ2] ... [パッチ196]
    ↓ Transformer (Self-Attention)
  [CLS'] [パッチ1'] [パッチ2'] ... [パッチ196']

[CLS]トークンはAttentionで全パッチの情報を集約
→ [CLS']が画像全体の表現になる

なぜ[CLS]を使うのか

方法 説明 欠点
全パッチの平均 単純な平均プーリング 重要な部分も重要でない部分も同じ重み
[CLS]トークン Attentionで重要なパッチに注目 学習で「どこを見るべきか」を獲得

位置エンコーディング(画像版)

なぜ必要か

パッチをフラット化すると位置情報が失われる:

元の画像:
  [顔]  [空]
  [体]  [木]

フラット化後:
  [顔] [空] [体] [木]  ← どれが隣同士かわからない

画像での位置エンコーディング

方法 説明 アプローチ
1次元の位置 パッチ0, パッチ1, パッチ2, ... テキストと同じRoPE的アプローチ
2次元の位置 パッチ(0,0), パッチ(0,1), パッチ(1,0), ... MRoPE的アプローチ(高さと幅を別々に)

テキストと画像の埋め込み比較

項目 テキスト 画像 (ViT)
入力単位トークン(単語/サブワード)パッチ(16×16ピクセル)
入力形式離散的(ID)連続的(ピクセル値)
埋め込み方法テーブル参照線形投影(行列積)
位置情報1次元(シーケンス位置)1次元 or 2次元(行・列)
代表ベクトル[EOS]や平均[CLS]や平均

動的解像度(Qwen2-VL以降)

従来のViTは全ての画像を固定サイズにリサイズしていましたが、最新のモデルでは動的解像度に対応しています。

従来のViT:
  全ての画像を224×224にリサイズ → 196パッチ固定

Qwen2-VL以降:
  画像サイズに応じてパッチ数が変動
  - 小さい画像: 少ないパッチ
  - 大きい画像: 多いパッチ(最大16,384パッチ)

  解像度は28の倍数に調整
  パッチサイズは14×14ピクセル

画像サイズ 448×448:
  → 448 ÷ 14 = 32
  → 32 × 32 = 1,024パッチ

画像サイズ 224×224:
  → 224 ÷ 14 = 16
  → 16 × 16 = 256パッチ

マルチモーダル(テキスト+画像)の統合

テキスト: "この画像に写っているのは"
画像:     [猫の画像]

処理:
  テキスト → トークン埋め込み → [T₁] [T₂] [T₃] [T₄] [T₅]
  画像     → パッチ埋め込み   → [I₁] [I₂] [I₃] ... [I₁₉₆]

統合(連結):
  [T₁] [T₂] [T₃] [T₄] [T₅] [I₁] [I₂] [I₃] ... [I₁₉₆]
                            ↑
                        テキストと画像を同じシーケンスに

→ Transformerで一緒に処理
→ テキストと画像の関係を学習

まとめ

テキスト埋め込み:
  単語 → ID → テーブル参照 → ベクトル

画像埋め込み (ViT):
  画像 → パッチ分割 → 線形投影 → ベクトル

共通点:
  - 入力を「トークン列」として扱う
  - Transformerで処理できる形式に変換
  - 位置エンコーディングで位置情報を追加

違い:
  - テキストは離散(テーブル)、画像は連続(行列積)
  - 画像は2次元の位置情報を持つ

参考文献

記事一覧に戻る