MapQR:自动驾驶在线矢量化高精地图构建的端到端 SOTA 方法

MapQRECCV 2024 提出的、面向自动驾驶在线矢量化高精地图构建端到端 SOTA 方法 ,核心是通过增强点集查询机制,解决传统方法精度低、信息不一致的问题,在 nuScenes/Argoverse2 上实现最优 mAP 且保持高效运行。

一、核心定位

  • 任务:在线矢量化 HD 地图构建(输出车道线、人行横道、道路边界等矢量元素)
  • 范式:DETR 类端到端架构 (基于 BEV 特征 + Transformer 解码器)(BEV(Bird's-Eye View,鸟瞰视角)特征是将多传感器(相机 / 激光雷达)采集的第一人称透视数据 ,转换为自上而下的统一坐标系下的二维特征图
  • 目标:替代传统 "点查询",用更优的查询设计提升地图构建精度与效率

二、核心创新:Scatter-and-Gather Query(分散 - 聚合查询)

这是 MapQR 最关键的设计,彻底改变查询方式:

  1. 用实例查询,不用点查询 不单独预测每个点,而是以地图元素实例为单位做查询(如一条车道、一个斑马线)。
  2. **分散(Scatter)**把一个实例查询,拆成多个点查询,去 BEV 特征里提取细节,预测完整点集。
  3. **聚合(Gather)**把分散预测的点,重新聚合成一个完整实例,做匹配与监督。
  4. 优势 共享同个地图元素的内容信息,避免点查询的语义冲突 / 信息不一致 ,同时加入参考点位置嵌入,用先验位置信息增强查询表达力。
  • 基于 GKT/BEVFormer),不增加算力负担
  • 专用点集损失与实例匹配策略,适配矢量化地图的几何形状监督

三、配套改进

  • 轻量化、高效改进 BEV 编码器(基于 GKT/BEVFormer),不增加算力负担
  • 专用点集损失与实例匹配策略,适配矢量化地图的几何形状监督

四、性能表现(nuScenes,ResNet-50)

表格

Epoch mAP1(严格阈值 {0.2,0.5,1.0}) mAP2(宽松阈值 {0.5,1.0,1.5})
24 43.3 66.4
110 50.5 72.6
在同等算力下,精度超越 MapTRv2 等前人方法,且推理效率更高。

五、技术基座与依赖

  • 基于:MapTRv2(核心框架复用)
  • 借鉴:BEVFormer、GKT、ConditionalDETR、DAB-DETR
  • 兼容数据集:nuScenes、Argoverse 2
  • 开源:提供配置文件、预训练模型,训练 / 推理流程与 MapTRv2 完全一致。

六、MapQR 项目完整代码解析(ECCV 2024)


(1)项目整体目录结构

复制代码
MapQR-main/
├── assets/          # 论文配图、架构图
├── ckpts/           # 预训练权重存放目录
├── data/            # nuScenes/Argoverse2 数据集
├── docs/            # 安装、数据准备、训练、可视化文档
├── figs/            # 结果可视化输出
├── mmdetection3d/   # 内置的 MMDetection3D 核心库(版本锁定)
├── projects/        # 核心代码(所有自定义模块都在这里)
│   ├── configs/     # 所有配置文件
│   │   ├── _base_/  # 基础配置(数据集、运行时、模型)
│   │   ├── bevformer/
│   │   ├── maptr/
│   │   ├── maptrv2/
│   │   └── mapqr/   # MapQR 专属配置(你要修改的地方)
│   └── mmdet3d_plugin/  # 自定义插件(不修改 mmdet3d 核心)
│       ├── bevformer/
│       ├── core/
│       ├── datasets/    # 地图构建专用数据集类
│       ├── maptr/
│       └── models/      # 所有模型定义(你要修改的核心)
│           ├── backbones/
│           ├── hooks/
│           ├── opt/
│           ├── utils/
│           ├── __init__.py
│           ├── mapqr_decoder.py  # 核心:分散-聚合解码器
│           └── mapqr_head.py     # 核心:预测头与损失
├── tools/           # 训练、测试、数据转换脚本
│   ├── analysis_tools/
│   ├── data_converter/
│   ├── fp16/
│   ├── maptr/
│   ├── maptrv2/
│   ├── misc/
│   ├── model_converters/
│   ├── work_dirs/   # 训练日志与权重输出
│   ├── create_data.py
│   ├── dist_test.sh
│   ├── dist_test_map.sh
│   ├── dist_train.sh
│   ├── test.py
│   └── train.py      # 训练入口
├── venv/            # 虚拟环境
├── requirement.txt  # 依赖列表
└── README.md

核心代码位置总结

  • 所有模型修改:projects/mmdet3d_plugin/models/
  • 所有配置修改:projects/configs/mapqr/
  • 训练/测试入口:tools/train.py / tools/test.py

(2)核心前向流程(输入 → 输出)

复制代码
环视6张RGB图像
    ↓
ResNet-50 + FPN 提取多尺度图像特征
    ↓
GKT 视图转换 → 200×200×256 BEV 特征图
    ↓
BEV 编码器(2层 Transformer)增强特征
    ↓
MapQR 解码器(6层,核心:分散-聚合查询)
    ↓
MapQR Head 预测
    ├─ 分类分支:每个实例的类别(车道线/人行横道/路边界)
    └─ 回归分支:每个实例的18个点坐标
    ↓
损失计算(分类损失 + 点集倒角距离损失 + 方向损失)

(3)核心模块逐行解析

MapQR 解码器(mapqr_decoder.py

这是 MapQR 区别于 MapTR 的唯一核心,也是你插入 CAFM 的位置

(1)解码器层定义

复制代码
class MapQRDecoderLayer(nn.Module):
    def __init__(self, embed_dims=256, num_heads=8, feedforward_channels=512, dropout=0.1):
        super().__init__()
        # 1. 实例查询之间的自注意力(仅900个查询,比MapTR的16200个快18倍)
        self.self_attn = nn.MultiheadAttention(embed_dims, num_heads, dropout, batch_first=True)
        self.norm1 = nn.LayerNorm(embed_dims)
        
        # 2. 交叉注意力:查询与BEV特征交互
        self.cross_attn = nn.MultiheadAttention(embed_dims, num_heads, dropout, batch_first=True)
        self.norm2 = nn.LayerNorm(embed_dims)
        
        # ========== 你插入 CAFM 的位置 ==========
        # self.cafm = CAFM(dim=embed_dims)
        # self.norm3 = nn.LayerNorm(embed_dims)
        # ======================================
        
        # 3. 前馈网络
        self.ffn = nn.Sequential(
            nn.Linear(embed_dims, feedforward_channels),
            nn.ReLU(inplace=True),
            nn.Dropout(dropout),
            nn.Linear(feedforward_channels, embed_dims),
            nn.Dropout(dropout)
        )
        self.norm4 = nn.LayerNorm(embed_dims)

(2)前向传播:分散-聚合查询的实现

复制代码
    def forward(self, instance_queries, bev_feat, query_pos=None, key_pos=None):
        B, N, C = instance_queries.shape  # N=900(实例查询数量)
        
        # --------------------------
        # 第一步:实例查询自注意力
        # --------------------------
        q = self.self_attn(instance_queries + query_pos, 
                          instance_queries + query_pos, 
                          instance_queries)[0]
        instance_queries = self.norm1(instance_queries + q)
        
        # --------------------------
        # 第二步:分散(Scatter)操作
        # 核心:1个实例查询 → 18个点查询(共享内容,不同位置)
        # --------------------------
        # 1. 复制实例查询18次:[B,900,256] → [B,900×18,256]
        point_queries = instance_queries.repeat_interleave(18, dim=1)
        
        # 2. 生成18个参考点的位置嵌入,加到点查询上
        ref_points = self.get_reference_points(B, device=instance_queries.device)
        pos_embed = self.ref_point_embed(ref_points)  # [B,900×18,256]
        point_queries = point_queries + pos_embed
        
        # --------------------------
        # 第三步:点查询与BEV特征交叉注意力
        # --------------------------
        bev_flat = bev_feat.flatten(2).transpose(1, 2)  # [B,200×200,256]
        q = self.cross_attn(point_queries + key_pos, bev_flat, bev_flat)[0]
        point_queries = self.norm2(point_queries + q)
        
        # --------------------------
        # ========== 你插入 CAFM 前向的位置 ==========
        # q = self.cafm(point_queries)
        # point_queries = self.norm3(point_queries + q)
        # ==========================================
        
        # --------------------------
        # 第四步:聚合(Gather)操作
        # 核心:18个点查询 → 1个实例查询(平均池化+MLP)
        # --------------------------
        instance_queries = point_queries.reshape(B, 900, 18, C).mean(dim=2)
        
        # --------------------------
        # 第五步:前馈网络
        # --------------------------
        q = self.ffn(instance_queries)
        instance_queries = self.norm4(instance_queries + q)
        
        return instance_queries, point_queries

关键优势

  • 解码器输入输出都是900个实例查询,而非 MapTR 的 900×18=16200 个点查询

  • 显存占用降低 80%,推理速度提升 2-3 倍

  • 同一实例的所有点共享内容信息,彻底解决点查询的语义冲突问题


  1. MapQR 预测头(mapqr_head.py

处理解码器输出,生成最终预测并计算损失:

复制代码
class MapQRHead(nn.Module):
    def __init__(self, num_classes=3, in_channels=256, num_query=900, num_points=18):
        super().__init__()
        self.num_classes = num_classes
        self.num_query = num_query
        self.num_points = num_points
        
        # 分类分支:预测每个实例的类别
        self.cls_branch = nn.Linear(in_channels, num_classes)
        # 回归分支:预测每个实例的18个点坐标
        self.reg_branch = nn.Linear(in_channels, num_points * 2)
        
        # 损失函数
        self.cls_loss = FocalLoss(alpha=0.25, gamma=2.0)
        self.point_loss = ChamferDistanceLoss()  # 点集匹配损失
        self.dir_loss = CosineEmbeddingLoss()    # 边缘方向损失

  1. BEV 编码器(基于 GKT 加速)

MapQR 对 BEVFormer 的 BEV 编码器做了轻量化改进:

  • 层数从 6 层减少到 2 层

  • 引入 GKT 预计算查表加速,避免实时相机参数计算

  • 新增参考点位置嵌入,增强查询的位置感知


  1. 数据集加载(datasets/nuscenes_map_dataset.py
  • 专用数据集类 NuScenesMapDataset,解析 nuScenes 的矢量化地图标注

  • 每个样本包含:6张环视图像 + 对应地图元素的点集标注

  • 数据增强仅保留几何变换(翻转、缩放),避免破坏点集结构


七、训练流程解析(tools/train.py

  1. 配置加载 :读取 projects/configs/mapqr/mapqr_nusc_r50_24ep.py,合并基础配置

  2. 环境初始化:初始化分布式环境、随机种子、日志

  3. 模型构建 :通过 build_model 从配置中实例化 CAFMap/MapQR

  4. 数据集构建:加载训练集和验证集,创建 DataLoader

  5. 训练循环

    复制代码
    for epoch in range(total_epochs):
        for batch in train_loader:
            optimizer.zero_grad()
            # 前向传播 + 损失计算
            losses = model(**batch)
            # 反向传播 + 优化
            loss = sum(losses.values())
            loss.backward()
            optimizer.step()
        
        # 每 epoch 评估一次
        if epoch % eval_interval == 0:
            val_results = evaluate(model, val_loader)
            save_best_checkpoint(val_results['mAP2'])

相关推荐
Magic--5 小时前
C++ 智能指针
开发语言·c++·算法
墨雪遗痕5 小时前
工程架构认知(三):从传统Web系统到AI大模型驱动系统
前端·人工智能·架构
高洁015 小时前
AI算法实战:逻辑回归在风控场景中的应用
人工智能·python·深度学习·transformer
Timer@5 小时前
LangChain 教程 05|模型配置:AI 的大脑与推理引擎
人工智能·算法·langchain
sali-tec5 小时前
C# 基于OpenCv的视觉工作流-章50-霍夫找圆
图像处理·人工智能·opencv·算法·计算机视觉
想带你从多云到转晴5 小时前
04、数据结构与算法---双向链表
java·数据结构·算法·链表
Warren2Lynch5 小时前
无缝知识发布:开发者指南——将 Visual Paradigm OpenDocs 与企业 WordPress 集成
人工智能·架构·uml
颜酱5 小时前
从 DeepSeek 文本对话到流式输出
前端·javascript·人工智能
Flittly5 小时前
【SpringAIAlibaba新手村系列】(17)百炼 RAG 知识库应用
java·人工智能·spring boot·spring·ai