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

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

本文是「视觉语言导航从入门到精通」系列的第二篇,详细介绍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)*

相关推荐
aigcapi1 分钟前
AI搜索排名提升:GEO优化如何成为企业增长新引擎
人工智能
彼岸花开了吗6 分钟前
构建AI智能体:八十、SVD知识整理与降维:从数据混沌到语义秩序的智能转换
人工智能·python·llm
MM_MS6 分钟前
Halcon图像锐化和图像增强、窗口的相关算子
大数据·图像处理·人工智能·opencv·算法·计算机视觉·视觉检测
yyy(十一月限定版)9 分钟前
初始matlab
开发语言·matlab
LawrenceLan9 分钟前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
listhi5209 分钟前
基于MATLAB的支持向量机(SVM)医学图像分割方法
开发语言·matlab
韩师傅13 分钟前
前端开发消亡史:AI也无法掩盖没有设计创造力的真相
前端·人工智能·后端
AI大佬的小弟14 分钟前
【小白第一课】大模型基础知识(1)---大模型到底是啥?
人工智能·自然语言处理·开源·大模型基础·大模型分类·什么是大模型·国内外主流大模型
hui函数15 分钟前
如何解决 pip install 编译报错 g++: command not found(缺少 C++ 编译器)问题
开发语言·c++·pip
山土成旧客20 分钟前
【Python学习打卡-Day40】从“能跑就行”到“工程标准”:PyTorch训练与测试的规范化写法
pytorch·python·学习