写点什么

基于 Hologres 构建智能驾驶图像高性能分析系统

  • 2025-11-18
    浙江
  • 本文字数:8521 字

    阅读完需:约 28 分钟

随着人工智能技术的深入发展,企业对数据的利用已不再局限于传统的结构化数据分析。越来越多的行业开始依赖多模态数据进行智能决策,涵盖商品推荐、驾驶行为分析、金融风控、教育个性化等多个场景。这些场景普遍具备一个共同特征:数据形态多样、分析需求复杂、检索方式多元。Hologres 4.0 的整体架构围绕“多模态分析检索 all-in-one”设计,实现“一份数据、一份计算、多模分析”的一站式目标,一条 SQL 即可完成从数据接入、AI 加工到多模查询的全流程。


智能驾驶场景中,可以看到采集的车机各种信号数据,以大宽表的形式存储在数据库中。这些信号数据通常会包含结构化数据(车辆状态、车机版本等)、半结构化数据(车机信号)、非结构化数据(轨迹照片等)。在业务应用的时候,要进行点查、OLAP 分析、全文检索、向量检索、混合检索等多种场景。


传统架构往往依赖多个独立引擎协同工作,导致系统复杂、成本高昂、数据不一致等问题频发。AI 时代的应用需要在一个统一平台上完成 OLAP 分析、点查服务、全文检索、向量搜索以及 AI 推理等多种能力的融合使用。本文以自动驾驶图像数据集为例,介绍 Hologres 如何在传统的结构化分析的基础上,完成文搜图、图搜图等多模态分析场景。

基于 Hologres 构建自动驾驶图像高性能分析系统

在自动驾驶系统中,车辆图片分析是环境感知模块的核心场景之一,主要用于实时解析车辆内外部摄像头捕捉的视觉信息,以实现对周围环境的精准理解与决策。本文以 BDD 自动驾驶数据集为例模拟自动驾驶场景,模拟真实驾驶场景,采集 10 万张包括驾驶区域、地理、环境、天气多样性等数据的图片,通过对图片的分析与检索,进行了行驶轨迹分析、环境感知优化及行人车辆识别精度提升等全栈技术验证,提升系统对复杂交通场景的适应能力、安全性和用户体验。


基于 Hologres 构建自动驾驶图像高性能分析系统包含的主要能力如下:

  • 非结构化数据(Object Table):支持通过表的形式读取 OSS 中非结构化数据(PDF、IMAGE、PPT 等)。

  • AI Function:在 Hologres 中可以用标准 SQL 的方式调用 Function,自动调用内置大模型,完成 AI 服务建设场景。

  • 数据加工:提供 Embed、Chunk 算子,可以对非结构化数据加工成结构化数据存储,无需使用外部算法就能自动 Embed。

  • 数据检索和分析:提供<font style="background-color:rgba(0, 0, 0, 0.04);">ai_gen</font><font style="background-color:rgba(0, 0, 0, 0.04);">ai_summarize</font>等算子,使用 SQL 就能对数据进行推理、问题总结以及翻译等能力。

  • Dynamic Table 介绍:支持增量刷新模式对非结构化数据自动加工,每次只计算增量的数据有效减少重复计算,降低资源利用率。

  • 向量检索:支持标准 SQL 的向量检索,用于非结构化数据的相似度搜索、场景识别等,在同一个查询中可以自由地实现向量和标量的检索。

  • 全文检索:通过倒排索引、分词等机制实现对非结构化数据的高效检索,支持关键词匹配、短语检索等丰富的检索方式,实现更加灵活的检索。

方案优势

通过如上核心能力,在 Hologres 中对图片检索的核心优势如下:

  • 完整的 AI 数据处理流程:涵盖从数据 Embed、Chunk、增量加工和检索/分析的全流程,与使用大数据系统一样轻松构建 AI 应用。

  • 标准 SQL 加工图片数据:无需使用专用开发语言,纯 SQL 就能完成图片数据提取、加工。

  • 一个平台支持跨模态检索:支持以文搜图、以图搜图,语义理解突破关键词局限,在 Hologres 就能实现跨模态检索。

  • 检索更精准、灵活和智能:可以轻松构建“关键词+语义+多模态”的混合检索链路,覆盖从精准搜索到意图理解的全场景需求。还能结合 AI Function 实现对用户意图的深度理解,语义关联和上下文推理,实现更智能的检索能力。

  • 数据不出库,安全性更高:不需要将数据导出到外部系统,与 Hologres 的多种安全能力无缝集成,并高效保护数据安全。

方案流程

本次方案的流程如下:


  1. 数据集准备。

将图片数据上传至 OSS 存储。


  1. 图片加工。

