2025年1月にリリースされたRU23.7において、ONNXフォーマットを使ったDB内Embeddingで画像を扱えるようになりました。
一方で、画像のEmbeddingに対応したモデルを23ai向けにONNXエクスポートするには、OML4Py 2.1以上が必要となっています。
そのOML4Py 2.1はRU23.7がリリースされた時点で未だ公開されていなかったのですが、やっと先日使えるようになりました。
という訳で早速、画像のDB内Embeddingを試すべく、せっかくなのでマルチモーダルEmbeddingモデルの clip-vit-large-patch14
を使って動作確認してみました。
なお、今回は OCI BaseDB の RU23.7 を使いました。
またマルチモーダル検索の動作確認にはAPEXで作った簡易アプリを利用しています。
以下のようにテキストで画像を検索するように実装しました。
また画像で画像を検索する機能も試してみました。
本検証用アプリはこちらからエクスポートしたファイルを取得できます。
検証用の画像は kaggle にて CC0: Public Domain
で公開されている以下データセットを使用しました。
https://www.kaggle.com/datasets/pavansanagapati/images-dataset
以降は検証手順のメモです。
検証手順
OML4Py 2.1のインストール
OML4Pyに必要なOSパッケージをインストール
$ sudo su -
## 不足パッケージの確認
$ rpm -qa perl-Env
$ rpm -qa libffi-devel
$ rpm -qa openssl
$ rpm -qa openssl-devel
$ rpm -qa tk-devel
$ rpm -qa xz-devel
$ rpm -qa zlib-devel
$ rpm -qa bzip2-devel
$ rpm -qa readline-devel
$ rpm -qa libuuid-devel
$ rpm -qa ncurses-devel
## 不足分をインストール
$ yum install perl-Env libffi-devel tk-devel bzip2-devel readline-devel libuuid-devel ncurses-devel
Python仮想環境の構築にあたりminicondaをインストール
## Anacondaインストール
$ mkdir -p ~/miniconda3
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
$ bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
## 不要ファイル削除
$ rm -rf ~/miniconda3/miniconda.sh
## Anaconda初期セットアップ
$ ~/miniconda3/bin/conda init bash
Python仮想環境を作成
$ conda create -n mltebd python=3.12
## 仮想環境のアクティベート
$ conda activate mltebd
pipを最新化
$ python3 -m pip install --upgrade pip
OML4Pyに必要なPythonパッケージをインストール
$ pip install pandas
$ pip install setuptools
$ pip install scipy
$ pip install matplotlib
$ pip install oracledb
$ pip install joblib
$ pip install scikit-learn
$ pip install numpy
$ pip install onnxruntime
$ pip install onnxruntime-extensions
$ pip install onnx
$ pip install --extra-index-url "https://download.pytorch.org/whl/cpu" torch
$ pip install transformers
$ pip install sentencepiece
以下サイトからOML4Py 2.1 以上をダウンロードし、サーバに配置
https://www.oracle.com/database/technologies/oml4py-downloads.html
zipファイルを解凍し、Perlスクリプトを使ってOML4Pyをインストール
$ mkdir oml4py
$ cd oml4py
$ unzip V1048628-01.zip
$ perl -Iclient client/client.pl
Oracle Machine Learning for Python 2.1 Client.
Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
Checking platform .................. Pass
Checking Python .................... Pass
Checking dependencies .............. Pass
Checking OML4P version ............. Pass
Current configuration
Python Version ................... 3.12.9
PYTHONHOME ....................... /home/oracle/miniconda3/envs/mltebd
Existing OML4P module version .... None
Operation ........................ Install/Upgrade
Proceed? [yes]
Processing ./client/oml-2.1-cp312-cp312-linux_x86_64.whl
Installing collected packages: oml
Successfully installed oml-2.1
Done
ONNXのエクスポート
以下マニュアルに沿って作業を進めます。
https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/onnx-pipeline-models-multi-modal-embedding.html
- Exporting a pre-configured image model to a file
clip-vit-large-patch14
のONNXファイル作成 (テキスト向けと画像向けの2種類を生成)
from oml.utils import ONNXPipeline
pipeline = ONNXPipeline("openai/clip-vit-large-patch14")
pipeline.export2file("clip")
これで clip_txt.onnx
と clip_img.onnx
の2つが作成されます。
検証用DBユーザ作成、権限付与
GRANT DB_DEVELOPER_ROLE TO dmuser identified by your_password;
GRANT CREATE MINING MODEL TO dmuser;
ALTER USER dmuser QUOTA UNLIMITED ON USERS;
ONNX用のディレクトリオブジェクト作成
CREATE OR REPLACE DIRECTORY dm_dump AS '/u01/app/mltebd';
GRANT READ ON DIRECTORY dm_dump TO dmuser;
GRANT WRITE ON DIRECTORY dm_dump TO dmuser;
ONNXをインポート
clip_txt.onnx
と clip_img.onnx
をDBにインポート
EXECUTE DBMS_VECTOR.LOAD_ONNX_MODEL( 'dm_dump', 'clip_txt.onnx', 'clip_txt');
EXECUTE DBMS_VECTOR.LOAD_ONNX_MODEL( 'dm_dump', 'clip_img.onnx', 'clip_img');
インポートされたことの確認
col model_name format a20
col algorithm_name format a20
col algorithm format a20
col attribute_name format a20
col attribute_type format a20
col data_type format a20
SELECT model_name, attribute_name, attribute_type, data_type, vector_info
FROM user_mining_model_attributes
WHERE model_name IN ('CLIP_TXT', 'CLIP_IMG')
ORDER BY ATTRIBUTE_NAME;
MODEL_NAME ATTRIBUTE_NAME ATTRIBUTE_TYPE DATA_TYPE VECTOR_INFO
-------------------- -------------------- -------------------- -------------------- --------------------------------------------------------
CLIP_TXT DATA TEXT VARCHAR2
CLIP_IMG DATA UNSTRUCTURED BLOB
CLIP_IMG ORA$ONNXTARGET VECTOR VECTOR VECTOR(768,FLOAT32)
CLIP_TXT ORA$ONNXTARGET VECTOR VECTOR VECTOR(768,FLOAT32)
データセット用のディレクトリオブジェクト作成
CREATE OR REPLACE DIRECTORY dataset_dir AS '/u01/app/dataset';
GRANT READ ON DIRECTORY dataset_dir TO dmuser;
GRANT WRITE ON DIRECTORY dataset_dir TO dmuser;
データセットを入れるための表を作成-
CREATE TABLE my_table (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
file_name VARCHAR2(255),
mime VARCHAR2(100),
image BLOB,
embedding VECTOR
);
表に各データセットの ファイル名、画像バイナリ、画像のベクトルデータ を格納
画像をベクトル化しつつ、表にデータを入れるPythonスクリプトを作成して実行
(なぜかjpgしかベクトル化されなかった)
import os
import oracledb
from oracledb import DB_TYPE_BLOB
# Oracle DB接続情報
user = 'dmuser'
password = 'your_password'
dsn = 'localhost:1521/pdb1'
# BaseDBはNNEによる暗号化を使っているため、
# thick modeで利用しないとDB接続できない
oracledb.init_oracle_client()
connection = oracledb.connect(user=user, password=password, dsn=dsn)
# ディレクトリ内のファイルを取得
directory_path = '/u01/app/dataset'
files = os.listdir(directory_path)
# 各ファイルの内容を読み取り、DBにINSERT
for file_name in files:
file_path = os.path.join(directory_path, file_name)
with open(file_path, 'rb') as file:
content = file.read()
cr = connection.cursor()
# 画像の読み込み
blob = cr.var(DB_TYPE_BLOB)
blob.setvalue(0, content)
# 画像をベクトル化しつつINSERT
insert_query = "INSERT INTO my_table (file_name, mime, image, embedding) VALUES (:1, 'image/jpeg', :2, VECTOR_EMBEDDING(CLIP_IMG USING TO_BLOB(:2) as DATA))"
cr.execute(insert_query, [file_name, blob])
cr.close()
# コミットして接続を閉じる
connection.commit()
connection.close()
APEX、ORDSのインストール
APEXの最新版を取得
$ curl -OL https://download.oracle.com/otn_software/apex/apex-latest.zip
$ unzip apex-latest.zip
APEXの静的ファイルの格納先を用意
$ mkdir i
$ cp -r -p apex/images i/24.2.0
PDBにログインしてインストール
$ cd apex
$ export NLS_LANG=American_America.AL32UTF8
$ sqlplus / as sysdba
SQL> alter session set container=pdb1;
SQL> @apexins SYSAUX SYSAUX TEMP /i/24.2.0/
APEXの日本語対応
SQL> @load_trans JAPANESE
APEX管理ユーザのパスワード変更
SQL> @apxchpwd
APEX管理ユーザのアンロック
SQL> ALTER USER APEX_PUBLIC_USER NO AUTHENTICATION ACCOUNT UNLOCK;
ORDSインストールのため、JDK 21をインストール
$ curl -OL https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm
$ dnf -y localinstall jdk-21_linux-x64_bin.rpm
$ java -version
java version "21.0.7" 2025-04-15 LTS
Java(TM) SE Runtime Environment (build 21.0.7+8-LTS-245)
Java HotSpot(TM) 64-Bit Server VM (build 21.0.7+8-LTS-245, mixed mode, sharing)
ORDSインストール
dnf -y --repofrompath ol8_oracle_software,http://yum.oracle.com/repo/OracleLinux/OL8/oracle/software/x86_64 install ords
ORDSの構成
$ su - oracle
$ export PATH=/usr/local/bin:$PATH
$ cd /etc/ords/config
$ ords install
Oracle REST Data Services - Interactive Install
Enter a number to select the TNS net service name to use from /u01/app/oracle/product/23.0.0/dbhome_1/network/admin/tnsnames.ora or specify the database connection
[1] ORCL_QZZ_KIX SERVICE_NAME=orcl_qzz_kix.pubsub1.tstosaka.oraclevcn.com
[2] PDB1 SERVICE_NAME=pdb1
[S] Specify the database connection
Choose [1]: 2
Connecting to administrator user: SYS AS SYSDBA for container: PDB1 using bequeath connection
Provide database user name with administrator privileges.
Enter the administrator username: sys
Enter the database password for SYS AS SYSDBA:
Retrieving information.
ORDS is not installed in the database. ORDS installation is required.
Enter a number to update the value or select option A to Accept and Continue
[1] Connection Type: TNS
[2] TNS Connection: TNS_NAME=PDB1 TNS_FOLDER=/u01/app/oracle/product/23.0.0/dbhome_1/network/admin
Administrator User: SYS AS SYSDBA
[3] Database password for ORDS runtime user (ORDS_PUBLIC_USER): <generate>
[4] ORDS runtime user and schema tablespaces: Default: SYSAUX Temporary TEMP
[5] Additional Feature: Database Actions
[6] Configure and start ORDS in Standalone Mode: Yes
[7] Protocol: HTTP
[8] HTTP Port: 8080
[9] APEX static resources location:
[A] Accept and Continue - Create configuration and Install ORDS in the database
[Q] Quit - Do not proceed. No changes
Choose [A]: 9
Enter the APEX static resources location: /u01/app/apex/i
Enter a number to update the value or select option A to Accept and Continue
[1] Connection Type: TNS
[2] TNS Connection: TNS_NAME=PDB1 TNS_FOLDER=/u01/app/oracle/product/23.0.0/dbhome_1/network/admin
Administrator User: SYS AS SYSDBA
[3] Database password for ORDS runtime user (ORDS_PUBLIC_USER): <generate>
[4] ORDS runtime user and schema tablespaces: Default: SYSAUX Temporary TEMP
[5] Additional Feature: Database Actions
[6] Configure and start ORDS in Standalone Mode: Yes
[7] Protocol: HTTP
[8] HTTP Port: 8080
[9] APEX static resources location: /u01/app/apex/i
[A] Accept and Continue - Create configuration and Install ORDS in the database
[Q] Quit - Do not proceed. No changes
Choose [A]:
...(略)...
2025-04-21T15:17:55.801Z INFO Oracle REST Data Services initialized
Oracle REST Data Services version : 25.1.0.r1001652
Oracle REST Data Services server info: jetty/12.0.13
Oracle REST Data Services java info: Java HotSpot(TM) 64-Bit Server VM (build: 21.0.7+8-LTS-245 mixed mode, sharing)
ORDSの自動起動を有効化
$ sudo su -
$ systemctl enable ords
$ systemctl stop ords
$ systemctl start ords
APEX管理画面へアクセスできるよう、BaseDBのポートを開放
$ sudo iptables -I INPUT 8 -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT -m comment --comment "Required for APEX"
$ sudo /sbin/service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
以下よりAPEX管理画面へアクセスできることを確認
http://your_public_ip:8080/apex/apex_admin
表内の画像をテキストでベクトル検索するAPEXアプリを作成
画面作成は省略しますが、テキスト入力のフォームとボタンを用意します。
検索結果の表示には対話モード・レポートを使いました。
対話モード・レポートのSQL問い合わせに以下SQLを入力するだけで、テキストから画像を検索するマルチモーダル検索が実装できちゃいます。
SELECT "ROWID","ID","FILE_NAME","MIME",SYS.DBMS_LOB.GETLENGTH("IMAGE")"IMAGE","EMBEDDING" FROM "MY_TABLE"
ORDER BY VECTOR_DISTANCE(embedding,
TO_VECTOR(VECTOR_EMBEDDING(CLIP_TXT USING :P5_SEARCH as DATA)), COSINE)
FETCH EXACT FIRST 3 ROWS ONLY
表内の画像を画像でベクトル検索するAPEXアプリを作成
ベクトル検索結果を一時格納する表を作成
CREATE TABLE res_table (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
file_name VARCHAR2(255),
mime VARCHAR2(100),
image BLOB
);
検索に使う画像をアップロードするアイテムを追加し、
検索結果の表示用に対話モード・レポートを使用します。
対話モード・レポートのSQL問合せに以下を入力
SELECT "ROWID","ID","FILE_NAME","MIME",SYS.DBMS_LOB.GETLENGTH("IMAGE")"IMAGE" FROM "RES_TABLE" ORDER BY "ID"
以下ベクトル検索処理をAPEXのプロセスとして定義し、
検索ボタンを押すと実行されるように設定します。
DECLARE
l_file apex_application_temp_files%rowtype;
BEGIN
-- 一時結果格納表をリセット
DELETE FROM res_table;
-- 検索用にアップロードされた画像の情報を抽出
SELECT * INTO l_file
FROM APEX_APPLICATION_TEMP_FILES
WHERE name IN
(
SELECT column_value
FROM APEX_STRING.SPLIT(:P6_SEARCH, ':')
);
-- 一時結果格納表へデータ保存
INSERT INTO res_table (file_name, mime, image)
SELECT file_name, mime, image
FROM my_table
ORDER BY VECTOR_DISTANCE(embedding,
TO_VECTOR(VECTOR_EMBEDDING(CLIP_IMG USING l_file.BLOB_CONTENT as DATA)), COSINE)
FETCH EXACT FIRST 3 ROWS ONLY;
COMMIT;
END;
以上、RU23.7 + OML4Py 2.1 でマルチモーダル検索を実装できました。
テキストからの画像検索はSQL一行で実装できてしまい、とても簡単です。
一方で現段階はインポート可能なONNXファイルのサイズ上限が1GBと厳しく、多言語対応のマルチモーダルEmbeddingモデルを扱うのが難しい仕様となっています。
検索ワードに日本語を使う上で、この点については今後の改善が待たれます。