Oracle AI Vector Search と Japanese Stable CLIP によるマルチモーダル画像検索

![text_search_cat_jp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74534/115d5ba5-e871-5d84-e9a6-a98ca49acbff.jpeg)

## はじめに
Oracle Database 23ai から Oracle Database にベクトル検索機能が登場しました。Oracle AI Vector Search です。以前、[Japanse Stable CLIP を使って画像の分類に取り組んでいました](https://qiita.com/yuji-arakawa/items/042937eaf16fa00cf491)。今回は Japanese Stable CLIP のテキストと画像の特徴ベクトルを同じ埋め込み空間に生成する機能とOracle AI Vector Search を使ってテキストから画像を検索したり、画像からその画像と類似した画像を検索するマルチモーダル・アプリケーションを作ってみました。

https://github.com/kutsushitaneko/image-similarity-search

Japanse Stable CLIP は、GPU の無い環境でも動作する軽快なモデルなので GPU 環境が無い方でもこのアプリケーションを試していただけます。

## Oracle AI Vector Search とは
ベクトルデータに基づいたセマンティックサーチを実現する Oracle Database の新し機能です。23ai から利用可能になりました。以下のような特徴があります。

1. ベクトルデータのサポート: 新しいVECTORデータ型を使用して、ベクトルを直接データベース内のテーブル（リレーション）に格納することができます。これにより、データベース内の構造化データやJSONなど様々なデータモデルのデータを組み合わせたアプリケーションを容易に構築できます。既存のデータベース・テーブルにベクトル列を追加することでアプリケーションにセマンティック検索機能を追加することも容易です。また、VECTOR型は異なる次元数や形式のベクトルをサポートしています
2. ベクトル検索をSQLで実行できるようにするための拡張が行われています。これにより、従来のSQLクエリと組み合わせてベクトル検索を行うことができます
3. インメモリ近傍グラフ索引やパーティション化された近傍索引などのベクトル索引を使用して、類似性検索を高速化します。これにより、大規模なデータセットに対しても高精度で迅速な検索が可能です
4. テキストデータのベクトル化手法の多様性：
    - インデータベースでベクトル化：ONNX形式の Embeddingモデルをインポート可能
    - データベースから外部の3rd Party Embedding モデル API を呼び出してベクトル化可能
    - 外部であらかじめ用意したベクトルデータを格納（SQLのINSERT文、SQL*Loader、Oracle Data Pump）

## Japanese Stable CLIP とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74534/d15b3c91-fba2-4afb-af3f-2d6179ae51f0.png)


日本語に特化した画像言語特徴抽出モデルです。マルチモーダル埋め込みモデルとも呼ばれます。画像の特徴ベクトル（エンベディング）とテキストの特徴ベクトル（エンベディング）を同じ埋め込み空間内に抽出（生成）することができます。つまり、モデル単体で任意の日本語テキストから画像を検索する画像検索やその逆であるテキスト検索（分類）が可能です（画像を説明するキャプションの生成（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の[ブログ](https://openai.com/index/clip/)、[実装](https://github.com/OpenAI/CLIP)）。CLIPは、インターネット等から収集された大規模な画像とテキストのペア（4億ペア）を用いて学習しています。学習は以下のような行われます。

<table>
<tr>
<td>
<img src="https://images.ctfassets.net/kftzwdyauwt9/fbc4f633-9ad4-4dc2-3809c22df5e0/0bd2d5abf90d052731538613e4a42668/overview-a.svg" alt="Figure 1. Summary of our approach. While standard image models jointly train an image feature extractor and a linear classifier to predict some label, CLIP jointly trains an image encoder and a text encoder to predict the correct pairings of a batch of (image, text) training examples. At test time the learned text encoder synthesizes a zero-shot linear classifier by embedding the names or descriptions of the target dataset’s classes.">
</td>
</tr>
<tr>
<td>
Learning Transferable Visual Models From Natural Language Supervision
(https://arxiv.org/abs/2103.00020) Figure 1. Summary of our approach.
</td>
</tr>
</table>

- 収集したデータセットから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）](https://arxiv.org/abs/2303.15343)が採用されています。従来の対照学習が正規化のためにバッチ内のすべての画像・テキストペアの情報を必要とするsoftmax関数に基づいていたのに対して、SigLIPでは、各画像-テキストペアを独立してSigmoid 関数を適用することで効率的な学習を実現しています。この効率的な学習により画像と言語の特徴抽出の精度が向上することを期待できます。また、[Conceptual 12M(CC12M)](https://github.com/google-research-datasets/conceptual-12m)のキャプションを日本語に翻訳したデータセットなどを用いることで日本語に対応しています。詳しくは、Stability AI社の[ブログ](https://ja.stability.ai/blog/japanese-stable-clip)と [Hugging Face の Model Card](https://huggingface.co/stabilityai/japanese-stable-clip-vit-l-16) を参照してください。

以下のブログ記事もご参照ください。

https://qiita.com/yuji-arakawa/items/042937eaf16fa00cf491

https://ja.stability.ai/blog/japanese-stable-clip

## 本アプリケーションの機能

- テキストによる類似画像検索
- 画像による類似画像検索
- 画像のメタデータ（生成プロンプト、キャプション）の表示
- PNGファイルのテキストチャンク情報の抽出と保存
- GPU の無い環境でも動作

## 前提条件

- Python 3.10以上
- Oracle Database 23ai インスタンス
- CPU上でも動作可能（GPUがあればなお良い）
- Hugging Face のアカウントがあること（[Hugging Face アカウント作成ページ](https://huggingface.co/join) で無料で登録することができます）
- Hugging Face の User Access Token を取得していること（[Hugging Face User Access Token 作成ページ](https://huggingface.co/settings/tokens) で無料で取得できます。"Type" は、"READ"）
- [stabilityai/japanese-stable-clip-vit-l-16](https://huggingface.co/stabilityai/japanese-stable-clip-vit-l-16) でコンタクト情報の登録が完了していること
- 動作は  OCI の VM.Standard3.Flex Compute Shape + Oracle Linux 8（CPUのみ） とローカルの Windows 11(CPUのみの場合とGPU利用の場合の両方) で確認しています。

## データベース環境のセットアップ
1. データベースのインストール

    日本オラクルの[チュートリアル](https://oracle-japan.github.io/ocitutorials/ai-vector-search/ai-vector106-23ai-langchain-rag/)の [1-1. Oracle Database 23ai Free環境でのセットアップ](https://oracle-japan.github.io/ocitutorials/ai-vector-search/ai-vector106-23ai-langchain-rag/#1-1-oracle-database-23ai-free%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97) もしくは [1-2. Base Database Service環境でのセットアップ](https://oracle-japan.github.io/ocitutorials/ai-vector-search/ai-vector106-23ai-langchain-rag/#1-2-base-database-service%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97) を実施してください。

    ユーザー名は docuser となっていますがお好みの任意の名前で作成してください。作成したユーザー名とパスワードは、.env ファイルに設定しますのでメモしておいてください。なお、この手順の中でユーザー（docuser） に様々な権限を付与していますが、これに VIEW を作成する権限も追加します。

    ユーザー名が docuser の場合は以下の SQL を sqlplus に sys ユーザーでログインして実行します。
    
    ```
    sqlplus sys@localhost:1521/freepdb1 as sysdba
    ```
    ```
    GRANT CREATE VIEW TO docuser;
    ```

2. テーブルの作成

    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 等の設定を行ってください（補足予定）。

1. リポジトリをクローン：

    git がインストールされていない場合は、以下のコマンドでインストールします。
    ```
    sudo dnf install git -y
    ```

    リポジトリをクローンします。
    ```
    git clone https://github.com/kutsushitaneko/image-similarity-search.git
    cd image-similarity-search
    ```
    
2. 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
    ```

3. （オプション）仮想環境の作成、アクティベート

    複数バージョンの 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
    ```

4. 必要なパッケージをインストールします：

    ```
    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のバージョンやインストール方法は[こちら](https://qiita.com/yuji-arakawa/items/6d0299c505315bc3cdb0#pytorch)を参考にしてみてください。

5. `.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
    ```

6. Hugging Face へログイン

    Japanese Stable CLIP のモデルを使用するために、Hugging Face へログインします。

    ```
    huggingface-cli login
    ```

    Hugging Face のバナーが表示されてトークン（User Access Token）の入力を促されます。

    ```TERMINAL
    $ 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
    ```


## 使用方法

1. 画像の登録：

    - ImageSearch.py と同じディレクトリに images ディレクトリを作成し、その中に画像ファイル群を保存します
    - register_images.py を実行して、データベースに画像ファイル群を登録します
        ```
        python register_images.py
        ```


2. PNGファイルのテキストチャンク情報の抽出と保存：

    PNGファイルについては、そのテキストチャンク情報を抽出して、データベースに登録します。PNGファイルが AUTOMATIC1111 もしくは CompyUI で生成したものであれば、その生成時のプロンプトも登録されます。JPEGファイルも画像検索対象にできますが、画像生成時のプロンプトやキャプションは登録されません。なお、プロンプトやキャプションの検索機能は未実装です。（20204/7/26 更新：SD3を想定してテキストチャンクのキーに "prompt" と "prompt_3" が同時に含まれている PNG ファイルにも対応しました。SD3で画像生成しつつ生成画像にテキストチャンクを埋め込む方法は[こちら](https://qiita.com/yuji-arakawa/items/1a8cfeff8f81ba808389)の記事で紹介しています）

    

    テキストチャンク情報の抽出とデータベースへの登録には、以下のコマンドを実行します。（images ディレクトリ配下にあるPNGファイルをスキャンしてテキストチャンク情報をデータベースへ登録します）
    
    
    ```
    python update_description_by_extracted_text_chunk.py
    ```

3. 検索システムの起動：

    次の 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インターフェースを使用して、テキストや画像による検索を行うことができます。

## 検索
- 左上の「検索テキスト」エリアに検索テキストを入力して、「検索」ボタンを押すと、そのテキストに関連する画像が表示されます

    ![text_search_cat_jp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74534/8a1276a8-b829-2e2c-160d-08b6e26c7ba8.jpeg)

    別の条件で検索するには「クリア」ボタンを押して検索テキストをクリアします（検索ボタンが有効になります）。検索条件を指定せずに「検索ボタン」をクリックするとアップロード日付が新しい順に16枚の画像が表示されます。
    なお、ベクトル検索による類似性検索ですので、フィルタリングとは異なり無関係な画像も類似度が低い画像として表示されます。テキストとの類似性が高い画像が左上に表示され、右、下へいくほど類似度が低い画像となります。画像は類似度が高い順に16枚表示されます。
- 右上の「検索画像」エリアに画像をアップロードして、「検索」ボタンを押すと、その画像に関連する画像が表示されます


    こちらも同様にベクトル検索による類似性検索ですので、フィルタリングとは異なり無関係な画像も類似度が低い画像として表示されます。
    
    ![text_search_cat_by_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74534/6bcea648-559d-d3a4-5bcc-f1320e477763.jpeg)

- 検索結果は中央のギャラリーエリアに表示されます。特定の画像をクリックして選択すると画像が拡大表示され、ギャラリーの下部にその画像の詳細が表示されます

    ![generation_prompt.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74534/0618da3a-352c-219d-a50e-8df960ad4ff7.jpeg)

    - ファイル名
    - ベクトル距離

        検索テキスト、もしくは、検索画像と、選択されている検索結果画像のベクトルの内積（の -1 倍）が表示されます。小さい程類似性が高くなります（画像を登録する際に特徴ベクトルを正規化しているため類似性検索では内積を使用しています）。
    - 画像生成プロンプト
    
        検索画像が生成された時のプロンプトが表示されます（現時点では、AUTOMATIC1111、ComfyUI で生成された画像に対応）。（20204/7/26 更新：テキストチャンクのキーに "prompt" と "prompt_3" が同時に含まれている PNG ファイルにも対応しました）
    - キャプション
    
        検索テキスト、もしくは、検索画像が生成された時のプロンプトが表示されます（現時点では、PNGのテキストチャンクをそのまま表示）。

## データベース・テーブル構造

### テーブル

```mermaid
erDiagram
    IMAGES ||--o{ IMAGE_EMBEDDINGS : has
    IMAGES ||--o{ IMAGE_DESCRIPTIONS : has
    EMBEDDING_MODELS ||--o{ IMAGE_EMBEDDINGS : used_by
    IMAGES {
        IMAGE_ID NUMBER PK
        IMAGE_DATA BLOB
        FILE_NAME VARCHAR2
        FILE_TYPE VARCHAR2
        UPLOAD_DATE TIMESTAMP
        GENERATION_PROMPT CLOB
    }
    EMBEDDING_MODELS {
        MODEL_ID NUMBER PK
        MODEL_NAME VARCHAR2
        MODEL_VERSION VARCHAR2
        IS_CURRENT CHAR
        VECTOR_DIMENSION NUMBER
    }
    IMAGE_EMBEDDINGS {
        EMBEDDING_ID NUMBER PK
        IMAGE_ID NUMBER FK
        MODEL_ID NUMBER FK
        EMBEDDING VECTOR
    }
    IMAGE_DESCRIPTIONS {
        DESCRIPTION_ID NUMBER PK
        IMAGE_ID NUMBER FK
        DESCRIPTION CLOB
    }
```

- IMAGES: 画像データとメタデータを保存
- EMBEDDING_MODELS: 埋め込みモデルの情報を管理
- IMAGE_EMBEDDINGS: 画像の埋め込みベクトルを保存
- IMAGE_DESCRIPTIONS: 画像の説明文を保存


画像データそのものを保存するテーブル（IMAGES）と画像のエンベディング（ベクトルデータ）を保存するテーブルを（IMAGE_EMBEDDINGS）分離しています。ベクトル化するエンベディングモデルのバージョンアップや異なるモデルへの変更を想定して１つの画像が複数のエンベディング（ベクトルデータ）を持てるようにしています。IMAGE_EMBEDDINGS テーブルの各レコードは、そのエンベディング（ベクトルデータ）を生成したモデルの MODEL_ID を持っています。EMBEDDING_MODELS の IS_CURRENT が'Y' であるモデルが現在使用されているモデルを示しています。

### ビュー

```mermaid
erDiagram
    CURRENT_EMBEDDING_MODEL {
        MODEL_ID NUMBER
        MODEL_NAME VARCHAR2
        MODEL_VERSION VARCHAR2
        VECTOR_DIMENSION NUMBER
    }
    CURRENT_IMAGE_EMBEDDINGS {
        EMBEDDING_ID NUMBER
        IMAGE_ID NUMBER
        EMBEDDING VECTOR
}
```

```SQL:現在有効なモデルの情報を提示するビュー
CREATE VIEW CURRENT_EMBEDDING_MODEL AS
SELECT model_id, model_name, model_version, vector_dimension
FROM EMBEDDING_MODELS
WHERE is_current = 'Y';
```

```SQL:現在有効なエンベディング（ベクトルデータ）を提示するビュー
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)
### 処理フロー

```mermaid
graph TD
    A[開始] --> D[Japanese Stable CLIPモデルのロード]
    D --> F[Oracleデータベースに接続]
    F --> G[imagesディレクトリ内の<BR>画像を1つ読み込む]
    G --> H[画像データのエンベディングを生成<BR>compute_image_embedding#40;#41;]
    H --> K[IMAGESテーブルに画像を挿入]
    K --> L[IMAGE_EMBEDDINGSテーブルに<BR>エンベディングを挿入]
    L --> M{すべての画像を<BR>処理したか?}
    M -->|No| G
    M -->|Yes| N[データベース接続を閉じる]
    N --> O[終了]
```

## 画像のメタデータ登録スクリプト（update_description_by_extracted_text_chunk.py）
画像ファイルが PNG 形式である場合、テキストチャンクの情報を IMAGE_DESCRIPTIONS テーブルに登録します。テキストチャンクの情報が画像生成AIのプロンプトであると判断した場合は IMAGES テーブルにプロンプトを登録します。
### 処理フロー
```mermaid
graph TD
    A[開始] --> E{imagesフォルダ内の<BR>PNGファイルを<BR>1つ読み込む}
    E --> H[extract_text_chunks#40;#41;<BR>PNGメタデータの抽出]
    H --> I{メタデータが<BR>存在するか?}
    I -->|No| E
    I -->|Yes| J[format_chunks#40;#41;<BR>メタデータをフォーマット]
    J --> K[データベースに接続]
    K --> L[ファイル名からIMAGESテーブルを<BR>検索してimage_idを取得]
    L --> O{メタデータの内容に<BR>基づいて処理を分岐}
    O -->|Stable Diffusion Web UI| P[generation_promptを更新]
    O -->|ComfyUI| P
    O -->|SD3モデル| P
    O -->|その他| Q[IMAGE_DESCRIPTIONSにデータを挿入]
    P --> R[データベースの変更をコミット]
    Q --> R
    R --> S[データベース接続を閉じる]
    S --> E
    E -->|すべてのファイルを処理| T[終了]
```

## マルチモーダル画像検索アプリ（ImageSearch.py）
テキストから画像と、画像から画像の２種類の類似性画像検索機能を提供する UI
### 処理フロー

```mermaid
graph TD
    A[開始] --> D[Japanese Stable CLIPモデルのロード]
    D --> E[ユーティリティ関数の定義]
    E --> F[Gradioインターフェースの定義]
    F --> G{ユーザーアクション}
    G -->|初期ロード| H[load_initial_images#40;#41;<br>最新の画像をロード]
    G -->|空の検索| H[load_initial_images#40;#41;<br>最新の画像をロード]
    G -->|テキスト検索| I[compute_text_embeddings#40;#41;<br>テキストエンベディングの計算]
    G -->|画像検索| J[compute_image_embeddings#40;#41;<br>画像エンベディングの計算]    
    I --> K[search_images#40;#41;<br>データベースで類似画像を検索]
    J --> K
    K --> L[検索結果の表示]
    H --> B[最新画像の表示]
    B --> G
    G -->|画像選択| M[on_select#40;#41;<br>選択画像の詳細表示]
    G -->|クリア| N[clear_inputs#40;#41;<br>入力フィールドをクリア]
    L --> G
    M --> G
    N --> G
    G -->|終了| O[アプリケーション終了]
```

## ライセンス

- このプロジェクトはMITライセンスの下で公開されています
- Japanese Stable CLIP のライセンスは Stability AI 社のライセンスをご確認ください
- サンプル画像は、Wikimedia Commons でライセンスが "制限なし" となっているもの、国立天文台が公開しているもの（Credit: NAOJ）、私個人が撮影したもの、私が Stabile Diffusion や DALL-E 3 で生成したものを動作確認用サンプルとして images ディレクトリに保存しています

## 謝辞

このプロジェクトは以下のリソースを使用しています

- [Japanese Stable CLIP](https://huggingface.co/stabilityai/japanese-stable-clip-vit-l-16)

## おまけ
他にもいろいろ記事を書いていますので良かったらお立ち寄りください。

https://qiita.com/yuji-arakawa/items/28f30a5434ba429f3f16

https://qiita.com/yuji-arakawa/items/8d065ae3df536f5cd559

https://qiita.com/yuji-arakawa/items/fd4fd0c026ecfa664d97

https://qiita.com/yuji-arakawa/items/654d936ca616334286b0

https://qiita.com/yuji-arakawa/items/1a8cfeff8f81ba808389

https://qiita.com/yuji-arakawa/items/042937eaf16fa00cf491

https://qiita.com/yuji-arakawa/items/6d0299c505315bc3cdb0

https://qiita.com/yuji-arakawa/items/05e3455572d3b09a53dc

https://qiita.com/yuji-arakawa/items/2d4f6eff17a5410dba2d

https://qiita.com/yuji-arakawa/items/597c4bd9f3d5b4212b51

https://aws.amazon.com/jp/blogs/news/leveraging-pinecone-on-aws-marketplace-as-a-knowledge-base-for-amazon-bedrock/