rinna株式会社が公開しているjapanese-cloob-vit-b-16のモデル(rinna株式会社によるプレスリリース)とベクトル・データベースPineconeを使って、テキストによる画像検索を行なうアプリケーションを作成します。APEXではユーザーインタフェースを作成します。
以下の処理を実装します。
- オブジェクト・ストレージに保存した画像のベクトル埋め込み(embedding)をrinna社のモデルをより生成し、Pineconeに保存する。
- 問い合わせテキストのベクトル埋め込みをrinna社のモデルをより生成し、Pinconeのインデックスを検索する。
- 検索された画像をアプリケーションに表示する。
作成したアプリケーションのGIF動画です。動物の名前で画像を検索しています。
上記のアプリケーションのエクスポートを、以下に置いています。
https://github.com/ujnak/apexapps/blob/master/exports/multimodal-search.zip
これより、アプリケーションの実装について説明します。
Pineconeのインデックス
rinna社のjapanese-cloob-vit-b-16は512次元のベクトル埋め込みを生成するため、作成するPineconeのインデックスの
Dimensionsは
512とします。ベクトル埋め込みを生成する際に、Pinecone社が公開している記事
Multi-modal ML with OpenAI's CLIPに従ってベクトル埋め込みを正規化します。記事に従って
Metricに
dotproductを指定しますが、cosineでも結果は変わりません。
PinconeのインデックスのURLは、APEXアプリケーションの置換文字列G_INDEXの置換値として設定します。
PineconeのAPI呼び出しに使う
Web資格証明として、
PINECONE_APIが作成済みとします。作成手順は、
こちらの記事に記載されています。
オブジェクト・ストレージへの画像アップロード
オブジェクト・ストレージにバケットを作成し、検索対象とする画像をアップロードします。
以下の例ではバケットsourcesを作成しています。
検索対象とする画像を、作成したバケットにアップロードします。
バケット名、
ネームスペースは、APEXアプリケーションの置換文字列
G_BUCKET、
G_NAMESPACEの置換値として設定します。
検索の対象とする画像を、バケットにアップロードします。
オブジェクト・ストレージに関する設定は、
こちらの記事で紹介しています。APEXアプリケーションから操作するために、あらかじめ
APIユーザーの作成や
Web資格証明を作成しておきます。また、事前承認済リクエストを生成するため、ポリシーを追加します。それぞれの準備については、
こちらの記事が参考になります。
これからの説明では、Web資格証明としてOCI API Access(静的IDはOCI_API_ACCESS)が作成済みとします。
ベクトル埋め込みを生成するRESTサービス
無料で使えるOracle CloudのAmpere A1のインスタンスを4OCPU、24GBメモリのシェイプで作成します。その上でPythonのコードを実行してベクトル埋め込みを生成します。
APIサーバーとして実行するためにFlaskを使います。準備作業については、
こちらの記事を参照してください。rinna株式会社のjapanese-cloob-vit-b-16を利用する手順は、Huggingfaceの
rinna/japanese-cloob-vit-b-16の記載通りです。パッケージのインストールを実施(1. Install package)し、テスト用のコードを実行(2. Run)して、動作を確認します。
画像のURLまたはテキストを受け付けて、rinna/japanese-cloob-vit-b-16のモデルを使ってベクトル埋め込みを生成するサーバーのコードです。generate-embedding.pyとして作成します。
Ubuntuのサーバー上で実行します。
python generate-embedding.py
ubuntu@mywhisper2:~$ python generate-embedding.py
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.13) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
* Serving Flask app 'generate-embedding'
* Debug mode: on
INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on https://127.0.0.1:8443
* Running on https://10.0.0.131:8443
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on https://127.0.0.1:8443
* Running on https://10.0.0.131:8443
INFO:werkzeug:Press CTRL+C to quit
Press CTRL+C to quit
INFO:werkzeug: * Restarting with stat
* Restarting with stat
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.13) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
WARNING:werkzeug: * Debugger is active!
* Debugger is active!
INFO:werkzeug: * Debugger PIN: 849-624-968
* Debugger PIN: 849-624-968
テキストのベクトル埋め込みを生成するには、
https://ホスト名/embed-textに
{ text: "問い合わせ文字列" }というJSONドキュメントを
POSTします。レスポンスとして
{ text: "問い合わせ文字列", embedding: [ベクトル埋め込み] }が返されます。
画像のベクトル埋め込みを生成するには、https://ホスト名/embed-imageに{ url: "画像のURL" }というJSONドキュメントをPOSTします。レスポンスとして{ url: "画像のURL", embedding: [ベクトル埋め込み] }が返されます。
ベクトル埋め込みを生成するRESTサービスを実装したサーバーは、APEXアプリケーションの置換文字列G_EMBEDの置換値であるベースURLとして設定します。
APEXアプリケーションの作成
アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前はMultimodal Searchとします。
アプリケーションの作成を実行します。
アプリケーションが作成されたら、アプリケーション定義の置換を開きます。
置換文字列G_INDEX、G_EMBED、G_NAMESPACE、G_BUCKETの置換値を設定します。
オブジェクト・ストレージに認証なしでアクセスするため(ベクトル埋め込みを生成するPythonのコードは、認証なしでオブジェクト・ストレージにアクセスする必要があります)、事前承認済リクエストのURLを生成します。
事前承認済リクエストのURLを保持するアプリケーション・アイテムG_PREAUTH_URLを作成します。
アプリケーションの計算を作成し、G_PREAUTH_URLに事前承認済リクエストのURLを設定します。
計算ポイントに認証後、計算タイプにファンクション本体を選択します。計算として以下のコードを記述します。
北米AshburnリージョンがURLに直書きされているため、リージョンが異なる場合はコードの変更が必要です。
オブジェクト・ストレージのバケットに保存されている、画像の一覧を取得するRESTデータ・ソースを作成します。
あらかじめオブジェクト・ストレージのエンドポイントを、リモート・サーバーとして作成します。今回の例では北米Ashburnリージョンのエンドポイントを使用するため、以下のエンドポイントをベースURLとしています。
https://objectstorage.us-ashburn-1.oraclecloud.com/
共有コンポーネントのRESTデータ・ソースを開き、作成を開始します。
RESTデータ・ソースの作成として最初からを選択します。
次へ進みます。
RESTデータ・ソース・タイプとして
Oracle Cloud Infrastructure(OCI)を選択し、
名前は
List Imagesとします。
URLエンドポイントは以下の形式で指定します。
https://objectstorage.
リージョン.oraclecloud.com/n/
ネームスペース/b/
バケット/o/
次へ進みます。
リモート・サーバーとして、
APIのエンドポイントとなるリモート・サーバーを選択します。
サービスURLパスは以下の形式で指定します。
n/ネームスペース/b/バケット/o/
次へ進みます。
認証が必要ですをオンにし、資格証明としてOCI API Access、またはオブジェクト・ストレージにアクセスできる他のWeb資格証明を指定します。
検出をクリックします。
ファイルの一覧が検出されます。
RESTデータ・ソースの作成をクリックします。
RESTデータ・ソースが作成されます。同期化の設定を行うために、作成されたRESTデータ・ソースList Imagesを開きます。
静的IDがlist_imagesであることを確認します。
画面右の同期化の管理を開きます。
同期先として新規表を選択し、表名としてVEC_IMAGESを設定します。同期化を設定することにより、毎回REST APIを呼び出す代わりに表VEC_IMAGESから画像の一覧を取り出せるようになります。
保存をクリックします。
同期化は作成されましたが、表VEC_IMAGESはまだ作成されていません。
表の作成をクリックします。
表VEC_IMAGESが作成されました。
詳細の
同期タイプを
置換にします。
保存して実行をクリックし、最初の同期を実行します。
同期が完了すると、ログに実行結果が表示されます。ステータスが成功であれば、表VEC_IMAGESにオブジェクト・ストレージのバケットに含まれるファイルの一覧が保存されています。
SQLワークショップのSQLコマンドを開いて、表VEC_IMAGESの内容を確認します。
select name from vec_images;
表VEC_IMAGESの画像(のベクトル埋め込み)がPineconeのインデックスのベクトルとして保存されているかどうか、フラグを保持する表VEC_IMAGE_INDEXESを作成します。
以下のDDLを実行します。
create table vec_image_indexes(
file_name varchar2(80) not null,
is_indexed varchar2(1)
);
ページ・デザイナでホーム・ページを開き、ユーザー・インターフェースを実装します。
画面上にボタンを4つ作成します。
それぞれボタン名とラベル名として、LOAD_FROM_BUCKET(Load From Bucket)、UPSERT_VECTORS(Upsert Vectors)、DELETE_VECTORS(Delete Vectors)、FIND_IMAGES(Find Images)とします。動作のアクションはすべてページの送信です。
レイアウトは適当に調整します。
問合せ文字列を指定するページ・アイテムP1_QUESTIONを作成します。タイプはテキスト・フィールド、ラベルはQuestionとします。
検索結果の数を指定するページ・アイテムP1_TOP_Kを作成します。タイプはテキスト・フィールド、ラベルはTop Kとします。
オブジェクト・ストレージ上にある画像の一覧と、Pineconeのインデックスにベクトル埋め込みが含まれているかどうかを示すフラグを表示する対話モード・レポートを作成します。
リージョンのタイトルはImage Indexes、ソースのSQL問合わせとして以下を記述します。
select 'image' as image, i.name, x.is_indexed
from vec_images i left outer join vec_image_indexes x on i.name = x.file_name
列IMAGEを選択し、オブジェクト・ストレージ上の画像が表示されるように、列の書式のHTML式として以下を記述します。
<img src="&G_PREAUTH_URL.#NAME#" width="20"></img>
ページ・アイテムP1_QUESTIONに動物の名前を入力し、問い合わせを行った結果を表示する対話モード・レポートを作成します。
リージョンのタイトルはResults、ソースのSQL問合わせとして以下を記述します。
select c001, n001 from apex_collections where collection_name = 'IMAGES'
レイアウトの新規行の開始をオフにし、リージョンImage Indexesの右横に配置します。
列
C001を選択し、検索結果の画像が表示されるように、
列の書式の
HTML式に以下を記述します。
<img src="&G_PREAUTH_URL.#C001#" width="200"></img>
プロセス・ビューを開き、4つのボタンを押したときに実行されるプロセスを作成します。
ボタンLOAD_FROM_BUCKETを押したときに実行されるプロセスを、Load From Bucketとして作成します。ソースのPL/SQLコードは以下になります。
ボタンUPSERT_VECTORSを押したときに実行されるプロセスを、Upsert Vectorsとして作成します。ソースのPL/SQLコードは以下になります。
ボタンFIND_IMAGESを押したときに実行されるプロセスを、Find Imagesとして作成します。ソースのPL/SQLコードは以下になります。
ボタンDELETE_VECTORSを押したときに実行されるプロセスを、Delete Vectorsとして作成します。ソースのPL/SQLコードは以下になります。
必ずしも必要な作業でありませんが、作成したRESTデータ・ソースのURLパス接頭辞を以下のように変更し、パラメータを定義するとRESTデータ・ソースの再利用が容易になります。
n/:namespace/b/:bucket/o/
パラメータのタイプはURLパターン、デフォルト値はそれぞれ&G_NAMESPACE.、&G_BUCKET.になります。必須ははいです。
今回作成したアプリケーションの説明は以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完