颈椎骨折CT检测挑战赛 — 十二机构三千例的逐椎骨标注

3,112 例颈椎 CT / C1–C7 逐椎骨标签 / 9 国 12 机构

来源 https://www.kaggle.com/competitions/rsna-2022-cervical-spine-fracture-detection/发布时间: 2026-10-26最后更新: 2026-10-26 阅读 4
颈椎骨折CT检测挑战赛 — 十二机构三千例的逐椎骨标注

信息速览

数据集名称颈椎骨折CT检测挑战赛 — 十二机构三千例的逐椎骨标注
数据类型原始影像,人工标注,元数据,补充材料
规模3,112 例颈椎 CT(骨折阳性 1,445 例 + 阴性 1,667 例),患者级去重数量官方未给出
接入方式https://www.kaggle.com/competitions/rsna-2022-cervical-spine-fracture-detection/
AI 就绪度

RSNA 2022 颈椎骨折 AI 挑战赛的数据集,在「公开可用的颈椎骨折 CT」这一格子里几乎是唯一的选项。它由北美放射学会联合美国神经放射学会、美国脊柱放射学会共同组织,六大洲十二家机构贡献影像,共三千一百一十二例轴位平扫颈椎 CT,阳性与阴性大致对半。

它真正稀缺的地方不是体量,而是标签的粒度。多数公开骨折集只回答「这张片子有没有骨折」,它把每一例拆成八个 0/1 字段:一个整例判定加 C1 到 C7 逐节椎骨的判定。模型必须同时说对「有没有」和「在哪一节」,这让「按解剖单元结构化标注」这件事第一次有了足够大的公开样本可依。

本页覆盖它的规模与结构、标注是怎么被设计出来的、评测指标为何特殊、外部验证掉点掉在哪里,以及在什么条件下不该选它。一屏速览见下表。

对象 维度 内容
1 官方名称 RSNA 2022 Cervical Spine Fracture Detection Challenge
2 主办 RSNA,联合 ASNR(美国神经放射学会)与 ASSR(美国脊柱放射学会)
3 平台与赛期 Kaggle,2022-07-28 至 2022-10-27
4 总量 三千一百余例颈椎 CT(文献口径),主办方页面称「超过一千四百例阳性」
5 阳性 / 阴性 阳性一千四百余例、阴性一千六百余例(论文口径)
6 影像条件 轴位平扫,1 mm 层厚;排除增强、既往术后、运动伪影、覆盖不全
7 标签层级 整例级 + 椎骨级(C1–C7)→ 边界框级 → 椎骨分割级,共四层
8 椎骨级标签量 每例 8 个二值字段,即整例 1 个加 7 节椎骨,总计约两万五千个判定
9 边界框覆盖 235 例,约合阳性病例的 16%
10 分割掩膜 NIfTI,标签值 1–7 为 C1–C7,8–19 为 T1–T12
11 训练 / 公共测试 / 私有测试 2,019 / 304 / 789 例(合计与总数差 0,三份互斥)
12 参赛规模 一千一百余名参赛者、八百八十余支队伍、近一万三千次提交
13 头部成绩 前八名平均 AUC 0.96、F1 90%、敏感度 88%、特异度 94%(私有测试集)
14 参照基线 此前已发表模型最高 AUC 0.85、F1 81%(同期综述口径)
15 本地形态 原包 DICOM 逐层存放;社区常用 npz 把整例压成单文件,约 16 GB 量级
16 许可 Kaggle 竞赛数据条款,非商业用途,免费获取
17 私有测试集 不公开,至今未放出

§1 它要解决的具体麻烦

1.1 颈椎骨折是一个「错了就不可逆」的读片任务

颈椎骨折在创伤影像里的地位有点特殊。它不像肺结节那样有随访余地,也不像骨折愈合那样有影像复查窗口。急诊颈椎 CT 上漏掉一处不稳定骨折,患者可能在搬运、翻身、插管的任何一个环节发生移位,后果是脊髓损伤乃至瘫痪。论文里给的数字是,颈椎骨折中约一成到一成一最终合并脊髓损伤。

同一批文献还指出另一面:美国每年新发椎体压缩骨折超过一百五十万例,而放射学上可见的椎体骨折中只有四分之一到三分之一在临床上被诊断出来。这个落差说明漏诊不是个别医生的疏忽,而是读片流程本身的系统性短缺——片子太多、层数太厚、时间太紧。

AI 在这个环节的位置因此很明确:不是替代判读,而是把「可能有骨折」的候选层提前推到阅片者眼前,降低纯视觉搜索的漏检率。这也是挑战赛设立的初衷,主办方在官方页面上把它表述为「帮助检测与定位」,不是「帮助诊断」。

1.2 三条常见的错误期待

第一条期待是「它能给我一个可以上线的检测器」。这是最普遍的误解。竞赛头部的分数确实漂亮,但那是同一批数据分布下的私有测试集成绩。后续两项独立外部验证都显示,同一个模型换一家医院、换一种扫描协议,敏感度会掉到六成七到八成六的区间,特异度掉得更狠,增强扫描上甚至有模型的敏感度只剩三成。

第二条期待是「它能让模型精确指出骨折线的位置」。它给了边界框,但只覆盖阳性病例里的一小部分,而且框是轴位切层上的二维矩形,不是三维的病灶体。想要「骨折线贴在哪个骨皮质、延伸几毫米」这一级的输出,这个数据集给不出来。

第三条期待是「三千例拿来从头预训练应该很稳」。这个规模在三维医学影像里只算中等;按椎骨级正例折算,可学的骨折灶只有一千多处,分摊到七节椎骨后每节不过一两百处,最冷门的节段更少。

1.3 它能给到的与给不到的

你的需求 它给的 够不够
判断整例有无颈椎骨折 每例一个 patient_overall 0/1 够,且是目前公开集里质量最高的一档
定位到具体哪一节椎骨骨折 C1–C7 七个 0/1 字段 够,但只在报告提及的层级上可信
给出骨折区域的空间位置 235 例的轴位二维框 勉强,覆盖约六分之一阳性例
做椎骨自动分割/编号 NIfTI 掩膜,标签 1–19 够做分割,但只覆盖训练集的一个子集
做骨折的逐体素分割 无 不够,完全给不到
判断骨折的新鲜与陈旧 无此字段 不够,急慢性混为一谈
评估模型在多国人群上的泛化 九国十二机构、跨六大洲的影像 够做分布多样性参照,不够做跨站点严格验证
直接套用到本地厚层或增强扫描 不覆盖此类协议 不够,需要自建本地测试集
复现竞赛的官方排名 评测公式公开、私有测试集不公开 公式能复现,排名不能

1.4 你的处境与它能帮到的事

这张表按「你现在手上是什么活」来排,而不是按数据集有什么来排。三种处境对应三种完全不同的用法,混着用是最常见的浪费。

你的处境 它能帮你什么 下一步该做什么
要给急诊科做一个「可疑骨折」的候选提示工具 提供足够大的多机构训练样本与一个漏诊导向的评测公式 先按 §9.2 的最短流程跑通基线,再用本院一年的连续急诊扫描做外部测试
要在自己的医院重建一套椎骨级标注规范 它的四层混合标注架构可以直接借:整例→椎骨→框→分割 重点读 §3.3 与 §7.3,把「报告为真」与「可以争议」两个机制一起搬过去
要评测一个已有的 3D 检测模型 一个分布明确、格式规整的公开基准 用官方加权 log loss 打分,同时报一层不加权的敏感度特异度,避免被单一指标带偏
数据只有厚层重建或增强扫描 训练样本的成像条件与你的不一致 不要直接微调后上线;先在本地小样本上量一次掉点,再决定是否需要域适应
想做骨折的像素级分割研究 只能借椎骨掩膜做定位先验 另找带骨折体素掩膜的数据集,把本集当作预训练或定位模块
需要一个可发表的多中心基准来证明泛化 九国十二机构的来源构成足以支撑「多中心」表述 但要在方法里说明它的患病率被人为调整过,不能当自然分布样本
教学场景,想给学生讲结构化标注 层级设计干净、字段少、易解释 直接用 §2.2 的字典表当讲义,配一例真实数据走一遍

1.5 一句话判断

它是目前唯一一个把「有没有骨折」拆到「哪一节椎骨骨折」并公开到可下载程度的颈椎 CT 数据集;拿它训练可以,拿它当绝对真相或者当性能承诺都不行。

1.6 不适合谁:四条边界

第一条,不适合想跳过本地验证直接采购或部署的团队。它的四成多患病率是人为调的,任何基于该数据集训练的模型输出的概率值都带着这个先验,直接拿到真实急诊(患病率约百分之四到七)会把阈值全部推错。这不是模型的错,是样本构成的错。

第二条,不适合做增强扫描或厚层重建的团队。纳入条件是轴位平扫一毫米层厚,静脉对比剂、覆盖不全、既往手术与运动伪影均被排除。设备若常规出三到五毫米层厚,训练与推理的分布从一开始就错位。

第三条,不适合把「临床可用」当作验收标准的项目。它的金标准主干是原始放射科报告,报告之后才被看出来的骨折仍按阴性计。换句话说,它测的是「模型能否复现当时放射科医生的判断」,不是「模型能否发现所有真实存在的骨折」。后者恰恰是漏诊改进研究才关心的事,而那个层次的真相,本数据集并不提供。

