Elasticで画像の類似検索を実装する方法

blog-thumb-website-search.png

Elasticでわずか数ステップで画像の類似検索を実装する方法をご覧ください。アプリケーション環境の設定を開始したら、NLPモデルをインポートし、最後に画像のセットの埋め込みを生成します。

Elasticでの画像の類似検索の概要 >> 

環境を設定する方法

最初のステップでは、アプリケーションの環境を設定します。一般的な要件は次のとおりです。

  • Git
  • Python 3.9
  • Docker
  • 数百個の画像

最適な結果を保証するために、数百個の画像を使用することが重要です。

作業フォルダーに移動し、作成されたリポジトリコードをチェックアウトします。リポジトリフォルダーに移動します。

$ git clone https://github.com/radoondas/flask-elastic-image-search.git
$ cd flask-elastic-image-search

Pythonを使用してコードを実行するため、すべての要件が満たされ、環境が準備されていることを確認する必要があります。ここで、仮想環境を作成し、すべての依存関係をインストールします。

$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install -r requirements.txt

Elasticsearchクラスターと埋め込みモデル

アカウントにログインし、Elasticsearchクラスターを設定します。次のスペックの小さいクラスターを設定します。

  • 2 GBのメモリーが搭載された1つのホットノード
  • 4 GBのメモリーが搭載された1つのML(機械学習)ノード(ElasticsearchにインポートするNLPモデルは最大で1.5 GBのメモリーを消費するため、このノードのサイズは重要です。)

デプロイの準備が完了したら、Kibanaに移動して、機械学習ノードの容量を確認します。ビューに1つの機械学習ノードが表示されます。その時点で読み込まれているモデルはありません。

Elandライブラリを使用して、OpenAIからCLIP埋め込みモデルをアップロードします。Elandは、Elasticsearchでデータを探索および分析するためのPython Elasticsearchクライアントで、テキストと画像の両方を処理できます。このモデルを使用して、テキスト入力から埋め込みを生成し、一致する画像をクエリで検索します。詳細については、Elandライブラリのドキュメントを参照してください。

次のステップでは、Elasticsearchエンドポイントが必要です。このエンドポイントは、デプロイ詳細セクションのElastic Cloudコンソールから取得できます。

エンドポイントURLを使用して、リポジトリのrootディレクトリで次のコマンドを実行します。ElandクライアントはElasticsearchクラスターに接続し、モデルを機械学習ノードにアップロードします。実際のクラスターURLは-urlパラメーターを使用して参照します。たとえば、次の例は「image-search.es.europe-west1.gcp.cloud.es.io」をクラスターURLとして参照します。

--url https://elastic:<password>@image-search.es.europe-west1.gcp.cloud.es.io:443

Elandインポートコマンドを入力します。

$ eland_import_hub_model --url https://elastic:<password>@<URL>:443 \
  --hub-model-id sentence-transformers/clip-ViT-B-32-multilingual-v1 \
  --task-type text_embedding --ca-certs app/conf/ess-cloud.cer \
  --start

出力は以下のようなものになります。

2022-12-12 13:40:52,308 INFO : Establishing connection to Elasticsearch
2022-12-12 13:40:52,327 INFO : Connected to cluster named 'image-search-8.6.1' (version: 8.5.3)
2022-12-12 13:40:52,328 INFO : Loading HuggingFace transformer tokenizer and model 'sentence-transformers/clip-ViT-B-32-multilingual-v1'
2022-12-12 13:41:03,032 INFO : Creating model with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'
2022-12-12 13:41:03,050 INFO : Uploading model definition
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 129/129 [00:42<00:00,  3.01 parts/s]
2022-12-12 13:41:45,902 INFO : Uploading model vocabulary
2022-12-12 13:41:46,120 INFO : Starting model deployment
2022-12-12 13:41:52,825 INFO : Model successfully imported with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'

接続状況によっては、アップロードに2、3分かかる場合があります。完了したら、機械学習Kibanaページの学習済みモデルの一覧を確認します。メニュー -> 分析 -> 機械学習 -> モデル管理 -> 学習済みモデル。NLP CLIPモデルの状態が「開始済み」であることを確認します。

MLジョブと学習済みモデルの同期が必要です」というメッセージが画面に表示された場合は、リンクをクリックしてモデルを同期します。

