はじめに

こんにちは。DX開発事業部の鹿嶋です。

近年のAI技術の進化は目覚ましく、その応用範囲は多岐にわたります。
中でも画像認識技術は、私たちの生活の様々な側面で実用化が進んでいます。

さて、私は街中を散歩しつつ野良ねこの写真を撮るというのが趣味の一つなのですが、今でも迷子のペットを探す張り紙を目にすることがあります。
昨今スマートフォンをかざすだけで植物の名前がわかる時代になりましたが、大切な家族の一員を探すのは、まだまだ張り紙とSNSに頼る必要があります。
もちろん情報の拡散力は昔より格段に上がりましたが、ここにもAI技術を活かせるのではないでしょうか。

私自身も2匹の猫をお世話している身として、最先端のAI画像認識技術で何かできないかと考え、類似画像検索を試してみました。

実際にやってみた

※今回、以下の手順については割愛させていただきます。

  • Google Cloud の新規プロジェクト作成
  • 必要となるAPIの有効化

1. 特徴量の抽出

まずは、検索対象となる画像を Cloud Storage に格納します。
今回は我が家のねこたちの画像、そして散歩先や旅先で出会ったねこたちに画像提供のご協力をいただきましたので、それらを格納しました。

次に格納した画像から、特徴量を抽出します。特徴量とは、簡単に言うと、何かを判断したり、コンピュータに理解させたりするために使う「ヒント」や「手がかり」のようなものと捉えてください。
この特徴量が多ければ多いほど、また的確であればあるほど、コンピュータはより正確に物事の判断や予測ができるようになります。

今回この特徴量の抽出には、Google Colaboratory を使用して Python コードを実行する形で行いました。

まずは必要なライブラリをインストールします。

from google.colab import auth
auth.authenticate_user()

# python ライブラリのインストール
!pip install google-cloud-storage tensorflow tensorflow-hub matplotlib google-cloud-aiplatform pillow

# ライブラリのインポート
import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
from google.cloud import storage
import json
import os
import io
from PIL import Image
from google.cloud import aiplatform
from IPython.display import display

次に、Cloud Storage に保存されている画像データを読み込み、AIモデルを使って特徴量を抽出します。
※長いので一部抜粋

# プロジェクト情報を設定
project_id = "YOUR_GCP_PROJECT_ID"
bucket_name = "YOUR_GCS_BUCKET_NAME"
input_image_prefix = "YOUR_INPUT_IMAGES_PREFIX"

# AIモデル(EfficientNet-B0)のロード
# 画像から特徴量(埋め込みベクトル)を抽出するために使用
try:
    feature_extractor = hub.KerasLayer("https://tfhub.dev/tensorflow/efficientnet/b0/feature-vector/1",
                                       trainable=False)
except Exception as e:
    # モデルロード失敗時は処理を終了
    exit()

// --- 省略 ---

processed_count = 0
for blob in blobs:
    # 画像ファイルのみを対象とし、ディレクトリや隠しファイルはスキップ
    if not blob.name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')) or blob.name.endswith('/'):
        continue

    try:
        # 画像をGCSからダウンロードし、PILで読み込み
        image_bytes = blob.download_as_bytes()
        image = Image.open(io.BytesIO(image_bytes))

        # AIモデル入力用に画像を前処理 (リサイズ, RGB変換, 正規化, バッチ次元追加)
        image = image.resize((224, 224)).convert("RGB")
        img_array = np.array(image) / 255.0
        img_array = np.expand_dims(img_array, axis=0)

        # AIモデルを通して特徴量(埋め込みベクトル)を取得
        features = feature_extractor(tf.constant(img_array)).numpy().flatten()

        # 画像ID(GCSパス)と特徴量をペアにしてリストに追加
        embeddings_data.append({
            "id": blob.name,
            "embedding": features.tolist()
        })
        processed_count += 1

処理完了後、抽出した特徴量データを Cloud Storage に格納します。

output_gcs_path = "YOUR_OUTPUT_GCS_PATH"

# 出力ファイルのBlob(GCS上のファイル)を作成します。
output_blob = bucket.blob(output_gcs_path)

# Cloud Storage に特徴量データをアップロード
with output_blob.open("w") as f:
    for item in embeddings_data:
        f.write(json.dumps(item) + "\n")

上記が完了後、Cloud Storage に特徴量データが格納されます。

 

2. Vertex AI ベクトル検索 のインデックス作成とデプロイ

特徴量データが準備できたので、こちらを Vertex AI に登録して、検索できるようにします。

Google Cloud Console にログインし、Vertex AI のメニューから「ベクトル検索」を選択します。

「新しいインデックスを作成」をクリックし、インデックス作成に必要となる情報を入力し、「作成」をクリックします。
※注: Vertex AI が Cloud Storage にアクセスするためのサービスアカウントがない、または適切な権限が付与されていない場合、エラーとなってインデックス作成が行えない場合があります。操作開始前に一度 IAM のメニューから状態を確認しておくことをオススメします。

次にインデックスエンドポイントのタブをクリックし、「新しいエンドポイントの作成」をクリックします。
エンドポイント作成に必要となる情報を入力し、「作成」をクリックします。

インデックスエンドポイントが作成された後は、インデックスタブに戻り、「デプロイ」をクリックして、デプロイに必要な情報を入力し、デプロイをスタートします。デプロイ完了までに数分〜数十分かかりますので、気長に待ちましょう。

3. 類似画像検索の実行

デプロイが完了したら、いよいよ類似画像検索を試していきます。
今回はガチガチのアプリケーション構築は行わず、Google Colaboratory から検索を試してみます。

基本的な流れは次のようになります。

  1. 検索したい画像元となる画像を用意する
  2. 上記の検索したい画像から「特徴量」を抽出する
  3. 抽出した特徴量を、デプロイした Vertex AI のエンドポイントに送信する
  4. 検索結果を受け取り、Cloud Storage の画像群から類似画像と判定された画像を表示する

今回は以下の画像を検索元とします。

みやび (♀) 世界で一番自分が可愛いと思っている

特徴量の抽出に関しては、先ほどの特徴量の抽出の手順と同じ手順で行います。

抽出完了後、Google Colaboratory から検索元画像をアップロードし、類似検索を行います。

4. 結果はいかに…

検索結果がこちら(※特徴量上位3件を表示)

おお、バッチリみやびがワンツーフィニッシュしていますね!
3位は姉弟ねこのうららの画像ですが、動物病院でもよく間違えられるので納得といえば納得。
ちなみに、今回の特徴量の抽出には「ねこ」を指定するような方法をとっていますが、この特徴量に対して、「いぬ」の画像を与えてみるとどういった結果が返ってくるでしょうか?

検証に際しまして、今回は知人の愛犬であるもなかさんにご協力いただきました。ありがとうございます。

もなかさん(♂) ボール遊びが好きらしい

気になる結果はこのようになりました。

格納されている画像に似たようなものがないため、仕方なしに3件挙げている感も否めませんが、これは生成AIが「ねこではない」と判別しているということに他なりません。また、類似度スコアを比べてみても、最大が23とかなり低い数値となっていることが確認できるかと思います。

5. おわりに

今回類似画像検索を試してみて、想像よりもきちんと判別してくれているな、といった印象を持ちました。

もちろん完璧ではありませんが、迷子のペットを探している飼い主さんにとって、少しでも手がかりになる可能性を感じています。従来の張り紙やSNSでの情報拡散に加えて、AI技術を組み合わせることで、より効率的な捜索が実現できるかもしれません!

今回はあくまでお試しでの確認となりましたが、今後はこの技術をWebアプリケーションとして発展させられるように頑張ります!