第四条,不适合需要骨折亚型或稳定性判断的研究。它只有「有/无」,没有 AO 分型、没有韧带损伤、没有椎管占位程度、没有爆裂骨折与压缩骨折的区分。任何需要回答「这处骨折稳不稳、要不要固定」的任务,它都无能为力。

§2 数据构成与规格

2.1 总量口径:官方说的和论文说的并不完全一致

这里必须先说明一个口径差。主办方 RSNA 的挑战赛页面写的是「收集自六大洲十二个站点的影像,包含超过一千四百例已诊断颈椎骨折的 CT,以及大致同等数量的阴性检查」。而 2023 年发表在 Radiology: Artificial Intelligence 上的数据集论文给出的是精确数:总计三千一百一十二例,其中阳性一千四百四十五例、阴性一千六百六十七例。

两句话并不冲突,官方页面用的是约数并向下取整。本页在需要精确值时用论文口径,在叙述机构来源时用官方口径。另有一项外部验证研究把机构分布写得更细:北美五家、南美一家、欧洲三家、非洲一家、亚洲一家、澳洲一家,合计十二家,跨越六大洲。

关于「十二国」与「十二机构」的对应关系,论文的表述是「12 institutions across nine countries and six continents」,而验证论文与官方页面只说十二家机构、六大洲。也就是说国家数是九个而不是十二个,因为个别国家贡献了不止一家机构。这一点在引用时容易被写成「十二国」,需要留意。

口径来源 总数 阳性 阴性 国家数
RSNA 官方挑战赛页 未给总数 超过一千四百例 「大致相当」 未给
数据集论文(Radiology: AI 2023) 3,112 1,445 1,667 9
成绩评估论文(Radiology: AI 2024) 同左 同左 同左 未给
外部验证论文(Radiology: AI 2024) 同左 同左 同左 未给
社区镜像与竞赛页 同左 — — —

2.2 字段与记录的完整字典

数据集里有四类资产:DICOM 影像目录、两份 CSV 标签表、NIfTI 分割掩膜。下面这张表把每一类里出现的字段逐条列出,包括数据类型与含义。这是从数据集论文的「Dataset Description and Usage」一节逐段拆出来的,不是从社区 notebooks 里抄的。

资产 字段 / 元素 类型 含义与取值
DICOM 目录 顶层目录名 字符串 等于 StudyInstanceUID 的值,一例检查一个目录
DICOM 目录 目录内文件名 字符串 等于 InstanceNumber 的值,即该层在扫描栈中的位置,加 .dcm
DICOM 头 StudyInstanceUID DICOM 标签 检查级唯一标识,也是全表的连接键
DICOM 头 InstanceNumber DICOM 标签 层序编号,决定轴位堆叠顺序
DICOM 头 层厚、像素间距 DICOM 标签 纳入时统一为 1 mm 层厚,其余元信息随原始采集保留
标签表一 StudyInstanceUID 字符串 主键,一行一例检查
标签表一 patient_overall 整数 0/1 该例任一颈椎节段是否被报告为骨折
标签表一 C1 整数 0/1 C1 是否被报告为骨折
标签表一 C2 整数 0/1 C2 是否被报告为骨折
标签表一 C3 整数 0/1 C3 是否被报告为骨折
标签表一 C4 整数 0/1 C4 是否被报告为骨折
标签表一 C5 整数 0/1 C5 是否被报告为骨折
标签表一 C6 整数 0/1 C6 是否被报告为骨折
标签表一 C7 整数 0/1 C7 是否被报告为骨折
标签表二 StudyInstanceUID 字符串 主键,与外层目录对应
标签表二 x 整数(像素) 边界框左上角横坐标,即最靠近 (0,0) 的点
标签表二 y 整数(像素) 边界框左上角纵坐标
标签表二 width 整数(像素) 边界框宽度
标签表二 height 整数(像素) 边界框高度
标签表二 slice_number 整数 该框所在的轴位层号,拼上 .dcm 即文件名
分割文件 文件名 字符串 等于 StudyInstanceUID 加 .nii(或 .nii.gz)
分割体素 标签值 0 整数 非椎体结构
分割体素 标签值 1–7 整数 C1 到 C7 对应椎骨
分割体素 标签值 8–19 整数 T1 到 T12 对应胸椎,纳入与否因例而异
分割体素 分割平面 属性 掩膜在矢状面上生成,DICOM 是轴位,需按 NIfTI 头信息对齐

2.3 一条记录的完整解剖

从打开一个目录到拿到一个可训练的张量,中间要走五步,每一步都有坑。下面用一例虚构但结构完全合规的记录来走一遍,字段名与真实数据一致。

先看标签层。假设某例检查的 StudyInstanceUID 末尾为 a1b2c3,标签表里这一行是:patient_overall 为 1,C1 到 C7 依次是 0、0、0、0、1、0、1。这说明该例有两节骨折,C5 与 C7。注意 patient_overall 不是 C1 到 C7 的求和,它来自报告的整体结论,在极少数情况下报告写了阳性但逐节未指明,这时的逐节字段与整例字段可能不完全自洽。

StudyInstanceUID,patient_overall,C1,C2,C3,C4,C5,C6,C7
1.2.826.0.1.3680043.8.498.a1b2c3,1,0,0,0,0,1,0,1

再看空间标注。同一例如果落在有框的子集里,边界框表会为该例的每一处骨折在若干层上各给一行。x、y、width、height 都是像素坐标,slice_number 是层号。框是二维的,跨层由后面的插值规则补齐。

StudyInstanceUID,x,y,width,height,slice_number
1.2.826.0.1.3680043.8.498.a1b2c3,203,178,41,36,142
1.2.826.0.1.3680043.8.498.a1b2c3,201,176,44,38,143
1.2.826.0.1.3680043.8.498.a1b2c3,198,174,46,40,144

第三步是把 DICOM 层堆成体。目录内的文件名不是顺序编号,而是 InstanceNumber,读取时必须按数值排序,不能按字符串排序,否则会出现 1、10、100、101 排在 2 前面这种乱序,重建出的体数据在 z 轴上被彻底打乱。这一类错误在初学者的流程里非常常见,因为它不会报错,只会让模型的 z 轴学习变得毫无意义。

第四步是处理分割掩膜的朝向。论文特别点了这件事:NIfTI 是在矢状面上生成的,DICOM 是轴位,两者要对齐必须读 NIfTI 头里的方向信息。如果不读,掩膜可能在 z 轴上被翻转,或者在 x 轴上被镜像,而影像看起来仍然是「一张脊柱 CT」,肉眼极难发现,模型学到的却是错位的空间关系。

第五步是窗宽窗位与重采样。原始数据是 Hounsfield 值,骨窗常用窗宽两千、窗位四五百,软组织窗完全看不出骨折线。如果要做多分辨率训练,各向异性的层内像素间距与层间距必须先对齐,常见做法是统一重采样到一毫米立方,但这会显著增加显存占用。

2.4 三个切分与其标签分布

竞赛把三千一百一十二例切成三份:训练集两千零一十九例、公共测试集三百零四例、私有测试集七百八十九例,三份之和正好等于总数,互不重叠。切分方式是按机构、年龄组、性别、骨折椎骨做分层随机抽样,目的是避免某一站点或某个年龄段在训练与测试之间失衡。

切分 例数 阳性和例数 阳性率 骨折灶总数 阳性例平均骨折数
训练集 2,019 961 47.6% 1,444 1.50
公共测试集 304 122 40.1% 175 未在摘要中给出
私有测试集 789 362 45.9% 672 2.86
合计 同左 同左 46.4% 2,291 —

这张表里最值得注意的是最后一列的反差:训练集阳性例平均每例 1.5 处骨折,私有测试集却是 2.86 处,几乎翻倍。这说明两个测试集被有意做成「更复杂」的样子——多发性骨折更难,单灶病例相对容易。也因此,竞赛分数不能直接与训练集上的交叉验证分数相比,两者测的根本不是同一难度的问题。

另一处值得注意的是阳性率。三份数据的阳性率都在四成到四成八之间,而真实急诊的颈椎骨折患病率只有百分之四到七。参赛者拿到的数据被刻意做成了近似平衡的分类任务,这与临床部署时的极不平衡先验完全是两回事。

2.5 与同类资源的字段差异

把本集放到已有的脊柱影像资源里比较,差异会非常清楚地浮现。下表只比较字段层面的可获取性,不比较数据质量高低。

资源 影像模态 逐椎骨标签 空间框 体素分割 骨折新鲜度 多中心
本集 颈椎 CT 平扫 有(C1–C7) 有(约两百余例) 仅椎骨 无 十二家机构
VerSe 脊柱 CT 大视野 有(编号) 无 有(椎骨实例) 有 Genant 分级(子集) 多中心
CTSpine1K 脊柱 CT 有(编号) 无 有(椎骨实例) 无 多来源拼接
RibFrac 胸部 CT 不适用 有(三维框) 有(骨折实例) 无 单牵头中心
VinDr-SpineXR 脊柱 X 线 不适用 有(二维框) 无 无 双院
CT-ICH 类颅内出血集 头颅 CT 不适用 无 无 无 视具体集

读这张表要注意一个事实:VerSe 与 CTSpine1K 的逐椎骨标签是「编号」,回答的是「这是第几节椎骨」,本集的逐椎骨标签是「状态」,回答的是「这一节有没有骨折」。两者在字段名上都是 C1 到 C7,但语义完全不同。把 VerSe 的标签用来训练骨折检测,会得到一组永远平衡、没有信息量的负样本。

