自動運転 (AD) システムにおいて、車両画像分析は環境認識モジュールの中核コンポーネントです。車両カメラからの視覚情報をリアルタイムで解析し、システムが周囲の状況を正確に理解して意思決定できるようにします。このトピックでは、BDD 自動運転データセットを使用して AD シナリオを実証します。このデータセットには、さまざまな運転エリア、地理、環境、気象条件など、多様なシナリオをカバーする 100,000 枚の画像が含まれています。これらの画像を分析・検索することで、このトピックではフルスタックの技術ソリューションを実証します。このソリューションには、運転軌跡分析、環境認識の最適化、歩行者および車両検出精度の向上が含まれます。その目的は、複雑な交通シナリオにおけるシステムの適応性、安全性、ユーザーエクスペリエンスを向上させることです。
コア機能
このトピックでは、画像処理とマルチモーダル検索分析に焦点を当てており、これには以下の Hologres のコア機能が含まれます。
オブジェクトテーブル: PDF、画像、PPT ファイルなどの非構造化データを、Object Storage Service (OSS) から直接、表形式で読み取ります。
AI 関数: Hologres で標準 SQL を使用して、AI サービスのために組み込みの LLM を自動的に呼び出す関数を呼び出します。
データ変換:
EmbedおよびChunkオペレーターを提供します。非構造化データを構造化データに変換して保存し、外部アルゴリズムなしで自動データ埋め込みを可能にします。データ取得と分析:
ai_genやai_summarizeなどのオペレーターを提供します。標準 SQL を使用して LLM の推論、要約、翻訳を行います。
動的テーブル: 増分更新モードをサポートし、非構造化データを自動的に処理します。このモードでは増分データのみを処理するため、冗長な計算とリソース消費が削減されます。
ベクトル検索: 標準 SQL を使用したベクトル検索をサポートし、非構造化データに対する類似検索やシーン認識を行います。同じクエリ内でベクトル検索とスカラー検索を自由に組み合わせることができます。
全文検索: 転置インデックスとトークン化を使用して、非構造化データを効率的に検索します。キーワード一致やフレーズ検索などの柔軟な検索方法をサポートし、多目的なデータ取得を実現します。
メリット
Hologres で画像検索にこれらの機能を使用する主な利点は次のとおりです。
AI データ処理のライフサイクル全体をカバー: データ埋め込み、チャンキング、増分処理、取得、分析。標準的なビッグデータシステムと同じくらい簡単に AI アプリケーションを構築できます。
標準 SQL で画像データを処理: 特別なプログラミング言語は不要です。SQL のみを使用して画像データを抽出し、変換します。
マルチモーダル検索のためのワンプラットフォーム: テキストから画像への検索と画像から画像への検索をサポートします。セマンティック理解は単純なキーワード一致を超えています。Hologres で直接マルチモーダル検索を実行できます。
より正確で、柔軟で、インテリジェントな検索: キーワード検索、セマンティック検索、マルチモーダル検索を組み合わせたハイブリッド検索パイプラインを簡単に構築でき、完全一致検索から複雑な意図認識まですべてのシナリオをカバーします。AI 関数を使用して、ユーザーの意図、セマンティックな関連付け、コンテキスト推論をより深く理解できます。
安全なインプレース分析: データはデータベース内に留まるため、外部システムにエクスポートする必要がありません。これにより、さまざまな Hologres のセキュリティ機能とシームレスに統合され、データを効率的に保護します。
ワークフロー
このソリューションのワークフローは次のとおりです。
データセットを準備します。
画像データを OSS にアップロードします。
画像を処理します。
オブジェクトテーブルを使用して画像メタデータを読み取ります。次に、増分更新を行う動的テーブルを作成してデータを埋め込みます。最後に、動的テーブルにベクトルインデックスを作成して、後続の検索パフォーマンスを最適化します。
ai_embedオペレーターを使用して自然言語の質問を埋め込みます。次に、ベクトル検索を実行して上位 N 件の結果を取得します。
準備
データ準備
このソリューションでは、ModelScope で公開されている BDD100K 自動運転画像データセット の
val.zipファイルを使用します。このデータセットは、複数の車両からの実際の運転データをシミュレートします。環境準備
V4.0 以降の Hologres インスタンスを購入し、データベースを作成します。
AI リソースを購入します。
この例では、1 ノードの
large-96core-512GB-384GBインスタンスを例として使用します。モデルをデプロイします。このソリューションのモデルと割り当てられたリソースは次のとおりです。
カテゴリ
値の例
モデル名
image_embed
モデルカテゴリ
clip-ViT-B-32
モデルの説明
画像埋め込み
レプリカあたりの vCPU
7
レプリカあたりのメモリ
30 GB
レプリカあたりの GPU
1 カード (96 GB)
レプリカ数
1
説明モデルリソースはデフォルトの割り当てを使用します。
手順
画像データをダウンロードして OSS にインポートします。
BDD100K 自動運転画像データセット から
val.zipファイルをダウンロードします。OSS コンソールにログインします。バケットを作成し、ダウンロードした
val.zipファイルをバケットにアップロードします。ファイルのアップロードの詳細については、「単純なアップロード」をご参照ください。説明フォルダ名には小文字を使用してください。
権限を付与します。
RAM コンソールにログインし、RAM ロールを作成して、必要な OSS 権限を付与します。
AliyunOSSReadOnlyAccess 権限を付与することをお勧めします。
RAM ロールにログイン権限と Hologres アクセス権限を追加します。
Alibaba Cloud アカウント
RAM ロールの信頼ポリシーを変更します。次の主要なパラメーターを更新します。
Action:
sts:AssumeRoleに更新します。Service:
hologres.aliyuncs.comに更新します。
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::1866xxxx:root" ], "Service": [ "hologres.aliyuncs.com" ] } } ], "Version": "1" }RAM ユーザー
RAM ユーザーに権限を付与します。
ページで、[ポリシーの作成] をクリックし、[スクリプトエディター] モードを選択してポリシーを作成します。詳細については、「カスタムポリシーの作成」をご参照ください。
Hologres はこのポリシーを使用して、現在の RAM ユーザーが指定された RAM ロールを偽装する権限を持っているかどうかを判断します。ポリシードキュメントは次のとおりです。
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "hologram:GrantAssumeRole", "Resource": "<arn_account>" } ] }ページで、対象の RAM ユーザーの [操作] 列にある [権限の追加] をクリックして、作成した権限ポリシーを付与します。詳細については、「RAM ユーザーへの権限付与」をご参照ください。
作成した RAM ロールに権限を付与します。
RAM ロールの信頼ポリシーを変更します。更新する主要なパラメーターは次のとおりです。
Action:
sts:AssumeRoleに更新します。Service:
hologres.aliyuncs.comに更新します。
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::1866xxxx:root" ], "Service": [ "hologres.aliyuncs.com" ] } } ], "Version": "1" }
画像を埋め込みます。
オブジェクトテーブルと動的テーブルを作成して、画像メタデータを読み取り、画像を埋め込みます。これを効率化するために、Hologres はロジックをストアドプロシージャにカプセル化します。詳細については、「付録: ストアドプロシージャの定義」をご参照ください。このストアドプロシージャは、次の機能を提供します。
画像メタデータを読み取るためのオブジェクトテーブルを作成します。
処理されたデータを保存するために、増分更新を行う動的テーブルである結果テーブルを作成します。ベクトルインデックスも作成されます。動的テーブルは手動で更新する必要があります。
動的テーブルの更新中に、
ai_embedオペレーターを使用して画像を埋め込みます。
ストアドプロシージャは次のように使用されます。
-- オブジェクトテーブルと動的テーブルを作成し、動的テーブルを使用して画像を埋め込むストアドプロシージャ CALL create_image_table_from_oss( oss_path => 'oss://xxxx/bdd100k/val/images', oss_endpoint => 'oss-ap-southeast-1-internal.aliyuncs.com', oss_role_arn => 'acs:ram::1xxxx:role/xxxx', image_table => 'public.dt_image_bdd100k', embedding_model =>'image_embed' );結果テーブルを更新します。
前のステップで作成したオブジェクトテーブルと動的テーブルは、データ変換を完了するために手動で更新する必要があります。このステップはストアドプロシージャにカプセル化されています。詳細については、「付録: ストアドプロシージャの定義」をご参照ください。このストアドプロシージャは、次の機能を提供します。
オブジェクトテーブルを一度更新して、画像メタデータを取得します。
動的テーブルを一度更新して、画像を埋め込みます。
ストアドプロシージャは次のように使用されます。
-- 動的テーブルを更新して画像を埋め込む CALL refresh_image_table( image_table => 'public.dt_image_bdd100k' );画像を検索します。
画像データが処理された後、ベクトル検索と AI 関数を使用して画像を検索できます。
テキストから画像への検索
clip-ViT-B-32モデルをテキストから画像への検索に使用する場合、クエリには英語を使用してください。クエリが中国語の場合は、LLM に切り替える必要があります。次の SQL 文は、テキストから画像への検索の例です。-- テキストから画像への検索 SELECT object_uri, approx_cosine_distance (embedding_vector, ai_embed ('image_embed', 'a red car in the rain')) AS score FROM public.dt_image_bdd100k ORDER BY score DESC LIMIT 1; object_uri | score ---------------------------------------------------------------+------- oss://****/bd****k/val/images/b836b14a-fb13****.jpg| 0.322337151 (5 rows)OSS で見つかった上位の結果は次のとおりです。