画像埋め込みを作成する方法

Elasticsearchクラスターを設定し、埋め込みモデルをインポートした後、画像データをベクトル化し、データセットのすべての画像の画像埋め込みを作成する必要があります。

画像埋め込みを作成するには、シンプルなPythonスクリプトを使用します。スクリプトの場所:create-image-embeddings.pyこのスクリプトは画像のディレクトリを走査し、個々の画像埋め込みを生成します。名前と相対パスが含まれたドキュメントが作成され、Elasticsearchインデックス「my-image-embeddings」に格納されます。このときには提供されたマッピングが使用されます。 

すべての画像(写真)を「app/static/images」フォルダーに置きます。サブフォルダーまであるディレクトリ構造を使用して、常に画像が整理されるようにします。すべての画像の準備ができたら、数個のパラメーターを使用してスクリプトを実行します。

合理的な結果を得るためには、少なくとも200~300個の画像を準備することが非常に重要です。画像が少なすぎると、検索する空間が非常に小さく、検索ベクトルまでの距離も非常に短くなるため、想定した結果が得られません。

image_embeddingsフォルダーでスクリプトを実行し、変数の値を使用します。

$ cd image_embeddings
$ python3 create-image-embeddings.py \
  --es_host='https://image-search.es.europe-west1.gcp.cloud.es.io:443' \
  --es_user='elastic' --es_password=<password> \
  --ca_certs='../app/conf/ess-cloud.cer'

画像の数、サイズ、CPU、ネットワーク接続によっては、このタスクに少し時間がかかります。データセット全体を処理する前に、画像の数を少なくして実験してください。
スクリプトが完了した後は、kibana devツールを使用して、インデックスmy-image-embeddingsが存在し、対応するドキュメントがあることを確認できます。

GET _cat/indices/my-image-embeddings?v

health status index               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   my-image-embeddings vfA3wOheT1C79R-PceDyXg   1   1       1222            0     24.4mb         12.2mb

ドキュメントを確認すると、(例のように)非常に類似したJSONオブジェクトがあります。画像名、画像ID、imagesフォルダー内の相対パスが表示されます。このパスは、検索時に画像を正しく表示するために、フロントエンドアプリケーションで使用されます。
このJSONドキュメントの最も重要な部分は「image_embedding」です。この部分には、CLIPモデルで生成された密ベクトルが含まれています。アプリケーションが画像または類似した画像を検索しているときに、このベクトルが使用されます。

{
   "_index": "my-image-embeddings",
   "_id": "_g9ACIUBMEjlQge4tztV",
   "_score": 6.703597,
   "_source": {
     "image_id": "IMG_4032",
     "image_name": "IMG_4032.jpeg",
     "image_embedding": [
       -0.3415695130825043,
       0.1906963288784027,
       .....
       -0.10289803147315979,
       -0.15871885418891907
       ],
     "relative_path": "phone/IMG_4032.jpeg"
   }
}

Flaskアプリケーションを使用して画像を検索する

環境が設定されたところで、次のステップを実行して、自然言語を使用して実際に画像を検索し、類似した画像を検出することができます。概念実証としてElasticが提供するFlaskアプリケーションを使用します。このWebアプリケーションにはシンプルなUIがあり、シンプルな方法で画像検索を行えます。このGitHub repoでプロトタイプFlaskアプリケーションを利用できます。 

このアプリケーションはバックグラウンドで2つのタスクを実行します。検索文字列を検索ボックスに入力した後、機械学習_inferエンドポイントを使用してテキストがベクトル化されます。その後、ベクトルが格納されたインデックスのmy-image-embeddingsに対して、密ベクトルを含むクエリが実行されます。

この例では、このようなクエリが2つあります。最初のAPI呼び出しは_inferエンドポイントを使用します。結果は密ベクトルです。

POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
  "docs" : [
    {"text_field": "endless route to the top"}
    ]
}

2番目のタスクの検索クエリでは、密ベクトルを利用して、スコア別にソートされた画像を取得します。

