【免费下载链接】NaVILA
[RSS'25] This repository is the implementation of "NaVILA: Legged Robot Vision-Language-Action Model for Navigation"
NaVILA 是一个面向四足机器人的视觉-语言-动作(Vision-Language-Action, VLA)导航模型,源自 RSS'25 论文。它让 Go2 这类腿式机器人仅凭一段自然语言指令(如"向前走并右转,绕过地毯停在桌子旁")就能完成真实世界导航。本文将带你完整读懂 NaVILA 的核心代码:评测入口如何调度多卡并行、NaVILATrainer的评测循环如何逐帧决策,以及"语言指令"是如何一步步拼装成喂给大模型的 Prompt 的。
上图展示了 NaVILA 的两级框架:上层的 VLA 模型接收历史视角(History Views)与当前视角(Current View),输出自然语言指令(如 "Move forward 75 cm");下层的实时运动策略(Policy)基于本体感知(Proprioception)和高度图(Height Map)把指令转化为关节位置,实现避障行走。
一、评测入口:一条命令如何拉起整个评测
🚀 评测入口是一个极简的脚本 r2r.sh:
bash scripts/eval/r2r.sh CKPT_PATH NUM_CHUNKS CHUNK_START_IDX "GPU_IDS"脚本接收 4 个参数:模型检查点路径、总分片数、起始分片号、GPU 列表。它把数据集按 GPU 数量切成多个 chunk,每张卡独立跑一个 run.py 进程:
CUDA_VISIBLE_DEVICES=${GPULIST[$IDX]} python run.py \ --exp-config vlnce_baselines/config/r2r_baselines/navila.yaml \ --run-type eval \ --num-chunks $TOTAL_CHUNKS \ --chunk-idx $CHUNK_IDX \ EVAL_CKPT_PATH_DIR $MODEL_PATH &run.py 里做了三件事:
- 用
get_config加载 navila.yaml 配置(其中TRAINER_NAME: navila决定了用哪个 Trainer); - 从
baseline_registry注册表中取出名为navila的 Trainer 类; - 根据
--run-type eval调用trainer.eval()。
这个"注册表 + 配置驱动"的设计是 Habitat 基线的经典套路:换算法只需换一个 Trainer 名,命令行完全不变。
二、NaVILATrainer 评测流程逐行解读
核心实现在 navila_trainer.py,NaVILATrainer继承自 base_il_trainer.py 中的BaseVLNCETrainer。
2.1 加载模型与冻结配置
eval()方法(L384-L399)只负责确定 GPU 设备并打开 TensorBoard writer,真正的逻辑在_eval_checkpoint()(L70-L355):
tokenizer, model, image_processor, context_len = load_pretrained_model(checkpoint_path, model_name)这里复用了 VILA 训练侧的 builder.py 加载多模态模型,得到四件套:分词器、模型、图像处理器、上下文长度。随后对 config 执行defrost()(解冻),改写DATASET.SPLIT、ROLES、NUM_CHUNKS等字段后freeze()——注意NUM_CHUNKS/CHUNK_IDX就是r2r.sh传入的分片信息,用于把 R2R val_unseen 数据集切成 N 份。
2.2 环境构建与首个观测
envs = construct_envs_auto_reset_false(config, get_env_class(config.ENV_NAME)) observations = envs.reset() observations = extract_instruction_tokens(observations, ...)- env_utils.py 创建 Habitat 仿真环境(VLN-CE 任务,Habitat 0.1.7);
- utils.py 中的
extract_instruction_tokens把指令传感器输出从{"tokens": [...]}字典结构解包为纯 token 列表,供后续 Prompt 使用。
2.3 主循环:每步如何产生动作
主循环while envs.num_envs > 0 and len(stats_episodes) < num_eps里,每轮迭代对应环境的一步,逻辑分两大分支:
分支一:动作队列非空(L153-L157)
若上一步模型生成了"前进 75 cm"这种超过单步粒度的指令,多余步数会放进queue_actions队列,本轮直接从队列取动作envs.step(...)执行,不重新调用大模型——这是省算力的关键设计。
分支二:调用 VLA 模型生成语言指令(L159-L283),这是全文最值得细读的部分:
- 拼历史帧(L161-L166):把
past_rgbs里保存的所有历史图像加上当前帧,交给sample_and_pad_images()(L38-L52)采样/补齐到固定 8 帧——帧数不足时用黑帧在头部补齐,再从时间轴上均匀抽 7 帧 + 保留最新 1 帧。 - 构造语言指令(L168-L180):从当前 episode 取出
instruction_text(如 "Walk to the desk…"),拼进固定模板,告知模型"你是导航机器人,分析这些图像决定下一步动作,可以是左转/右转一定角度、前进一定距离,或停止"。 - 对话模板包装(L182-L186):用 conversation.py 中
llama_3模板把问题包成 Llama 3 的 system/user 对话格式,get_prompt()生成最终 Prompt 字符串。 - 图文 Token 化(L188-L195):
process_images把 8 张图编码为视觉特征张量;tokenizer_image_token(mm_utils.py)把 Prompt 里的<image>占位符替换为图像 token。 - 解码生成(L201-L213):
model.generate(..., do_sample=False, temperature=0.0, max_new_tokens=32)贪心解码,并用KeywordsStoppingCriteria在遇到对话分隔符时提前停止,最后batch_decode得到自然语言输出。
2.4 语言输出 → 环境动作的映射
🧭 模型输出的是自然语言,而 Habitat 环境只认离散动作。代码用一组正则完成"语义解析"(L222-L234):
| 正则模式 | 动作编号 | 含义 |
|---|---|---|
stop | 0 | 停下(任务结束) |
is move forward | 1 | 前进 |
is turn left | 2 | 左转 |
is turn right | 3 | 右转 |
随后对数值部分做二次解析与"量化吸附"(L242-L280):
- 前进距离从
move forward (\d+) cm提取,不是 25 的倍数就吸附到最近的 25/50/75 cm; - 转角从
turn left/right (\d+) degree提取,不是 15 的倍数就吸附到 15/30/45°; - 第一个 25cm/15° 立即
envs.step执行,剩余步数压入queue_actions队列。
任何解析失败都有兜底默认值(距离 25cm、角度 15°、未知动作用前进),保证评测永不中断。
2.5 回合结束:统计与视频
每步结束后(L285-L347),代码把新观测帧追加进past_rgbs;若开启了视频选项,就把当前观测渲染成带地图的可视化帧并附上指令文本。当某环境done时:
- 把该回合的
infos(SPL、成功率、距离目标等)存入stats_episodes,调用envs.reset_at(i)载入新 episode; - 用 utils.py 的
generate_video()把整回合画面合成 mp4 存到videos/目录; - 若下一个 episode 与已评过的重复,则通过
_pause_envs()暂停该环境槽位,防止重复评测。
全部跑完后,stats_episodes以 JSON 落盘为{split}_{num_chunks}-{chunk_idx}.json;若文件已存在则直接跳过,天然支持断点续评。
三、语言指令生成逻辑小结 💡
把 2.3 节串起来,"语言指令"的完整生成链路是:
- 数据来源:VLN-CE 数据集中每条 episode 的
instruction_text(人工撰写的导航指令); - 历史感知:8 帧图像序列(7 历史 + 1 当前)统一编码为视觉 token;
- Prompt 组装:固定英文任务模板 +
<image>占位符 + 指令文本 + Llama 3 对话模板; - 受限解码:贪心解码、最多 32 token,用分隔符做停止条件——模型被"逼着"只回答一句简短的动作指令;
- 鲁棒解析:正则匹配动作类别 + 数值提取 + 网格吸附 + 默认值兜底。
这套设计的巧妙之处在于:不训练专用的离散动作头,而是让大模型直接输出人类可读的指令,再用规则层翻译成环境动作,既保留了 VLM 的零样本泛化能力,又保证了控制的确定性。
四、结果汇总与查看分数
多卡评测结束后,运行:
python scripts/eval_jsons.py ./eval_out/CKPT_NAME/VLN-CE-v1/val_unseen NUM_CHUNKSeval_jsons.py 会扫描所有分片 JSON,聚合出各 episode 的distance_to_goal、success、spl、ndtw、path_length等指标并打印汇总分数。可视化视频则保存在./eval_out/CKPT_NAME/VLN-CE-v1/val_unseen/videos下。
五、总结
NaVILA 的评测代码虽然只有几百行,却串起了完整的多模态评测工程:
- 分片调度:
r2r.sh+NUM_CHUNKS/CHUNK_IDX实现多卡数据并行; - 配置驱动:YAML + 注册表解耦算法与入口;
- 视觉记忆:8 帧历史采样让模型"看见过去";
- 语言即接口:自然语言指令作为大模型与离散控制之间的桥梁,配正则解析与兜底机制;
- 可复现评测:JSON 落盘断点续评 + 视频可视化 + 指标聚合。
阅读路径建议:先跑通 README.md 的评测安装步骤,再按run.py→NaVILATrainer.eval()→ 主循环的顺序精读 navila_trainer.py,最后对照 discrete_planner.py 理解 15°/25cm 的动作空间设定,即可完全掌握 NaVILA 的实现原理。
【免费下载链接】NaVILA
[RSS'25] This repository is the implementation of "NaVILA: Legged Robot Vision-Language-Action Model for Navigation"
相关推荐
Qwen3-Coder 多语言代码生成评估实战:基于 MultiPL-E 的完整评测指南
Qwen3 Coder 多语言代码生成评估实战:基于 MultiPL E 的完整评测指南 导读 本文面向需要在 Qwen3 Coder https://link
人工智能大模型代码模型模型评测微调LoRAAI Agent代码智能体Qwen如何快速掌握Kandinsky 2.2:从CLIP编码到扩散生成的完整指南
如何快速掌握Kandinsky 2.2:从CLIP编码到扩散生成的完整指南 Kandinsky 2.2是一款强大的多语言文本到图像 latent diffusi
Dagger代码生成原理:从注解到Java源代码的完整流程
Dagger代码生成原理:从注解到Java源代码的完整流程 Dagger是一个快速的依赖注入框架,专为Android和Java设计。它采用编译时代码生成技术,通
依赖注入代码生成后端移动开发开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考