0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

gemini-embedding-2-previewでテキスト・画像の類似度比較を検証

0
Posted at

概要

3月にリリースされた gemini-embedding-2-preview は、テキスト・画像・動画・音声をインプットとして受け付け、同じフォーマットのエンベディングを出力できます。

これにより理論上、画像同士の類似度比較や、画像とテキストの類似度比較など、非常に多くの用途が生まれると考えられます。

今回は上記の用途について軽く検証してみたいと思います。

検証内容

  • face1.jpg から face5.jpg までは、Pexelsでダウンロードしたすべて異なる人物の表情画像(テストのため、それぞれ何の表情であるかは明記しません)
  • face16.jpg は1人の人物の表情が4x4に分割された画像で、face16.py を使って個別の画像に分割します。

※補足:画像ソースはPexelsから入手したため、著作権的な問題はありません。

検証1: 画像×テキスト 表情類似度(複数人)

  • face1.jpgface5.jpg(5人の異なる表情)を使用
  • 各画像を「怒」「哀」「楽」のテキストとそれぞれコサイン類似度で比較(「喜」は「楽」とほぼ同じなので省略)
  • 5×3 の類似度行列を作成し、モデルが画像とテキスト間の表情マッチングをどの程度捉えられるか検証

検証2: 画像×テキスト 表情類似度(同一人物)

  • face16.jpgface16.py で4×4分割した16枚を使用(同一人物の異なる表情)
  • 各画像を「怒」「哀」「楽」のテキストとそれぞれコサイン類似度で比較(「喜」は「楽」とほぼ同じなので省略)
  • 16×3 の類似度行列を作成し、同一人物で表情だけ変わった場合の検出精度を検証

検証3: 画像×画像 顔識別

  • face1.jpgface5.jpg の5枚 + face16.jpg から分割した中から5枚、合計10枚を使用
  • 10枚間すべてのペアでコサイン類似度を比較(10×10 の類似度行列)
  • 異なる人物 vs 同一人物(face16分割)のスコア差から、モデルの顔識別能力を検証

主なソースコード

画像をエンベディングに変換

def embed_image(
   client: genai.Client,
   image_path: str | os.PathLike,
   max_retries: int = 3,
   sleep_sec: float = 10.0,
) -> np.ndarray:
   image_path = Path(image_path)
   with open(image_path, "rb") as f:
       image_bytes = f.read()


   def _call() -> np.ndarray:
       result = client.models.embed_content(
           model=EMBEDDING_MODEL,
           contents=[
               types.Part.from_bytes(
                   data=image_bytes,
                   mime_type="image/jpeg",
               )
           ],
       )
       return np.array(result.embeddings[0].values, dtype=np.float32)


   return run_with_retry(_call, max_retries=max_retries, sleep_sec=sleep_sec) # 失敗の自動処理のためにリトライを組まれた

テキストをエンベディングに変換

def embed_text(
   client: genai.Client,
   text: str,
   max_retries: int = 3,
   sleep_sec: float = 10.0,
) -> np.ndarray:
   """テキスト 1 件を `gemini-embedding-2-preview` で embedding する."""


   def _call() -> np.ndarray:
       result = client.models.embed_content(
           model=EMBEDDING_MODEL,
           contents=[text],
       )
       return np.array(result.embeddings[0].values, dtype=np.float32)


   return run_with_retry(_call, max_retries=max_retries, sleep_sec=sleep_sec)

類似度の計算

def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
   denom = float(np.linalg.norm(a) * np.linalg.norm(b))
   if denom == 0.0:
       return 0.0
   return float(np.dot(a, b) / denom)


def build_similarity_matrix(
   rows: Sequence[np.ndarray],
   cols: Sequence[np.ndarray] | None = None,
) -> np.ndarray:
   col_vectors = cols if cols is not None else rows
   matrix = np.zeros((len(rows), len(col_vectors)), dtype=np.float32)
   for i, r in enumerate(rows):
       for j, c in enumerate(col_vectors):
           matrix[i, j] = cosine_similarity(r, c)
   return matrix

結果

まず、こちらが検証に使用したサンプル画像です。

face1.jpg
face1.jpg

face2.jpg
face2.jpg

face3.jpg
face3.jpg

face4.jpg
face4.jpg

face5.jpg
face5.jpg

face16.jpg(これをface_01からface_16までに分割)
face16.jpg

検証1

日本語テキストとの類似度はあまり良くない結果でした。

experiment1_heatmap.png

英語(Angry, Sad, Happyなど)を使ってもう1回分析してみたところ、日本語より少し良くなりました。これならなんとなく使えるレベルだと思います。

experiment4_heatmap.png

検証2

同一人物であれば、顔立ちによる変数(ノイズ)がなくなるので、より正確に測れると思います。

experiment2_heatmap.png

experiment5_heatmap.png

何だかんだで精度が良くなったと感じます。

そもそも、なぜ「怒」・「哀」・「楽」のスコアの差がこれほど小さいのかについて考えてみました。
1つの画像から抽出されるエンベディングには非常に多くの情報が含まれており、「人間」「顔」「表情」などもその一部です。「怒」・「哀」・「楽」は表情としてはそれぞれ違いますが、どれも「表情」という枠組みのサブセットに過ぎないため、全体のエンベディングの中で比較するとそこまで大きな差が出ないというのも合理的だと言えます。

検証3

experiment3_heatmap.png

明らかに同一人物同士だと類似度が高くなることが確認できました。

最後に

以上の検証はマルチモーダルなエンベディングモデルのほんの一部の用途に過ぎないので、今後また他の用途についても検証していきたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?