§3 核心层一:这个数据集的身份

3.1 它是一次挑战赛的产物,而不是一次数据发布

理解它的身份,先要理解它的来路。它不是某个实验室整理完就挂到 figshare 上的数据集,而是围绕一次比赛生产的。比赛有赛期、有排行榜、有奖金、有颁奖典礼,数据是服务于这些的。这带来三个直接后果。

第一,数据被切成训练与两个测试集,且测试集标签不公开。私有测试集至今没有放出,这意味着任何声称「在本数据集测试集上达到某个分数」的外部研究,说的其实是自己划的验证集,不是官方测试集。第二,数据被刻意调过分布,阳性率约一半,为的是让排行榜分数有区分度。第三,数据在赛后仍可下载,但条款是竞赛数据条款,而不是学术通用的开放许可。

这三条都不是缺点,是设计选择的自然结果。问题只在于很多人直接下载了训练集就开始训练,从没读过这些选择,于是把竞赛分数当成了临床性能的预期。

3.2 谁做的、为什么做、可不可信

主办方是北美放射学会,这是全球规模最大的放射学专业组织之一,其年度会议是影像 AI 领域的重要发布场合。协办的两个学会分别是美国神经放射学会与美国脊柱放射学会,前者代表神经影像的专科视角,后者代表脊柱影像的专科视角。这个组合说明数据集的设计初衷不是「做一个通用影像集」,而是「把脊柱放射专科医师的判断标准化成可学习的标签」。

论文作者来自多伦多圣迈克尔医院与多伦多大学医学影像系,通讯作者是 Hui Ming Lin。资助方包括美国国家癌症研究所的 R01 项目,以及多伦多圣迈克尔医院的 Odette 人工智能讲席教授基金。数据策展与标注贡献者名单在论文末尾列出,包含二十余名策展贡献者与四十余名 ASNR/ASSR 志愿标注医师。

可信度可以从三个旁证判断:论文发表在 RSNA 自办的 Radiology: Artificial Intelligence 上,属于同行评议期刊;数据被至少三项独立研究用作外部评估的基准;竞赛在 Kaggle 上是公开赛事,一千一百余名参赛者、近一万三千次提交,任何明显的标注错误都会在社区里被迅速发现。

3.3 标注架构:四层混合,是一套可借鉴的工程方案

这是整个数据集最值得细看的地方,也是它区别于其他公开骨折集的核心。论文把标注策略称为「hybrid schema」,从病人级到像素级分四层,每一层的覆盖范围不同。

层级 覆盖范围 标注内容 怎么做出来的
整例级 全部三千余例 有无任何颈椎骨折 原始放射科报告的整体结论
椎骨级 全部三千余例 C1–C7 各自有无骨折 从原始报告抽取具体节段
边界框级 235 例(阳性例的约 16%) 轴位二维矩形 志愿医师在网页平台画框
分割级 训练集的一个子集 椎骨编号 1–19 由标注或算法生成后人工确认

这套架构的巧思在于「前置标注负担」。传统做法是让专家从零开始看片子、画框、做分割,一例要几十分钟。这里换了个做法:先由各贡献机构在临床工作中产出的放射科报告作为主干标签,再让志愿医师做质量复核而不是从零标注。论文原话的意思是,临床当时的报告是最准确的评估,因为那一刻放射科医生的注意力最集中。

代价是标注者与金标准报告之间的分歧。针对这一点,论文设计了一个允许「申诉」的机制:志愿标注者如果不同意报告结论,可以提出异议,由组织委员会成员仲裁。这个机制看似小事,实际上是把「标注不一致」从数据噪声变成了可记录的流程产物。

边界框的产生也有讲究。最初让标注者逐层画框,一致性很差。后来改为只在骨折模式横截面面积出现局部极大或极小的「关键层」画框,然后在相邻关键层之间插值补齐。这样既省时间,又保证了层间的连续性。最终的金标准框不是取平均,而是取「所有个体框的最大包络」,论文明确说这是为了偏向敏感度。

3.4 四层标签各自的受众

这套四层设计并不是为了让一个模型同时学会四件事,而是让不同能力的研究者各取所需。

层级 适合谁 能训出什么 学不到的
整例级 做筛查分流的产品团队 二分类提示器 位置
椎骨级 做结构化报告的研究者 多标签分类器 骨折形态
边界框级 做 3D 检测的算法团队 轴位检测头 三维病灶体
分割级 做椎骨定位与配准的团队 椎骨分割器 任何骨折信息

值得注意的是,分割层与骨折层是解耦的。分割掩膜标的是椎骨编号,不是骨折灶;它存在的目的是帮助模型定位「这是第几节椎骨」,从而把椎骨级分类变成一个「先定位再判定」的两阶段任务。论文在讨论部分明确说,提供分割掩膜是为了让算法学会检测骨折所在层级。

§4 核心层二:它的质量与特色

4.1 分层抽样与「难度错位」的设计

数据切分用的是分层随机抽样,分层变量是机构、年龄组、性别、骨折椎骨。这四个变量恰好对应四类最常见的混杂:机构差异带来设备与协议差异,年龄组带来骨密度与退变程度差异,性别影响骨量与体型,骨折椎骨则直接影响类别不平衡。

论文强调这样做是为了「减轻训练与外部或内部测试之间意外的性能下降」。但如 §2.4 所揭示,训练集与私有测试集在「每例骨折数」上有明显差异,训练集平均 1.5 处、私有测试集平均 2.86 处。这不是抽样失误,而是测试集的难度被有意加大了。

对使用者来说,这个设计有一个具体后果:如果你从训练集里切出验证集来调参,得到的分数会系统性偏乐观,因为验证集里的阳性例大多是单灶、相对好找。真正接近竞赛难度的评估,需要在本地构造一个「多灶病例占比更高」的测试集。

4.2 真实世界的骨折分布被保留了

尽管患病率被调平,骨折在各椎骨上的分布却保留了下来。论文给了一组很有说服力的对照:一项覆盖二十一家机构的多中心研究发现,钝性创伤颈椎骨折中最常见的三个节段是 C2、C6、C7,三者合计占全部骨折的 63.3%。本数据集中这三个节段同样最常见(其中 C7 居首),合计占 62.4%。两个数字相差不到一个百分点。

这件事的意义在于,模型学到的椎骨级先验与真实世界一致。如果数据集的骨折集中在某几节而真实世界集中在另几节,模型在临床上的层级判定会系统性偏移。作者显然意识到了这一点,并在切分时把「骨折椎骨」列为分层变量。

观察项 真实世界多中心研究 本数据集 差值
前三大常见节段 C2、C6、C7 C6、C7、C2(C7 居首) 集合相同
三者合计占比 63.3% 62.4% 0.9 个百分点
C4 相对表现 未单独报告 各模型中最低 —

有意思的是,成绩评估论文发现前八名模型在 C4 上的表现显著低于 C1、C2 与 C7。这可以部分解释为 C4 在分布中相对少见,样本少导致学得差;也可以解释为 C4 的解剖位置靠近常见的退变区域,视觉混淆更强。两种解释都可能成立,论文没有下结论。

4.3 案例:一例 C5 与 C7 双灶骨折如何在四层标签里留下痕迹

用一个虚构病例说明这套标注体系如何运作。病例代号 CASE-C5C7:六十岁男性,跌倒后颈痛,急诊颈椎 CT 平扫,报告为「C5 右侧椎板骨折,C7 左侧横突骨折」,无脊髓压迫。

整例层 patient_overall 为 1;椎骨层 C5 与 C7 置 1,其余五列为 0。这两行标签已经足以支撑一个多标签分类任务。

若它落在有框的子集里,C5 与 C7 的骨折会在各自面积最大的几层上各得一个框,层间由插值补齐。横突在轴位上靠外且细长,框的宽高比与椎板骨折差别明显,这是可学的形态线索。

若它还有分割掩膜,模型可先用掩膜定位 C5 的连通域,再在域内判定有无骨折,把「哪一节」从分类转为定位。

这一例在四层里的贡献并不均匀:整例与椎骨层只给「有」,框层给「在哪」,分割层给「椎骨轮廓」。§4.3 的案例是「多灶、跨节段、报告可抽」这类最常见阳性病例的缩影。

4.4 质量控制的三个可查环节

第一个环节是任务组内的逐例质检。成绩评估论文提到,任务组的放射科医生对每一例检查都做了质量复核。这一步决定了「标签表里的数字是否与报告一致」,是整个链条的第一道闸。

第二个环节是志愿标注者的训练与再培训。论文描述了初始培训包含示例框、图文流程文档与教学视频,每位标注者先做练习例,练习期的表现按委员会预设的金标准框评估,不达标者重新培训。这是一个可复制的质量控制动作,任何自建标注项目都可以照搬。

第三个环节是分歧仲裁。标注者可以质疑金标准报告,质疑由组织委员会成员裁决。这意味着数据集中可能存在「标注者认为报告错了但未被采纳」的病例,也可能存在「被采纳修正」的病例。论文没有给出这类病例的数量,因此无法评估仲裁对标签的净影响。

4.5 它的特色在于「报告即真相」这一取向

把它的质量与同类资源横向摆在一起,最大的特色并不是影像质量,而是真相的定义方式。

