1. RefCOCO 数据集到底解决的是什么问题
第一次接触 RefCOCO 的人,多半是在做多模态任务时被“指代消解”或者“视觉定位”卡住了。简单说,RefCOCO 是一个指代图像分割与视觉定位领域被引用最多的基准数据集之一,它的全称是 Referring Expressions dataset,由北卡罗来纳大学教堂山分校的研究团队在 2014 年前后构建并公开。它要解决的核心问题是:给一张包含多个同类物体的图片,再给一句自然语言描述,比如“左边那只坐着的小狗”,让模型把这句话对应的那个物体框出来或者分割出来。
这件事听起来简单,做起来非常难。因为自然语言里充满了歧义、相对位置、属性修饰和上下文依赖。传统目标检测只能告诉你“图里有狗”,但没法告诉你“是哪一只狗”。RefCOCO 的价值就在于,它把“语言”和“像素级定位”绑在了一起,给研究者提供了一个可以量化评估的标准考场。
它适合谁?如果你在做视觉语言预训练、多模态大模型、指代分割、人机交互中的指向理解,或者只是想找一个能同时练手 NLP 和 CV 的数据集,RefCOCO 基本是绕不开的。哪怕你只是用 YOLO 做检测,想扩展到“按描述找目标”,RefCOCO 的标注格式和评估逻辑也值得认真看一遍。
我见过不少团队一上来就堆模型,结果连 RefCOCO 的 split 都没搞明白,训练集和验证集混用,最后指标虚高。所以这篇内容我会从数据构成、标注机制、评估协议、实操加载、常见坑几个角度,把 RefCOCO 拆开讲清楚。
2. RefCOCO 家族的数据构成与版本差异
2.1 原始 RefCOCO、RefCOCO+、RefCOCOg 的区别
很多人以为 RefCOCO 就是一个数据集,其实它是一组。最常被一起提及的是三个变体:RefCOCO、RefCOCO+、RefCOCOg。它们都基于 COCO 图像,但指代表达的收集方式和难度设计不同。
| 变体 | 指代表达特点 | 主要考察能力 | 典型难点 |
|---|---|---|---|
| RefCOCO | 允许使用绝对位置词,如“左边的”“右边的” | 基础指代定位 | 位置词可能造成捷径学习 |
| RefCOCO+ | 禁止使用绝对位置词 | 纯外观与属性理解 | 必须依赖颜色、形状、类别 |
| RefCOCOg | 表达更长、更自然,平均长度明显增加 | 长文本理解与细粒度定位 | 句子结构复杂,指代链长 |
RefCOCO 的表达里经常出现“on the left”“second from right”这类词,模型很容易学会“看位置猜答案”。RefCOCO+ 把这类词禁掉了,逼着模型去理解“穿红衣服的人”“拿伞的那个”这种外观描述。RefCOCOg 则是另一批标注,句子更像日常说话,比如“一个穿着蓝色上衣正在跳起来接飞盘的人”,长度和复杂度都上了一个台阶。
注意:如果你在论文里只写“我们在 RefCOCO 上评估”,审稿人通常会默认你指的是原始 RefCOCO。如果用了 RefCOCO+ 或 RefCOCOg,必须明确写清楚,否则会被认为实验不完整。
2.2 图像来源与标注规模
RefCOCO 系列的图像全部来自 COCO 2014。COCO 本身有 12 万多张图,RefCOCO 从中挑选了包含多个同类实例的图片,因为只有多个同类物体同时出现,“指代”才有意义。如果一张图里只有一只猫,那“那只猫”就没有区分度。
具体规模上,RefCOCO 大约有 14 万条指代表达,覆盖约 5 万张图像中的 8 万多个物体实例。RefCOCO+ 规模相近,RefCOCOg 大约有 10 万条表达,但句子更长。每条表达都对应一个目标实例的分割掩码,这也是它既能做检测评估又能做分割评估的原因。
这里有个细节:RefCOCO 的标注不是一个人写的,而是通过交互式界面收集的。标注员看到一张图和一个高亮物体,然后写一句话来描述它。另一个人再根据这句话去点选目标。只有点对了,这句话才被保留。这种“写-猜-验证”的机制保证了表达的可理解性,但也带来了一些系统性偏差,比如标注员倾向于用颜色和位置,导致某些属性词出现频率异常高。
2.3 与 COCO 检测任务的关系
RefCOCO 不是凭空造出来的新图像集,它复用了 COCO 的图像和实例分割标注。这意味着你可以直接把 COCO 预训练的检测器或分割器拿过来做 backbone,不需要重新适应图像分布。这也是它被广泛使用的原因之一:迁移成本低。
但要注意,RefCOCO 的评估不是简单的 mAP。它用的是“指代准确率”,即模型预测的框或掩码与目标实例的 IoU 超过某个阈值(通常是 0.5)就算对。这个指标更贴近“人指哪个,模型找哪个”的实际需求。
3. 标注格式与文件结构拆解
3.1 核心文件组成
下载 RefCOCO 后,你通常会看到几个关键文件:refs(unc).p、refs(google).p、instances.json、train2014/、val2014/等。不同来源的压缩包命名略有差异,但核心结构一致。
refs(unc).p和refs(google).p是 Python pickle 文件,里面存的是指代表达和对应的标注信息。每个样本通常包含:
sent_ids:句子 ID 列表sentences:原始句子和解析后的 tokenann_id:对应 COCO 实例标注 IDref_id:指代 IDimage_id:图像 IDsplit:train / val / testcategory_id:类别 ID
instances.json是 COCO 格式的实例标注,包含 segmentation、bbox、area 等字段。你需要把 refs 里的ann_id和 instances 里的id对上,才能拿到目标的分割掩码。
3.2 一个典型样本的字段含义
假设你加载了一条 RefCOCO 样本,它可能长这样:
{ 'ref_id': 12345, 'image_id': 67890, 'split': 'train', 'sentences': [ {'sent_id': 1, 'sent': 'the dog on the left', 'tokens': ['the', 'dog', 'on', 'the', 'left']}, {'sent_id': 2, 'sent': 'left dog', 'tokens': ['left', 'dog']} ], 'ann_id': 111, 'category_id': 18 }category_id对应 COCO 的类别编号,18 通常是 dog。ann_id是这条指代对应的唯一实例标注。注意,同一个目标可能有多个句子,它们共享同一个ann_id。评估时,模型对每个句子分别预测,然后按句子平均。
3.3 图像与标注的对应关系
RefCOCO 的图像文件名就是 COCO 的格式,比如COCO_train2014_000000123456.jpg。你需要根据image_id拼出文件名。标注里的image_id和 COCO 的image_id一致,所以可以直接用 COCO API 加载。
这里有个容易踩的坑:RefCOCO 的 train / val / test split 和 COCO 的 split 不完全一样。RefCOCO 自己重新划分了训练、验证和测试集,而且 test 集的标注不是全部公开的。公开的 test 集通常只有输入,没有答案,需要提交到官方服务器评估。不过后来很多论文用的是 RefCOCO 的 val 集作为测试,因为 val 有公开标注。
提示:如果你只是做课程项目或内部实验,用 val 集评估完全够用。但如果要发论文,最好按官方 split 来,否则对比结果时会被质疑。
4. 评估协议与指标计算细节
4.1 IoU 阈值与准确率
RefCOCO 最常用的指标是Precision@0.5,也叫 Acc@0.5。计算方式很简单:模型对每个指代表达输出一个预测框或掩码,计算它与真实目标掩码的 IoU。如果 IoU > 0.5,这条算对;否则算错。最后用正确数除以总数。
有些论文还会报告 Acc@0.75 和 Acc@0.9,用来衡量高精度定位能力。分割任务通常用掩码 IoU,检测任务用框 IoU。两者不能混用,对比时要看清楚。
4.2 多句子平均与多实例处理
一个目标可能对应多个句子,评估时通常有两种做法:一是把所有句子拉平,每个句子独立算一次;二是先按目标聚合,再按目标平均。大多数论文用的是第一种,因为更简单,而且句子数量本身反映了数据分布。
另外,如果一张图里有多个同类实例,模型可能预测了错误的那个。这时候即使预测框和某个实例 IoU 很高,只要不是目标实例,就算错。所以 RefCOCO 本质上是一个实例级的评估,不是类别级。
4.3 与 COCO mAP 的区别
COCO mAP 是类别平均,只要检测到同类物体就算对,不区分是哪一个。RefCOCO 是实例平均,必须找到指定的那一个。这就是为什么很多在 COCO 上 mAP 很高的模型,在 RefCOCO 上表现一般。因为 COCO 允许“差不多就行”,RefCOCO 要求“就是它”。
我实测过一个在 COCO 上 AP 超过 45 的检测器,直接拿来做 RefCOCO 的框预测,Acc@0.5 只有 30 出头。原因就是它没有语言理解能力,只能靠类别先验猜,遇到多个同类实例就随机选一个。
5. 实操加载与训练流程
5.1 环境准备与数据下载
先装好 Python 环境,建议用 conda 建一个独立环境。需要的主要库包括numpy、Pillow、pycocotools、torch、torchvision。如果你要做分割,还要装opencv-python或pycocotools自带的分割工具。
数据下载方面,RefCOCO 的官方页面提供压缩包,但链接有时会变。常见做法是从 COCO 官网下载 train2014 和 val2014 图像,再单独下载 RefCOCO 的标注文件。标注文件不大,几十 MB,图像集则有好几 GB。
# 以 COCO 2014 为例,下载训练和验证图像 wget http://images.cocodataset.org/zips/train2014.zip wget http://images.cocodataset.org/zips/val2014.zip unzip train2014.zip unzip val2014.zipRefCOCO 标注文件通常命名为refcoco.zip或类似,解压后得到refs(unc).p等文件。把它们放到一个data/refcoco/目录下,图像放到data/coco/下。
5.2 用 Python 加载 RefCOCO 标注
下面是一个最小加载示例,帮你把 refs 和 instances 对上:
import pickle import json from pycocotools.coco import COCO # 加载 RefCOCO 标注 with open('data/refcoco/refs(unc).p', 'rb') as f: refs = pickle.load(f) # 加载 COCO 实例标注 coco = COCO('data/coco/annotations/instances_train2014.json') # 取第一条样本 ref = refs[0] ann_id = ref['ann_id'] ann = coco.loadAnns(ann_id)[0] img = coco.loadImgs(ann['image_id'])[0] print('句子:', [s['sent'] for s in ref['sentences']]) print('图像文件:', img['file_name']) print('目标框:', ann['bbox']) print('分割掩码 RLE 长度:', len(ann['segmentation']['counts']))这段代码能让你快速看到一条样本的全貌。注意refs(unc).p里的ann_id是整数,直接传给loadAnns即可。如果报错说找不到,检查一下 instances 文件是不是 train2014 的,因为 RefCOCO 的 train split 可能跨了 COCO 的 train 和 val 图像。
5.3 构建训练数据管道
训练时,你需要把图像、指代句子和目标掩码一起喂给模型。典型流程是:
- 根据
image_id读取图像,做 resize 和归一化。 - 把句子 tokenize,转成词向量或 token IDs。
- 根据
ann_id取出目标掩码,缩放到和图像相同的尺寸。 - 模型输出预测掩码或框,计算损失。
损失函数通常用二值交叉熵做分割,或者用 L1 + GIoU 做框回归。如果是多模态模型,还会加一个对比损失,让图像特征和文本特征对齐。
import torch from torch.utils.data import Dataset from PIL import Image import numpy as np class RefCOCODataset(Dataset): def __init__(self, refs, coco, img_dir, transform=None): self.refs = refs self.coco = coco self.img_dir = img_dir self.transform = transform def __len__(self): return len(self.refs) def __getitem__(self, idx): ref = self.refs[idx] ann = self.coco.loadAnns(ref['ann_id'])[0] img_info = self.coco.loadImgs(ann['image_id'])[0] img_path = f"{self.img_dir}/{img_info['file_name']}" image = Image.open(img_path).convert('RGB') mask = self.coco.annToMask(ann) sentence = ref['sentences'][0]['sent'] if self.transform: image = self.transform(image) return image, sentence, torch.from_numpy(mask).float()这个 Dataset 是最简版本,实际训练时还要处理句子长度不一、掩码尺寸对齐、数据增强等问题。但骨架就是这样,先跑通再优化。
5.4 训练中的关键参数与经验值
根据我自己的实验和常见论文配置,RefCOCO 训练有几个经验值可以参考:
| 参数 | 常见取值 | 说明 |
|---|---|---|
| 输入图像尺寸 | 416x416 或 512x512 | 太大显存吃不消,太小掩码精度下降 |
| 批量大小 | 8-16 | 取决于显存,RefCOCO 图像分辨率不低 |
| 学习率 | 1e-4 到 5e-5 | 用 Adam 或 AdamW |
| 训练轮数 | 20-40 | 通常 30 轮左右收敛 |
| 文本编码器 | BERT-base 或 LSTM | BERT 效果更好但更吃显存 |
| 分割头 | 3 层卷积 + 上采样 | 输出和输入同尺寸的掩码 |
注意:RefCOCO 的句子长度差异很大,RefCOCOg 尤其长。如果直接用固定长度截断,会丢失关键信息。建议用动态 padding,或者把最大长度设到 40 以上。
6. 常见问题与排查技巧实录
6.1 加载标注时报 KeyError
最常见的原因是ann_id在 instances 文件里找不到。RefCOCO 的标注可能引用了 COCO train2014 和 val2014 两个图像集,如果你只加载了其中一个 instances 文件,就会缺一部分。解决办法是把两个 instances 合并,或者根据 split 分别加载。
另一个原因是 pickle 文件版本不兼容。Python 2 和 Python 3 的 pickle 协议不同,如果下载的是老版本文件,可能需要用encoding='latin1'参数:
with open('refs(unc).p', 'rb') as f: refs = pickle.load(f, encoding='latin1')6.2 图像和掩码尺寸对不上
COCO 的annToMask返回的掩码尺寸是原始图像尺寸。如果你在 transform 里把图像 resize 了,掩码也要同步 resize,而且要用最近邻插值,不能用双线性,否则边缘会糊。
import cv2 mask = coco.annToMask(ann) mask_resized = cv2.resize(mask, (new_w, new_h), interpolation=cv2.INTER_NEAREST)6.3 评估指标忽高忽低
如果 Acc@0.5 波动很大,先检查是不是随机种子没固定。RefCOCO 的样本顺序如果每次不一样,加上模型有随机 dropout,结果就会跳。固定torch.manual_seed和numpy.random.seed能缓解。
其次检查 IoU 计算方式。框 IoU 和掩码 IoU 差别很大,掩码 IoU 通常更低。如果你用框 IoU 评估一个分割模型,指标会虚高。论文里如果没写清楚,对比时容易吃亏。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| 加载 refs 报错 | pickle 版本不兼容 | 加 encoding='latin1' |
| ann_id 找不到 | instances 文件不完整 | 合并 train 和 val 的 instances |
| 掩码全黑 | annToMask 用错 ann_id | 打印 ann 确认 segmentation 存在 |
| 训练 loss 不降 | 学习率太大或文本编码器没冻结 | 先冻结文本编码器,只训分割头 |
| 验证指标为 0 | split 用错 | 确认 val 集有公开标注 |
| 显存溢出 | 图像尺寸太大 | 降到 416 或 320 |
6.5 独家避坑技巧
第一,RefCOCO 的 test 集没有公开标注,但很多人会偷偷用 val 集当 test。如果你要对比论文,最好确认对方用的是哪个 split。有些论文写“RefCOCO test”,其实是 val,这种细节在复现时很致命。
第二,RefCOCO+ 禁止位置词,但标注里偶尔还是会出现“left”这种词,因为标注员可能没严格遵守。训练时如果发现模型过度依赖位置词,可以手动过滤掉包含位置词的句子,做一个更干净的子集。
第三,RefCOCOg 的句子很长,用 LSTM 编码容易遗忘前面的信息。如果资源允许,直接上 BERT 或 RoBERTa,效果提升明显。我试过同一个分割头,换文本编码器后 Acc@0.5 能差 5 个点以上。
第四,数据增强要小心。随机裁剪可能把目标裁掉,随机翻转会改变“左边”“右边”的语义。如果一定要翻转,记得把句子里的位置词也换掉,否则模型会学到错误对应。
7. 与其他数据集的配合使用与扩展思路
RefCOCO 不是孤立的。做多模态定位时,通常会把它和 COCO、Visual Genome、Flickr30k Entities 一起用。COCO 提供类别级检测能力,Visual Genome 提供更密集的区域描述,Flickr30k 提供图像-句子对。RefCOCO 则专注于实例级指代。
如果你在做 YOLO 系列的自定义训练,想扩展到指代任务,可以把 RefCOCO 的框标注转成 YOLO 格式,加上文本输入分支。不过 YOLO 本身没有语言理解能力,需要额外接一个文本编码器,再把文本特征融合到检测头。这个改造工作量不小,但思路是通的。
另一个方向是零样本指代分割。用 CLIP 这类视觉语言模型做 backbone,不训练或只微调少量参数,直接在 RefCOCO 上评估。这类方法在 RefCOCOg 上表现通常不如全监督,但泛化能力更强。
提示:如果你只是想把 RefCOCO 当练手项目,建议先从 RefCOCO 的 val 集开始,用一个小模型跑通全流程,再逐步换大模型和复杂结构。不要一上来就复现 SOTA,容易卡在数据加载上。
我个人在实际操作中的体会是,RefCOCO 的难点不在模型结构,而在数据管道的细节。标注文件、图像路径、split 划分、掩码对齐,任何一环出错都会导致指标异常。先把这些基础打牢,再谈模型创新,会稳很多。