原文发表在知乎,链接,格式会更整齐一些,且附带原论文的中文翻译,欢迎移步。


这篇笔记面向想弄清 InternVLA-N1 实际在算什么的读者。它按论文《InternVLA-N1: An Open Dual-System Vision-Language Navigation Foundation Model with Learned Latent Plans》和 InternNav 仓库里的实现来写。第 1 节只讲推理时两个系统的输入和输出。第 2 节再讲分阶段训练,NavDP、点目标和数据构造都放在训练过程里。

论文与当前仓库并非完全相同的版本。论文的 System 1 采用 NavDP 风格的策略;当前仓库还提供基于 NextDiT 的 DualVLN 实现。下面会分别标明论文设定、代码做法和用于解释的估算,尤其不能把 NavDP 的预训练流程直接套到 NextDiT 的权重上。

相关入口:

在这里插入图片描述

1. 推理时两个系统的输入和输出

InternVLA-N1 把视觉语言导航拆成慢速规划和快速执行。

System 2 是 Qwen2.5-VL 上微调的规划器。它读自然语言指令和第一人称彩色图像,决定下一步该看图像里的哪个位置,或者直接给出停止、转向。论文里的设计频率大约是 2 Hz。

System 1 是扩散策略,负责在局部规划通向中期目标、避开障碍的路径。长指令的终点可能在十几米甚至上百米之外,当前画面里看不见。中期目标是当前画面内可见的下一处导航路点,通常只覆盖整段指令的一部分,也可能已经是最终目标。System 1 根据它持续生成局部路径,System 2 则根据新的观测更新计划,直到指令结束。更新并不必须等到机器人走到旧目标附近:开源实现还会按累计执行步数或观测调用计数等条件触发重新规划。

1.1 System 2

真正送进视觉语言模型的是:

  • 指令。提示词是固定的:你是导航助手,任务是「……」,请输出图像中下一个路点坐标,完成时输出停止。引号里换成这一次的自然语言指令,例如:「走出卧室,直走,在楼梯口右转,进入左边的浴室。」
  • 当前彩色图像,常规规划轮次先缩放到 384×384。
  • 历史彩色图像,从本段已经看到的帧里均匀抽样,默认最多 8 张。这组历史图只给 System 2,不直接作为 System 1 的图像历史输入。后面训练里的时间错开不会取消这组历史。若模型输出 ↓,则进入多轮交互:保留前面的对话与图像,再追加一张供下视轮次使用的图像;这时输入不只是历史图加一张当前图。当前真机示例服务在这个分支复用了同一张上传图像,并没有重新采集一个下视视角。
  • 图 4 里的机器人状态指位姿。开源推理函数的参数里有这一项,但函数体内没有读取它。送进模型的只有提示词和图像。仿真和真机服务传进去的还是一个固定的单位矩阵,不是真实位姿。真机上的里程计不进 System 2,只在轨迹返回之后,由客户端把它从车体坐标变到世界坐标。

一次规划先做文本生成,最多 128 个新词元。两种结果不会同时拿去执行:

  • 文本里有数字。解析成图像坐标,例如 320 180。然后再做一次前向,取出序列末尾 4 个查询位置的隐状态(参考上图中的latent query),作为潜在计划,形状是 1×4×3584。像素坐标和潜在计划出在同一次规划里,但是两次计算:先有文字,再有查询向量看过文字和图像之后的隐状态。这份潜在计划就是交给 System 1 的中期目标。查询是阶段二才训练的(详情见下文中的第 2.2 节的描述)。
  • 文本里是动作符号。解析成离散动作,不再计算潜在计划。画面里找不到路点时输出左转或右转;指令完成时输出停止。往前走交给 System 1,不由 System 2 连着输出前进。
文本动作编号含义
STOP0停止
↑1前进
←2左转
→3右转
↓5相机向下看。实现里用来再要一张俯视图像,论文正文没有展开

1.2 System 1

