🔖

Azure AI Visionのマルチモーダル埋め込みを試す

2024/12/19に公開

はじめに

こちらの記事は Azure PoC 部 Advent Calendar 2024 の 19 日目の記事です。

あまり知られていないのですが、Azure AI Vision では、マルチモーダル埋め込み生成に対応しています。
マルチモーダル埋め込みでは、テキストと画像を同じベクトル空間にベクトル化する手法です。
マルチモーダル埋め込みの代表的な手法としては CLIP ( Contrastive Language–Image Pre-training )などがあります。

Azure AI Vision でのマルチモーダル埋め込みの実装詳細は公開されていませんが、多言語に対応した形で画像、テキストとも 1,024 次元のベクトルが取得できます。

Azure AI Vision のマルチモーダル埋め込み機能(画像 → ベクトル化)

まずは画像をベクトル化する関数を用意します。
Image RetrievalVectorize Streamエンドポイントを呼び出す形で実装しています。

https://learn.microsoft.com/ja-jp/rest/api/computervision/image-retrieval/vectorize-stream?view=rest-computervision-v4.0-preview (2023-04-01)&tabs=HTTP

import requests


def get_image_embedding(
    image_data: bytes,
    endpoint: str,
    key: str,
    api_version: str = "2023-04-01-preview",
    model_version: str = "2023-04-15",
) -> list[float] | None:
    """画像の埋め込みベクトルを取得する関数

    Args:
        image_data (bytes): 画像データ
        endpoint (str): Azure AI Visionのエンドポイント
        key (str): Azure AI Visionのキー
        api_version (str, optional): API バージョン Defaults to "2023-04-01-preview".
        model_version (str, optional): モデルバージョン Defaults to "2023-04-15".

    Returns:
        list[float] | None: 1024次元のベクトル。エラーが発生した場合はNoneを返す
    """
    url = f"{endpoint}/computervision/retrieval:vectorizeImage?api-version={api_version}&{model_version}"
    headers = {
        "Content-type": "application/octet-stream",
        "Ocp-Apim-Subscription-Key": key,
    }
    try:
        resp = requests.post(url, data=image_data, headers=headers)

        if resp.ok:
            return resp.json()["vector"]
        else:
            print(f"An error occurred while processing {resp.status_code}")
            return None
    except Exception as e:
        print(f"An error occurred while processing {e}")
        return None

Azure AI Vision の API バージョンは最新は2024-02-01ですが、マルチモーダル埋め込み系の API は2023-04-01-previewでしか呼び出すことができませんでした。

Azure AI Vision のマルチモーダル埋め込み機能(テキスト → ベクトル化)

同様にテキストをベクトル化する関数を用意します。
こちらもImage RetrievalVectorize Textエンドポイントを呼び出す形で実装します。

https://learn.microsoft.com/ja-jp/rest/api/computervision/image-retrieval/vectorize-text?view=rest-computervision-v4.0-preview (2023-04-01)&tabs=HTTP

import requests
import json


def get_text_embedding(
    text: str,
    endpoint: str,
    key: str,
    api_version: str = "2023-04-01-preview",
    model_version: str = "2023-04-15",
) -> list[float] | None:
    """テキストの埋め込みベクトルを取得する関数

    Args:
        text (str): テキスト
        endpoint (str): Azure AI Visionのエンドポイント
        key (str): Azure AI Visionのキー
        api_version (str, optional): API バージョン Defaults to "2023-04-01-preview".
        model_version (str, optional): モデルバージョン Defaults to "2023-04-15".

    Returns:
        list[float] | None: 1024次元のベクトル。エラーが発生した場合はNoneを返す
    """
    url = f"{endpoint}/computervision/retrieval:vectorizeText?api-version={api_version}&{model_version}"
    headers = {
        "Content-type": "application/json",
        "Ocp-Apim-Subscription-Key": key,
    }
    try:
        resp = requests.post(url, data=json.dumps({"text": text}), headers=headers)

        if resp.ok:
            return resp.json()["vector"]
        else:
            print(f"An error occurred while processing {resp.status_code}")
            return None
    except Exception as e:
        print(f"An error occurred while processing {e}")
        return None

画像とテキストの類似度を計算してみる

2 つのベクトルをコサイン類似度を計算する関数を用意しておきます。

import numpy as np


def calc_cosine_similarity(vector1: list[float], vector2: list[float]) -> float:
    """コサイン類似度を計算する関数

    Args:
        vector1 (list[float]): べクトル1
        vector2 (list[float]): ベクトル2

    Returns:
        float: コサイン類似度
    """
    return np.dot(vector1, vector2) / (
        np.linalg.norm(vector1) * np.linalg.norm(vector2)
    )

それでは実際に画像とテキストをそれぞれベクトル化してコサイン類似度を計算してみます。

今回はいらすとやの以下の画像を使って試してみます。

https://www.irasutoya.com/2018/10/blog-post_80.html

画像のベクトル化

先ほどのget_image_embedding関数を使って画像のベクトル値を取得します。

endpoint = "<Azure AI Visionのエンドポイント>"
key = "<Azure AI Visionのキー>"
# ベクトル化対象ファイル
file_path = "./pet_robot_soujiki_cat.png"

with open(file_path, "rb") as f:
    image_data = f.read()

image_vector = get_image_embedding(
    image_data=image_data,
    endpoint=endpoint,
    key=key,
)
if image_vector:
    print("Vector is successfully generated")
    print(image_vector)
Vector is successfully generated
[1.2333984, -1.7792969, -1.9472656, ..., -2.2128906, -2.1328125] # ベクトル値は省略

テキストのベクトル化

同様にget_text_embedding関数を使ってテキストのベクトル値を取得します。

text_vector = get_text_embedding(
    text="灰色の猫",
    endpoint=endpoint,
    key=key,
)

if text_vector:
    print("Vector is successfully generated")
    print(text_vector)
Vector is successfully generated
[-0.00023115672, -0.041656945, -0.026567545, ..., -0.030063469, -0.0257012]  # ベクトル値は省略

コサイン類似度の計算

calc_cosine_similarity関数を使って取得した画像のベクトル値とテキストのベクトル値のコサイン類似度を計算します。

similarity = calc_cosine_similarity(vector1=image_vector, vector2=text_vector)
print(similarity)
0.3607935767576095s

今回の結果だとコサイン類似度が 0.36 なのであまり類似度が高いとは言えない形になりましたが、テキストと画像を同じベクトル空間で比較できること自体は確認できました。

まとめ

本記事では Azure AI Vision のマルチモーダル埋め込み機能を試してみました。
API バージョンが2023-04-01-preview版でないと使えないのは地味にハマりポイントでした。

今後はよりプロダクション向けに Azure AI Search にベクトル値を保存して、検索でマルチモーダル埋め込みを活用していく部分を紹介できればと思います。

参考

https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/concept-image-retrieval#input-requirements

Discussion