视觉语言导航从入门到精通(二)

视觉语言导航从入门到精通(二):经典数据集与评估指标

本文是「视觉语言导航从入门到精通」系列的第二篇,详细介绍VLN领域的主流数据集和评估指标。


文章目录

  • [1. VLN数据集概览](#1. VLN数据集概览)
  • [2. Room-to-Room (R2R) 数据集](#2. Room-to-Room (R2R) 数据集)
  • [3. 其他重要数据集](#3. 其他重要数据集)
  • [4. 模拟器介绍](#4. 模拟器介绍)
  • [5. 评估指标详解](#5. 评估指标详解)
  • [6. 数据集使用实战](#6. 数据集使用实战)

1. VLN数据集概览

1.1 数据集发展时间线

2023 VLN-Video 2022 R2R-CE RxR-CE 2021 SOON 2020 REVERIE ALFRED 2019 R4R RxR CVDN 2018 Touchdown EQA-v1 2017 R2R Matterport3D

1.2 数据集对比总览

数据集 环境 指令数 平均长度 特点
R2R 室内 21,567 29词 最经典的VLN数据集
RxR 室内 126,069 78词 多语言、更详细
R4R 室内 233,613 58词 更长路径
REVERIE 室内 21,702 18词 高层指令+目标定位
CVDN 室内 2,050对话 - 对话式导航
SOON 室内 4,064 47词 目标物体定位
Touchdown 室外 9,326 89词 街景导航
ALFRED 室内 25,743 - 导航+操作

2. Room-to-Room (R2R) 数据集

2.1 数据集简介

R2R是VLN领域最经典、使用最广泛的benchmark数据集。

R2R 数据集统计信息

类别 详情
环境来源 Matterport3D (90个真实室内场景)
train 61个场景, 14,025条指令
val_seen 61个场景, 1,020条指令 (训练环境)
val_unseen 11个场景, 2,349条指令 (新环境)
test 18个场景, 4,173条指令 (新环境)
平均路径长度 10米
平均步数 6步
每条路径指令数 3条人工指令
平均指令长度 29个单词
词汇量 约3,000词

2.2 数据格式

json 复制代码
{
  "distance": 10.97,
  "scan": "QUCTc6BB5sX",
  "path_id": 3279,
  "path": [
    "3f35f1c609304b4391f30f7cc8f4d0a7",
    "18d35d73a3a146c0868ff75ce0a8f8fa",
    "a07c0fba01d94a0c80c3e03c9b238e03",
    "553f9977b38d4c8eb150e8fd26b0b0dd",
    "f66d1c25c30c4371be39e30e21af4e70"
  ],
  "heading": 4.52,
  "instructions": [
    "Walk out of the bathroom and turn left. Walk through the bedroom and out to the balcony. Wait near the railing.",
    "Exit the bathroom, turn left and walk into the bedroom. Turn right and walk to the end of the balcony. Stop at the end of the balcony near the two chairs.",
    "Walk out of the bathroom and take a left. Walk past the bed and head out to the balcony. Stop when you reach the end by the table and chairs."
  ]
}

2.3 数据可视化

R2R 数据结构示意图

场景中的导航图由多个viewpoint节点组成,节点之间通过边连接表示可导航关系:
Node A Node B Node C Node D Node E Node F Node G

示例路径: A → B → E → G

指令: "从A出发,向前走到B,左转经过E,到达G停下"

2.4 R2R的优缺点

优点

  • 真实室内环境,视觉真实度高
  • 数据量适中,便于快速验证
  • 社区活跃,baseline丰富
  • 标准benchmark,便于对比

缺点

  • 离散导航,动作空间有限
  • 指令相对简单
  • 环境数量有限
  • 缺乏交互和操作

3. 其他重要数据集

3.1 RxR (Room-across-Room)

python 复制代码
# RxR数据集特点
rxr_features = {
    "多语言": ["English", "Hindi", "Telugu"],  # 三种语言
    "指令更长": "平均78个词vs R2R的29词",
    "指令更详细": "包含更多视觉参照物描述",
    "pose traces": "提供详细的姿态轨迹标注",
    "规模更大": "126,069条指令",
}

RxR vs R2R 对比

特征 R2R RxR
指令长度 29词 78词
数据量 21,567 126,069
语言 英语 英/印地/泰卢固
标注方式 静态标注 动态录制

3.2 REVERIE

REVERIE关注高层指令理解和目标物体定位:

复制代码
任务对比:

R2R:     "Walk into the kitchen and stop by the refrigerator"
         → 精确的路径描述

REVERIE: "Go to the kitchen and bring me a cup from the cabinet"
         → 高层意图 + 目标物体

REVERIE需要同时完成:
1. 导航到正确位置
2. 定位目标物体(给出bounding box)
复制代码
对话式导航示例:

User:   "I need to find the bathroom"
Agent:  [导航中...到达某位置]
User:   "No, not this one. The one with the blue tiles."
Agent:  [继续导航...调整方向]
User:   "Yes! Go inside and stop by the mirror."
Agent:  [完成导航]

特点:多轮对话、交互式、可以请求帮助

3.4 ALFRED

复制代码
ALFRED = 导航 + 物体操作

任务示例:
"把沙发上的遥控器放到电视柜上"

需要执行的动作序列:
1. 导航到沙发
2. 拾取遥控器 (PickUp)
3. 导航到电视柜
4. 放下遥控器 (PutDown)

动作空间:
- 导航动作: MoveAhead, RotateLeft, RotateRight, LookUp, LookDown
- 操作动作: PickUp, PutDown, Open, Close, ToggleOn, ToggleOff, Slice

3.5 Continuous环境数据集

类型 离散导航 (R2R) 连续导航 (R2R-CE, RxR-CE)
移动方式 在预定义viewpoint之间跳转 连续的3D空间移动
动作空间 选择下一个viewpoint 前进距离、转向角度
特点 更简单,但不够真实 更真实,但更困难

4. 模拟器介绍

4.1 Matterport3D Simulator

python 复制代码
# 安装Matterport3D Simulator
"""
git clone https://github.com/peteanderson80/Matterport3DSimulator.git
cd Matterport3DSimulator
mkdir build && cd build
cmake ..
make
"""

# 基本使用示例
import MatterSim

# 创建模拟器
sim = MatterSim.Simulator()
sim.setDatasetPath('/path/to/matterport/data')
sim.setNavGraphPath('/path/to/connectivity')
sim.setCameraResolution(640, 480)
sim.setCameraVFOV(60)  # 垂直视角
sim.setDiscretizedViewingAngles(True)
sim.setBatchSize(1)
sim.initialize()

# 创建新episode
sim.newEpisode(['scanId'], ['viewpointId'], [heading], [elevation])

# 获取当前状态
state = sim.getState()[0]
print(f"Location: {state.location.viewpointId}")
print(f"Heading: {state.heading}")
print(f"RGB shape: {state.rgb.shape}")

# 执行动作 - 移动到相邻viewpoint
sim.makeAction([next_viewpoint_idx], [heading], [elevation])

4.2 Habitat Simulator

python 复制代码
# Habitat用于连续导航环境
import habitat

# 配置文件
config = habitat.get_config("configs/tasks/vln_r2r.yaml")

# 创建环境
env = habitat.Env(config=config)

# 重置环境
observations = env.reset()

# 动作空间(连续)
action_space = {
    "MOVE_FORWARD": 0,   # 前进25cm
    "TURN_LEFT": 1,      # 左转10度
    "TURN_RIGHT": 2,     # 右转10度
    "STOP": 3            # 停止
}

# 执行动作
observations = env.step(action_space["MOVE_FORWARD"])

4.3 模拟器对比

特性 Matterport3D Sim Habitat
导航类型 离散 连续/离散
渲染速度 较慢 快(GPU加速)
物理引擎
扩展性 一般
社区支持 R2R为主 广泛

5. 评估指标详解

5.1 主要评估指标

python 复制代码
def calculate_vln_metrics(predicted_path, ground_truth_path, threshold=3.0):
    """
    计算VLN常用评估指标

    Args:
        predicted_path: 预测路径的viewpoint序列
        ground_truth_path: 真实路径的viewpoint序列
        threshold: 成功判定阈值(米)
    """
    metrics = {}

    # 1. Navigation Error (NE) - 导航误差
    # 预测终点与真实终点的距离
    final_position = predicted_path[-1]
    goal_position = ground_truth_path[-1]
    metrics['NE'] = euclidean_distance(final_position, goal_position)

    # 2. Success Rate (SR) - 成功率
    # 如果NE < threshold,则认为成功
    metrics['SR'] = 1.0 if metrics['NE'] < threshold else 0.0

    # 3. Oracle Success Rate (OSR) - Oracle成功率
    # 路径上任意点距离目标小于threshold即成功
    min_distance = min([euclidean_distance(p, goal_position)
                        for p in predicted_path])
    metrics['OSR'] = 1.0 if min_distance < threshold else 0.0

    # 4. Success weighted by Path Length (SPL) - 路径长度加权成功率
    # SPL = SR * (shortest_path_length / max(predicted_length, shortest_length))
    gt_length = path_length(ground_truth_path)
    pred_length = path_length(predicted_path)
    metrics['SPL'] = metrics['SR'] * (gt_length / max(pred_length, gt_length))

    # 5. Normalized Dynamic Time Warping (nDTW)
    # 衡量路径相似度
    metrics['nDTW'] = normalized_dtw(predicted_path, ground_truth_path)

    # 6. Success weighted by nDTW (sDTW)
    metrics['sDTW'] = metrics['SR'] * metrics['nDTW']

    return metrics

5.2 指标详细说明

复制代码
NE = distance(predicted_end, goal)

解释:预测路径终点与目标点的欧氏距离
范围:[0, ∞),越小越好
Success Rate (SR) ↑
复制代码
SR = 1 if NE < 3m else 0

解释:导航误差小于阈值(通常3米)即为成功
范围:[0, 1],越大越好
SPL (Success weighted by Path Length) ↑
复制代码
SPL = SR × (L* / max(L_p, L*))

其中:
  SR = 成功率 (0或1)
  L* = 最短路径长度
  L_p = 预测路径长度

解释:在成功的基础上,考虑路径效率。若导航失败则SPL=0
范围:[0, 1],越大越好
nDTW (normalized Dynamic Time Warping) ↑
复制代码
nDTW = exp(-DTW(P, Q) / (|P| × d_th))

P = 预测路径
Q = 参考路径
d_th = 距离阈值

解释:衡量两条路径的相似程度
范围:[0, 1],越大越好

5.3 指标可视化对比

场景示例:目标在G点

情况 路径示意 SR SPL 说明
完美成功 S → → → G 1 1 最短路径到达
成功但绕路 S → ↓ → ← G 1 0.5 到达但路径较长
失败 S → → X (G在别处) 0 0 停在错误位置
经过未停 S → G → → X 0 0 经过目标但未停止 (OSR=1)

5.4 各数据集使用的指标

数据集 主要指标 次要指标
R2R SR, SPL NE, OSR
RxR SR, SPL, nDTW, sDTW NE
REVERIE SR, SPL, RGS, RGSPL -
CVDN GP (Goal Progress) -
R2R-CE SR, SPL, NE, OSR -

6. 数据集使用实战

6.1 下载数据

bash 复制代码
# 1. 下载Matterport3D数据(需要申请)
# https://niessner.github.io/Matterport/

# 2. 下载R2R数据集
git clone https://github.com/peteanderson80/Matterport3DSimulator.git
cd Matterport3DSimulator/tasks/R2R/data

# 目录结构:
# R2R/data/
# ├── R2R_train.json
# ├── R2R_val_seen.json
# ├── R2R_val_unseen.json
# └── R2R_test.json

6.2 数据加载代码

python 复制代码
import json
import numpy as np

class R2RDataset:
    """R2R数据集加载器"""

    def __init__(self, split='train', data_path='./data'):
        self.split = split
        self.data_path = data_path
        self.data = self.load_data()

    def load_data(self):
        """加载数据"""
        file_path = f"{self.data_path}/R2R_{self.split}.json"
        with open(file_path, 'r') as f:
            data = json.load(f)

        # 展开instructions
        new_data = []
        for item in data:
            for i, instruction in enumerate(item['instructions']):
                new_item = {
                    'path_id': item['path_id'],
                    'scan': item['scan'],
                    'path': item['path'],
                    'heading': item['heading'],
                    'instruction': instruction,
                    'instr_id': f"{item['path_id']}_{i}"
                }
                new_data.append(new_item)

        return new_data

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]


# 使用示例
train_dataset = R2RDataset(split='train')
print(f"训练集大小: {len(train_dataset)}")

sample = train_dataset[0]
print(f"场景ID: {sample['scan']}")
print(f"指令: {sample['instruction']}")
print(f"路径长度: {len(sample['path'])} 步")

6.3 特征提取

python 复制代码
import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from torchvision.models import ResNet152_Weights
from PIL import Image
import numpy as np

class ImageFeatureExtractor:
    """视觉特征提取器"""

    def __init__(self, model_name='resnet152'):
        # 加载预训练模型(使用新版API)
        if model_name == 'resnet152':
            self.model = models.resnet152(weights=ResNet152_Weights.IMAGENET1K_V2)
            self.model = nn.Sequential(*list(self.model.children())[:-1])
            self.feat_dim = 2048

        self.model.eval()
        self.model.cuda()

        self.transform = transforms.Compose([
            transforms.Resize((224, 224)),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                               std=[0.229, 0.224, 0.225])
        ])

    def extract(self, image):
        """提取单张图像特征"""
        if isinstance(image, np.ndarray):
            image = Image.fromarray(image)

        image = self.transform(image).unsqueeze(0).cuda()

        with torch.no_grad():
            features = self.model(image)

        return features.squeeze().cpu().numpy()

    def extract_panorama(self, images, num_views=36):
        """提取全景图特征 (36个视角)"""
        features = []
        for img in images:
            feat = self.extract(img)
            features.append(feat)
        return np.stack(features)  # [36, 2048]


# 使用CLIP提取特征(更现代的方法)
import clip

class CLIPFeatureExtractor:
    def __init__(self):
        self.model, self.preprocess = clip.load("ViT-B/32", device="cuda")

    def extract_image(self, image):
        image = self.preprocess(image).unsqueeze(0).cuda()
        with torch.no_grad():
            features = self.model.encode_image(image)
        return features.squeeze().cpu().numpy()

    def extract_text(self, text):
        tokens = clip.tokenize([text]).cuda()
        with torch.no_grad():
            features = self.model.encode_text(tokens)
        return features.squeeze().cpu().numpy()

6.4 DataLoader实现

python 复制代码
from torch.utils.data import Dataset, DataLoader

class R2RBatchDataset(Dataset):
    """支持批处理的R2R数据集"""

    def __init__(self, split, tokenizer, max_length=80):
        self.data = R2RDataset(split=split).data
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        item = self.data[idx]

        # 文本编码
        encoded = self.tokenizer(
            item['instruction'],
            padding='max_length',
            truncation=True,
            max_length=self.max_length,
            return_tensors='pt'
        )

        return {
            'instr_id': item['instr_id'],
            'scan': item['scan'],
            'path': item['path'],
            'heading': item['heading'],
            'input_ids': encoded['input_ids'].squeeze(),
            'attention_mask': encoded['attention_mask'].squeeze()
        }

# 创建DataLoader
from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
train_dataset = R2RBatchDataset('train', tokenizer)

train_loader = DataLoader(
    train_dataset,
    batch_size=32,
    shuffle=True,
    num_workers=4,
    collate_fn=custom_collate_fn  # 自定义collate处理变长路径
)

总结

本文详细介绍了VLN领域的主要数据集和评估指标:

数据集要点

  • R2R: 最经典的benchmark,适合入门
  • RxR: 更大规模,多语言支持
  • REVERIE: 高层指令+目标定位
  • 连续环境: R2R-CE, RxR-CE更接近真实

评估指标要点

  • SR: 最基本的成功率
  • SPL: 考虑路径效率的成功率
  • nDTW/sDTW: 路径相似度

参考文献

1\] Anderson P, et al. "Vision-and-Language Navigation: Interpreting visually-grounded navigation instructions in real environments." *CVPR 2018*. \[2\] Ku A, et al. "Room-Across-Room: Multilingual Vision-and-Language Navigation with Dense Spatiotemporal Grounding." *EMNLP 2020*. \[3\] Qi Y, et al. "REVERIE: Remote Embodied Visual Referring Expression in Real Indoor Environments." *CVPR 2020*. \[4\] Krantz J, et al. "Beyond the Nav-Graph: Vision-and-Language Navigation in Continuous Environments." *ECCV 2020*. *** ** * ** *** > 下一篇我们将深入讲解VLN的核心模型架构! *上一篇:[视觉语言导航从入门到精通(一):基础概念与背景介绍](./01_VLN%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5%E4%B8%8E%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D.md)* *下一篇:[视觉语言导航从入门到精通(三):核心模型架构详解](./03_%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9E%8B%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3.md)*

相关推荐
_OP_CHEN6 小时前
【从零开始的Qt开发指南】(十一)Qt常用控件之多元素控件与容器类控件深度解析
开发语言·qt·前端开发·多元素控件·gui开发·qt常用控件·容器类控件
qdprobot6 小时前
齐护AiTall pro ESP32S3 小智AI对话 MQTT MCP 开发板Mixly Scratch Steam图形化编程创客教育
人工智能·mqtt·scratch·mixly·mcp·小智ai·齐护机器人aitall pro
程砚成6 小时前
美容行业的未来:当科技照进美与健康
大数据·人工智能
SmoothSailingT6 小时前
C#——Lazy<T>懒加载机制
开发语言·单例模式·c#·懒加载
AI科技星6 小时前
质量定义方程的物理数学融合与求导验证
数据结构·人工智能·算法·机器学习·重构
无限大.6 小时前
为什么玩游戏需要独立显卡?——GPU与CPU的分工协作
python·玩游戏
javaforever_cn6 小时前
AI Agent 智能体与MCP开发实践-基于Qwen3大模型-王晓华 案例实战 第二章
人工智能
deephub6 小时前
llama.cpp Server 引入路由模式:多模型热切换与进程隔离机制详解
人工智能·python·深度学习·llama
轻竹办公PPT6 小时前
汇总12款Word生成PPT工具,哪款更适合日常汇报?
人工智能·powerpoint