部署时 System 1 的条件是 System 2 交过来的潜在计划,形状是 1×4×3584,加上当前观测。它不再读像素坐标的数字。这一步是阶段二才接上的(详情见下文中的第 2.2 节的描述)。

下面是两种实现,由选用哪一套模型权重决定。一次推理只用其中一种。

  • NextDiT,发布名是 DualVLN。把 3584 维投到 768 维,作为扩散 Transformer 的条件。异步版本还会看两张彩色图:给出这份计划时的那一帧,和此刻的当前帧。这套实现生成轨迹时不用深度。同步版本只看潜在计划,不再编码图像。
  • 和 System 2 联合微调过的 NavDP。把 3584 维压到 384 维,再把 4 个向量收成 1 个目标向量。图像同样是上面这两帧,另外各配一张深度。

这里的「两帧」不是 System 2 的 8 张历史图。原版 NavDP 的输入确实包含最近 8 帧彩色图,那是阶段一的做法(详情见下文中的第 2.1 节的描述)。接到双系统里之后,异步推理只保留两帧:System 2 做计划的那一帧,用来记住当时指的是哪里;当前帧,用来看现在脚下有什么。更早的历史已经进了潜在计划,不再重复送给 System 1。

默认模型输出是 32 条采样轨迹,每条包含 32 个增量,每个增量有沿参考车体坐标系的前后位移、侧向位移和航向变化三个分量。训练标签先沿平滑路径的弧长重采样成 33 个位置,名义覆盖范围约 3.3 米,再转成 32 个增量;路径不足时重复末端位置。由此得到的相邻位置间隔约为 0.1 米,但这只是标签的设计,模型预测并没有强制等间距或最长 3.3 米的约束。输出不含时间戳或速度。真机客户端把重建的折线交给模型预测控制器,其默认期望速度是 0.3 米/秒,内部时间步长为 0.1 秒。

后处理先将平面位移增量反归一化并累加,为每条轨迹补上原点,得到 33 个二维位置,再对 32 条轨迹取平均,合成一条折线。开源真机客户端丢掉最前面 3 个点,再交给控制器。折线的参考坐标系对应输入图像采集时的机器人位姿,第 1 个点是该坐标系的原点。如果预测接近训练标签、局部路径也足够长,那么第 4 个点大约位于沿路径前行 0.3 米处;预测、转弯、末端重复以及轨迹平均都会影响这个距离。代码没有解释为什么丢掉 3 个点,不能据此认定机器人已经走过了这段路。

当前客户端把规划循环的最短周期设为约 0.3 秒。每轮结束时只睡眠 max(0, 0.3 - 本轮已耗时),补足剩余时间;如果图像处理、网络请求和推理已经超过 0.3 秒,就不再补睡。因此请求频率上限约为 3.3 Hz,实际可能更低。未触发 System 2 更新时,服务沿用上一份潜在计划,只重新运行 System 1;返回新轨迹后,客户端更新控制器的参考线。

论文 §5.5 报告的是另一套优化部署的耗时:复用 System 2 多轮对话的 KV-cache 后,轨迹词元推理从约 1.1 秒降到 0.7 秒;System 1 经 TensorRT 优化后,约 0.03 秒可并行生成 32 条轨迹。当前 Python 真机服务没有把保存的跨轮 KV-cache 传回 generate,这条调用路径也没有使用 TensorRT,不能直接套用论文耗时或图中的 30 Hz。如果仅为理解滚动规划而假设机器人以 0.3 米/秒前进、每 0.3 秒更新一次轨迹,那么两次更新间位移约为 0.09 米。这只是估算,不能据此确定每条预测路径实际执行了多长。