维度 本集的做法 常见做法 后果
真相来源 原始临床报告 + 志愿复核 专家重读全片 成本低、规模大,但继承原报告误差
分歧处理 允许申诉、委员会仲裁 多数投票或直接采用 有记录,但仲裁影响未量化
框的合成 取最大包络 取平均或取交集 偏向敏感度,框偏大
分割来源 椎骨编号,矢状面生成 轴位直接标注 需要对头信息做朝向校正
负面病例 报告为无骨折即入阴性组 双读确认 阴性组可能含漏诊
患病率 调至约一半 保留自然分布 概率输出不可直接用于临床

「报告即真相」是把双刃剑。它让数据集得以做到三千例的规模,付出的代价是阴性的定义变成「当时没被报告」,而不是「确实没有」。

§5 核心层三:怎么把数据取下来并用起来

5.1 获取路径与合规前提

数据在 Kaggle 竞赛页上,赛后保持可下载。获取需要三件事:一个 Kaggle 账号、在竞赛页上点击加入并接受竞赛规则、通过 API token 或网页下载。私有测试集不在可下载范围内,公共测试集也不单独提供标签。

许可方面需要说清两件事。第一,它是 Kaggle 竞赛数据条款,允许免费下载与非商业研究使用,但不是 CC 系列的开放许可,商业用途需要另行接洽。第二,论文本身是订阅制刊物,与数据许可无关;引用时应当分别引用论文与数据。

环节 做什么 需要注意
账号 注册 Kaggle 账号 需邮箱验证
规则 在竞赛页接受竞赛规则 未接受时数据页显示为锁定状态
凭证 生成 API token 放到 ~/.kaggle/kaggle.json 权限建议设为 600
下载 用命令行工具拉取 体积大,建议先拉标签表验证流程
复现 只拉训练集 测试集无标签,拉了也用不上

5.2 命令行下载与完整性检查

最省事的路径是用 Kaggle 官方命令行工具。下面的脚本先拉标签表,再拉影像,最后做一次结构检查。脚本假定你已经把 token 放到默认位置。

#-- 配置:把 token 放到默认位置并收紧权限
mkdir -p ~/.kaggle
cp kaggle.json ~/.kaggle/kaggle.json
chmod 600 ~/.kaggle/kaggle.json

#-- 建工作目录
WORK=~/data/rsna-cspine
mkdir -p "$WORK" && cd "$WORK"

#-- 先只拉标签表,几百 KB,用于验证账号与规则是否已接受
kaggle competitions download -c rsna-2022-cervical-spine-fracture-detection \
  -f train.csv -p .

#-- 确认标签表可用后再拉全量影像(体积很大,建议挂在后台)
kaggle competitions download -c rsna-2022-cervical-spine-fracture-detection \
  -f train.zip -p .

#-- 解压并统计目录数
unzip -q train.zip
find train -maxdepth 1 -mindepth 1 -type d | wc -l

第三行到第四行的顺序很重要。先拉 train.csv 能在几十秒内暴露「规则没接受」「token 权限不对」这类问题;如果一上来就拉全量,等到下载失败时可能已经过去半小时。

5.3 读标签表并对齐切分

标签表本身很小,用 pandas 直接读即可。这一段的关键不是读,而是对齐:后续任何划分都必须按 StudyInstanceUID 做,不能按行或按切片做。

import pandas as pd
from pathlib import Path

root = Path.home() / "data" / "rsna-cspine"
labels = pd.read_csv(root / "train.csv")
levels = [f"C{i}" for i in range(1, 8)]

#-- 逐椎骨标签求和,检验与整例标签是否自洽
labels["n_levels"] = labels[levels].sum(axis=1)
inconsistent = labels[(labels["patient_overall"] == 0) & (labels["n_levels"] > 0)]
print("整例阴性但椎骨阳性的例数:", len(inconsistent))
print("阳性例数:", int(labels["patient_overall"].sum()))
print("每节椎骨的阳性别数:")
print(labels[levels].sum().to_string())

#-- 按 StudyInstanceUID 做患者无关切分,避免同一患者跨集
studies = labels["StudyInstanceUID"].unique()
rng = __import__("numpy").random.default_rng(42)
rng.shuffle(studies)
cut = int(len(studies) * 0.85)
train_ids, val_ids = set(studies[:cut]), set(studies[cut:])
print("训练例数:", len(train_ids), "验证例数:", len(val_ids))

这段代码里那句「整例阴性但椎骨阳性」的检查值得单独说。由于整例标签来自报告的整体结论、椎骨标签来自具体节段描述,两者理论上一致,但报告写法千差万别,实际可能出现少数不自洽的行。跑一次这个检查,能让你对标签的干净程度有个直观的量级判断,而不是凭想象。

5.4 把一例 DICOM 堆成体

读一例的方式有多种,这里用 pydicom 手工堆叠,好处是把层序与几何信息都显式掌握在手里。

import numpy as np
import pydicom
from pathlib import Path

def load_study(study_dir: Path) -> tuple[np.ndarray, np.ndarray]:
    slices = []
    for f in study_dir.glob("*.dcm"):
        ds = pydicom.dcmread(str(f), force=True)
        slices.append(ds)
    #-- 必须按 InstanceNumber 数值排序,不能按文件名排序
    slices.sort(key=lambda d: int(d.InstanceNumber))
    #-- 用 RescaleSlope/Intercept 转成 Hounsfield 单位
    vol = np.stack([
        d.pixel_array.astype(np.float32) * float(getattr(d, "RescaleSlope", 1.0))
        + float(getattr(d, "RescaleIntercept", 0.0))
        for d in slices
    ])
    z = np.array([float(d.SliceLocation) for d in slices], dtype=np.float32)
    dz = np.abs(np.diff(z)).mean() if z.size > 1 else 1.0
    spacing = np.array([float(slices[0].PixelSpacing[0]),
                        float(slices[0].PixelSpacing[1]),
                        float(dz)], dtype=np.float32)
    return vol, spacing

vol, spacing = load_study(Path.home() / "data" / "rsna-cspine" / "train" / "sample_study_id")
print(vol.shape, vol.min(), vol.max(), spacing)

输出的三个数值得逐一核对:形状应当接近「层数 × 512 × 512」,最小值通常在负一千附近(空气),最大值在几百到一千以上(皮质骨)。如果最小值是 0、最大值是四千多,说明没有做 rescale,还是原始像素值,骨窗会完全错位。

5.5 转成 npz 并做骨窗归一化

原始 DICOM 逐层存放,训练时反复读盘会成为瓶颈。社区通行的做法是把每例压成一个 npz,体积从十几 GB 级降到 GB 级,读取速度提升明显。下面这段转换保留骨窗,以 float16 存储,兼顾精度与体积。

import numpy as np
from pathlib import Path

def to_bone_window(vol: np.ndarray, ww: float = 2000.0, wl: float = 400.0) -> np.ndarray:
    lo, hi = wl - ww / 2.0, wl + ww / 2.0
    x = np.clip(vol, lo, hi)
    return ((x - lo) / (hi - lo)).astype(np.float16)

def convert(in_dir: Path, out_dir: Path) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)
    for study_dir in sorted(p for p in in_dir.iterdir() if p.is_dir()):
        out_path = out_dir / f"{study_dir.name}.npz"
        if out_path.exists():
            continue
        vol, spacing = load_study(study_dir)
        np.savez_compressed(out_path,
                            image=to_bone_window(vol),
                            spacing=spacing)
    print("done:", len(list(out_dir.glob("*.npz"))))

convert(Path.home() / "data" / "rsna-cspine" / "train",
        Path.home() / "data" / "rsna-cspine" / "npz")

需要提醒的是,社区流传的 npz 版本并非本页生成,其预处理细节(是否做窗宽窗位、是否重采样、数组顺序是 z-y-x 还是 z-x-y)各家不一。拿别人的 npz 直接训练之前,务必抽一例与原始 DICOM 对照,确认空间顺序与灰度范围,否则模型会学到错误的几何。

5.6 复现官方评分函数

竞赛的评分是一个加权的二值交叉熵,对八个标签分别计算后取平均。关键设计在权重上:整例漏诊的惩罚是逐椎骨漏诊的七倍。理解这一点,才能理解为什么排行榜前面的模型偏向保守。

import numpy as np

def weighted_log_loss(y_true: np.ndarray, y_pred: np.ndarray,
                      weight: float = 7.0, eps: float = 1e-15) -> float:
    #-- y_true / y_pred 形状均为 (n, 8),第 0 列为整例,第 1–7 列为 C1–C7
    p = np.clip(y_pred.astype(np.float64), eps, 1.0 - eps)
    y = y_true.astype(np.float64)
    per_label = -(y * np.log(p) + (1.0 - y) * np.log(1.0 - p))
    #-- 正例(有骨折)按 1 计权,负例按 weight 计权
    w = np.where(y > 0.5, 1.0, weight)
    return float((per_label * w).mean())

rng = np.random.default_rng(0)
y_true = (rng.random((1000, 8)) < 0.35).astype(int)
y_perfect = y_true.astype(float) * 0.999 + 0.0005
y_random = rng.random((1000, 8))
print("满分近似:", round(weighted_log_loss(y_true, y_perfect), 4))
print("随机猜测:", round(weighted_log_loss(y_true, y_random), 4))

第二行注释里那个权重方向容易被写反。竞赛的意图是让「把有骨折的病例判成无骨折」代价更高,也就是负类预测(预测概率低而真实为阳性)要被罚得更重。对照 §5.6 的代码与 §7.0 的讨论一起读,能看清这套指标为什么逼着模型往敏感度一侧靠。

§6 与库内条目的关系

6.1 关系图谱

