本記事では、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次元の位置情報を持つ
参考文献
- Dosovitskiy, A., et al. (2020). An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale. ICLR 2021.
- Wang, P., et al. (2024). Qwen2-VL: Enhancing Vision-Language Model's Perception of the World at Any Resolution. arXiv:2409.12191.