采用 VLN-CE 离散动作接口时,仿真评测使用前进 0.25 米、左转 15°、右转 15°和停止四种任务动作。轨迹离散化函数沿折线模拟转向和前进,当模拟位置距离这条局部轨迹的终点不超过 0.2 米时,就结束动作列表的构造;继续前进会远离终点等情况也会使它提前结束。这里不会追加 STOP,也不表示导航任务已经完成。任务完成的 STOP 由 System 2 输出。当前仿真代理每次从 System 1 的动作列表中最多取 4 步,部分异步模式下默认累计执行至 8 步就重新请求 System 2,也可能提前触发更新。真机客户端直接跟踪连续折线。

2. 分阶段训练

论文的训练分两段,前后接得上,但优化的东西不同。

阶段一两个系统分开训。System 2 学「看图说出路点或转向」。System 1 学「给定一个明确目标,走出局部路径」。这时 System 1 还不接收潜在计划。阶段二冻住 System 2 原有的权重,加进 4 个潜在查询,让 System 1 改吃这份隐状态。世界模型是阶段二的可选扩展,不参与部署。

当前仓库的 DualVLN 训练脚本 从 System 2 checkpoint 开始,并新建 NextDiT 轨迹模块,没有加载阶段一 NavDP 权重的步骤。因此,下文阶段一的 System 1 结构用于解释论文的 NavDP 风格策略;不能把它理解成当前 NextDiT 必然继承的一套预训练权重。

2.1 阶段一:分开训练

System 2。 从 Qwen2.5-VL 出发,在 VLN-CE 子集上做监督微调。论文按「当前画面还能看见的最远路点」把轨迹切开,得到约 500 万个样本。论文 §4.4 写的是视觉编码器、连接层和语言模型一起训练一个 epoch;当前仓库的 System 2 训练脚本 配置为 2 epochs。

论文把任务概括为预测像素坐标、转向或停止。当前代码对有路点的样本构造了更具体的多轮对话:先输入指令、最多 8 张历史图和当前视图,标准答案为 ↓;再提供同一时刻配置的下视图,标准答案为像素坐标。这两个视图的俯仰角由数据配置决定,也可能相同。找不到路点的样本监督转向动作,任务结束的样本监督 STOP。语言模型损失监督这些助手回复,包括 ↓。

阶段一不追加潜在查询占位符。当前脚本设置 pixel_goal_only=False,数据中不返回轨迹训练字段;到了阶段二,设置 pixel_goal_only=True,返回轨迹数据,数据整理器才会在序列末尾追加 4 个查询占位符。转向和停止样本在当前数据构造中不带未来位姿,也不进入这条轨迹训练分支。

VLN-CE 子集复用了 R2R、RxR、ScaleVLN 等数据中的路径和指令,再在 Habitat 里用最短路径跟随器重放路径,重新采集观测和动作。动作包括前进 0.25 米和左右转 15°,路点再被投影成像素坐标。

System 1,论文中的 NavDP 风格策略。 论文里 System 1 的扩散损失和安全打分损失遵循 NavDP。NavDP 是同一组作者的工作,全称 Learning Sim-to-Real Navigation Diffusion Policy with Privileged Information Guidance,arXiv:2505.08712,后来发表在 ICRA 2026。InternVLA 的阶段一在它上面又加了图像目标和像素目标两条对齐支路。除了彩色图用的 DepthAnything 编码器加载预训练权重、在所附训练配置中冻结,其余模块从头训练。数据是 VLN-N1。

原版 NavDP 部署时的输入是:

  • 最近 8 帧彩色图。这就是 NavDP 论文里的历史图像,用来看刚走过的局部环境。
  • 当前深度一帧,只留 0.1 米到 5 米,把轨迹对齐到米制尺度。
  • 一个目标。原论文是相对车体的平面坐标 ((x_g, y_g)),经过编码后作为条件。没有目标的探索任务使用编码空间中的全零目标嵌入,而不是把目标坐标设为 ((0,0)) 再送进编码器。InternVLA 把点目标写成 ((x, y, \theta)):目标点在当前坐标系里的位置,加上目标朝向。它不带时间,也不是图像上的像素。

