全部產品
Search
文件中心

Hologres:最佳實務:自動駕駛映像高效能分析系統

更新時間:Sep 24, 2025

在自動駕駛系統中,車輛圖片分析是環境感知模組的核心情境之一,主要用於即時解析車輛內外部相機擷取的視覺資訊,以實現對周圍環境的精準理解與決策。本文以BDD自動駕駛資料集為例類比自動駕駛情境,類比真實駕駛情境,採集10萬張包括駕駛地區、地理、環境、天氣多樣性等資料的圖片,通過對圖片的分析與檢索,進行了行駛軌跡分析、環境感知最佳化及行人車輛識別精度提升等全棧技術驗證,提升系統對複雜交通情境的適應能力、安全性和使用者體驗。

核心能力介紹

本文主要實現對圖片的加工與多模檢索分析,包含的主要能力如下:

  • 非結構化資料(Object Table):支援通過表的形式讀取OSS中非結構化資料(PDF、IMAGE、PPT等)。

  • AI Function:在Hologres中可以用標準SQL的方式調用Function,自動調用內建大模型,完成AI服務建設情境。

    • 資料加工:提供Embed、Chunk運算元,可以對非結構化資料加工成結構化資料存放區,無需使用外部演算法就能自動Embed。

    • 資料檢索和分析:提供ai_genai_summarize等運算元,使用SQL就能對資料進行推理、問題總結以及翻譯等能力。

  • Dynamic Table介紹:支援增量重新整理模式對非結構化資料自動加工,每次只計算增量的資料有效減少重複計算,降低資源使用率。

  • 向量檢索:支援標準SQL的向量檢索,用於非結構化資料的相似性搜尋、情境識別等,在同一個查詢中可以自由地實現向量和標量的檢索。

  • 全文檢索索引:通過倒排索引、分詞等機制實現對非結構化資料的高效檢索,支援關鍵詞匹配、短語檢索等豐富的檢索方式,實現更加靈活的檢索。

方案優勢

通過如上核心能力,在Hologres中對圖片檢索的核心優勢如下:

  • 完整的AI資料處理流程:涵蓋從資料Embed、Chunk、增量加工和檢索/分析的全流程,與使用巨量資料系統一樣輕鬆構建AI應用。

  • 標準SQL加工圖片資料:無需使用專用開發語言,純SQL就能完成圖片資料提取、加工。

  • 一個平台支援跨模態檢索:支援以文搜圖、以圖搜圖,語義理解突破關鍵詞局限,在Hologres就能實現跨模態檢索。

  • 檢索更精準、靈活和智能:可以輕鬆構建“關鍵詞+語義+多模態”的混合檢索鏈路,覆蓋從精準搜尋到意圖理解的全情境需求。還能結合AI Function實現對使用者意圖的深度理解,語義關聯和上下文推理,實現更智能的檢索能力。

  • 資料不出庫,安全性更高:不需要將資料匯出到外部系統,與Hologres的多種安全能力無縫整合,並高效保護資料安全。

方案流程介紹

本次方案的流程如下:

  1. 資料集準備。

    將圖片資料上傳至OSS儲存。

  2. 圖片加工。

    使用Object Table讀取圖片的中繼資料資訊,然後建立增量重新整理的Dynamic Table對資料進行Embed,並為Dynamic Table構建向量索引,以便後續檢索能夠充分利用索引的功能。

  3. 使用ai_embed運算元將自然語言的問題進行Embedding,然後使用向量檢索輸出Top N的結果。

準備工作

  • 資料準備

    本文使用ModelScope公開的BDD100K 自動駕駛映像資料集val.zip檔案,類比多個車輛真是行駛資料。

  • 環境準備

    1. 購買Hologres V4.0及以上版本執行個體並建立資料庫

    2. 購買AI資源

      本文以large-96core-512GB-384GB、1個節點為例。

    3. 模型部署。本次方案使用的模型以及分配的資源為:

      類別

      樣本值

      模型名稱

      image_embed

      模型類別

      clip-ViT-B-32

      模型作用描述

      圖片Embedding

      單副本CPU(Core)

      7

      單副本記憶體

      30 GB

      單副本GPU

      1卡(96 GB)

      資源副本數

      1

      說明

      上述模型的資源均為預設分配的資源。