在千方医数集的脊柱与创伤板块里,这个数据集处在「骨折检测」与「椎骨分割」两条线的交叉点上。把它与邻近资源摆在一起看,各自的定位会更清楚。

邻接资源 模态 与它的关系 互补点
VerSe 脊柱 CT 大视野 同属椎骨级标注,但标的编号不是状态 可借 VerSe 训椎骨分割,再迁到本集做定位
CTSpine1K 脊柱 CT 规模相近,标注同为椎体实例 它的骨折信息为零,适合做预训练底座
RibFrac 胸部 CT 同为骨折检测挑战赛,但骨折级与三维框 可对照两套挑战赛的评测设计差异
VinDr-SpineXR 脊柱 X 线 同为脊柱创伤,模态不同 可作为「平片初筛 + CT 确诊」两级流程的一环
CT-ICH 类头颅出血集 头颅 CT 同为急诊「不能漏」任务 评测思路(漏诊加权)可互相借鉴
3D-IRCADb 腹部 CT 同为 3D 分割,病灶类别不同 无直接互补

从关系图谱上能看出一条清楚的线:本集是唯一一个把「骨折」与「椎骨节段」两个概念在同一张表里绑定的公开资源。VerSe 只有节段没有骨折,RibFrac 只有骨折没有「按椎骨逐节」的组织方式。这个绑定关系正是它的不可替代性所在。

6.2 检索路径

如果要在库内找与它最接近的资源,建议沿三条路径。

第一条按模态与解剖走:CT + 骨骼肌肉影像,会命中 VerSe、CTSpine1K、RibFrac 与本集,这条路径适合做横向对比。第二条按任务类型走:目标检测 + 挑战赛数据集,会命中 RibFrac、本集以及若干非骨折类检测集,适合研究挑战赛的评测设计。第三条按临床场景走:急诊、创伤、漏诊,会命中 CT-ICH 一类词条,适合跨部位借鉴「不能漏」任务的设计经验。

三条路径里,第一条最实用,因为脊柱 CT 的数据工程问题(层序、朝向、重采样、椎骨编号混乱)在各家集上是共通的,读完一篇能少踩一整套坑。

§7 质量评估与局限性

7.0 阅读本节前的一个前置校正

在看任何分数之前,先做一次认知校正:这个数据集上的一切性能数字,测的都是「能否复现当时的报告」,而不是「能否发现所有真实骨折」。 这是一个容易发生的误判。

道理不复杂。金标准的主干是原始放射科报告,报告写「无骨折」的病例就进了阴性组。如果那例其实有一处细微骨折被当时的医生漏了,标签仍然是阴性。模型若正确地检出了它,在评分上反而被算作假阳性。论文自己在局限性里承认了这一点:有些骨折在回顾时可见,但因原始报告未提及,仍按报告处理。

这意味着两件事。其一,竞赛分数高的模型未必是「更会找骨折」的模型,而是「更会复现报告口径」的模型。其二,用本集训练出来的模型去改进漏诊率,是在跟训练标签的噪声对抗,天花板由标签质量决定。后面几节的所有评价,都要放在这个校正之后读。

7.1 五维评分

下面的评分是本页按 DAIMS 框架给出的编辑判断,不是任何官方评分。每一维都附了判断依据,便于你自己复核。

维度 评分(5 分制) 判断依据
规模 4.5 三千余例、九国十二机构,是公开颈椎骨折集里最大的一档
标注深度 3.5 四层架构设计优秀,但框只覆盖阳性例的约六分之一
真相可靠性 3.0 报告即真相,继承报告误差;有仲裁机制但影响未量化
分布代表性 3.0 骨折节段分布贴近真实,患病率却被人为调平
工程可用性 4.0 目录结构规整、字段少、文档清楚;体积大是唯一硬门槛
综合 3.6 定位为「训练与基准的首选」,不是「部署前的最后一道验证」

规模一项给到 4.5 而不是满分,原因是它的患者级去重数量官方没有给出。一例检查不等于一名患者,同一名患者可能有多例随访影像。在按患者做统计或做患者级交叉验证时,缺少这一信息会造成不便。

7.2 指标的特殊性:为什么这里不能用准确率

竞赛用加权对数损失,而不是准确率或 AUC。这不是标新立异,是这个任务的类别结构逼出来的。

第一,八个标签的阳性率差异很大。整例阳性率约四成七,而单节椎骨的阳性率更低,最冷门的节段可能只有百分之几。在这种结构下,一个永远预测「无骨折」的模型,准确率可以做到九成以上,却完全没有临床价值。对数损失对这种「全负预测」的惩罚是直接而猛烈的。

第二,漏诊与误诊的代价严重不对称。把一个有骨折的患者判成无骨折,可能导致患者在没有保护的情况下被搬动;把一个无骨折的患者判成有骨折,代价是多一次复查或一段颈托。前者是不可逆的,后者是可逆的。七倍的整例权重就是把这个不对称写进了公式。

第三,椎骨级判定要求模型具备定位能力。只答对「有骨折」不够,还要答对「在哪一节」。这把一个二分类任务变成了八个标签的联合判定,单一指标无法概括。

指标 对全负预测的惩罚 对定位错误的敏感度 是否被官方采用
准确率 几乎不惩罚 不敏感 否
AUC 中等 不敏感 仅作事后评估
F1 高 中等 仅作事后评估
敏感度/特异度 视阈值 不敏感 仅作事后评估
加权对数损失 高 敏感 是,排行榜唯一指标

7.3 已知的、可枚举的偏差

偏差不是「数据不好」的同义词,它是「数据在某些维度上偏离真实世界」的客观事实。下面按影响程度排列。

扫描协议偏差。 纳入条件是轴位平扫、一毫米层厚。厚层重建、冠状或矢状重建、增强扫描全部不在覆盖范围内。这不是小问题:很多基层医院常规出的是三毫米层厚,一些创伤中心在全身体扫描时会给对比剂。两项外部验证都显示,协议一变,性能就变。其中一项在增强扫描上遇到的特异度最低只有 16.4%。

术后病例缺失偏差。 论文明确说排除了既往颈椎术后的患者,理由是钉棒产生的条纹伪影与解剖结构改变会干扰标注。模型因此从未见过带内固定的颈椎,而这类患者在创伤中心并不罕见,且他们的骨折风险更高。

骨折新鲜度混淆偏差。 急性和慢性骨折被同等对待,表里都记为 1。对创伤筛查来说,陈旧骨折不是需要紧急处理的病变,把它标成阳性会让模型在老年退变人群里大量报警。

患病率偏差。 阳性率约四成七,真实急诊只有百分之四到七。这个偏差对排序类指标(AUC)影响不大,对概率类指标(对数损失、校准曲线)影响巨大。

阳性病例复杂度偏差。 训练集阳性例平均 1.5 处骨折,私有测试集 2.86 处。这意味着在训练集上验证的模型,面临的病例比真正的评测简单。

图像级标注稀疏偏差。 边界框只覆盖两百余例,占阳性例的约六分之一。想让模型学「骨折长什么样」的形态特征,能用的监督信号只有阳性例的六分之一,其余阳性例只有一个「有」字,没有位置。

7.4 外部验证矩阵

外部验证是这个数据集最值得参考的部分,因为它回答了「竞赛分数能否迁移」这个最实际的问题。目前公开的独立验证至少有四项,结论方向一致但幅度不同。

研究 外部数据 规模 敏感度 特异度 关键结论
竞赛内部评估 私有测试集 789 例 88%(均值) 94%(均值) 前八名 AUC 均值 0.96
多伦多一级创伤中心 连续急诊 CT 1,828 例扫描 67.0%(平扫) 92.9%(平扫) 增强扫描上特异度掉到 72.1%
另一家一级创伤中心 100 例配对样本 100 例 86% 70% 特异度掉幅最大,敏感度基本保持
漏诊回顾研究 报告为阴性的连续检查 6,979 例扫描 未报 未报 七个模型中至少四个判阳的三百五十六例里,四十例经复核确为真骨折

这四项放在一起看,得到的图景是:敏感度相对稳健,从八成八掉到六成七到八成六之间;特异度不稳,从九成四掉到七成上下。这个不对称很关键。对一个「不能漏」的筛查工具来说,敏感度的保持是好消息;但特异度掉到七成意味着每十个无骨折患者里有三个会被提示,在急诊高负荷场景下会造成明显的报警疲劳。

第三项研究里还有一组数字特别值得注意:在六千九百七十九例被放射科报告为阴性的检查中,七个模型中有四个以上判阳的有三百五十六例,经两名神经放射医师复核,其中四十例确为真骨折。这四十例里,最常见的漏诊部位是 C7 横突、C5 棘突、C6 棘突。也就是说,人类最容易漏的是附件骨折,而这恰好也是模型相对擅长的地方。

7.5 它为何能持续:一个「真相定义权」形成的正反馈

这个数据集之所以在发布数年后仍是该方向的首选,靠的不是体量,而是它占据了「真相定义权」的位置。

逻辑是这样的:由于它是唯一一个公开的、带椎骨级标签的多中心颈椎骨折集,任何新方法想声称自己在该任务上有效,最自然的选择就是在它上面做对比。对比多了,它就变成了事实上的公共基准。变成了公共基准,新的标注、新的外部验证、新的衍生研究都会围绕它展开,于是它的标签错误被一次次暴露和修正,可用性进一步提高,吸引更多人来用。

