SatNav Uni-NaVid Baseline
本文介绍如何使用 SatNav-v0.1 trajectory 训练 Uni-NaVid,并在 SatSim 中完成单卡或多卡 在线评测。Uni-NaVid 使用独立 Python 环境和外部模型代码,不与 SatNav Core、Classic 或其他 VLM baseline 共用环境。
1. 模型与 SatNav 接口
Uni-NaVid 根据导航指令和连续 RGB observation 生成最多四个文本动作。SatNav adapter 将 模型输出转换为四个 primitive action:
模型输出 |
SatNav action |
环境行为 |
|---|---|---|
|
|
结束当前 Episode |
|
|
前进 10 m |
|
|
左转 15° |
|
|
右转 15° |
模型生成的动作会进入队列,再按照 SatNav 的逐步交互接口依次执行。评测过程中,adapter 会 持续维护新增 observation 和导航特征缓存,并在每个 Episode 开始时重置模型状态。
SatNav 当前适配的上游版本为
jzhzhang/Uni-NaVid@79ef5ea3fea14c205342d1ab070563d84c7a966a。
使用模型代码和权重前,请阅读 UPSTREAM、
NOTICE 和
Upstream License。
2. 准备独立环境
在 SatNav 仓库根目录创建 Uni-NaVid 环境:
conda env create -f baselines/vlm/uninavid/environment/conda.yml
conda activate satnav-uninavid
export PYTHONNOUSERSITE=1
python -m pip install torch==2.5.1 torchvision==0.20.1 \
--index-url https://download.pytorch.org/whl/cu121
安装与 Python 3.9、PyTorch 2.5、CUDA 和本机 ABI 匹配的 FlashAttention wheel:
export UNINAVID_FLASH_ATTN_WHEEL=/path/to/flash_attn.whl
test -f "$UNINAVID_FLASH_ATTN_WHEEL"
python -m pip install "$UNINAVID_FLASH_ATTN_WHEEL"
继续安装其余依赖和 SatNav:
python -m pip install -r baselines/vlm/uninavid/requirements.txt
python -m pip install -e .
python -m pip check
Uni-NaVid adapter 直接读取 SatNav trajectory 中的 JPEG,不需要将图像转换为 MP4,也不需要 额外安装 Decord。上游 Uni-NaVid 源码将在后续步骤中通过路径加载,不要将其安装为 Python package。
检查关键依赖和入口:
python - <<'PY'
import accelerate
import deepspeed
import flash_attn
import torch
import transformers
print("torch", torch.__version__)
print("transformers", transformers.__version__)
print("accelerate", accelerate.__version__)
print("deepspeed", deepspeed.__version__)
print("flash_attn", flash_attn.__version__)
PY
python -m baselines.vlm.uninavid.dataset --help
python -m baselines.vlm.uninavid.trainer --help
python -m baselines.vlm.uninavid.evaluate --help
python -m baselines.vlm.uninavid.checkpoint --help
command -v python
记录 command -v python 的输出,后续将其设置为 UNINAVID_PYTHON。
3. 准备上游代码
将 Uni-NaVid clone 到 SatNav 仓库之外,并 checkout 到适配版本:
git clone https://github.com/jzhzhang/Uni-NaVid.git /path/to/Uni-NaVid
git -C /path/to/Uni-NaVid checkout --detach \
79ef5ea3fea14c205342d1ab070563d84c7a966a
确认 checkout 位于正确 revision,且没有本地修改:
git -C /path/to/Uni-NaVid rev-parse HEAD
git -C /path/to/Uni-NaVid status --short
训练和评测启动时会检查当前 revision 和工作区状态。不要修改该 checkout,也不要在同一目录 中切换到其他 Uni-NaVid 版本后继续使用已有输出。
4. 准备 SatNav 数据
4.1 Episode、GeoTIFF 与 Trajectory
按照 Episode 数据下载、卫星场景下载和 轨迹数据生成准备 SatNav-v0.1。Uni-NaVid 直接读取 trajectory 中的 JPEG:
trajectory_data/
├── annotations.json
└── images/
└── <episode>/
└── rgb/
├── 001.jpg
└── ...
在当前终端设置数据路径:
export SATNAV_DATA_ROOT=/path/to/SatNav-v0.1
export SATNAV_SCENES_DIR=/path/to/scenes
export SATNAV_TRAJECTORY_ROOT=/path/to/trajectory_data
先检查 Episode 和 59 个 GeoTIFF:
bash scripts/validation/data_validation.sh
4.2 校验 Trajectory
检查 Uni-NaVid 的四动作窗口、action 和 frame 对齐:
python -m baselines.vlm.uninavid.dataset \
"$SATNAV_TRAJECTORY_ROOT" \
--expected-episodes 105164 \
--expected-samples 1399366 \
--strict-frames \
--decode-samples 32
正式训练开始前,launcher 还会自动检查完整 train split。缺失图片、越界路径、action 不合法 或 frame 数量不足都会直接终止训练,不会静默跳过样本。
5. 下载模型
选择模型保存目录,并设置上一节准备的上游代码路径:
export UNINAVID_REPO=/path/to/Uni-NaVid
export UNINAVID_MODEL_ROOT=/path/to/uninavid-models
mkdir -p "$UNINAVID_MODEL_ROOT"
5.1 SatNav 已发布 checkpoint
SatNav Baseline Model Zoo 提供两个 Uni-NaVid checkpoint:
将所需 checkpoint 下载到 UNINAVID_MODEL_ROOT:
python -m huggingface_hub.commands.huggingface_cli download \
Eku127/uninavid-satnav-continue-1ep-lr1e-5 \
--local-dir "$UNINAVID_MODEL_ROOT/uninavid-satnav-continue-1ep-lr1e-5"
评测时将下载后的目录传给 --model-path,同时仍需准备下文中的 EVA 权重和 processor。发布
目录包含推理所需文件,不包含 optimizer 与 scheduler state。
已发布 checkpoint 在完整 split 和 500 步上限下的参考结果如下:
Checkpoint |
Split |
Episode 数 |
NE ↓ |
OS ↑ |
SR ↑ |
SPL ↑ |
|---|---|---|---|---|---|---|
Scratch |
|
4,574 |
174.68 |
60.43 |
25.12 |
24.81 |
Scratch |
|
8,756 |
228.46 |
49.94 |
20.36 |
20.00 |
Continue |
|
4,574 |
87.11 |
68.17 |
49.69 |
49.15 |
Continue |
|
8,756 |
149.85 |
55.85 |
36.72 |
36.29 |
5.2 训练起点与共用资源
下载 Uni-NaVid 完整 checkpoint 和 EVA 权重:
bash baselines/vlm/uninavid/scripts/download.sh \
--source-dir "$UNINAVID_REPO" \
--model-root "$UNINAVID_MODEL_ROOT" \
--model-revision main
如果 Hugging Face 模型仓库要求授权,请先在当前环境完成登录,再重新运行下载命令。下载器 支持断点复用,并会同时确认上游代码版本和 EVA 文件。
下载完成后的主要路径为:
uninavid-models/
├── eva_vit_g.pth
├── uninavid-satnav-scratch-1ep-lr1e-5/
├── uninavid-satnav-continue-1ep-lr1e-5/
└── huggingface/
└── Uni-NaVid/
└── uninavid-7b-full-224-video-fps-1-grid-2/
此外,image processor 位于上游代码目录:
Uni-NaVid/uninavid/processor/clip-patch14-224/
6. 配置本地路径
此时环境、上游代码、SatNav 数据和模型目录均已准备完成。复制 Uni-NaVid 本地配置模板:
mkdir -p baselines/vlm/uninavid/.local
cp baselines/vlm/uninavid/local.env.example \
baselines/vlm/uninavid/.local/env.sh
在 baselines/vlm/uninavid/.local/env.sh 中填写前面步骤得到的实际路径:
export UNINAVID_REPO="${UNINAVID_REPO:-/path/to/Uni-NaVid}"
export UNINAVID_MODEL_ROOT="${UNINAVID_MODEL_ROOT:-/path/to/uninavid-models}"
export UNINAVID_MODEL="${UNINAVID_MODEL:-/path/to/uninavid-models/huggingface/Uni-NaVid/uninavid-7b-full-224-video-fps-1-grid-2}"
export UNINAVID_EVA="${UNINAVID_EVA:-/path/to/uninavid-models/eva_vit_g.pth}"
export UNINAVID_PROCESSOR="${UNINAVID_PROCESSOR:-${UNINAVID_REPO}/uninavid/processor/clip-patch14-224}"
export UNINAVID_PYTHON="${UNINAVID_PYTHON:-/path/to/satnav-uninavid/bin/python}"
export UNINAVID_FLASH_ATTN_WHEEL="${UNINAVID_FLASH_ATTN_WHEEL:-/path/to/flash_attn.whl}"
export SATNAV_UNINAVID_TRAIN_DATA="${SATNAV_UNINAVID_TRAIN_DATA:-/path/to/trajectory_data}"
export SATNAV_UNINAVID_EVAL_EPISODES="${SATNAV_UNINAVID_EVAL_EPISODES:-/path/to/SatNav-v0.1/episodes/eval/{split}/all_episodes.json}"
export SATNAV_UNINAVID_SCENES_DIR="${SATNAV_UNINAVID_SCENES_DIR:-/path/to/scenes}"
export SATNAV_UNINAVID_OUTPUT="${SATNAV_UNINAVID_OUTPUT:-output/baselines/vlm/uninavid}"
各变量对应的来源为:
变量 |
路径来源 |
|---|---|
|
第 3 节 clone 的 Uni-NaVid 目录 |
|
第 5 节选择的模型保存目录 |
|
下载后的完整 Uni-NaVid checkpoint |
|
下载后的 |
|
上游代码中的 |
|
第 2 节 |
|
第 2 节安装的 FlashAttention wheel |
|
第 4 节校验通过的 |
|
SatNav-v0.1 eval Episode 路径模板 |
|
第 4 节校验通过的 GeoTIFF 目录 |
|
训练和评测输出根目录 |
启动脚本会自动读取该文件。临时在终端显式设置的同名环境变量优先于 .local/env.sh。
本地数据、模型、上游代码、输出目录和环境路径均不应提交到 Git。
如需在当前终端后续命令中直接使用这些变量,加载本地配置:
source baselines/vlm/uninavid/.local/env.sh
7. 训练配置与 Checkpoint 检查
训练前先确认下载的完整 checkpoint 可以加载:
python -m baselines.vlm.uninavid.checkpoint \
--model-path "$UNINAVID_MODEL" \
--uninavid-repo "$UNINAVID_REPO" \
--eva-path "$UNINAVID_EVA" \
--processor-path "$UNINAVID_PROCESSOR" \
--device cuda:0
该命令会检查 checkpoint、tokenizer、vision tower 和 FlashAttention 是否能够完整加载。 缺失、不兼容或形状不匹配的权重会直接报错。
默认训练参数位于 baselines/vlm/uninavid/configs/train.yaml:
参数 |
默认值 |
|---|---|
Action window |
4 |
Epochs |
1 |
Per-device batch size |
1 |
Gradient accumulation |
1 |
Learning rate |
|
Warmup ratio |
|
Save interval |
1,000 steps |
DataLoader workers |
2 |
训练使用 baselines/vlm/uninavid/configs/zero1.json 中的 DeepSpeed ZeRO-1。默认更新 language
model 和 multimodal projector,同时保持 vision tower 冻结。训练结束后,launcher 会重新
加载完整输出,确认可用于后续评测。
训练命令中的 --max-steps 表示 optimizer step 数;评测命令中的同名参数表示每个 Episode
最多执行的 primitive action 数。
8. Smoke 训练
先运行两个 optimizer step,检查数据、模型更新和 checkpoint 保存:
CUDA_DEVICES=0,1,2,3,4,5,6,7 \
bash baselines/vlm/uninavid/scripts/train.sh \
--gpus 8 \
--trajectory-root "$SATNAV_UNINAVID_TRAIN_DATA" \
--model-path "$UNINAVID_MODEL" \
--eva-path "$UNINAVID_EVA" \
--output-dir output/baselines/vlm/uninavid/train/smoke \
--max-steps 2 \
--save-steps 1 \
--batch-size 1 \
--gradient-accumulation 1 \
--warmup-ratio 0 \
--dataloader-workers 0 \
--max-samples 16 \
--disable-augmentation
Smoke 使用 8 张 GPU,因此 --max-samples 16 可以形成两个完整 global microbatch。调整 GPU
数或 batch size 时,样本上限至少应为 GPU 数 × per-device batch size。
训练成功后,输出目录包含可直接评测的完整模型、训练日志和 checkpoint-*。launcher 还会
自动确认 language model 与 projector 已更新,并且冻结的 vision tower 没有变化。
9. 完整训练与 Resume
使用完整 SatNav-v0.1 trajectory 训练:
CUDA_DEVICES=0,1,2,3,4,5,6,7 \
bash baselines/vlm/uninavid/scripts/train.sh \
--gpus 8 \
--trajectory-root "$SATNAV_UNINAVID_TRAIN_DATA" \
--model-path "$UNINAVID_MODEL" \
--eva-path "$UNINAVID_EVA" \
--output-dir output/baselines/vlm/uninavid/train/v0-1
默认训练一个 epoch。显存不足时可以减小 --batch-size,并使用
--gradient-accumulation 调整有效 batch size。
训练中断且输出目录中已经存在 checkpoint-* 时,使用完全相同的参数和输出目录重新执行,
并添加 --resume:
CUDA_DEVICES=0,1,2,3,4,5,6,7 \
bash baselines/vlm/uninavid/scripts/train.sh \
--gpus 8 \
--trajectory-root "$SATNAV_UNINAVID_TRAIN_DATA" \
--model-path "$UNINAVID_MODEL" \
--eva-path "$UNINAVID_EVA" \
--output-dir output/baselines/vlm/uninavid/train/v0-1 \
--resume
Resume 只适用于继续同一次训练。更换模型、数据、配置、GPU 数量或采样参数时,应使用新的 输出目录。
10. 配置在线评测
设置待评测 checkpoint。训练输出目录本身就是完整 checkpoint:
export UNINAVID_CHECKPOINT=/path/to/trained-uninavid-checkpoint
检查 Episode、scene 和输出路径能否解析:
bash baselines/vlm/uninavid/scripts/eval.sh \
--model-path "$UNINAVID_CHECKPOINT" \
--eva-path "$UNINAVID_EVA" \
--episodes "$SATNAV_UNINAVID_EVAL_EPISODES" \
--scenes-dir "$SATNAV_UNINAVID_SCENES_DIR" \
--split val_seen \
--limit 4 \
--max-steps 5 \
--gpus 1 \
--dry-run
Dry run 只检查配置、数据选择和输出目录,不加载模型,也不执行环境交互。
11. 单 GPU Smoke 评测
选择 4 个 Episode,每个 Episode 最多执行 5 步:
CUDA_DEVICES=0 \
bash baselines/vlm/uninavid/scripts/eval.sh \
--model-path "$UNINAVID_CHECKPOINT" \
--eva-path "$UNINAVID_EVA" \
--episodes "$SATNAV_UNINAVID_EVAL_EPISODES" \
--scenes-dir "$SATNAV_UNINAVID_SCENES_DIR" \
--split val_seen \
--limit 4 \
--max-steps 5 \
--gpus 1 \
--output-dir output/baselines/vlm/uninavid/eval/v0-1/val_seen/5steps-1rank \
--fail-on-episode-error
结果结构为:
<output-dir>/
├── rank_00000/
│ ├── episodes.jsonl
│ └── done.json
└── summary.json
确认 summary.json 的 status 为 complete、error_episode_count 为 0,并检查
distance_to_goal、success、oracle_success、spl 和 path_length。
12. 多 GPU 评测
每个 rank 都读取完整 Episode 文件,统一 evaluator 会完成稳定排序和 stride sharding,不需要 提前拆分数据。两张 GPU 的 smoke 命令为:
CUDA_DEVICES=0,1 \
bash baselines/vlm/uninavid/scripts/eval.sh \
--model-path "$UNINAVID_CHECKPOINT" \
--eva-path "$UNINAVID_EVA" \
--episodes "$SATNAV_UNINAVID_EVAL_EPISODES" \
--scenes-dir "$SATNAV_UNINAVID_SCENES_DIR" \
--split val_seen \
--limit 4 \
--max-steps 5 \
--gpus 2 \
--output-dir output/baselines/vlm/uninavid/eval/v0-1/val_seen/5steps-2rank \
--fail-on-episode-error
所有 rank 成功退出后,launcher 会自动生成合并后的 summary.json。
13. 完整评测
完整 val_seen 评测使用 500 步上限和全部 Episode:
CUDA_DEVICES=0,1,2,3,4,5,6,7 \
bash baselines/vlm/uninavid/scripts/eval.sh \
--model-path "$UNINAVID_CHECKPOINT" \
--eva-path "$UNINAVID_EVA" \
--episodes "$SATNAV_UNINAVID_EVAL_EPISODES" \
--scenes-dir "$SATNAV_UNINAVID_SCENES_DIR" \
--split val_seen \
--limit -1 \
--max-steps 500 \
--gpus 8 \
--output-dir output/baselines/vlm/uninavid/eval/v0-1/val_seen/500steps-8rank \
--fail-on-episode-error
完成后,将 split 和输出目录改为 val_unseen 再运行一次。
SATNAV_UNINAVID_EVAL_EPISODES 中的 {split} 会自动替换为当前 split。
评测中断后,可以使用完全相同的参数和输出目录重新执行,并在命令末尾添加 --resume。
Resume 会跳过当前 rank 已经写入的 Episode。更换 checkpoint、数据、seed、GPU 数量或评测
参数时,应使用新的输出目录。
14. 常见问题
为什么提示 Uni-NaVid revision 不匹配或工作区不干净?
确认 UNINAVID_REPO 指向正确目录,并恢复到适配版本:
git -C "$UNINAVID_REPO" checkout --detach \
79ef5ea3fea14c205342d1ab070563d84c7a966a
git -C "$UNINAVID_REPO" status --short
status --short 应无输出。不要在该 checkout 中保存模型、日志或其他本地文件。
为什么模型下载失败?
确认当前机器可以访问 Hugging Face,并检查模型仓库是否要求登录或接受使用条款。完成授权后 重新运行相同下载命令即可复用已经下载的文件。
为什么找不到 EVA 或 processor?
UNINAVID_EVA 应指向下载器生成的 eva_vit_g.pth;UNINAVID_PROCESSOR 应指向固定上游
checkout 中包含 preprocessor_config.json 的 clip-patch14-224/ 目录。
为什么 checkpoint 无法加载?
确认使用的是完整 Uni-NaVid checkpoint,而不是单独的 adapter 或部分权重。模型目录应同时 包含 config、tokenizer、权重索引和全部权重 shard。
为什么数据校验提示 frame 数量不足?
检查 annotations.json 中的 video 路径是否对应当前 images/,以及 trajectory 生成过程
是否完整结束。不要组合来自不同 trajectory export 的 annotation 和图像目录。
为什么训练启动后长时间没有加载模型?
训练会先检查完整 SatNav-v0.1 trajectory。数据位于网络存储或低速磁盘时,该阶段可能需要 较长时间;建议将 annotation 和 JPEG 放在本地高速存储。
为什么 Resume 被拒绝?
确认输出目录中存在 checkpoint-*,并使用与首次训练完全相同的模型、数据、配置、GPU 数量
和采样参数。需要改变实验设置时,请创建新的输出目录。
为什么重新评测时没有执行部分 Episode?
使用 --resume 时,evaluator 会跳过当前输出目录中已经完成的 Episode。只有继续完全相同
的评测时才应复用该目录;其他情况请指定新的 --output-dir。