GET my-image-embeddings/_search
{
  "knn": {
    "field": "image_embedding",
    "k": 5,
    "num_candidates": 10,
    "query_vector": [
    -0.19898493587970734,
    0.1074572503566742,
    -0.05087625980377197,
    ...
    0.08200495690107346,
    -0.07852292060852051
  ]
  },
  "fields": [
    "image_id", "image_name", "relative_path"

  ],
  "_source": false
}

Flaskアプリケーションを起動して実行するには、リポジトリのrootフォルダーに移動し、.envファイルを構成します。構成ファイルの値は、Elasticsearchクラスターに接続するために使用されます。次の変数の値を挿入する必要があります。これらの値は、画像埋め込み生成で使用される値と同じです。

  • ES_HOST='URL:PORT'
  • ES_USER='elastic'
  • ES_PWD='password'

準備ができたら、メインフォルダーでFlaskアプリケーションを実行し、開始されるまで待ちます。

# In the main directory 
$ flask run --port=5001

アプリケーションが起動したら、次のような出力が表示されます。この出力の最後には、アプリケーションにアクセスするために開く必要があるURLが表示されます。

flask run --port=5001
 * Serving Flask app 'flask-elastic-image-search.py' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5001
Press CTRL+C to quit

おめでとうございます!アプリケーションが起動して実行され、インターネットブラウザーを使用してhttp://127.0.0.1:5001からアクセスできます。

画像検索タブに移動して、画像を最も適切に説明するテキストを入力します。非キーワードまたは説明テキストを使用してみてください。

次の例では、「endless route to the top」というテキストが入力されました。 結果はデータセットから表示されます。ユーザーが結果セットに1つの特定の画像を表示したい場合は、画像の横のボタンをクリックすると、類似した画像が表示されます。ユーザーはこの操作を何回でも繰り返し、画像データセットで独自のパスを構築できます。

画像をアップロードするだけでも、検索は動作します。アプリケーションは画像をベクトルに変換して、データセットで類似した画像を検索します。このためには、3番目のタブの[類似した画像]に移動し、ディスクから画像をアップロードして、[検索]をクリックします。

Elasticsearchで使用しているNLP(sentence-transformers/clip-ViT-B-32-multilingual-v1)モデルは多言語で、多数の言語での推論をサポートしているため、自分の言語で画像を検索してください。その後に、英語のテキストも使用して、結果を検証してください。

使用されているモデルが汎用モデルで、かなり精度が高いものの、得られる結果はユースケースや他の要因によって異なることに注意することが重要です。正解率を高める必要がある場合は、汎用モデルを適応させるか、独自のモデルを開発する必要があります。CLIPモデルは検索の出発点として提供されているだけのものです。

コードの概要

完全なコードはGitHub リポジトリにあります。routes.pyのコードはアプリケーションのメインロジックを実装していますが、このコードを調べているかもしれません。明確なルート定義のほかに、_inferおよび_searchエンドポイント(infer_trained_modelおよびknn_search_images)を定義する方法に注目してください。画像埋め込みを生成するコードは、create-image-embeddings.pyファイルにあります。

まとめ

Flaskアプリが設定されたので、独自の画像セットを簡単に検索できます。Elasticはプラットフォーム内でベクトル検索のネイティブ統合を提供しています。これにより、外部プロセスとの通信を回避できます。柔軟性が高いため、PyTorchを使用して開発できるカスタム埋め込みモデルを開発して採用できます。

セマンティック画像検索は、画像検索の従来の他のアプローチに比べ、次のような利点を提供します。

  • より高い正解率:ベクトル類似性は、画像のテキストメタ記述に頼らずに、コンテキストと関連性を取り込みます。
  • ユーザーエクスペリエンスの強化:関連性があると考えられるキーワードを推測するのではなく、検索している対象を記述するか、サンプル画像を入力します。
  • 画像データベースの分類:画像のカタログ分類については心配する必要はありません。類似検索では、大量の画像から関連する画像が検索され、それらを整理する必要はありません。

ユースケースがテキストデータの方を信頼している場合は、セマンティック検索を実装し、自然言語処理をテキストに応用する方法について前のブログで詳細に学習できます。テキストデータでは、ベクトル類似性と従来のキーワードスコアリングの組み合わせが最適です。
導入の準備は万端ですか?バーチャルイベントハブ で実践ベクトル検索ワークショップに登録し、 オンラインディスカッションフォーラムのコミュニティに参加してください。