输出是一条局部路径,原论文默认 24 个路点,外加一个安全分。推理时从噪声采样多条候选,按安全分挑一条。真机上没有地图,安全分是网络根据彩色图和深度估的。

点目标、像素目标、图像目标在阶段一训练中同时构造。点目标取所选目标片段末端的状态,图像目标和像素目标的编码都要回归到它。动作标签则按预测窗口截取、采样,因此点目标可能位于本次预测路径的终点之外;“要去的目标”和“本次预测能走到的位置”需要分开理解。

  • 像素目标是图像上的 ((u, v)),周围画一块随机大小的白掩码,再和对应图像拼在一起。同一个像素可以对应不同深度。
  • 图像目标是两张已经渲染好的图沿通道拼起来:所选目标帧看到的画面,和当前帧。启用 prior_sample=True 时,目标帧采样会偏向更远的时间索引;所附训练配置默认为 False,使用随机索引采样。

对齐损失每次都算两项。扩散条件则从这三种特征里按样本轮换着填进目标槽。两个用来编码图像目标和像素目标的 ViT 从头训练:图像目标由两张 RGB 图拼成 6 通道;像素目标的掩码最终压成单通道,与一张 RGB 图拼成 4 通道,异步形式再加当前 RGB 图,成为 7 通道。第一层卷积相应调整输入通道数。编码观测彩色图的那个 ViT 才加载 DepthAnything 的预训练权重。两个线性头接在目标编码器的平均池化和特征投影之后、轨迹解码器之前,读的是目标编码器的输出。

下图是这一阶段的训练数据流。左栏单独画对齐损失,是为了让线不要穿过条件槽和解码器。左栏的图像特征、像素特征与右栏是同一份编码器输出。

在这里插入图片描述

图右侧动作头和安全打分头并列,都接在同一个解码器后面。一条轨迹是一串路点,每步三个数:前进、侧向、转角。送入方式相同:每个路点过一层线性变换变成一个向量,整串向量作为解码器的查询;彩色图和深度是旁边的记忆。

动作头训练时送进去的是加过噪声的专家路径,标签是实际加上的那份噪声,不是干净路径本身。打分头送进去的是没加噪声的路径,一次两条:A* 专家路径,以及把它随机转 (\pm 60^\circ) 后可能靠近障碍的变体。打分头输出一个数,标签是按路点到障碍距离算好的安全分。模型自己采样的多条轨迹只在推理时交给打分头挑选。

总损失是动作损失、安全打分损失、对齐损失按 0.8、0.2、0.5 相加。动作损失本身又是「没有目标」和「混合了几种目标」两路噪声误差各占一半。推理时换 32 个初始噪声,就得到 32 条候选,不需要 32 条标签。多种走法来自整个数据集里相近的观测对应过不同的专家路径。

VLN-N1 就是造这些专家路径的数据。场景来自 Replica、Matterport3D、Gibson、3D-Front、HSSD 和 HM3D。论文图 2 给这个子集的量级是 3000 多个场景、400 多小时、4000 万张图像、60 万条指令。生成分成三截,对应论文图 3。

在这里插入图片描述

先按网格建欧氏符号距离场,随机起点和终点上跑 A*,把路点从障碍旁推开,再平滑。BlenderProc 沿轨迹渲染第一人称彩色图和深度。规划器就是这个距离场上的 A*,不是生成式模型。然后按急转弯等几何位置切成子片段,用 LLaVA-OneVision 写描述,再用语言模型改写,并摘要成一条长指令。论文 §3.1 将改写模型记为“Qwen3-72B”,但 Qwen3 官方发布的型号列表没有这个规格,具体型号待核实。最后按地标是否足够打分,过滤缺乏地标的轨迹。图上标的是从 278,292 条滤到 213,471 条。

