news 2026/8/28 6:18:29

【Alpamayo源码解析】自车历史轨迹如何被量化并注入 Prompt(附与 OpenDriveVLA 对比)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Alpamayo源码解析】自车历史轨迹如何被量化并注入 Prompt(附与 OpenDriveVLA 对比)

在 NVIDIA 开源的 Alpamayo 项目中,实现了将连续的自车历史轨迹坐标离散化为 Token,并无缝注入到大模型的 Prompt 中,让大模型不仅“看懂”图像和文本,还能“理解”车辆过去的行驶轨迹。
本文围绕推理过程中fuse_traj_tokens函数的调用,解析了自车历史轨迹从连续坐标到离散 token、再到替换 prompt 占位符的过程,并与 OpenDriveVLA 的多模态特征注入机制进行了简要对比。


一、input_ids

在推理代码 test_inference.py 中,模型首先通过 HuggingFace 的 processor 对输入消息进行 tokenize,得到 input_ids:

# dict_keys(['input_ids', 'attention_mask', 'pixel_values', 'image_grid_thw'])tokenized_data=data["tokenized_data"]input_ids=tokenized_data.pop("input_ids")
  • input_ids 是什么?
    是一个形状为 [B, seq_len] 的 PyTorch LongTensor,包含了 VLM 分词后的完整文本 Prompt。
  • 主要包括哪些字段?
    为了支持多模态和轨迹预测,input_ids 中不仅包含常规文本,还包括许多特殊的占位符 Token:
内容模块说明
系统/用户 Prompt常规的指令文字
图像占位符对应 pixel_values 中的图片特征占位,如<|image_pad|>
历史轨迹占位符<|traj_history_start|><|traj_history|>...<|traj_history_end|>这是本文的核心,后续将被替换为真实的历史轨迹 Token
推理/生成标记<|cot_start|>(思维链起始)、<|traj_future_start|>(未来轨迹生成起始)
  • input_ids 中的历史轨迹占位符
    上述表格中,input_ids中包含了历史轨迹占位符 token。在构造消息时(helper.create_message),有这样一段设计:
num_traj_token=48hist_traj_placeholder=(f"<|traj_history_start|>{'<|traj_history|>'*num_traj_token}<|traj_history_end|>")

这意味着 prompt 中预先放了48 个<|traj_history|>token,前后分别用<|traj_history_start|><|traj_history_end|>包裹。这些 token 在 tokenize 后变成对应的整数 ID,占据input_ids中的固定位置。
这些占位符的作用就是预留的slot——后续会用量化后的真实轨迹 token 来替换。

二、自车轨迹的离散化与量化

大语言模型(LLM)的自回归架构只能处理离散的 Token(整数),无法直接理解连续的 XYZ 坐标。因此,Alpamayo 引入了Delta Tokenizer(增量分词器),将连续的轨迹转化为离散的数字 ID。

量化过程主要分为以下 4 个关键步骤(核心代码位于delta_tokenizer.pyencode函数):

  • 1. 计算增量(Delta)位置
    模型不关心车辆在整个地图上的绝对坐标,只关心 “相对于上一步,车辆移动了多少”。
# shape: (1,16,3) --> (1,17,3), 对于3D tensor, 在第二维前面填充一个元素, 默认是0xyz=torch.nn.functional.pad(fut_xyz,[0,0,1,0,0,0])xyz=xyz[:,1:]-xyz[:,:-1]

通过相邻帧求差,将绝对坐标转换为步进增量。第一个时间步的增量是相对于原点 (0, 0, 0) 的偏移。这降低了对绝对坐标的依赖,使量化范围更集中。

  • 2. 归一化到 [0, 1] 区间
    为了统一量纲,根据配置的物理范围(例如 x/y 轴 [-4m, 4m],z 轴 [-10m, 10m]),将增量值线性映射到 [0, 1] 之间。
ego_xyz_max=torch.tensor(self.ego_xyz_max,dtype=xyz.dtype,device=xyz.device)ego_xyz_min=torch.tensor(self.ego_xyz_min,dtype=xyz.dtype,device=xyz.device)xyz=(xyz-ego_xyz_min)/(ego_xyz_max-ego_xyz_min)
  • 3. 量化为整数 Token
    将 [0, 1] 的浮点数映射到有限的词汇表(Bins)中。默认情况下,词汇表大小为 1000(num_bins=1000)。
# self.num_bins = 1000xyz=(xyz*(self.num_bins-1)).round().long()# 乘以 999 并四舍五入xyz=xyz.clamp(0,self.num_bins-1)# 安全裁剪到 [0, 999]

本质:这是一个向量量化编码器。连续的物理位移被离散化为了0~999的整数 Token。

  • 4. 展平与词表偏移
    将形状从 (B, Th, 3) 展平为 (B, Th×3)。对于 16 个历史时间步,每步 3 个 token(x, y, z),共输出 48 个 token。
    随后,在tokenize_history_trajectory中,还会加上一个start_idxself.hist_token_start_idx = 154669),将历史轨迹 Token 偏移到独立的词表区间,与未来轨迹 Token 互不重叠,让模型能通过 ID 范围直接区分二者。

三、将量化 token 注入 Prompt