使用 Object Table 读取图片的元数据信息,然后创建增量刷新的 Dynamic Table 对数据进行 Embed,并为 Dynamic Table 构建向量索引,以便后续检索能够充分利用索引的功能。


  1. 使用<font style="color:rgb(24, 24, 24);background-color:rgba(0, 0, 0, 0.04);">ai_embed</font>算子将自然语言的问题进行 Embedding,然后使用向量检索输出 Top N 的结果。

准备工作

  • 数据准备

本文使用 ModelScope 公开的 BDD100K 自动驾驶图像数据集中val.zip文件,模拟多个车辆真是行驶数据。


  • 环境准备

  • 购买 Hologres V4.0 及以上版本实例并创建数据库。

  • 购买 AI 资源。

本文以large-96core-512GB-384GB、1 个节点为例。

  • 模型部署。本次方案使用的模型以及分配的资源为:


说明:上述模型的资源均为默认分配的资源。

操作步骤

  1. 下载图片数据并导入至 OSS。

  • 下载 BDD100K 自动驾驶图像数据集中的<font style="color:#000000;background-color:rgba(0, 0, 0, 0.04);">val.zip</font>文件。

  • 登录 OSS 管理控制台,创建 Bucket 并将已下载的<font style="color:#000000;background-color:rgba(0, 0, 0, 0.04);">val.zip</font>文件上传至该 Bucket 路径下。上传操作详情,请参见简单上传。


说明:文件夹名称请使用小写。


  1. 账号授权。

a. 登录 RAM 控制台,创建阿里云 RAM 角色并授予 OSS 的相关权限。

推荐授予 AliyunOSSReadOnlyAccess 权限。

b. 为上述阿里云 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 用户(子账号)

a. 为 RAM 用户授权。

  • 权限管理 > 权限策略页面,单击创建权限策略,并选择脚本编辑模式创建权限策略。具体操作,请参见创建自定义权限策略

Hologres 可通过该策略判断当前 RAM 用户是否具备创建对应 RAM 角色的权限。权限策略内容如下。

{  "Version": "1",  "Statement": [    {      "Effect": "Allow",      "Action": "hologram:GrantAssumeRole",      "Resource": "<arn账号>"    }  ]}
复制代码
  • 份管理 > 用户页面,单击目标 RAM 用户操作列中的添加权限,为 RAM 用户(子账号)授予上述步骤已创建的权限策略。具体操作,请参见为 RAM 用户授权。

b. 为已创建的 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"}
复制代码
  1. 对图片进行 Embedding。

创建 Object Table 和 Dynamic Table 读取图片元数据,并对图片加工 Embedding。因为流程较长,Hologres 直接将过程封装成附录:存储过程。该存储过程包括的能力如下:

  • 创建一张 Object Table,用于读取图片的元数据。

  • 创建一张增量刷新的 Dynamic Table 结果表,用于存储加工后的数据,并设置向量索引。该 Dynamic Table 未设置自动刷新,需要手动刷新。

  • Dynamic Table 的刷新过程中会使用ai_embed对图片进行 Embedding。

该存储过程的使用如下:

--存储过程,创建Object Table和Dynamic Table,使用dt对图片进行EmbeddingCALL 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');
复制代码
  1. 刷新结果表。

通过上述步骤创建的 Object Table 和 Dynamic Table 都需要手动刷新,才能完成数据加工。该步骤已被封装为附录:存储过程,该存储过程包括的能力如下:

  • 刷新一次 Object Table 获取图片元数据。

  • 刷新一次 Dynamic Table,进行图片的 Embedding 加工。

该存储过程的使用如下:

--刷新Dynamic Table,将图片EmbeddingCALL refresh_image_table(    image_table => 'public.dt_image_bdd100k');
复制代码


  1. 图片检索。

图片数据处理过后可以使用向量检索和 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 scoreFROM    public.dt_image_bdd100kORDER BY    score DESCLIMIT 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 scoreFROM    public.dt_image_bdd100kWHERE    object_uri <> 'oss://hm-**-hangzhou/bd****k/val/images/b9b53753-91a5****.jpg' --排除自身ORDER BY    score DESCLIMIT 1;
object_uri | score ---------------------------------------------------------------+------ oss://****/bd****k/val/images/c0e9b7c4-cd8b****.jpg | 0.918008327
复制代码


在 OSS 中找到召回的图片,并做对比,结果如下:

附录:存储过程

  • 创建 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;
复制代码


如果想体验更多操作流程,欢迎到阿里云官网领取 Hologres 免费试用,开通 Hologres4.0,并按照操作文档实践。

https://help.aliyun.com/zh/hologres/user-guide/visual-data-analysis-for-autonomous-driving

用户头像

还未添加个人签名 2020-10-15 加入

分享阿里云计算平台的大数据和AI方向的技术创新和趋势、实战案例、经验总结。

评论

发布
暂无评论
基于 Hologres 构建智能驾驶图像高性能分析系统_sql_阿里云大数据AI技术_InfoQ写作社区