这个循环的关键在于「唯一性」。如果出现第二个同量级、同标注粒度的公开集,这个正反馈就会减弱,因为研究者有了替代选项。但从目前的文献看,替代者尚未出现。VerSe 有椎骨但没有骨折,RibFrac 有骨折但不在颈椎,VinDr-SpineXR 是平片。这个空位至今空着,就是它持续存在的根本原因。

回顾 §4.3 的案例可以看得更具体。C5 椎板骨折与 C7 横突骨折在同一例里并存,两处骨折的形态、位置、所在层段都不一样,却共用同一行整例标签。这正是这套标注体系的典型形态:粗层保证规模,细层提供可学的信号。任何想照搬这套架构的团队,都要先想清楚自己的粗层用什么替代;如果没有临床报告可抽取,规模就做不起来。

再看 §4.3 的案例在外部验证里的处境。多灶病例恰是跨机构测试中最容易掉点的一类:退变背景复杂、骨折线细微、附件位置靠外。而外部验证里被模型检出的漏诊病例,最常见的部位正是横突与棘突,与 §4.3 的案例里 C7 横突那一处属于同一类病变。这类病变既是模型的相对强项,也是人类阅片的相对弱项,二者的差距正好构成辅助工具的价值区间。

§8 生态位与历史

8.1 历史沿革:挑战赛序列里的第八站

RSNA 的 AI 挑战赛从 2017 年开始,逐年一个主题。把序列排开看,能看出主办方选题的思路:从单器官的检出开始,逐步走向多结构、多任务、需要空间推理的问题。

年份 挑战主题 模态 任务形态
2017 儿童骨龄 手部 X 线 回归
2018 肺炎检测 胸片 二维检测
2019 颅内出血检测 头颅 CT 多标签分类
2020 肺栓塞检测 胸部 CT 增强 三维检测
2021 脑肿瘤与 COVID-19 MRI / 胸片 分割 / 分类
2022 颈椎骨折检测 颈椎 CT 平扫 逐椎骨多标签 + 定位
2023 腹部创伤检测 腹部 CT 多器官三维检测
2024 腰椎退变分类 腰椎 MRI 多标签分类
2025 颅内动脉瘤检测 头颅 CTA 三维检测
2026 膝关节异常检测 膝 MRI 多标签分类

2022 年这一站的位置有点特殊。它接在肺栓塞之后,两者都是三维检测,但肺栓塞的标签是「血管内有无栓子」,解剖单元是血管树;颈椎骨折的解剖单元是椎骨,是离散的、可编号的、有明确边界的。从「连续管腔」到「离散骨块」,标注的组织方式完全不同。这也是为什么它的椎骨级设计值得单独研究。

值得注意的是 2023 年的腹部创伤挑战赛沿用了类似的思路:把腹部切成若干器官,逐器官判定有无损伤。这与颈椎的「逐椎骨判定」是同一种设计哲学的延续——先按解剖单元切分,再在每个单元内做判定。理解了 2022 年这一站的标注架构,2023 年那一站几乎不用重新学。

8.2 与前后两站在方法论上的继承

从 2022 年往前看,颅内出血那一年确立了「多标签 + 加权对数损失」的评测范式:把一次检查拆成若干互不排斥的亚型,各算各的损失。颈椎骨折站沿用了这套范式,但把标签从「病变亚型」换成了「解剖节段」,这是一个小改动,带来的差别却不小。

亚型标签之间是竞争关系(同一个出血灶不会既是脑实质出血又是蛛网膜下腔出血),节段标签之间则是并列关系(一个人可以同时有 C5 和 C7 骨折)。这决定了后者更适合用 sigmoid 而非 softmax,也决定了后者的阳性率更低、更不平衡。

从 2022 年往后看,腰椎退变那一站延用了「按节段拆分」的思路,但任务变成了多分类——每个节段要判定椎管狭窄、神经根压迫、关节突肥大等多个等级的严重程度。这是同一套解剖切分哲学在更复杂的标签体系上的延伸。

8.3 它在今天的生态位

放到 2026 年的时点看,这个数据集的位置可以用三句话概括。

第一,它是这个任务的公共基准。任何声称在颈椎骨折检测上有效的方法,几乎都会在它上面报一次数。这一点短期内不会改变,因为没有替代品。

第二,它不是部署前的最后一道关。这一点越来越清楚。三项独立外部验证都把「竞赛分数不等于临床性能」这句话坐实了。真正要做临床验证的团队,需要自建本地连续样本测试集,本集只能作为训练与内部对比的底座。

第三,它的价值有一部分转移到了「标注方法论」上。随着越来越多的团队开始自建数据集,这套四层混合标注、报告主干、申诉仲裁、关键层插值、最大包络合成的做法,作为一套可复制的工程方案,参考价值甚至超过了数据本身。

用途 现在是否仍然成立 说明
训练基线模型 成立 仍是首选,规模与标注粒度无出其右
横向对比新方法 成立 已成为事实基准
证明临床可部署 不成立 需本地连续样本外部验证
作为标注规范模板 成立 四层架构可直接借鉴
作为挑战赛评测设计样本 成立 漏诊加权的思路值得复用
作为骨折分割的训练源 不成立 无骨折体素标签

8.4 如果要给它写一段「它从哪里来」

它来自一个很具体的临床窘境:颈椎 CT 读片量大、层数多、退变叠加、时间紧,而漏诊的后果不可逆。它也来自一个很具体的工程判断:让专家从零标注三千例是不现实的,于是把标注负担前移到临床报告,让专家做复核而非创作。

这两个起点共同决定了它的所有特征:规模能做大,因为成本被摊薄了;标注会继承报告误差,因为真相来自报告;图像级标注稀疏,因为志愿医师的时间只够覆盖一小部分;评测偏向漏诊,因为要解决的问题就是漏诊。

理解了这条因果链,它的每一处「局限」都不再像是疏忽,而是取舍。

§9 使用指引

9.1 三种角色的路径

做产品原型的团队。 你的目标是尽快验证「这个提示工具在本院环境下有没有价值」。路径是:先用本集训练一个粗糙的椎骨级多标签模型,不追求 SOTA,两三天能跑通即可;然后立刻转到本院,取连续一年的急诊颈椎 CT,手工标注全部阳性例,构造本地测试集;最后比较本地测试集与公共基准上的敏感度差距。差距就是你需要做域适应的量。不要在本集上反复调参追求排行榜位置,那条路的边际收益很低。

做算法研究的团队。 你的目标是在公开基准上给出可信的对比。路径是:用官方加权对数损失作为主指标,按 StudyInstanceUID 做患者无关切分,在同一份训练集上训练所有对比方法,用同一套阈值选择规则(比如 Youden 指数)确定工作点。同时报一层不加权的敏感度与特异度,避免读者只看到对数损失而不理解误诊率。如果可能,附上按椎骨节段拆分的分项结果——C4 普遍最差这件事,值得每个方法都报一下。

做标注规范的团队。 你的目标是在本院建一套可持续的标注流程。路径是:直接照搬 §3.3 的四层架构,先把本院报告的结论抽成整例标签与节段标签,这层几乎零成本;再把志愿医师的时间集中在边界框上,只标关键层然后插值;最后决定要不要做分割。关键在于建立申诉机制——它把标注分歧从隐性噪声变成显性记录,是这套方案里最容易被忽略、也最有价值的一环。

9.2 一条最短的可用流程

如果你只想在半天内跑通一个能出数的基线,下面这条路最短。它不追求性能,只追求「从下载到 AUC」的闭环完整。

import numpy as np
import pandas as pd
from pathlib import Path
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score

root = Path.home() / "data" / "rsna-cspine"
labels = pd.read_csv(root / "train.csv")
levels = [f"C{i}" for i in range(1, 8)]

def featurize(study_id: str) -> np.ndarray:
    #-- 用已转好的 npz;没有就回退到轻量统计特征
    p = root / "npz" / f"{study_id}.npz"
    if not p.exists():
        return np.zeros(6, dtype=np.float32)
    v = np.load(p)["image"].astype(np.float32)
    bone = (v > 0.5).astype(np.float32)
    return np.array([
        bone.mean(),
        bone[:, :, :256].mean() - bone[:, :, 256:].mean(),
        float(v.std()),
        float(np.diff(v, axis=0).std()),
        float(bone.sum(axis=0).max()),
        float(v.shape[0]),
    ], dtype=np.float32)

ids = labels["StudyInstanceUID"].tolist()
X = np.stack([featurize(s) for s in ids])
y = labels["patient_overall"].to_numpy()

rng = np.random.default_rng(42)
idx = rng.permutation(len(ids))
cut = int(len(ids) * 0.8)
tr, va = idx[:cut], idx[cut:]

clf = LogisticRegression(max_iter=1000).fit(X[tr], y[tr])
proba = clf.predict_proba(X[va])[:, 1]
print("验证集 AUC:", round(roc_auc_score(y[va], proba), 4))

这段代码的意义不在模型(六个手工特征加逻辑回归,性能必然很差),而在流程完整性:它验证了标签表可读、npz 可读、索引对齐、切分正确、指标可算。跑通之后,把 featurize 换成任何一个三维 CNN 的特征提取,管线不用改。

要提醒的是,这段代码在 npz 缺失时会返回全零特征,指标会退化成 0.5 左右的随机水平。看到这个数不要以为是模型的问题,先确认 npz 是否已经生成。

9.3 引用方式

引用这个数据集时应当分开引两件事:数据本身与描述数据的论文。竞赛页面有官方的引用格式,论文有 DOI。

