📋 このステップで学ぶこと
CLIPとは何か、なぜ革新的なのか
Contrastive Learning(対照学習)の仕組み
画像とテキストを同じ空間に埋め込む方法
ゼロショット画像分類の実装
画像検索(テキスト→画像、画像→画像)
CLIPと生成AI(DALL-E、Stable Diffusion)の関係
マルチモーダルAIの現在と未来
🎨 1. CLIP(Contrastive Language-Image Pre-training)
CLIP は、OpenAIが2021年に発表した画像とテキストを統合的に理解するモデルです。「画像」と「テキスト」という2つの異なる種類のデータを、同じ空間で扱えるようにした革新的な技術です。
1-1. CLIPの基本アイデア
💡 CLIPが解決した問題
従来の画像分類の限界:
・クラスが事前に固定されている(例:ImageNetの1000クラス)
・新しいクラスを追加するには再訓練が必要
・「猫」「犬」など決められたラベルでしか分類できない
CLIPの革新:
・任意のテキストで画像を分類できる
・訓練なしで新しいクラスに対応(ゼロショット)
・「オレンジ色の猫」「窓辺で寝ている猫」など自由に記述可能
【従来の画像分類 vs CLIPの画像分類】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
従来の画像分類(CNN、ViTなど)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: 猫の画像
↓
モデル(ImageNet 1000クラス分類用に訓練)
↓
出力: 確率分布
[0.85(猫), 0.05(犬), 0.03(虎), …]
↓
予測: 「猫」(クラス281)
問題点:
・「ペルシャ猫」と「三毛猫」を区別したい
→ できない(ImageNetには細かい品種がない)
・「寝ている猫」と「遊んでいる猫」を区別したい
→ できない(行動のクラスがない)
・新しいクラス「マンチカン」を追加したい
→ 再訓練が必要(大量のデータと計算資源)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIPの画像分類
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: 猫の画像 + 自由なテキスト候補
テキスト候補(自分で決める!):
“a photo of a Persian cat”
“a photo of a tabby cat”
“a photo of a Munchkin”
“a photo of a sleeping cat”
“a photo of a playing cat”
↓
モデル(画像とテキストの類似度を計算)
↓
出力: 各テキストとの類似度
“Persian cat”: 0.78
“tabby cat”: 0.12
“Munchkin”: 0.05
“sleeping cat”: 0.82 ← 最高!
“playing cat”: 0.08
↓
予測: 「sleeping cat」(寝ている猫)
利点:
・任意のテキストで分類可能
・事前に定義されたクラスに縛られない
・細かい属性(色、行動、品種など)も表現可能
・訓練なしで新しいクラスに対応
1-2. CLIPのアーキテクチャ
CLIPは2つのエンコーダ で構成されています。画像を処理するImage Encoderと、テキストを処理するText Encoderです。
【CLIPの構造】
┌─────────────────────────────────────────────────────────┐
│ CLIP │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Image Encoder │ │ Text Encoder │ │
│ │ │ │ │ │
│ │ ViT または │ │ Transformer │ │
│ │ ResNet │ │ (GPT-2スタイル)│ │
│ │ │ │ │ │
│ │ 入力: 画像 │ │ 入力: テキスト │ │
│ │ 224×224×3 │ │ 最大77トークン │ │
│ │ │ │ │ │
│ │ 出力: 512次元 │ │ 出力: 512次元 │ │
│ │ ベクトル │ │ ベクトル │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ↓ ↓ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 同じ512次元の埋め込み空間 │ │
│ │ │ │
│ │ 画像埋め込み ●───────────● テキスト埋め込み│ │
│ │ ↑ │ │
│ │ 類似度計算 │ │
│ │ (コサイン類似度) │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
重要なポイント:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 同じ次元数の埋め込み
・画像: 512次元ベクトル
・テキスト: 512次元ベクトル
→ 直接比較可能!
2. 意味的な類似性
・「猫の画像」と「a photo of a cat」は近い位置
・「猫の画像」と「a photo of a dog」は遠い位置
→ 意味的に近いものが空間的にも近くなる
3. コサイン類似度
・2つのベクトルの角度の近さを測定
・1に近い: 非常に類似
・0に近い: 無関係
・-1に近い: 正反対
1-3. 埋め込み空間のイメージ
CLIPの核心は、画像とテキストを同じ空間に配置 することです。この空間では、意味的に近いものは近くに、遠いものは遠くに配置されます。
【埋め込み空間の視覚的イメージ】
512次元空間(2次元に簡略化して図示):
↑
│
│ ★”a dog playing”
★”a cat” │ 🐕画像
🐱画像 │
│
────────────────┼────────────────→
│
│ ★”a car on road”
★”a cat │ 🚗画像
sleeping” │
🐱画像 │
│
凡例:
🐱🐕🚗: 画像の埋め込み位置
★: テキストの埋め込み位置
特徴:
・「猫の画像」は「a cat」というテキストの近くに配置
・「犬の画像」は「a dog」というテキストの近くに配置
・「猫の画像」と「犬のテキスト」は遠い位置
これにより:
・画像とテキストの類似度を直接計算できる
・「この画像は何?」という質問に、テキストで答えられる
・「このテキストに合う画像は?」という検索もできる
1-4. Contrastive Learning(対照学習)
CLIPはContrastive Learning(対照学習) という手法で訓練されています。これは「正しいペアを近づけ、間違ったペアを遠ざける」学習方法です。
【Contrastive Learningの基本アイデア】
目標:
正例(Positive): 対応する画像-テキストペア → 近づける
負例(Negative): 対応しない画像-テキストペア → 遠ざける
例(4ペアのバッチ):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
バッチデータ:
ペア1: (🐱画像, “a photo of a cat”)
ペア2: (🐕画像, “a photo of a dog”)
ペア3: (🚗画像, “a photo of a car”)
ペア4: (🌸画像, “a photo of a flower”)
正例(近づけたいペア):
🐱画像 ↔ “a photo of a cat” ← 正しいペア
🐕画像 ↔ “a photo of a dog” ← 正しいペア
🚗画像 ↔ “a photo of a car” ← 正しいペア
🌸画像 ↔ “a photo of a flower” ← 正しいペア
負例(遠ざけたいペア):
🐱画像 ↔ “a photo of a dog” ← 間違いペア
🐱画像 ↔ “a photo of a car” ← 間違いペア
🐱画像 ↔ “a photo of a flower” ← 間違いペア
🐕画像 ↔ “a photo of a cat” ← 間違いペア
… (すべての間違いペア)
学習:
正例の類似度を最大化
負例の類似度を最小化
【類似度行列の計算】
バッチサイズ N の場合:
画像埋め込み: I = [I₁, I₂, I₃, …, Iₙ] (N個)
テキスト埋め込み: T = [T₁, T₂, T₃, …, Tₙ] (N個)
類似度行列 S = I × Tᵀ (N×N行列)
例: N=4の場合
T₁(猫) T₂(犬) T₃(車) T₄(花)
┌───────────────────────────────────┐
I₁(🐱) │ [0.90] 0.15 0.08 0.12 │
I₂(🐕) │ 0.18 [0.85] 0.10 0.15 │
I₃(🚗) │ 0.05 0.08 [0.92] 0.06 │
I₄(🌸) │ 0.10 0.12 0.05 [0.88] │
└───────────────────────────────────┘
[ ] で囲まれた対角要素 = 正例(高くしたい)
それ以外の要素 = 負例(低くしたい)
理想的な類似度行列:
T₁ T₂ T₃ T₄
┌─────────────────────────────┐
I₁ │ [1.0] 0.0 0.0 0.0 │
I₂ │ 0.0 [1.0] 0.0 0.0 │
I₃ │ 0.0 0.0 [1.0] 0.0 │
I₄ │ 0.0 0.0 0.0 [1.0] │
└─────────────────────────────┘
→ 対角要素が1、それ以外が0
1-5. 損失関数(InfoNCE Loss)
CLIPの訓練ではInfoNCE Loss という損失関数を使います。これは対角要素を最大化し、非対角要素を最小化する損失です。
【InfoNCE Lossの仕組み】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
損失関数の定義
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像→テキスト方向の損失:
L_i2t = -log( exp(s_ii / τ) / Σⱼ exp(s_ij / τ) )
説明:
s_ii: i番目の画像とi番目のテキストの類似度(正例)
s_ij: i番目の画像とj番目のテキストの類似度
τ: 温度パラメータ(学習可能、通常0.07程度)
意味:
正例の類似度を、すべてのテキストとの類似度の合計で割る
→ 正例の確率を最大化
テキスト→画像方向の損失:
L_t2i = -log( exp(s_ii / τ) / Σⱼ exp(s_ji / τ) )
説明:
i番目のテキストからi番目の画像を選ぶ確率を最大化
総損失:
L_total = (L_i2t + L_t2i) / 2
→ 双方向で学習(画像→テキスト、テキスト→画像)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
具体例(N=4)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
類似度行列(温度適用後):
T₁ T₂ T₃ T₄
┌─────────────────────────────┐
I₁ │ 12.86 2.14 1.14 1.71 │ ← s_ij / τ
I₂ │ 2.57 12.14 1.43 2.14 │
I₃ │ 0.71 1.14 13.14 0.86 │
I₄ │ 1.43 1.71 0.71 12.57 │
└─────────────────────────────┘
I₁の損失計算:
分子: exp(12.86) = 385,240
分母: exp(12.86) + exp(2.14) + exp(1.14) + exp(1.71)
= 385,240 + 8.5 + 3.1 + 5.5 = 385,257
確率 = 385,240 / 385,257 = 0.99996
損失 = -log(0.99996) ≈ 0.00004(非常に小さい = 良い)
もし正例の類似度が低かったら:
分子: exp(2.0) = 7.4
分母: exp(2.0) + exp(3.0) + … = 50.0
確率 = 7.4 / 50.0 = 0.148
損失 = -log(0.148) ≈ 1.91(大きい = 悪い)
→ 正例の類似度を高くするほど損失が小さくなる
1-6. 大規模データでの事前学習
CLIPの強さの秘密は、4億ペア という膨大な画像-テキストペアで訓練されていることです。
【CLIPの訓練データと規模】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
訓練データ: WebImageText(WIT)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
データ数: 4億ペア(400,000,000)
ソース: インターネットから収集
・Webページの画像とalt-text(代替テキスト)
・画像キャプション
・自然言語で記述された画像の説明
例:
画像: 夕日の写真
テキスト: “a beautiful sunset over the Pacific Ocean”
画像: 猫の写真
テキスト: “an orange tabby cat sleeping on a blue couch”
特徴:
・自然言語(人間が書いたテキスト)
・多様なドメイン(動物、風景、食べ物、人物、建物…)
・多様な表現(詳細な説明、簡潔なタグ、詩的な表現…)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
訓練の規模
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
モデルサイズ:
・Image Encoder: ViT-L/14(約300Mパラメータ)
・Text Encoder: Transformer(約63Mパラメータ)
・合計: 約400Mパラメータ
バッチサイズ: 32,768
→ 1バッチで32,768×32,768 = 10億以上の負例!
→ 非常に効果的な対照学習
訓練:
・256個のV100 GPU
・約2週間
・約400億サンプルを処理
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
なぜこれほど大規模なデータが必要か
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 多様な概念を学習
・一般的な物体(猫、犬、車…)
・抽象的な概念(美しい、怖い、快適…)
・細かい属性(色、形、動作、状態…)
2. 言語の多様性に対応
・同じ概念の異なる表現
“cat” = “kitty” = “feline” = “猫”
・文脈による意味の違い
3. ゼロショット能力の獲得
・見たことのない組み合わせにも対応
・「紫色の象」など訓練データにないものも理解
CLIPモデル
Image Encoder
パラメータ数
ImageNet精度
特徴
CLIP ViT-B/32
ViT-Base, パッチ32
150M
68.3%
高速、軽量
CLIP ViT-B/16
ViT-Base, パッチ16
150M
72.0%
バランス良好
CLIP ViT-L/14
ViT-Large, パッチ14
428M
75.5%
高精度
CLIP ViT-L/14@336
ViT-Large, 336px
428M
76.6%
最高精度
🎯 ゼロショットでこの精度がすごい理由
上記のImageNet精度はゼロショット (ImageNetで訓練していない)での結果です。
比較:
・ResNet-50(ImageNetで訓練): 76.5%
・CLIP ViT-L/14@336(ゼロショット): 76.6%
→ 訓練なしで、訓練済みモデルと同等の精度!
→ CLIPは「訓練していないタスク」でも高性能
🎯 2. ゼロショット画像分類
2-1. ゼロショット分類の仕組み
ゼロショット分類 とは、特定のタスク用に訓練していないモデルで分類を行うことです。CLIPでは、テキストプロンプトを使って任意のクラスに対応できます。
【ゼロショット分類のプロセス】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ1: テキストプロンプトの作成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
分類したいクラスをテキストで記述
例: 6クラス分類(猫、犬、鳥、馬、羊、牛)
クラス1: “a photo of a cat”
クラス2: “a photo of a dog”
クラス3: “a photo of a bird”
クラス4: “a photo of a horse”
クラス5: “a photo of a sheep”
クラス6: “a photo of a cow”
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ2: テキスト埋め込みの計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各テキストをText Encoderで埋め込み
“a photo of a cat” → T₁ (512次元)
“a photo of a dog” → T₂ (512次元)
“a photo of a bird” → T₃ (512次元)
“a photo of a horse” → T₄ (512次元)
“a photo of a sheep” → T₅ (512次元)
“a photo of a cow” → T₆ (512次元)
text_features = [T₁, T₂, T₃, T₄, T₅, T₆] # shape: (6, 512)
※ これは事前に計算しておける(一度だけ)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ3: 画像埋め込みの計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
分類したい画像をImage Encoderで埋め込み
猫の画像 → I (512次元)
image_features = I # shape: (1, 512)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ4: 類似度の計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像とすべてのテキストの類似度を計算
similarity = image_features @ text_features.T
# shape: (1, 6)
結果例:
[0.85, 0.12, 0.08, 0.05, 0.03, 0.02]
猫↑ 犬 鳥 馬 羊 牛
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ5: 確率に変換して予測
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
類似度をsoftmaxで確率に変換
probs = softmax(similarity * 100)
# 100を掛けるのはスケール調整のため
結果例:
猫: 94.32% ← 最高確率
犬: 3.21%
鳥: 0.87%
馬: 0.75%
羊: 0.52%
牛: 0.33%
予測: 「猫」
2-2. プロンプトエンジニアリング
CLIPの精度はプロンプトの書き方 に大きく影響されます。効果的なプロンプトを設計することをプロンプトエンジニアリング と呼びます。
【プロンプトの書き方による精度の違い】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
基本形
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
シンプルなプロンプト:
“cat”
問題:
・文脈がない
・「cat」という単語だけでは曖昧
ImageNet精度: 約65%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
改善版1: 文脈を追加
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
文脈付きプロンプト:
“a photo of a cat”
効果:
・「写真である」という文脈
・より明確な意味
ImageNet精度: 約70%(+5%)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
改善版2: 複数テンプレートの平均
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
複数のテンプレートを使用:
テンプレート1: “a photo of a {class}”
テンプレート2: “a photo of the {class}”
テンプレート3: “a good photo of a {class}”
テンプレート4: “a bad photo of a {class}”
テンプレート5: “a cropped photo of the {class}”
テンプレート6: “a close-up photo of a {class}”
テンプレート7: “a bright photo of the {class}”
テンプレート8: “a dark photo of the {class}”
…(合計80個のテンプレート)
各テンプレートで埋め込みを計算 → 平均を取る
ImageNet精度: 約76%(+6%)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ドメイン特化
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
データセットに応じてプロンプトを調整:
衛星画像:
“a satellite photo of {class}”
“an aerial view of {class}”
医療画像:
“a CT scan showing {class}”
“an X-ray of {class}”
食べ物:
“a photo of {class}, a type of food”
ペット:
“a photo of a {class}, a type of pet”
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
カスタムクラス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIPなら自由にクラスを定義できる:
従来: [“cat”, “dog”, “bird”](固定)
CLIP:
[“sleeping cat”, “playful cat”, “angry cat”] ← 状態で分類
[“orange cat”, “black cat”, “white cat”] ← 色で分類
[“Persian”, “Siamese”, “Tabby”] ← 品種で分類
2-3. 実装:ゼロショット画像分類
CLIPを使ったゼロショット画像分類を実装します。OpenAIの公式CLIPライブラリを使用します。
※ コードが横に長い場合は横スクロールできます
# ===================================================
# CLIPでゼロショット画像分類
# ===================================================
# 必要なライブラリをインポート
import torch
import clip
from PIL import Image
# ===================================================
# 1. モデルのロード
# ===================================================
# 使用するデバイスを設定
# GPUが使えればGPU、なければCPU
device = “cuda” if torch.cuda.is_available() else “cpu”
# CLIPモデルをロード
# clip.load()の引数:
# – “ViT-B/32”: モデルの種類(ViT-Base、パッチサイズ32)
# – device: 計算デバイス(GPUまたはCPU)
# 戻り値:
# – model: CLIPモデル本体
# – preprocess: 画像の前処理関数
model, preprocess = clip.load(“ViT-B/32″, device=device)
print(f”モデル: ViT-B/32″)
print(f”デバイス: {device}”)
実行結果:
モデル: ViT-B/32
デバイス: cuda
# ===================================================
# 2. 画像の前処理
# ===================================================
# 画像を読み込み
# Image.open(): PILで画像を開く
# .convert(‘RGB’): RGB形式に変換(グレースケールやRGBAの場合に対応)
image = Image.open(“cat.jpg”).convert(‘RGB’)
# CLIPの前処理を適用
# preprocess(image):
# – リサイズ(224×224)
# – 正規化(CLIPの訓練時と同じ統計量)
# – テンソルに変換
# .unsqueeze(0): バッチ次元を追加 (3, 224, 224) → (1, 3, 224, 224)
# .to(device): 指定デバイスに転送
image_input = preprocess(image).unsqueeze(0).to(device)
print(f”画像テンソルのshape: {image_input.shape}”)
実行結果:
画像テンソルのshape: torch.Size([1, 3, 224, 224])
# ===================================================
# 3. テキストプロンプトの作成
# ===================================================
# 分類したいクラスのリスト
# 任意のクラスを自由に定義できる!
classes = [“cat”, “dog”, “bird”, “horse”, “sheep”, “cow”]
# プロンプトテンプレートを使ってテキストを作成
# “a photo of a {class}” という形式にすると精度が上がる
text_prompts = [f”a photo of a {c}” for c in classes]
print(“テキストプロンプト:”)
for prompt in text_prompts:
print(f” – {prompt}”)
実行結果:
テキストプロンプト:
– a photo of a cat
– a photo of a dog
– a photo of a bird
– a photo of a horse
– a photo of a sheep
– a photo of a cow
# ===================================================
# 4. テキストのトークン化
# ===================================================
# clip.tokenize(): テキストをトークン(数値)に変換
# CLIPのText Encoderへの入力形式に変換
# .to(device): 指定デバイスに転送
text_inputs = clip.tokenize(text_prompts).to(device)
print(f”テキストトークンのshape: {text_inputs.shape}”)
# shape: (6, 77) → 6つのテキスト、各77トークン(パディング含む)
実行結果:
テキストトークンのshape: torch.Size([6, 77])
# ===================================================
# 5. 埋め込みの計算と類似度算出
# ===================================================
# 勾配計算を無効化(推論時は不要)
with torch.no_grad():
# 画像の埋め込みを計算
# model.encode_image(): Image Encoderで画像を埋め込み
# 戻り値: (1, 512) のテンソル
image_features = model.encode_image(image_input)
# テキストの埋め込みを計算
# model.encode_text(): Text Encoderでテキストを埋め込み
# 戻り値: (6, 512) のテンソル
text_features = model.encode_text(text_inputs)
# ===================================================
# 6. 正規化(コサイン類似度のため)
# ===================================================
# L2正規化: ベクトルの長さを1にする
# これによりドット積がコサイン類似度になる
# norm(dim=-1, keepdim=True): 最後の次元で正規化
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
# ===================================================
# 7. 類似度の計算
# ===================================================
# 行列積で類似度を計算
# image_features: (1, 512)
# text_features.T: (512, 6)
# 結果: (1, 6) → 画像と各テキストの類似度
# 100.0を掛けてスケール調整(CLIPの慣習)
similarity = 100.0 * image_features @ text_features.T
# softmaxで確率に変換
# dim=-1: 最後の次元(クラス次元)でsoftmax
probs = similarity.softmax(dim=-1)
print(f”類似度(スケール後): {similarity[0].tolist()}”)
print(f”確率: {probs[0].tolist()}”)
実行結果:
類似度(スケール後): [26.15, 21.34, 19.87, 18.92, 17.54, 16.89]
確率: [0.9432, 0.0321, 0.0087, 0.0075, 0.0052, 0.0033]
# ===================================================
# 8. 結果の表示
# ===================================================
print(“\n” + “=” * 50)
print(“ゼロショット分類結果”)
print(“=” * 50)
# 各クラスの確率を表示
for i, class_name in enumerate(classes):
prob = probs[0, i].item()
bar = “█” * int(prob * 50) # 確率を視覚的に表示
print(f”{class_name:10s}: {prob*100:6.2f}% {bar}”)
# 最も確率の高いクラスを予測として表示
predicted_idx = probs[0].argmax().item()
predicted_class = classes[predicted_idx]
confidence = probs[0, predicted_idx].item()
print(“=” * 50)
print(f”予測: {predicted_class} (信頼度: {confidence*100:.2f}%)”)
実行結果:
==================================================
ゼロショット分類結果
==================================================
cat : 94.32% ███████████████████████████████████████████████
dog : 3.21% █
bird : 0.87%
horse : 0.75%
sheep : 0.52%
cow : 0.33%
==================================================
予測: cat (信頼度: 94.32%)
🎯 完成コード
以下は上記のコードをまとめた完成版です:
# CLIPゼロショット画像分類 – 完成コード
import torch
import clip
from PIL import Image
# モデルのロード
device = “cuda” if torch.cuda.is_available() else “cpu”
model, preprocess = clip.load(“ViT-B/32”, device=device)
# 画像の前処理
image = Image.open(“cat.jpg”).convert(‘RGB’)
image_input = preprocess(image).unsqueeze(0).to(device)
# テキストプロンプトの作成
classes = [“cat”, “dog”, “bird”, “horse”, “sheep”, “cow”]
text_prompts = [f”a photo of a {c}” for c in classes]
text_inputs = clip.tokenize(text_prompts).to(device)
# 推論
with torch.no_grad():
# 埋め込みの計算
image_features = model.encode_image(image_input)
text_features = model.encode_text(text_inputs)
# 正規化
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
# 類似度計算と確率変換
similarity = 100.0 * image_features @ text_features.T
probs = similarity.softmax(dim=-1)
# 結果表示
print(“ゼロショット分類結果:”)
for i, class_name in enumerate(classes):
prob = probs[0, i].item()
print(f”{class_name}: {prob*100:.2f}%”)
# 予測
predicted_idx = probs[0].argmax().item()
print(f”\n予測: {classes[predicted_idx]}”)
🔍 3. 画像検索(Image Retrieval)
CLIPは画像とテキストを同じ空間に埋め込むため、テキストから画像を検索 したり、画像から類似画像を検索 したりすることができます。
3-1. テキストから画像を検索
【テキスト→画像検索の仕組み】
事前処理(一度だけ):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像データベース内のすべての画像を埋め込み
画像1 → I₁ (512次元)
画像2 → I₂ (512次元)
画像3 → I₃ (512次元)
…
画像N → Iₙ (512次元)
→ 埋め込みを保存(インデックス)
検索時:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 検索クエリ(テキスト)を埋め込み
“a cat playing with a ball” → Q (512次元)
2. クエリとすべての画像の類似度を計算
similarity = Q @ [I₁, I₂, …, Iₙ]ᵀ
→ (1, N) の類似度ベクトル
3. 類似度が高い順にソート
→ Top-K画像を返す
例:
クエリ: “a sunset over mountains”
結果:
1位: 山の夕日の写真 (類似度: 0.89)
2位: 海の夕日の写真 (類似度: 0.76)
3位: 山の朝日の写真 (類似度: 0.68)
…
3-2. 実装:テキストから画像検索
※ コードが横に長い場合は横スクロールできます
# ===================================================
# CLIPでテキストから画像を検索
# ===================================================
import torch
import clip
from PIL import Image
import os
import matplotlib.pyplot as plt
# モデルのロード
device = “cuda” if torch.cuda.is_available() else “cpu”
model, preprocess = clip.load(“ViT-B/32”, device=device)
# ===================================================
# 1. 画像データベースの準備
# ===================================================
# 画像ディレクトリ
image_dir = “image_database”
# 画像ファイルのリストを取得
# .jpg, .png, .jpeg 形式のファイルを対象
image_files = [f for f in os.listdir(image_dir)
if f.lower().endswith((‘.jpg’, ‘.png’, ‘.jpeg’))]
print(f”画像データベース: {len(image_files)}枚”)
実行結果:
画像データベース: 1000枚
# ===================================================
# 2. 全画像の埋め込みを事前計算
# ===================================================
# 埋め込みを格納するリスト
image_features_list = []
print(“画像の埋め込みを計算中…”)
with torch.no_grad():
for i, img_file in enumerate(image_files):
# 画像のパス
img_path = os.path.join(image_dir, img_file)
# 画像を読み込み・前処理
image = Image.open(img_path).convert(‘RGB’)
image_input = preprocess(image).unsqueeze(0).to(device)
# 埋め込みを計算
image_features = model.encode_image(image_input)
# L2正規化
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
# リストに追加
image_features_list.append(image_features)
# 進捗表示(100枚ごと)
if (i + 1) % 100 == 0:
print(f” {i + 1}/{len(image_files)} 完了”)
# すべての埋め込みを1つのテンソルに結合
# shape: (N, 512)
all_image_features = torch.cat(image_features_list, dim=0)
print(f”\n画像埋め込みのshape: {all_image_features.shape}”)
実行結果:
画像の埋め込みを計算中…
100/1000 完了
200/1000 完了
…
1000/1000 完了
画像埋め込みのshape: torch.Size([1000, 512])
# ===================================================
# 3. テキストクエリで検索
# ===================================================
def search_images_by_text(query, top_k=5):
“””
テキストクエリで画像を検索
Args:
query: 検索テキスト
top_k: 返す画像の数
Returns:
検索結果(ファイル名とスコアのリスト)
“””
# テキストをトークン化
text_input = clip.tokenize([query]).to(device)
with torch.no_grad():
# テキストの埋め込みを計算
text_features = model.encode_text(text_input)
# L2正規化
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
# 全画像との類似度を計算
# text_features: (1, 512)
# all_image_features: (N, 512)
# 結果: (1, N) → (N,)
similarity = (text_features @ all_image_features.T)[0]
# Top-K画像を取得
top_k_values, top_k_indices = similarity.topk(top_k)
# 結果を整形
results = []
for idx, score in zip(top_k_indices, top_k_values):
results.append({
‘filename’: image_files[idx.item()],
‘score’: score.item()
})
return results
# 検索を実行
query = “a cat playing with a ball”
results = search_images_by_text(query, top_k=5)
print(f”\n検索クエリ: ‘{query}'”)
print(“-” * 50)
for i, result in enumerate(results):
print(f”{i+1}. {result[‘filename’]} (スコア: {result[‘score’]:.3f})”)
実行結果:
検索クエリ: ‘a cat playing with a ball’
————————————————–
1. cat_playing_001.jpg (スコア: 0.342)
2. kitten_toy_005.jpg (スコア: 0.318)
3. cat_ball_012.jpg (スコア: 0.295)
4. playful_cat_003.jpg (スコア: 0.287)
5. orange_cat_008.jpg (スコア: 0.264)
3-3. 画像から類似画像を検索
# ===================================================
# 画像から類似画像を検索
# ===================================================
def search_similar_images(query_image_path, top_k=5):
“””
クエリ画像に類似した画像を検索
Args:
query_image_path: クエリ画像のパス
top_k: 返す画像の数
Returns:
検索結果(ファイル名とスコアのリスト)
“””
# クエリ画像を読み込み・前処理
query_image = Image.open(query_image_path).convert(‘RGB’)
query_input = preprocess(query_image).unsqueeze(0).to(device)
with torch.no_grad():
# クエリ画像の埋め込みを計算
query_features = model.encode_image(query_input)
# L2正規化
query_features = query_features / query_features.norm(dim=-1, keepdim=True)
# 全画像との類似度を計算
similarity = (query_features @ all_image_features.T)[0]
# Top-K画像を取得(自分自身を除外するため+1)
top_k_values, top_k_indices = similarity.topk(top_k + 1)
# 結果を整形(自分自身を除外)
results = []
query_filename = os.path.basename(query_image_path)
for idx, score in zip(top_k_indices, top_k_values):
filename = image_files[idx.item()]
# クエリ画像自身は除外
if filename == query_filename:
continue
results.append({
‘filename’: filename,
‘score’: score.item()
})
if len(results) >= top_k:
break
return results
# 類似画像検索を実行
query_path = “image_database/my_cat.jpg”
results = search_similar_images(query_path, top_k=5)
print(f”\nクエリ画像: {os.path.basename(query_path)}”)
print(“類似画像:”)
print(“-” * 50)
for i, result in enumerate(results):
print(f”{i+1}. {result[‘filename’]} (スコア: {result[‘score’]:.3f})”)
実行結果:
クエリ画像: my_cat.jpg
類似画像:
————————————————–
1. orange_tabby_015.jpg (スコア: 0.892)
2. sleeping_cat_007.jpg (スコア: 0.856)
3. cat_sofa_023.jpg (スコア: 0.834)
4. tabby_cat_001.jpg (スコア: 0.821)
5. domestic_cat_019.jpg (スコア: 0.798)
🎨 4. CLIPと生成AI
CLIPは、DALL-E 2やStable Diffusionといったテキストから画像を生成するAI の基盤技術として使われています。
4-1. DALL-E 2でのCLIPの役割
【DALL-E 2の構造(簡略版)】
DALL-E 2(2022年、OpenAI):
テキスト → 画像を生成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
構成要素
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. CLIP Text Encoder
・テキストを埋め込みに変換
・CLIPで事前学習済み
2. Prior(プライアー)
・テキスト埋め込み → 画像埋め込みを予測
・「このテキストに対応する画像の埋め込みはこれ」
3. Decoder(デコーダ)
・画像埋め込み → 実際のピクセル
・Diffusion Modelで生成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
処理の流れ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: “an astronaut riding a horse on Mars”
↓
┌─────────────────────────────────────────────┐
│ CLIP Text Encoder │
│ │
│ テキスト → テキスト埋め込み(512次元) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Prior │
│ │
│ テキスト埋め込み → 画像埋め込み(512次元)│
│ │
│ 「このテキストならCLIPの画像埋め込み空間の │
│ この辺りに対応する画像があるはず」 │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Diffusion Decoder │
│ │
│ 画像埋め込み → 実際の画像(1024×1024) │
│ │
│ ノイズから徐々にクリーンな画像を生成 │
└─────────────────────────────────────────────┘
↓
出力: 火星で馬に乗る宇宙飛行士の画像
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIPの役割
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. テキストの理解
・4億ペアで学習した豊富な知識
・「宇宙飛行士」「馬」「火星」を理解
2. 画像埋め込み空間の提供
・Priorのターゲット空間
・意味的に整理された空間
3. 品質の評価
・生成画像がテキストに合っているか確認
4-2. Stable DiffusionでのCLIPの役割
【Stable Diffusionの構造(簡略版)】
Stable Diffusion(2022年、Stability AI):
テキスト → 画像を生成(オープンソース)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
構成要素
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. CLIP Text Encoder
・テキストを埋め込みに変換
・出力: (77, 768) のテキスト埋め込み
・77: 最大トークン数
・768: 埋め込み次元
2. U-Net(ノイズ除去ネットワーク)
・ノイズ画像 → 少しクリーンな画像
・Cross-Attentionでテキスト埋め込みを参照
3. VAE Decoder
・潜在空間 → ピクセル空間
・512×512の画像を生成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
処理の流れ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: “a beautiful sunset over mountains”
↓
┌─────────────────────────────────────────────┐
│ CLIP Text Encoder │
│ │
│ テキスト → テキスト埋め込み(77×768) │
└─────────────────────────────────────────────┘
↓
↓ テキスト埋め込みをU-Netに渡す
↓
┌─────────────────────────────────────────────┐
│ Diffusion Process(50ステップ) │
│ │
│ ステップ1: │
│ ノイズ画像(潜在空間) │
│ ↓ │
│ U-Net(テキスト埋め込みを参照) │
│ ← Cross-Attention でテキストを見る │
│ ↓ │
│ 少しクリーンな画像 │
│ │
│ ステップ2〜50: │
│ 繰り返し… │
│ ↓ │
│ クリーンな画像(潜在空間) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ VAE Decoder │
│ │
│ 潜在空間 → ピクセル空間(512×512) │
└─────────────────────────────────────────────┘
↓
出力: 山の上の美しい夕日の画像
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cross-Attentionの仕組み
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
U-Netの各層でCross-Attentionを実行:
Query(Q): 現在の画像特徴
Key(K): テキスト埋め込み
Value(V): テキスト埋め込み
Attention = softmax(Q × Kᵀ / √d) × V
意味:
画像の各位置が「テキストのどの部分に注目するか」を計算
例:
画像の「空の部分」→ テキストの「sunset」に注目
画像の「下の部分」→ テキストの「mountains」に注目
→ テキストに従った画像が生成される!
💡 なぜCLIPが生成AIに不可欠なのか
1. 豊富な知識
・4億ペアの画像-テキストで学習
・あらゆる概念を理解している
2. 意味的な埋め込み空間
・「宇宙飛行士」と「astronaut」が同じ位置
・関連する概念が近くに配置
3. 画像とテキストの対応
・テキスト埋め込みから画像を生成できる
・生成画像がテキストに合っているか評価できる
現代のText-to-Image生成はCLIPなしでは成り立たない!
🌐 5. マルチモーダルAIの未来
5-1. マルチモーダルAIの進化
【マルチモーダルAIの発展史】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第1世代: 単一モダリティ(〜2020年)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像のみ:
・CNN、ViT
・画像分類、物体検出
テキストのみ:
・BERT、GPT
・言語理解、文章生成
→ それぞれ独立、連携なし
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第2世代: 2モダリティ統合(2021年〜)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像 + テキスト:
・CLIP(2021年): 画像-テキスト埋め込み
・DALL-E(2021年): テキスト→画像生成
・Stable Diffusion(2022年): オープンソース生成
応用:
・ゼロショット分類
・画像検索
・Text-to-Image生成
→ 画像とテキストの統合的理解
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第3世代: 真のマルチモーダル(2023年〜)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
すべてのモダリティを統合:
GPT-4V(GPT-4 Vision, 2023年):
・画像とテキストの同時入力
・画像に関する質問応答
・画像の内容を説明
・画像内のテキストを読む
Gemini(Google, 2023年):
・テキスト、画像、音声、動画を統合
・ネイティブなマルチモーダル
・より自然な理解
Claude 3(Anthropic, 2024年):
・画像理解能力
・複雑な図表の分析
→ 人間のような総合的理解
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
未来: エージェント型AI(これから)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
すべてのモダリティ + 行動:
入力:
・視覚(カメラ)
・聴覚(マイク)
・触覚(センサー)
・テキスト(指示)
出力:
・テキスト(回答)
・音声(話す)
・行動(ロボット操作)
例:
「テーブルの上の赤いカップを取って」
→ 視覚で赤いカップを認識
→ 言語で指示を理解
→ ロボットアームで取る
→ 人間のように世界を理解し行動
5-2. CLIPの位置づけ
分野
CLIPの影響
今後の発展
画像生成
DALL-E、Stable Diffusionの基盤
動画生成、3D生成への拡張
検索エンジン
テキスト-画像横断検索
音声、動画を含む統合検索
アクセシビリティ
画像の自動説明
リアルタイムシーン理解
医療
医療画像と報告書の対応付け
画像+カルテの統合診断
ロボティクス
言語による物体指定
言語指示による行動制御
🎯 今後の学習の方向性
CLIPを学んだ今、次のステップとして以下の分野を検討してください:
1. NLP(自然言語処理)
・テキスト理解はマルチモーダルAIの基礎
・Transformerの深い理解
2. 生成AI(Diffusion Models)
・DALL-E、Stable Diffusionの詳細
・Diffusion Modelsの数学的基礎
3. 最新論文のフォロー
・GPT-4V、Gemini、Claude 3などの最新動向
・急速に進化する分野なので継続的な学習が重要
📝 練習問題
問題1:CLIPの基本的な使い方(基礎)
CLIPを使って、ある画像を「sunny day」「rainy day」「snowy day」の3つのクラスで分類するコードを書いてください。
解答を見る
解答:
import torch
import clip
from PIL import Image
# モデルのロード
device = “cuda” if torch.cuda.is_available() else “cpu”
model, preprocess = clip.load(“ViT-B/32”, device=device)
# 画像の前処理
image = Image.open(“weather.jpg”).convert(‘RGB’)
image_input = preprocess(image).unsqueeze(0).to(device)
# テキストプロンプトの作成
# 天気の状態をクラスとして定義
classes = [“sunny day”, “rainy day”, “snowy day”]
text_prompts = [f”a photo of a {c}” for c in classes]
text_inputs = clip.tokenize(text_prompts).to(device)
# 推論
with torch.no_grad():
# 埋め込みの計算
image_features = model.encode_image(image_input)
text_features = model.encode_text(text_inputs)
# 正規化
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
# 類似度計算と確率変換
similarity = 100.0 * image_features @ text_features.T
probs = similarity.softmax(dim=-1)
# 結果表示
print(“天気分類結果:”)
for i, class_name in enumerate(classes):
prob = probs[0, i].item()
print(f”{class_name}: {prob*100:.2f}%”)
# 予測
predicted_idx = probs[0].argmax().item()
print(f”\n予測: {classes[predicted_idx]}”)
ポイント:
・クラスは自由に定義できる
・”a photo of a {class}” の形式がベストプラクティス
・天気以外にも感情、時間帯、季節など様々な属性で分類可能
問題2:Contrastive Learningの仕組み(中級)
CLIPのContrastive Learningにおいて、バッチサイズ4の場合の学習プロセスを説明してください。正例と負例はいくつありますか?
解答を見る
解答:
【バッチサイズN=4の場合】
バッチデータ:
ペア1: (画像1, テキスト1)
ペア2: (画像2, テキスト2)
ペア3: (画像3, テキスト3)
ペア4: (画像4, テキスト4)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
正例(Positive)の数
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
対応する画像-テキストペア:
画像1 ↔ テキスト1
画像2 ↔ テキスト2
画像3 ↔ テキスト3
画像4 ↔ テキスト4
正例の数 = N = 4個
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
負例(Negative)の数
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
対応しない画像-テキストペア:
画像1 ↔ テキスト2, テキスト3, テキスト4 (3個)
画像2 ↔ テキスト1, テキスト3, テキスト4 (3個)
画像3 ↔ テキスト1, テキスト2, テキスト4 (3個)
画像4 ↔ テキスト1, テキスト2, テキスト3 (3個)
負例の数 = N × (N-1) = 4 × 3 = 12個
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
類似度行列
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
T1 T2 T3 T4
┌──────────────────────────┐
I1 │ [正] 負 負 負 │
I2 │ 負 [正] 負 負 │
I3 │ 負 負 [正] 負 │
I4 │ 負 負 負 [正] │
└──────────────────────────┘
対角要素(4個): 正例 → 高くしたい
非対角要素(12個): 負例 → 低くしたい
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIPの実際の訓練(参考)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
バッチサイズ N = 32,768 の場合:
正例: 32,768個
負例: 32,768 × 32,767 ≈ 10億個
→ 非常に多くの負例から学習
→ 効果的な対照学習が可能
問題3:ゼロショット分類のメカニズム(中級)
CLIPがゼロショット分類(訓練なしで新しいクラスを分類)できる理由を説明してください。
解答を見る
解答:
【ゼロショット分類が可能な理由】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由1: 共通の埋め込み空間
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIPは画像とテキストを同じ512次元空間に埋め込む
意味的に近いものは空間的にも近い:
・「猫の画像」と “a photo of a cat” は近い位置
・「犬の画像」と “a photo of a dog” は近い位置
→ 新しいテキストでも、意味的に近い画像を見つけられる
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由2: 大規模データでの事前学習
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4億ペアの画像-テキストで学習:
・あらゆる概念を学習済み
・一般的な物体、抽象的な概念、細かい属性
・様々な表現方法(同義語、言い換え)
→ 見たことのない組み合わせにも対応可能
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由3: テキストの柔軟性
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
任意のテキストでクラスを定義:
・”a photo of a cat” → 猫クラス
・”a photo of a sleeping cat” → 寝ている猫クラス
・”a photo of an orange cat” → オレンジ色の猫クラス
新しいクラスを追加:
・訓練データになくても、テキストで定義すれば分類可能
・「マンチカン」「スコティッシュフォールド」など
→ 分類器を再訓練する必要がない
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由4: 言語の汎化能力
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Text Encoderが言語を深く理解:
・”cat” と “kitty” と “feline” は同じ意味
・”red car” は「赤」と「車」の組み合わせ
合成的な理解:
・訓練データに「紫色の象」がなくても
・「紫色」と「象」の意味を組み合わせて理解
→ 未知の概念の組み合わせにも対応
問題4:CLIPと生成AIの関係(上級)
Stable DiffusionにおいてCLIPがどのように使われているか、Cross-Attentionとの関係も含めて説明してください。
解答を見る
解答:
【Stable DiffusionでのCLIPの役割】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. テキストエンコーディング
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CLIP Text Encoderがテキストを埋め込み:
入力: “a beautiful sunset over mountains”
↓
CLIP Text Encoder
↓
出力: テキスト埋め込み (77, 768)
・77: 最大トークン数
・768: 埋め込み次元
この埋め込みが画像生成の「条件」になる
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2. Cross-Attentionによる条件付け
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
U-Net(ノイズ除去ネットワーク)の各層で
Cross-Attentionを実行:
Query (Q): 現在の画像特徴 (H×W, C)
Key (K): テキスト埋め込み (77, 768)
Value (V): テキスト埋め込み (77, 768)
Attention = softmax(Q × Kᵀ / √d) × V
意味:
画像の各位置が「テキストのどの単語に注目するか」
例(”a beautiful sunset over mountains”の場合):
画像の「空の部分」→ “sunset” に高いAttention
画像の「下の部分」→ “mountains” に高いAttention
画像全体 → “beautiful” に中程度のAttention
→ テキストの各単語が画像の適切な位置に反映される
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. CLIPが重要な理由
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(1) 豊富な事前知識
・4億ペアで学習した概念の理解
・”sunset”、”mountains”の意味を知っている
(2) 意味的な埋め込み
・類似した概念は近い埋め込み
・”sunset” ≈ “dusk” ≈ “evening sky”
(3) 画像との対応
・CLIPは画像-テキストの対応を学習済み
・Text Encoderの出力が画像生成に適している
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. 生成プロセスの流れ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ1: テキスト埋め込み
“a sunset…” → CLIP → (77, 768)
ステップ2-51: Diffusion(50回繰り返し)
ノイズ画像 + テキスト埋め込み
↓ U-Net(Cross-Attention)
少しクリーンな画像
↓ …繰り返し…
クリーンな画像(潜在空間)
ステップ52: デコード
潜在空間 → VAE Decoder → 512×512画像
→ テキストに従った画像が生成される!
問題5:プロンプトエンジニアリング(上級)
CLIPでの分類精度を上げるためのプロンプトエンジニアリングのテクニックを3つ挙げ、それぞれの効果を説明してください。
解答を見る
解答:
【プロンプトエンジニアリングのテクニック】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テクニック1: 文脈の追加
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
悪い例: “cat”
良い例: “a photo of a cat”
効果:
・「写真である」という文脈を追加
・より明確な意味を持つ
・精度が約5%向上
理由:
・CLIPの訓練データは「画像+説明文」
・説明文は通常「a photo of …」の形式
・訓練データと同じ形式だと埋め込みが適切
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テクニック2: 複数テンプレートの平均
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
単一テンプレート:
“a photo of a {class}”
複数テンプレート:
“a photo of a {class}”
“a photo of the {class}”
“a good photo of a {class}”
“a close-up photo of a {class}”
“a dark photo of the {class}”
… (合計80個など)
各テンプレートで埋め込み → 平均を取る
効果:
・テンプレートによる偏りを軽減
・より安定した埋め込み
・精度が約6%向上
理由:
・単一のテンプレートは特定の状況に偏る
・平均することで汎用的な埋め込みを得る
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テクニック3: ドメイン特化
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
汎用プロンプト:
“a photo of a {class}”
ドメイン特化プロンプト:
衛星画像: “a satellite photo of {class}”
医療画像: “a CT scan showing {class}”
食べ物: “a photo of {class}, a type of food”
ペット: “a photo of a {class}, a type of pet”
効果:
・データセットの特性に合わせた分類
・曖昧さの解消
・精度が数%向上(ドメインによる)
理由:
・CLIPは文脈を理解する
・「これは衛星画像」と伝えることで
適切な解釈が行われる
例:
“field” だけだと曖昧(畑?野原?球場?)
“a satellite photo of a field” なら農地
“a photo of a field, a type of sports venue” ならグラウンド
📝 STEP 19 のまとめ
✅ このステップで学んだこと
1. CLIPの基本
・画像とテキストを同じ512次元空間に埋め込む
・Contrastive Learningで正例を近く、負例を遠くに学習
・4億ペアの大規模データで事前学習
2. ゼロショット分類
・任意のテキストでクラスを定義
・訓練なしで新しいクラスに対応
・プロンプトエンジニアリングで精度向上
3. 画像検索
・テキストから画像を検索
・画像から類似画像を検索
・事前に埋め込みを計算しておく
4. 生成AIの基盤
・DALL-E 2、Stable Diffusionの中核技術
・Cross-Attentionでテキストを画像生成に反映
💡 重要ポイント
CLIPの革新性:
・画像とテキストの統合的理解
・ゼロショット能力による柔軟性
・生成AI(Text-to-Image)の基盤技術
マルチモーダルAIの未来:
・GPT-4V、Gemini、Claude 3などの最新モデル
・視覚、言語、音声、行動の統合
・CLIPはその先駆けとして歴史的な意義を持つ
これでPart 5(Vision Transformerと最新技術)が完了しました!
次のPart 6では、応用タスク を学びます。
STEP 20では、顔認識と顔検出から始めます!