资讯动态

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

发布时间:2026/8/28 6:18:29 来源:尧图企业网站定制
在 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_datadata[tokenized_data]input_idstokenized_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_token48hist_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.py的encode函数1. 计算增量Delta位置模型不关心车辆在整个地图上的绝对坐标只关心 “相对于上一步车辆移动了多少”。# shape: (1,16,3) -- (1,17,3), 对于3D tensor, 在第二维前面填充一个元素, 默认是0xyztorch.nn.functional.pad(fut_xyz,[0,0,1,0,0,0])xyzxyz[:,1:]-xyz[:,:-1]通过相邻帧求差将绝对坐标转换为步进增量。第一个时间步的增量是相对于原点 (0, 0, 0) 的偏移。这降低了对绝对坐标的依赖使量化范围更集中。2. 归一化到 [0, 1] 区间为了统一量纲根据配置的物理范围例如 x/y 轴 [-4m, 4m]z 轴 [-10m, 10m]将增量值线性映射到 [0, 1] 之间。ego_xyz_maxtorch.tensor(self.ego_xyz_max,dtypexyz.dtype,devicexyz.device)ego_xyz_mintorch.tensor(self.ego_xyz_min,dtypexyz.dtype,devicexyz.device)xyz(xyz-ego_xyz_min)/(ego_xyz_max-ego_xyz_min)3. 量化为整数 Token将 [0, 1] 的浮点数映射到有限的词汇表Bins中。默认情况下词汇表大小为 1000num_bins1000。# self.num_bins 1000xyz(xyz*(self.num_bins-1)).round().long()# 乘以 999 并四舍五入xyzxyz.clamp(0,self.num_bins-1)# 安全裁剪到 [0, 999]本质这是一个向量量化编码器。连续的物理位移被离散化为了0~999的整数 Token。4. 展平与词表偏移将形状从 (B, Th, 3) 展平为 (B, Th×3)。对于 16 个历史时间步每步 3 个 tokenx, 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.maskinput_idspad_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.py—fuse_traj_tokens、tokenize_history_trajectorysrc/alpamayo_r1/models/delta_tokenizer.py—DeltaTrajectoryTokenizer.encodesrc/alpamayo_r1/helper.py— prompt 模板构造本文为笔者阅读与跟踪ALpamayo开源代码后撰写的CSDN原创文章转载请注明出处。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价