操作步驟

  1. 下載圖片資料並匯入至OSS。

    1. 下載BDD100K 自動駕駛映像資料集中的val.zip檔案。

    2. 登入OSS管理主控台建立Bucket並將已下載的val.zip檔案上傳至該Bucket路徑下。上傳操作詳情,請參見簡單上傳

      說明

      檔案夾名稱請使用小寫。

  2. 帳號授權。

    1. 登入RAM控制台,建立阿里雲RAM角色並授予OSS的相關許可權。

      推薦授予AliyunOSSReadOnlyAccess許可權。

    2. 為上述阿里雲RAM角色添加登入和Hologres的存取權限。

      • 阿里雲帳號(主帳號)

        修改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使用者(子帳號)

        1. 為RAM使用者授權。

          1. 許可權管理 > 權限原則頁面,單擊建立權限原則,並選擇指令碼編輯模式建立權限原則。具體操作,請參見建立自訂權限原則

            Hologres可通過該策略判斷當前RAM使用者是否具備建立對應RAM角色的許可權。權限原則內容如下。

            {
              "Version": "1",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": "hologram:GrantAssumeRole",
                  "Resource": "<arn帳號>"
                }
              ]
            }
          2. 身份管理 > 使用者頁面,單擊目標RAM使用者操作列中的添加許可權,為RAM使用者(子帳號)授予上述步驟已建立的權限原則。具體操作,請參見為RAM使用者授權

        2. 為已建立的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"
          }
  3. 對圖片進行Embedding。

    建立Object Table和Dynamic Table讀取圖片中繼資料,並對圖片加工Embedding。因為流程較長,Hologres直接將過程封裝成附錄:預存程序。該預存程序包括的能力如下:

    • 建立一張Object Table,用於讀取圖片的中繼資料。

    • 建立一張增量重新整理的Dynamic Table結果表,用於儲存加工後的資料,並設定向量索引。該Dynamic Table未設定自動重新整理,需要手動重新整理。

    • Dynamic Table的重新整理過程中會使用ai_embed對圖片進行Embedding。

    該預存程序的使用如下:

    --預存程序,建立Object Table和Dynamic Table,使用dt對圖片進行Embedding
    CALL create_image_table_from_oss(
        oss_path => 'oss://xxxx/bdd100k/val/images',
        oss_endpoint => 'oss-cn-hangzhou-internal.aliyuncs.com',
        oss_role_arn => 'acs:ram::1xxxx:role/xxxx',
        image_table => 'public.dt_image_bdd100k',
        embedding_model =>'image_embed'
    );
  4. 重新整理結果表。

    通過上述步驟建立的Object Table和Dynamic Table都需要手動重新整理,才能完成資料加工。該步驟已被封裝為附錄:預存程序,該預存程序包括的能力如下:

    • 重新整理一次Object Table擷取圖片中繼資料。

    • 重新整理一次Dynamic Table,進行圖片的Embedding加工。

    該預存程序的使用如下:

    --重新整理Dynamic Table,將圖片Embedding
    CALL refresh_image_table(
        image_table => 'public.dt_image_bdd100k'
    );
    
  5. 圖片檢索。

    圖片資料處理過後可以使用向量檢索和AI Function進行檢索。

    以文搜圖

    如果使用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中找到第一個結果的圖片如下:

    image

    以圖搜圖

    以圖搜圖的樣本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中找到召回的圖片,並做對比,結果如下:

    image

附錄:預存程序

  • 建立Object Table和Dynamic Table

    -- Query查詢結果預設限制200行,如需更多資料請修改limit,最多展示10000行或20M。
    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. 拆 schema name + table name
        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
                -- 檢查 dynamic table 是否存在
                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 尋找 RUNNING 重新整理任務並取消
                    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 刪除 Dynamic Table
                    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 無論如何,Object Table 都要刪除
                EXECUTE format('DROP OBJECT TABLE IF EXISTS %s;', full_obj_ident);
            END;
        END IF;
    
        -- 3. 建立 Object Table
        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. 重新整理 Object Table
        RAISE NOTICE 'Refresh object table: %', obj_table_name;
        EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident);
    
        COMMIT;
    
        -- 5. embedding 模型選擇
        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;
    
    
    
    
  • Object Table和Dynamic Table

    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. 解析 schema 和表名
        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. 重新整理 Object Table
        RAISE NOTICE 'Refreshing Object Table: %', obj_table_name;
        EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident);
    
        -- 3. 重新整理 Dynamic Table
        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. 解析 schema 和表名
        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 尋找 RUNNING 重新整理任務並取消
        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 刪除 Dynamic Table
        RAISE NOTICE 'Dropping Dynamic Table: %', image_table_name;
        EXECUTE format('DROP TABLE IF EXISTS %s;', full_image_table_ident);
    
        -- 2.4 刪除 Object Table
        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;