Lin HM, Colak E, Richards T, Kitamura FC, Prevedello LM, Talbott J, et al.
The RSNA Cervical Spine Fracture CT Dataset.
Radiology: Artificial Intelligence. 2023;5(5):e230034.
doi:10.1148/ryai.230034

RSNA. RSNA 2022 Cervical Spine Fracture Detection Challenge.
Kaggle. https://www.kaggle.com/competitions/rsna-2022-cervical-spine-fracture-detection/

如果引用的是竞赛成绩而不是数据集,应改引成绩评估论文:Radiology: Artificial Intelligence 2024 年那篇,DOI 为 10.1148/ryai.230256。注意这篇有一份勘误(Erratum),DOI 为 10.1148/ryai.249002,引用具体数值时建议核对勘误内容。

§10 AI 使用声明

序号 项目 说明
1 内容生成方式 由 AI 辅助撰写,事实以官方挑战赛页面与已发表论文为准
2 主要事实来源 RSNA 挑战赛官方页面、Radiology: Artificial Intelligence 数据集论文与成绩评估论文
3 数字核验方式 逐条比对主办方页面与论文原文,口径不一致处并列呈现,不擅自统一
4 未核实内容 npz 压缩后的体积量级、社区镜像的具体预处理细节
5 未覆盖内容 私有测试集的标签分布、患者级去重数量、仲裁机制的实际使用频率
6 评价与判断 §7 的五维评分为编辑判断,非任何机构评分
7 更新策略 有新版本或新验证研究时更新,不追改历史数值
8 免责声明 不可用于临床决策;任何部署前须完成本地连续样本验证

常见误读(避坑清单)

常见说法 实际 证据
它是三千例的数据集,所以很大 三千例是检查数,患者级去重数量官方未给出;按病灶折算的阳性灶约两千余处,分摊到七节椎骨每节百余处 数据集论文只给检查数,未给患者数
阳性率接近一半,可以直接上线 阳性率是人为调平的,真实急诊为百分之四到七,相差近十倍 外部验证论文明确指出竞赛集阳性率远高于真实世界
中心分数 0.96,临床可以直接用 同批模型换到外部医院,特异度掉到七成上下,增强扫描上最低只有一成六 一级创伤中心外部验证
它能做骨折的像素级分割 分割掩膜标的是椎骨编号 1–19,不是骨折灶 数据集论文对分割文件的描述
所有阳性例都有骨折框 只有两百余例有框,约占阳性例的六分之一 数据集论文对边界框子集的描述
阴性例就是确证无骨折 阴性来自「报告未提及骨折」,报告漏掉的骨折仍算阴性 数据集论文局限性一节的自述
可以按切片随机划分训练与验证 同一患者可能有多例检查,必须按 StudyInstanceUID 切分 目录结构以一例检查为单位组织
层厚三毫米和五毫米也能直接喂进去 纳入条件是一毫米层厚平扫,厚层与增强都在排除之列 数据集论文纳入标准
术后带内固定的病例也能用 既往手术病例被排除,模型没学过硬件的伪影形态 数据集论文局限性一节
骨折在各椎骨的分布也被调平了 患病率调平了,骨折节段分布保留了真实世界形态 论文将 C2/C6/C7 占比与多中心研究对照

FAQ

Q1:这个数据集现在还能下载吗?
可以。竞赛结束后 Kaggle 竞赛页数据长期可下载,需注册账号并接受数据条款。私有测试集不公开,公共测试集的标签也不提供。

Q2:为什么说它是椎骨级的标注?
标签表把每一例拆成八个二值字段:一个整例判定加七个逐节判定。模型必须同时答对「有没有」与「在哪一节」,这是它与多数公开骨折集最本质的区别。

Q3:能不能用它直接做骨折分割?
不能。NIfTI 掩膜标的是椎骨编号,不是骨折灶;空间信息只有轴位二维框这一种粗粒度形式。

Q4:验证集该怎么切才不算作弊?
按 StudyInstanceUID 切。同一患者可能有多例检查,按切片随机切会让同一人同时出现在两侧,分数虚高。目录本身以一例检查为单位,按目录切最省事。

Q5:四成多的阳性率需要重采样吗?
训练时可下采样负例加速收敛,验证集不要动,否则指标不代表真实先验下的表现。要贴近临床,应另建按真实患病率抽取的本地测试集。

Q6:竞赛的评分函数能直接复用吗?
能复用公式,但要知道整例漏诊权重被放大了七倍,是漏诊导向的设计。若场景更怕假阳性,需自行调权重并重定阈值。

Q7:一句话里说的「npz 约 16 GB」是怎么来的?
这是社区常用的预处理形态:把每例 DICOM 堆成体后压成单个 npz 文件,整包体积约在这个量级。本页未逐例核验该体积,也未核验各版本 npz 的预处理细节,引用时宜标注为「社区镜像口径」。

Q8:为什么外部验证里特异度掉得比敏感度厉害?
外部医院的无骨折病例里混入更多退变、骨量减少与增强扫描者,模型易把正常变异判成骨折;阳性病例形态相对典型,仍能被找到,故敏感度保持较好。

Q9:C4 为什么普遍表现最差?
成绩评估论文发现前八名模型在 C4 上的 AUC 与 F1 显著低于 C1、C2、C7。可能因 C4 样本少且靠近常见退变区,论文未下结论。

Q10:可以用它的标签训练,再用 VerSe 做定位吗?
可以,这是常见组合。VerSe 的椎骨实例分割提供「第几节在哪」的空间先验,迁到本集做两阶段模型通常更稳。注意两套数据的编号规则与视野范围不同。

Q11:论文有一份勘误,会影响什么?
勘误(DOI 10.1148/ryai.249002)对应成绩评估那篇。引用 AUC、F1、敏感度、特异度时宜核对勘误,确认未被修订。

Q12:如果只想拿它当教学材料,怎么用最省事?
用 §2.2 的字典表配一例真实数据走一遍:读标签行、找到目录、按 InstanceNumber 堆体、查灰度范围。一节课能让人看懂「结构化标注」这件事。

术语表

术语 英文 含义
颈椎 cervical spine 脊柱最上段的七节椎骨,编号 C1 至 C7
寰椎 atlas (C1) 第一节颈椎,无椎体,呈环状
枢椎 axis (C2) 第二节颈椎,有向上突出的齿状突
横突 transverse process 椎骨向两侧伸出的骨性突起
棘突 spinous process 椎骨向后方伸出的骨性突起
椎板 lamina 椎弓后部连接棘突的骨板
椎骨级标签 vertebra-level label 针对单节椎骨的独立判定,本集为 C1–C7 各一个
整例级标签 study-level label 针对整次检查的判定,本集为 patient_overall
StudyInstanceUID — DICOM 中标识一次检查的唯一字符串,本集的主键
InstanceNumber — DICOM 中标识切片在扫描栈中位置的编号
层厚 slice thickness 相邻切片中心之间的距离,本集纳入标准为一毫米
轴位 axial 横断面成像平面,本集影像的采集平面
矢状位 sagittal 沿身体前后方向的纵切面,本集分割掩膜的生成平面
重建 reformat 由原始轴位数据重建出的其他方向图像
骨窗 bone window 用于观察骨结构的窗宽窗位设置,常用窗宽两千、窗位四五百
Hounsfield 单位 HU CT 的衰减值单位,空气约负一千,皮质骨可达数百以上
各向异性 anisotropy 层内像素间距与层间距不相等,三维影像常见
重采样 resampling 把体数据统一到同一体素间距,常见为一毫米立方
边界框 bounding box 包住目标的矩形,本集为轴位二维框
最大包络 largest envelope 多名标注者的框取并集后的外接框
椎骨分割 vertebral segmentation 标出每节椎骨所在的体素,本集标签值 1–19
加权对数损失 weighted log loss 本集官方评分,整例漏诊权重为椎骨级的七倍
阳性率 prevalence 有骨折的例数占比,本集约四成七,真实急诊百分之四到七
外部验证 external validation 在数据集之外的医院数据上测试模型
患者无关切分 patient-level split 保证同一患者不跨训练与验证两侧
检定特征曲线下面积 AUC 衡量排序能力的指标,与阈值无关
敏感度 sensitivity 有骨折被判为阳性的比例
特异度 specificity 无骨折被判为阴性的比例
域偏移 domain shift 训练与推理数据的分布差异
非商业许可 non-commercial license 允许免费研究使用,商业用途需另行授权

附录 A:核心数字核对表

项 值 来源 来源层级
总检查数 3,112 数据集论文 论文
阳性例数 见 §2.1 口径表 数据集论文 论文
阴性例数 见 §2.1 口径表 数据集论文 论文
贡献机构数 12 官方页面 + 论文 官方 + 论文
覆盖国家数 9 数据集论文摘要 论文
覆盖大洲数 6 官方页面 官方
训练集例数 2,019 数据集论文 论文
公共测试集例数 304 数据集论文 论文
私有测试集例数 789 数据集论文 论文
训练集阳性灶数 1,444 成绩评估论文 论文
私有测试集阳性灶数 672 成绩评估论文 论文
有边界框的例数 235 数据集论文 论文
志愿标注医师数 40 余名 成绩评估论文 论文
参赛人数 1,108 成绩评估论文 论文
参赛队伍数 883 成绩评估论文 论文
提交次数 12,871 成绩评估论文 论文
前八名平均 AUC 0.96 成绩评估论文 论文
前八名平均 F1 90% 成绩评估论文 论文
赛期起止 2022-07-28 至 2022-10-27 成绩评估论文 + 官方 论文 + 官方
奖金总额 30,000 美元 官方页面 官方
层厚纳入标准 1 mm 数据集论文 论文
npz 整包体积 约 16 GB(量级) 社区镜像口径 未核实

