はじめに
Oracle Database 23ai から Oracle Database にベクトル検索機能が登場しました。Oracle AI Vector Search です。以前、Japanse Stable CLIP を使って画像の分類に取り組んでいました。今回は Japanese Stable CLIP のテキストと画像の特徴ベクトルを同じ埋め込み空間に生成する機能とOracle AI Vector Search を使ってテキストから画像を検索したり、画像からその画像と類似した画像を検索するマルチモーダル・アプリケーションを作ってみました。
Japanse Stable CLIP は、GPU の無い環境でも動作する軽快なモデルなので GPU 環境が無い方でもこのアプリケーションを試していただけます。
Oracle AI Vector Search とは
ベクトルデータに基づいたセマンティックサーチを実現する Oracle Database の新し機能です。23ai から利用可能になりました。以下のような特徴があります。
- ベクトルデータのサポート: 新しいVECTORデータ型を使用して、ベクトルを直接データベース内のテーブル(リレーション)に格納することができます。これにより、データベース内の構造化データやJSONなど様々なデータモデルのデータを組み合わせたアプリケーションを容易に構築できます。既存のデータベース・テーブルにベクトル列を追加することでアプリケーションにセマンティック検索機能を追加することも容易です。また、VECTOR型は異なる次元数や形式のベクトルをサポートしています
- ベクトル検索をSQLで実行できるようにするための拡張が行われています。これにより、従来のSQLクエリと組み合わせてベクトル検索を行うことができます
- インメモリ近傍グラフ索引やパーティション化された近傍索引などのベクトル索引を使用して、類似性検索を高速化します。これにより、大規模なデータセットに対しても高精度で迅速な検索が可能です
- テキストデータのベクトル化手法の多様性:
- インデータベースでベクトル化:ONNX形式の Embeddingモデルをインポート可能
- データベースから外部の3rd Party Embedding モデル API を呼び出してベクトル化可能
- 外部であらかじめ用意したベクトルデータを格納(SQLのINSERT文、SQL*Loader、Oracle Data Pump)
Japanese Stable CLIP とは
日本語に特化した画像言語特徴抽出モデルです。マルチモーダル埋め込みモデルとも呼ばれます。画像の特徴ベクトル(エンベディング)とテキストの特徴ベクトル(エンベディング)を同じ埋め込み空間内に抽出(生成)することができます。つまり、モデル単体で任意の日本語テキストから画像を検索する画像検索やその逆であるテキスト検索(分類)が可能です(画像を説明するキャプションの生成(Image Captioning)や画像に関する質問に答えるVisual Question Answering (VQA)が可能な Vision-Language モデルとは異なります。stability ai のVision-Language モデルには、Japanese Stable VLM があります)。
CLIP とは
モデル名の最後の "CLIP" は、"Contrastive Language-Image Pre-training" の略でオリジナルのモデルは2021年にOpenAIによって公開されました(OpenAIのブログ、実装)。CLIPは、インターネット等から収集された大規模な画像とテキストのペア(4億ペア)を用いて学習しています。学習は以下のような行われます。
Learning Transferable Visual Models From Natural Language Supervision (https://arxiv.org/abs/2103.00020) Figure 1. Summary of our approach. |
- 収集したデータセットからN個の画像-テキストのペアをピックアップします(オリジナルの CLIP では、32768 のミニバッチ毎)
- N個の画像とN個のテキストそれぞれの特徴ベクトルを計算します(画像とテキストは同一の埋め込み空間にマッピングされます)
- N個の画像の特徴ベクトルとN個のテキストの特徴ベクトルのすべての組み合わせの類似度を計算します(N^2組)
- 画像とテキストの組み合わせが関連のあるペアである場合(上図の対角の水色のN組)に類似度が高くなり、無関係な組み合わせである場合(N^2 - N組)には類似度が低くなるように学習します
テキストの特徴ベクトルを生成するテキストエンコーダーには transformer を、画像の特徴ベクトルを生成する画像エンコーダーには、ResNet(CNNをベースにしたモデル)かVision Transformer (ViT)を利用することができます。
従来の画像分類モデルは分類可能なカテゴリー(分類クラス)が学習に用いられたラベルだけに限定されていましたが、CLIPは大規模な画像・テキストのペアを学習していることからFine-tuningをすることなく任意の分類カテゴリーに対する分類が可能です。これはゼロショット画像分類と呼ばれています(任意のテキストを用いた画像検索も可能です)。
Japanese Stable CLIP の特徴
Japanese Stable CLIP では、画像エンコーダーには、ViTを使用し、学習手法にSigLIP(Sigmoid loss for Language-Image Pre-training)が採用されています。従来の対照学習が正規化のためにバッチ内のすべての画像・テキストペアの情報を必要とするsoftmax関数に基づいていたのに対して、SigLIPでは、各画像-テキストペアを独立してSigmoid 関数を適用することで効率的な学習を実現しています。この効率的な学習により画像と言語の特徴抽出の精度が向上することを期待できます。また、Conceptual 12M(CC12M)のキャプションを日本語に翻訳したデータセットなどを用いることで日本語に対応しています。詳しくは、Stability AI社のブログと Hugging Face の Model Card を参照してください。
以下のブログ記事もご参照ください。
本アプリケーションの機能
- テキストによる類似画像検索
- 画像による類似画像検索
- 画像のメタデータ(生成プロンプト、キャプション)の表示
- PNGファイルのテキストチャンク情報の抽出と保存
- GPU の無い環境でも動作
前提条件
- Python 3.10以上
- Oracle Database 23ai インスタンス
- CPU上でも動作可能(GPUがあればなお良い)
- Hugging Face のアカウントがあること(Hugging Face アカウント作成ページ で無料で登録することができます)
- Hugging Face の User Access Token を取得していること(Hugging Face User Access Token 作成ページ で無料で取得できます。"Type" は、"READ")
- stabilityai/japanese-stable-clip-vit-l-16 でコンタクト情報の登録が完了していること
- 動作は OCI の VM.Standard3.Flex Compute Shape + Oracle Linux 8(CPUのみ) とローカルの Windows 11(CPUのみの場合とGPU利用の場合の両方) で確認しています。
データベース環境のセットアップ
-
データベースのインストール
日本オラクルのチュートリアルの 1-1. Oracle Database 23ai Free環境でのセットアップ もしくは 1-2. Base Database Service環境でのセットアップ を実施してください。
ユーザー名は docuser となっていますがお好みの任意の名前で作成してください。作成したユーザー名とパスワードは、.env ファイルに設定しますのでメモしておいてください。なお、この手順の中でユーザー(docuser) に様々な権限を付与していますが、これに VIEW を作成する権限も追加します。
ユーザー名が docuser の場合は以下の SQL を sqlplus に sys ユーザーでログインして実行します。
sqlplus sys@localhost:1521/freepdb1 as sysdba
GRANT CREATE VIEW TO docuser;
-
テーブルの作成
sqlplus でデータベースへログインします(例です。ユーザー名、DSNは適宜書き換えてください)
sqlplus docuser@localhost:1521/freepdb1
以下のSQLで必要なテーブル群とインデックスを作成します
-- IMAGES テーブル CREATE TABLE IMAGES ( image_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, image_data BLOB, file_name VARCHAR2(255), file_type VARCHAR2(50), upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, generation_prompt CLOB ); -- EMBEDDING_MODELS テーブル CREATE TABLE EMBEDDING_MODELS ( model_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, model_name VARCHAR2(255), model_version VARCHAR2(50), is_current CHAR(1) CHECK (is_current IN ('Y', 'N')), vector_dimension NUMBER ); -- IMAGE_EMBEDDINGS テーブル CREATE TABLE IMAGE_EMBEDDINGS ( embedding_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, image_id NUMBER, model_id NUMBER, embedding VECTOR, CONSTRAINT fk_image_embedding FOREIGN KEY (image_id) REFERENCES IMAGES(image_id), CONSTRAINT fk_model_embedding FOREIGN KEY (model_id) REFERENCES EMBEDDING_MODELS(model_id) ); -- Vector indexの作成 CREATE VECTOR INDEX image_embedding_idx ON IMAGE_EMBEDDINGS(embedding) ORGANIZATION NEIGHBOR PARTITIONS WITH DISTANCE DOT; -- IMAGE_DESCRIPTIONS テーブル CREATE TABLE IMAGE_DESCRIPTIONS ( description_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, image_id NUMBER, description CLOB, CONSTRAINT fk_image_description FOREIGN KEY (image_id) REFERENCES IMAGES(image_id) ); -- 全文検索インデックスの作成 CREATE INDEX idx_image_prompt ON IMAGES(generation_prompt) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('SYNC (ON COMMIT)'); CREATE INDEX idx_image_description ON IMAGE_DESCRIPTIONS(description) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('SYNC (ON COMMIT)'); -- 現在使用中のモデルを取得するビュー CREATE VIEW CURRENT_EMBEDDING_MODEL AS SELECT model_id, model_name, model_version, vector_dimension FROM EMBEDDING_MODELS WHERE is_current = 'Y'; -- 現在のモデルによるエンベディングを取得するビュー CREATE VIEW CURRENT_IMAGE_EMBEDDINGS AS SELECT ie.embedding_id, ie.image_id, ie.embedding FROM IMAGE_EMBEDDINGS ie JOIN CURRENT_EMBEDDING_MODEL cem ON ie.model_id = cem.model_id;
本アプリのインストール
データベースインスタンスが稼働しているサーバー(OCIコンピュートインスタンスなど)のローカルにインストールする場合以外は、本アプリケーションがネットワーク越しに Oracle Database のリスナーへアクセスできるよう Firewall 等の設定を行ってください(補足予定)。
-
リポジトリをクローン:
git がインストールされていない場合は、以下のコマンドでインストールします。
sudo dnf install git -y
リポジトリをクローンします。
git clone https://github.com/kutsushitaneko/image-similarity-search.git cd image-similarity-search
-
Python のバージョン確認
次のコマンドで Python のバージョンを確認します。3.10 以上であることを確認してください。
python --version
3.10 よりも前のバージョンである場合は新しいバージョンをインストールします。以下は、Oracle Linux 8 に Python 3.11 をインストールする例です。
sudo dnf update -y sudo dnf install -y oracle-epel-release-el8 sudo dnf config-manager --set-enabled ol8_codeready_builder sudo dnf install -y python3.11 python --version
-
(オプション)仮想環境の作成、アクティベート
複数バージョンの Python がインストールされているサーバーで Python 3.11 の仮想環境を作成する例(Linuxの場合)
python3.11 -m venv .venv source .venv/bin/activate
Windows コマンドプロンプト、PowerShell の場合
py -3.11 -m venv .venv .venv\Scripts\activate
Windows Git Bash の場合
py -3.11 -m venv .venv source .venv/bin/activate
-
必要なパッケージをインストールします:
pip install --upgrade pip pip install -r requirements.txt
なお、GPU を使用する場合は、CUDA 用にコンパイルされた PyTorch をインストールする必要があります。
pip install -r requirements.txt
の後、pip uninstall torch
で一旦 CPU用の PyTorchを uninstall して、CUDA 用の PyTorch をインストールします。インストールする PyTorchのバージョンやインストール方法はこちらを参考にしてみてください。 -
.env
ファイルを作成し、以下の環境変数を設定します:your_username と your_password は、1-1 もしくは 1-2 で作成したデータベースにログインするためのユーザー名とパスワードです。
your_database_dsn は、1-1 または 1-2 で設定したデータベースの接続情報です。DB_USER=your_username DB_PASSWORD=your_password DB_DSN=your_database_dsn
-
Hugging Face へログイン
Japanese Stable CLIP のモデルを使用するために、Hugging Face へログインします。
huggingface-cli login
Hugging Face のバナーが表示されてトークン(User Access Token)の入力を促されます。
$ huggingface-cli login _| _| _| _| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _|_|_|_| _|_| _|_|_| _|_|_|_| _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _| _|_|_|_| _| _| _| _|_| _| _|_| _| _| _| _| _| _|_| _|_|_| _|_|_|_| _| _|_|_| _| _| _| _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _| _| _| _|_| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _| _| _| _|_|_| _|_|_|_| To login, `huggingface_hub` requires a token generated from https://huggingface.co/settings/tokens . Enter your token (input will not be visible):
ここで Hugging Face のトークン(User Access Token)を入力します
Add token as git credential? (Y/n)
ここで、トークンを Git の認証情報として追加するかを選択します。どちらでも本アプリケーションの実行には影響ありません
トークンが正しければ次のように表示されますToken is valid (permission: read). Your token has been saved to C:\Users\yujim\.cache\huggingface\token Login successful
使用方法
-
画像の登録:
- ImageSearch.py と同じディレクトリに images ディレクトリを作成し、その中に画像ファイル群を保存します
- register_images.py を実行して、データベースに画像ファイル群を登録します
python register_images.py
-
PNGファイルのテキストチャンク情報の抽出と保存:
PNGファイルについては、そのテキストチャンク情報を抽出して、データベースに登録します。PNGファイルが AUTOMATIC1111 もしくは CompyUI で生成したものであれば、その生成時のプロンプトも登録されます。JPEGファイルも画像検索対象にできますが、画像生成時のプロンプトやキャプションは登録されません。なお、プロンプトやキャプションの検索機能は未実装です。(20204/7/26 更新:SD3を想定してテキストチャンクのキーに "prompt" と "prompt_3" が同時に含まれている PNG ファイルにも対応しました。SD3で画像生成しつつ生成画像にテキストチャンクを埋め込む方法はこちらの記事で紹介しています)
テキストチャンク情報の抽出とデータベースへの登録には、以下のコマンドを実行します。(images ディレクトリ配下にあるPNGファイルをスキャンしてテキストチャンク情報をデータベースへ登録します)
python update_description_by_extracted_text_chunk.py
-
検索システムの起動:
次の Python スクリプトで アプリケーションを起動します。ローカルで実行している場合は Gradio の UI が手元のブラウザに表示されます。
python ImageSearch.py
OCI などのリモート環境などで自動的にブラウザが立ち上がらない場合は、ターミナルに表示されている
public URL
を手動でブラウザにコピーしてアクセスしてください。(.venv) ImageSearch $ python ImageSearch.py Running on local URL: http://127.0.0.1:8899 Running on public URL: https://xxxxxxxxxxxxxxxxxx.gradio.live
ブラウザで表示されるGradioインターフェースを使用して、テキストや画像による検索を行うことができます。
検索
-
左上の「検索テキスト」エリアに検索テキストを入力して、「検索」ボタンを押すと、そのテキストに関連する画像が表示されます
別の条件で検索するには「クリア」ボタンを押して検索テキストをクリアします(検索ボタンが有効になります)。検索条件を指定せずに「検索ボタン」をクリックするとアップロード日付が新しい順に16枚の画像が表示されます。
なお、ベクトル検索による類似性検索ですので、フィルタリングとは異なり無関係な画像も類似度が低い画像として表示されます。テキストとの類似性が高い画像が左上に表示され、右、下へいくほど類似度が低い画像となります。画像は類似度が高い順に16枚表示されます。 -
右上の「検索画像」エリアに画像をアップロードして、「検索」ボタンを押すと、その画像に関連する画像が表示されます
こちらも同様にベクトル検索による類似性検索ですので、フィルタリングとは異なり無関係な画像も類似度が低い画像として表示されます。
-
検索結果は中央のギャラリーエリアに表示されます。特定の画像をクリックして選択すると画像が拡大表示され、ギャラリーの下部にその画像の詳細が表示されます
-
ファイル名
-
ベクトル距離
検索テキスト、もしくは、検索画像と、選択されている検索結果画像のベクトルの内積(の -1 倍)が表示されます。小さい程類似性が高くなります(画像を登録する際に特徴ベクトルを正規化しているため類似性検索では内積を使用しています)。
-
画像生成プロンプト
検索画像が生成された時のプロンプトが表示されます(現時点では、AUTOMATIC1111、ComfyUI で生成された画像に対応)。(20204/7/26 更新:テキストチャンクのキーに "prompt" と "prompt_3" が同時に含まれている PNG ファイルにも対応しました)
-
キャプション
検索テキスト、もしくは、検索画像が生成された時のプロンプトが表示されます(現時点では、PNGのテキストチャンクをそのまま表示)。
-
データベース・テーブル構造
テーブル
- IMAGES: 画像データとメタデータを保存
- EMBEDDING_MODELS: 埋め込みモデルの情報を管理
- IMAGE_EMBEDDINGS: 画像の埋め込みベクトルを保存
- IMAGE_DESCRIPTIONS: 画像の説明文を保存
画像データそのものを保存するテーブル(IMAGES)と画像のエンベディング(ベクトルデータ)を保存するテーブルを(IMAGE_EMBEDDINGS)分離しています。ベクトル化するエンベディングモデルのバージョンアップや異なるモデルへの変更を想定して1つの画像が複数のエンベディング(ベクトルデータ)を持てるようにしています。IMAGE_EMBEDDINGS テーブルの各レコードは、そのエンベディング(ベクトルデータ)を生成したモデルの MODEL_ID を持っています。EMBEDDING_MODELS の IS_CURRENT が'Y' であるモデルが現在使用されているモデルを示しています。
ビュー
CREATE VIEW CURRENT_EMBEDDING_MODEL AS
SELECT model_id, model_name, model_version, vector_dimension
FROM EMBEDDING_MODELS
WHERE is_current = 'Y';
CREATE VIEW CURRENT_IMAGE_EMBEDDINGS AS
SELECT ie.embedding_id, ie.image_id, ie.embedding
FROM IMAGE_EMBEDDINGS ie
JOIN CURRENT_EMBEDDING_MODEL cem ON ie.model_id = cem.model_id;
アプリケーションは、CURRENT_IMAGE_EMBEDDINGS ビューを参照することで現在有効なエンベディング(ベクトルデータ)にアクセスできます。エンベディングモデルの移行の際には、新しいモデルで生成したエンベディング(ベクトルデータ)を IMAGE_EMBEDDINGS に追加登録し、移行のタイミングで EMBEDDINGS_MODELS の IS_CURRENT を更新することでスムースな移行を実現できます。なお、アプリケーション側では同時にクエリーベクトルも新しいモデルで生成するように修正する必要があります(この部分はモデルの変更などでモデルの呼び出し方自体が変わる可能性もありあらかじめ決定できないため未実装です)。
テーブルとビューの DDL はcreate_all_tables.sql
です。
画像登録スクリプト(register_images.py)
処理フロー
画像のメタデータ登録スクリプト(update_description_by_extracted_text_chunk.py)
画像ファイルが PNG 形式である場合、テキストチャンクの情報を IMAGE_DESCRIPTIONS テーブルに登録します。テキストチャンクの情報が画像生成AIのプロンプトであると判断した場合は IMAGES テーブルにプロンプトを登録します。
処理フロー
マルチモーダル画像検索アプリ(ImageSearch.py)
テキストから画像と、画像から画像の2種類の類似性画像検索機能を提供する UI
処理フロー
ライセンス
- このプロジェクトはMITライセンスの下で公開されています
- Japanese Stable CLIP のライセンスは Stability AI 社のライセンスをご確認ください
- サンプル画像は、Wikimedia Commons でライセンスが "制限なし" となっているもの、国立天文台が公開しているもの(Credit: NAOJ)、私個人が撮影したもの、私が Stabile Diffusion や DALL-E 3 で生成したものを動作確認用サンプルとして images ディレクトリに保存しています
謝辞
このプロジェクトは以下のリソースを使用しています
おまけ
他にもいろいろ記事を書いていますので良かったらお立ち寄りください。