轨迹量化完成后,得到了一串离散的 Token 序列(形状为 [B, 48] 的 hist_idx),然后需要将其嵌入到 input_ids 中。

这一流程调用了 replace_pad_token 函数来实现:

defreplace_pad_token(input_ids:torch.Tensor,new_ids:torch.Tensor,pad_idx:int)->torch.Tensor:"""Replace pad tokens in input_ids with new token values."""mask=input_ids==pad_idxreturninput_ids.masked_scatter(mask,new_ids)

找到 input_ids 中所有等于pad_idx(占位符ID = 155684)的位置,生成布尔掩码 mask;
使用 PyTorch 的masked_scatter操作,将量化好的new_ids按顺序填充到这些位置中。

四、OpenDriveVLA 与 Alpamayo 的 Prompt 构建差异

对比 Alpamayo 与 OpenDriveVLA,核心区别体现在视觉特征处理历史轨迹注入两个维度:
1. 视觉特征的注入:BEV感知特征 vs 原始 2D 图像

  • OpenDriveVLA:高度依赖BEV(鸟瞰图)3D 结构化感知结果。它将 3D 视觉特征(Scene/Track/Map)通过投影层映射为连续的特征向量序列,拼接到 Prompt 中。

📌 参考笔者对OpenDriveVLA特征嵌入的文章:
(四)OpenDriveVLA的5类Prompt设计与跨模态特征注入机制
(五)揭秘 OpenDriveVLA:结构化感知如何“跨模态对齐”大模型?

  • Alpamayo:放弃复杂的 BEV 特征提取,直接依赖视觉编码器提取的 2D 多视角图像特征,让大模型直接从原始 2D 图像中理解 3D 空间。

2. 历史轨迹的嵌入:文本化拼接 vs Token 量化

  • OpenDriveVLA:将历史轨迹(如过去 2 秒的坐标点)直接格式化为人类可读的文本字符串(例如 “Historical trajectory (last 2 seconds): [(-0.30,-17.01),…]”),作为文本 Prompt 的一部分直接拼接进去。LLM 的 Tokenizer 会将其切分为普通的数字 Token,完全依赖大模型的文本阅读与推理能力来理解这些物理坐标。

📌 参考笔者OpenDriveVLA推理数据加载的文章:
(三)深度拆解 OpenDriveVLA 推理数据加载:基于__getitem__()方法获取单帧数据

  • Alpamayo:历史轨迹作为独立的外部物理条件,将过去若干帧的真实历史轨迹序列(XYZ坐标+旋转)进行 Delta 量化,转为离散 Token,显式嵌入到 Prompt 序列中。

参考

  • 项目地址:NVIDIA/alpamayo
  • 核心文件:
    • src/alpamayo_r1/models/alpamayo_r1.py— 推理入口
    • src/alpamayo_r1/models/base_model.pyfuse_traj_tokenstokenize_history_trajectory
    • src/alpamayo_r1/models/delta_tokenizer.pyDeltaTrajectoryTokenizer.encode
    • src/alpamayo_r1/helper.py— prompt 模板构造

(本文为笔者阅读与跟踪ALpamayo开源代码后,撰写的CSDN原创文章,转载请注明出处。)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 6:14:40

重磅推荐欧米到家潍坊中央空调维修-优质服务及正规操作检修|快速上门深度排查故障原因|权威靠谱受市民好评

核心导读潍坊中央空调出现不制冷、制冷效果差、漏水、异响、频繁停机、故障代码或部分房间没有效果时&#xff0c;维修的关键并不是立即加氟或更换配件&#xff0c;而是先判断故障究竟来自冷媒系统、电控系统、风路水路&#xff0c;还是安装与维护问题。欧米到家面向潍坊家庭、…

作者头像 李华
网站建设 2026/8/28 6:11:30

IoT安全设计与评估服务全解析:从威胁建模到渗透测试的落地实践

最近业内有一件事挺值得关注的&#xff1a;几家做物联网安全的公司开始抱团&#xff0c;把IoT安全设计和安全评估服务打包成一套完整解决方案往外推。乍一听像是商务新闻&#xff0c;但干过嵌入式、搞过设备入网认证的人应该都明白&#xff0c;这背后其实是整个物联网行业被安全…

作者头像 李华
网站建设 2026/8/28 6:11:15

还在纠结MD5是加密还是散列?Python实现秒懂,真相扎心了

MD5&#xff08;负5&#xff09;, 它属于一种被广泛运用的信息摘要算法, 该算法于1992年由美国密码学家罗纳德李维斯特初次提出。为什么, 有人觉得是那种能够用以加密的, 而有人却觉得是散列, 究竟为什么?MD5到底是什么&#xff1f;那么, MD5算法究竟是什么呢? 我们能够把MD5…

作者头像 李华
网站建设 2026/8/28 6:09:59

从零构建全栈旅游小程序:Spring Boot + 微信原生 + Vue 3 实战架构

简介&#xff1a;全栈开发涉及前端、后端与数据库的协同构建&#xff0c;是现代软件工程的核心实践。其原理在于通过清晰的技术分层与模块化设计&#xff0c;实现高效的数据流转与业务逻辑处理&#xff0c;从而提升开发效率与系统可维护性。在技术价值上&#xff0c;成熟的全栈…

作者头像 李华