附录 B:数字的来源分层

第一层,官方页面。 主办方的挑战赛页面给出的数字包括:超过一千四百例已诊断骨折的 CT、大致同等的阴性检查、十二个站点、六大洲、七节椎骨、三万美元奖金、赛期与协办学会。这一层的特点是都是约数或整数,用于对外叙述而非计量。凡是与论文冲突的地方,一律以论文为准并注明差异。

第二层,论文摘要与正文。 三篇论文构成第二层:数据集论文给出总量、阳性阴性拆分、切分方式、字段定义与局限性;成绩评估论文给出参赛规模、头部成绩、各椎骨表现与评分公式的权重;两项外部验证论文给出跨机构测试的敏感度与特异度。这一层是精确数值的主来源。

第三层,未核实。 包括:社区 npz 镜像的具体体积与预处理细节;患者级去重后的真实人数;仲裁机制被使用的次数与其对标签的净影响;各机构贡献的例数明细(论文有表,但正文文本未逐条列出,本页未逐格转录);私有测试集在各椎骨上的阳性分布。

三层的使用原则是:第一层用于定性叙述与口径对照,第二层用于精确计量与引用,第三层一律标注「未核实」而不给具体数。

附录 C:完整参考文献

  1. Lin HM, Colak E, Richards T, Kitamura FC, Prevedello LM, Talbott J, et al. The RSNA Cervical Spine Fracture CT Dataset. Radiology: Artificial Intelligence. 2023;5(5):e230034. doi:10.1148/ryai.230034
  2. Lin HM, Colak E, Richards T, Kitamura FC, Prevedello LM, Talbott J, et al. Performance of the Winning Algorithms of the RSNA 2022 Cervical Spine Fracture Detection Challenge. Radiology: Artificial Intelligence. 2024. doi:10.1148/ryai.230256
  3. Erratum for: Performance of the Winning Algorithms of the RSNA 2022 Cervical Spine Fracture Detection Challenge. Radiology: Artificial Intelligence. 2024. doi:10.1148/ryai.249002
  4. Assessing the Performance of Models from the 2022 RSNA Cervical Spine Fracture Detection Competition at a Level I Trauma Center. Radiology: Artificial Intelligence. 2024.
  5. External Validation of a Winning Artificial Intelligence Algorithm from the RSNA 2022 Cervical Spine Fracture Detection Challenge. American Journal of Neuroradiology. 2025. doi:10.3174/ajnr.a8715
  6. Machine Learning to Detect Cervical Spine Fractures Missed by Radiologists on CT: Analysis Using Seven Award-Winning Models From the 2022 RSNA Cervical Spine Fracture AI Challenge. American Journal of Roentgenology. 2025. doi:10.2214/ajr.24.32076
  7. RSNA. RSNA Cervical Spine Fracture AI Challenge (2022). https://www.rsna.org/artificial-intelligence/ai-image-challenge/cervical-spine-fractures-ai-detection-challenge-2022
  8. RSNA. RSNA 2022 Cervical Spine Fracture Detection. Kaggle. https://www.kaggle.com/competitions/rsna-2022-cervical-spine-fracture-detection/
  9. Goldberg W, Mueller C, Panacek E, et al. Distribution and patterns of blunt traumatic cervical spine injury. Annals of Emergency Medicine. 2001;38(1):17–21.(数据集论文引以为真实世界骨折节段分布的对照)
  10. Sekuboyina A, Husseini ME, Bayat A, et al. VerSe: A Vertebrae labelling and segmentation benchmark for multi-detector CT images. Medical Image Analysis. 2021;73:102166.(库内邻接条目)

附录 D:任务代码

import json
import numpy as np
import pandas as pd
import pydicom
from pathlib import Path

BONE_WW, BONE_WL = 2000.0, 400.0

def load_study(study_dir: Path):
    slices = [pydicom.dcmread(str(f), force=True) for f in study_dir.glob("*.dcm")]
    if not slices:
        return None, None
    slices.sort(key=lambda d: int(d.InstanceNumber))
    vol = np.stack([
        d.pixel_array.astype(np.float32) * float(getattr(d, "RescaleSlope", 1.0))
        + float(getattr(d, "RescaleIntercept", 0.0))
        for d in slices
    ])
    z = np.array([float(d.SliceLocation) for d in slices], dtype=np.float32)
    dz = float(np.abs(np.diff(z)).mean()) if z.size > 1 else 1.0
    spacing = [float(slices[0].PixelSpacing[0]), float(slices[0].PixelSpacing[1]), dz]
    return vol, spacing

def bone_window(vol: np.ndarray) -> np.ndarray:
    lo, hi = BONE_WL - BONE_WW / 2.0, BONE_WL + BONE_WW / 2.0
    return ((np.clip(vol, lo, hi) - lo) / (hi - lo)).astype(np.float16)

def main(dicom_root: str, out_root: str, label_csv: str) -> None:
    dicom_root, out_root = Path(dicom_root), Path(out_root)
    labels = pd.read_csv(label_csv)
    keep = set(labels["StudyInstanceUID"])
    out_root.mkdir(parents=True, exist_ok=True)
    index = []
    for study_dir in sorted(p for p in dicom_root.iterdir() if p.is_dir()):
        sid = study_dir.name
        if sid not in keep:
            continue
        out_path = out_root / f"{sid}.npz"
        if not out_path.exists():
            vol, spacing = load_study(study_dir)
            if vol is None:
                continue
            np.savez_compressed(out_path, image=bone_window(vol),
                                spacing=np.asarray(spacing, dtype=np.float32))
        else:
            spacing = np.load(out_path)["spacing"].tolist()
        index.append({"study_id": sid, "npz": out_path.name,
                      "dx": spacing[0], "dy": spacing[1], "dz": spacing[2]})
    pd.DataFrame(index).to_csv(out_root / "index.csv", index=False)
    print(json.dumps({"converted": len(index)}, ensure_ascii=False))

if __name__ == "__main__":
    import sys
    main(sys.argv[1], sys.argv[2], sys.argv[3])

调用方式是三个位置参数:DICOM 根目录、输出目录、标签表路径。脚本对已经转换过的例会跳过,因此中断后可以直接重跑。index.csv 里记下了每例的三个体素间距,训练时做各向异性处理要用到。

附录 E:如果只记五件事

一、它是目前唯一公开的、带 C1–C7 逐椎骨骨折标签的多中心颈椎 CT 数据集,三千余例,十二家机构,非商业条款下可下载。

二、它的标签分四层:整例、椎骨、边界框、椎骨分割。框只覆盖阳性例的约六分之一,分割标的是椎骨不是骨折。

三、它的患病率被调到约一半,真实急诊只有百分之四到七。概率值不能直接用,阈值必须在本地重定。

四、它的真相来源是原始报告,所以它测的是「能否复现报告」,不是「能否发现所有真实骨折」。这一点是所有性能数字的前提。

五、外部验证显示敏感度相对稳健(六成七到八成六),特异度不稳(七成上下)。部署前必须有本地连续样本测试集,竞赛分数不能当承诺。

编辑说明

本篇于 2026-10-26 完成初稿。事实核对的路数是:先读主办方 RSNA 的挑战赛专题页,取其对规模与机构来源的表述;再读 Radiology: Artificial Intelligence 上的数据集论文全文,取字段定义、切分方式、标注架构与局限性自述;再读同刊的成绩评估论文,取参赛规模、头部成绩与评分权重;最后读两项独立外部验证,取跨机构性能掉点的量级。

未做的事:未下载全量影像逐例统计,因此所有「每节椎骨阳性别数」「npz 实际体积」类数字均不给出,或标注为社区口径。未联系主办方核对患者级去重数量。未核验勘误的具体修订条目。

已知的口径差:官方页面说「超过一千四百例阳性」,论文说精确为一千四百四十五例;官方说「大致同等数量的阴性」,论文给出的阴性例数与阳性仅差两百余例,并非严格相等。两处差异均按论文为准并在正文注明。

页脚之外的元话语一律不写进正文,正文里的判断都以「据哪份材料」为限,超出材料的推断一律标为编辑判断。若后续出现同量级的同任务公开集,本篇的「唯一性」论断需要修订。


相关数据集导航

以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:

  • medpelvis3d — 共享标签:医学影像 / CT / 目标检测 / 骨骼肌肉影像
  • deeplesion — 共享标签:医学影像 / CT / 目标检测
  • fdtooth — 共享标签:医学影像 / CT / 目标检测
  • verse-spine — 共享标签:医学影像 / CT / 挑战赛数据集 / 骨骼肌肉影像
  • lndb — 共享标签:医学影像 / CT / 目标检测 / 挑战赛数据集
  • uls23 — 共享标签:医学影像 / CT / 目标检测 / 挑战赛数据集
  • mela — 共享标签:医学影像 / CT / 目标检测 / 挑战赛数据集
  • mura — 共享标签:医学影像 / 目标检测 / 骨骼肌肉影像
  • luna16 — 共享标签:医学影像 / CT / 目标检测
  • grazpedwri-dx — 共享标签:医学影像 / 目标检测 / 骨骼肌肉影像

导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

返回 AI-Ready 数据集