NavDP 自己的数据也是这条路子:距离场、A*、渲染。方法部分写大约 20 万条轨迹、100 万米以上;论文表 1 的数据卡是 3154 个场景、1627 公里、4000 万张图像。距离场和 A* 只负责产生标签,不进入网络。

另一份物理仿真数据 VLN-PE 不参与上面这条流水线。它在 InternUtopia 里用四足、人形和轮式机器人的运动控制器去跟 R2R 路径,并去掉要上下楼梯的片段,用来看仿真到真机的差距。

2.2 阶段二:用潜在查询接上两个系统

阶段一的 System 1 没有接收潜在查询的位置。查询是这一阶段新加的接口,用来替换点目标、图像目标和像素目标。

潜在查询是 4 个可学习向量,形状是 1×4×3584,放在 System 2 序列末尾新追加的 4 个轨迹占位符上。它们本身不是坐标,也不是轨迹。System 2 做完前向之后,这 4 个位置的最后一层隐状态才交给 System 1。这些位置能注意到指令、图像和前面的回答文字;训练时回答由标签提供,推理时由模型生成。读出的隐状态就是两个系统之间的潜在计划。

NextDiT 用 Linear(3584,768) → GELU → Linear(768,768) 构成的投影模块,把每个潜在向量变成 768 维条件。NavDP 先降维,再收成 1 个目标向量,用它作为目标条件。

论文写的是冻结 System 2、只微调新加的潜在计划和 System 1。冻结的是 Transformer 原有权重,优化器不改注意力层和前馈层。查询向量在冻结之后被重新设为可训练。训练时的前向计算没有停掉梯度,所以扩散损失可以穿过冻结网络,更新这 4 个输入向量。查询学到的是:在这个固定网络里,怎样设置这 4 个输入,才能让读出来的隐状态足够让 System 1 把未来轨迹还原对。

异步训练错开的是两边观测的时刻,同时保留 System 2 的历史图像。论文 §4.4 描述的是:System 1 接收时刻 (T) 的最新观测,System 2 使用更早的观测,时间间隔 (K) 从 ((0,12)) 中随机选取。

当前 数据代码采用的具体做法是:固定片段起点,给 System 2 提供起点之前最多 8 张历史图,以及起点处的当前视图和下视轮次图像;再从该片段中抽取多个时刻的图像和未来路径,训练 System 1 复用同一份计划。默认每隔 2 帧取一次,片段较长时加大采样间隔,使采样帧数不超过 max_len=12。这里的 12 限制的是帧数,实际时间差可能超过 12 步,不能把它当作论文随机延迟范围的直接实现。两种做法都让 System 1 学习在计划来自较早观测时继续规划。

推出来的用法也有两种,不是两套参数锁在一起更新。

  • 同步:System 1 用完一次潜在计划就丢掉,下一步必须再等 System 2。同步版的 NextDiT 条件里只有这 4 个潜在向量,不再编码最新彩色图像。
  • 部分异步:同一份潜在计划可以配着新的当前图像(NavDP 还有深度)多次调用 System 1,直到已经执行的步数达到上限。发布用的 DualVLN 配置走的是这条。第 1.2 节说的「两帧」就是这个异步用法。

2.3 可选扩展:世界模型

论文 4.5 节的世界模型不在控制环里,InternNav 的推理代码也没有它。

骨干是预训练的 Wan2.1,13 亿参数的视频扩散模型。原来用 T5 编码文本作为条件,这里改成 System 2 的潜在计划,再在 InternData-N1 上微调。给定这份计划,模型生成走向该中期目标的第一人称未来画面。论文没有把它写成冻结权重,但没写清是整个模型都更新,还是只更新新接上的条件接口。仓库里没有这段训练代码。

它迫使那 4 个查询带上「沿计划往前会看到什么」,而不只是帮助扩散策略去噪。论文报告,加上这个视频预测目标后,R2R-CE 上的联合微调从 4 个训练轮减到 2 个训练轮就能到当时的最好成绩。部署时机器人只跑 System 2 和 System 1。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