画像から画像への検索
次の SQL 文は、画像による検索の例です。
-- 画像で検索 SELECT object_uri, approx_cosine_distance (embedding_vector, ai_embed ('image_embed', to_file ('oss://xxxx/val/images/b9b53753-91a5d5f8.jpg', 'oss-cn-hangzhou-internal.aliyuncs.com', 'acs:ram::18xxx:role/xxx'))) AS score FROM public.dt_image_bdd100k WHERE object_uri <> 'oss://hm-**-hangzhou/bd****k/val/images/b9b53753-91a5****.jpg' -- 画像自体を除外 ORDER BY score DESC LIMIT 1; object_uri | score ---------------------------------------------------------------+------ oss://****/bd****k/val/images/c0e9b7c4-cd8b****.jpg | 0.918008327取得された画像は OSS で見つかります。クエリ画像と上位の結果を以下に示します。

付録: ストアドプロシージャの定義
オブジェクトテーブルと動的テーブルの作成
-- デフォルトでは、クエリは最大 200 行を返します。より多くのデータを返すには、LIMIT 句を変更します。最大 10,000 行または 20 MB のデータを表示できます。 CREATE OR REPLACE PROCEDURE create_image_table_from_oss( oss_path TEXT, oss_endpoint TEXT, oss_role_arn TEXT, image_table TEXT, embedding_model TEXT DEFAULT NULL, overwrite BOOLEAN DEFAULT FALSE ) AS $$ DECLARE image_schema_name TEXT; image_table_name TEXT; obj_table_name TEXT; full_image_table_ident TEXT; full_obj_ident TEXT; embed_expr TEXT; create_sql TEXT; embedding_dims INT; BEGIN -- 1. スキーマ名とテーブル名を分割します。 IF position('.' in image_table) > 0 THEN image_schema_name := split_part(image_table, '.', 1); image_table_name := split_part(image_table, '.', 2); ELSE image_schema_name := 'public'; image_table_name := image_table; END IF; obj_table_name := image_table_name || '_obj_table'; full_image_table_ident := format('%I.%I', image_schema_name, image_table_name); full_obj_ident := format('%I.%I', image_schema_name, obj_table_name); -- 2. 上書きするには、まずテーブルとインデックスを削除します。 IF overwrite THEN DECLARE dyn_table_exists BOOLEAN; rec RECORD; BEGIN -- 動的テーブルが存在するかどうかを確認します。 SELECT EXISTS ( SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = image_table_name AND n.nspname = image_schema_name ) INTO dyn_table_exists; IF dyn_table_exists THEN -- 2.1 動的テーブルの自動更新を無効にします。 -- RAISE NOTICE 'Disabling auto refresh for %', full_image_table_ident; -- EXECUTE format('ALTER TABLE IF EXISTS %s SET (auto_refresh_enable=false)', full_image_table_ident); -- 2.2 実行中の更新タスクを見つけてキャンセルします。 FOR rec IN EXECUTE format( $f$ SELECT query_job_id FROM hologres.hg_dynamic_table_refresh_log(%L) WHERE status = 'RUNNING'; $f$, image_table ) LOOP RAISE NOTICE 'Found running refresh job: %', rec.query_job_id; IF hologres.hg_internal_cancel_query_job(rec.query_job_id::bigint) THEN RAISE NOTICE 'Cancel job % succeeded.', rec.query_job_id; ELSE RAISE WARNING 'Cancel job % failed.', rec.query_job_id; END IF; END LOOP; -- 2.3 動的テーブルを削除します。 EXECUTE format('DROP TABLE IF EXISTS %s;', full_image_table_ident); ELSE RAISE NOTICE 'Dynamic table % does not exist, skip cancel job and drop.', full_image_table_ident; END IF; -- 2.4 いずれの場合も、オブジェクトテーブルを削除する必要があります。 EXECUTE format('DROP OBJECT TABLE IF EXISTS %s;', full_obj_ident); END; END IF; -- 3. オブジェクトテーブルを作成します。 RAISE NOTICE 'Create object table: %', obj_table_name; EXECUTE format( $f$ CREATE OBJECT TABLE %s WITH ( path = %L, oss_endpoint = %L, role_arn = %L ); $f$, full_obj_ident, oss_path, oss_endpoint, oss_role_arn ); COMMIT; -- 4. オブジェクトテーブルを更新します。 RAISE NOTICE 'Refresh object table: %', obj_table_name; EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident); COMMIT; -- 5. 埋め込みモデルを選択します。 IF embedding_model IS NULL OR length(trim(embedding_model)) = 0 THEN embed_expr := 'ai_embed(file)'; EXECUTE 'SELECT array_length(ai_embed(''dummy''), 1)' INTO embedding_dims; ELSE embed_expr := format('ai_embed(%L, file)', embedding_model); EXECUTE format( 'SELECT array_length(ai_embed(%L, ''dummy''), 1)', embedding_model ) INTO embedding_dims; END IF; RAISE NOTICE 'embedding dimension is: %', embedding_dims; -- 6. RAG 出力用の動的テーブルを作成します。 RAISE NOTICE 'create dynamic table: %', image_table_name; EXECUTE format( $f$ CREATE DYNAMIC TABLE %s( CHECK(array_ndims(embedding_vector) = 1 AND array_length(embedding_vector, 1) = %s) ) WITH ( vectors = '{ "embedding_vector": { "algorithm": "HGraph", "distance_method": "Cosine", "builder_params": { "base_quantization_type": "sq8_uniform", "max_degree": 64, "ef_construction": 400, "precise_quantization_type": "fp32", "use_reorder": true } } }', auto_refresh_mode = 'incremental', freshness = '5 minutes', auto_refresh_enable = 'false' ) AS SELECT object_uri, etag, %s AS embedding_vector FROM %s; $f$, full_image_table_ident, embedding_dims, embed_expr, obj_table_name ); COMMIT; RAISE NOTICE ''; RAISE NOTICE 'Create image table success: %', image_table; RAISE NOTICE ' Vector index is: %.embedding_vector', image_table; END; $$ LANGUAGE plpgsql;オブジェクトテーブルと動的テーブル
-- 動的テーブルを更新して画像を埋め込みます CREATE OR REPLACE PROCEDURE refresh_image_table( image_table TEXT ) AS $$ DECLARE image_schema_name TEXT; image_table_name TEXT; obj_table_name TEXT; full_image_table_ident TEXT; full_obj_ident TEXT; BEGIN -- 1. スキーマとテーブル名を解析します。 IF position('.' in image_table) > 0 THEN image_schema_name := split_part(image_table, '.', 1); image_table_name := split_part(image_table, '.', 2); ELSE image_schema_name := 'public'; image_table_name := image_table; END IF; obj_table_name := image_table_name || '_obj_table'; full_image_table_ident := format('%I.%I', image_schema_name, image_table_name); full_obj_ident := format('%I.%I', image_schema_name, obj_table_name); -- 2. オブジェクトテーブルを更新します。 RAISE NOTICE 'Refreshing Object Table: %', obj_table_name; EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident); -- 3. 動的テーブルを更新します。 RAISE NOTICE 'Refreshing Dynamic Table: %', image_table_name; EXECUTE format('REFRESH TABLE %s;', full_image_table_ident); RAISE NOTICE 'Refresh image table complete: %', image_table; END; $$ LANGUAGE plpgsql;オブジェクトテーブルと動的テーブルの削除
CREATE OR REPLACE PROCEDURE drop_image_table( image_table TEXT ) AS $$ DECLARE image_schema_name TEXT; image_table_name TEXT; obj_table_name TEXT; full_image_table_ident TEXT; full_obj_ident TEXT; rec RECORD; BEGIN -- 1. スキーマとテーブル名を解析します。 IF position('.' in image_table) > 0 THEN image_schema_name := split_part(image_table, '.', 1); image_table_name := split_part(image_table, '.', 2); ELSE image_schema_name := 'public'; image_table_name := image_table; END IF; obj_table_name := image_table_name || '_obj_table'; full_image_table_ident := format('%I.%I', image_schema_name, image_table_name); full_obj_ident := format('%I.%I', image_schema_name, obj_table_name); -- 2. テーブルを削除します。 -- 2.1 動的テーブルの自動更新を無効にします。 -- RAISE NOTICE 'Disabling auto refresh for %', full_image_table_ident; -- EXECUTE format('ALTER TABLE IF EXISTS %s SET (auto_refresh_enable=false)', full_image_table_ident); -- 2.2 実行中の更新タスクを見つけてキャンセルします。 FOR rec IN EXECUTE format( $f$ SELECT query_job_id FROM hologres.hg_dynamic_table_refresh_log(%L) WHERE status = 'RUNNING'; $f$, image_table ) LOOP RAISE NOTICE 'Found running refresh job: %', rec.query_job_id; IF hologres.hg_internal_cancel_query_job(rec.query_job_id::bigint) THEN RAISE NOTICE 'Cancel job % succeeded.', rec.query_job_id; ELSE RAISE WARNING 'Cancel job % failed.', rec.query_job_id; END IF; END LOOP; -- 2.3 動的テーブルを削除します。 RAISE NOTICE 'Dropping Dynamic Table: %', image_table_name; EXECUTE format('DROP TABLE IF EXISTS %s;', full_image_table_ident); -- 2.4 オブジェクトテーブルを削除します。 RAISE NOTICE 'Dropping Object Table: %', obj_table_name; EXECUTE format('DROP OBJECT TABLE IF EXISTS %s;', full_obj_ident); RAISE NOTICE 'Drop image table complete: %', image_table; END; $$ LANGUAGE plpgsql;