
今天想聊聊一个医疗健康方向的检测项目疼痛检测数据集这套数据集一共2200张图像已经整理成YOLO训练格式专为医疗健康场景下的疼痛线索识别准备。很多朋友一听到“疼痛检测”第一反应是疼痛明明是主观感受机器怎么检测其实这里检测的不是痛觉本身而是疼痛引发的可观测表现——比如面部表情单元的变化、身体姿态的收紧、手脚的抓握动作甚至皮肤或伤口区域的异常表现。用目标检测模型把这些区域定位出来再结合评分规则就能把传统依赖患者自评的量表变成可量化的图像指标。这套东西能用在护理监测、康复训练评估、术后镇痛效果跟踪、临床试验筛查这些场景对正在做医疗AI、或者想拿YOLO练手的人来说处理好一份真实场景的小规模医疗数据集比单纯在COCO上跑通一个模型有价值得多。下面我按数据准备、标注、训练、坑点、部署五个环节把整个过程讲透。1. 项目整体构思与数据集定位1.1 为什么盯上疼痛检测这个方向临床疼痛评估一直是个老大难问题。传统量表比如VAS、NRS都依赖患者自己打分患者意识清醒、表达能力正常的时候还行可一旦进了ICU、术后复苏期或者遇到婴幼儿、认知障碍人群主观评分基本就废了。护士只能靠经验观察患者表情、体动、生命体征变化来判断是否疼痛这种方式不仅主观而且很难标准化尤其在夜班人员紧张的时候漏判风险很高。疼痛检测数据集要解决的就是把“疼痛表现”变成模型可学习的目标。比如面部疼痛表情里的眉间收缩、眼周紧闭、口角下拉这些在表情识别领域已经有大量研究支持手部保护性动作里的握拳、紧抓床栏、按压伤口附近也是疼痛行为的典型提示还有躯体紧张、蜷缩、异常制动等姿态同样可以作为线索。目标检测相比分类和关键点检测有一个很直接的优势框能同时给出“哪里疼”的提示比如左侧腹部区域的保护性体位检测框落在哪个位置本身就有定位信息。这对后续结合病史、护理记录做决策非常有帮助。另外从项目可落地性来看病房摄像头、陪护监控、康复训练摄像头都已经很普及图像采集无创、无接触、成本低。YOLO这类单阶段检测器又足够快完全可以在边缘设备上做实时分析。所以我把这个项目的技术路线定为用YOLO做疼痛线索的目标检测先定位“疑似疼痛表现”的区域再配合后端评分规则输出风险等级。这个思路不追求直接给出“患者痛不痛”的结论而是给临床人员提供一个客观、可追溯的观察辅助。1.2 2200张数据的规模够不够用我在各种群里被问得最多的问题就是2200张够吗大多数人被“深度学习需要海量数据”这句话吓住了但实际上数据需求量取决于任务复杂度和场景变化幅度。如果任务是COCO那种80类、场景千变万化的大规模通用检测2200张远远不够但对于医学场景里目标类别集中、背景相对固定的检测任务2200张是一个很合理的起步量。具体算一下假设每张图包含1到4个标注目标2200张图大约能产生3000到8000个标注框。YOLO做迁移学习时预训练权重已经学到了丰富的底层纹理和边缘特征我们需要训练的是医疗场景的语义和框回归能力这个数据量足够把模型从“只会看通用物体”微调成“能认疼痛表现”的检测器。我习惯按8比1比1划分训练集、验证集、测试集也就是大约1760张用于训练220张用于调参220张用于最终评估。220张测试图对于统计mAP和召回率已经能给出基本可信的数字。当然这个规模也有明确的上限。面部表情在低光、遮挡、侧脸角度下会剧烈变化不同年龄段、不同人种、不同文化背景下的疼痛表达差异也很大2200张不会覆盖全部长尾情况。所以我的定位是把它当作第一个可运行的基线数据集跑通整个YOLO训练部署流程验证检测方案的有效性后续再按场景缺口做定向扩充。直接拿这个规模去投标、去做大规模临床实验那是不现实的用来做技术验证和产品原型完全够。1.3 为什么选择YOLO作为检测底座这个项目最终是要在病房、康复中心这类环境里跑的不是所有地方都有强力GPU服务器。YOLO是单阶段检测器一次前向直接输出边界框和类别推理速度快模型体积小YOLOv8n的权重只有几MB量化之后能轻松跑在Jetson、RK3588这类边缘设备上。这一点对医疗场景很重要因为视频数据涉及隐私很多医院希望摄像头画面不出内网本地化推理是刚需快模型比大模型更有实用价值。YOLO的生态成熟也是一个重要原因。Ultralytics把训练、验证、导出、部署的工具链全部整合好了标注格式就是一个txt文件数据组织结构固定甚至不需要自己写复杂的训练循环。医疗团队里如果有医生、护理人员参与他们可以快速理解“每个txt文件对应一张图片里的框坐标”这种逻辑沟通成本很低。对于小规模医疗数据集YOLO的训练收敛速度和稳定性也要优于那些依赖海量数据的大Transformer模型后者在小数据上很容易欠拟合而且推理耗时高。但我要强调一点YOLO在这个项目里是定位“疑似疼痛线索”的前端不是最终诊断工具。疼痛是主观体验单靠一帧图像无法给出确定性结论。实际产品里YOLO输出的每个检测框需要做时序滤波并结合患者病历、心率、血压等多模态信息综合判断。模型的作用是把“人眼可能漏掉的表情和动作变化”及时标出来让护士再有针对性地复核。这个定位想清楚后YOLO的很多参数选择就都有了依据。2. 数据处理与标注规范2.1 数据来源与清洗策略数据来源是医疗AI项目的第一道红线。疼痛表情相关的公开数据集有不少包括学术机构发布的疼痛表情数据库、人脸表情数据集里带有疼痛标签的子集以及部分公开的护理监测研究数据。这些数据使用时必须确认授权范围看清楚是否允许用于模型训练和二次分发。如果和医院合作涉及患者面部图像必须有伦理审批和完整的脱敏流程。最忌讳的是从网上爬取各种来源不明的图片来做医疗数据后续不但论文发表不了还可能惹出一堆合规麻烦。拿到原始图后第一步是去重。疼痛表情视频抽帧经常会抽出大量高度相似的帧比如一个持续两秒的表情在30fps下就有60帧几乎一样的画面。如果全部进入训练集模型会对这套重复特征过拟合验证集指标虚高真实场景一换人就垮。我的做法是先用感知哈希算法做相似度聚类同一个视频片段里每隔一定间隔抽样一帧更严谨一点还可以按视频片段分组保证同一个人的同一个动作不会同时出现在训练集和验证集里。清洗环节还要删掉明显不合格的图分辨率过低导致五官模糊、严重过曝或欠曝、大面积遮挡、多个人脸混杂且面部极小等。这些图不是“增强样本”而是噪声。我在第一轮清洗时把2200张图里大概10%到15%的图剔掉了再多引入一些补拍和公开数据源最终保持总规模在2200左右。宁可总数少一点也要保证每一张都有清晰的标注价值。2.2 标注工具与YOLO格式转换细节标注工具我用过LabelImg、AnyLabeling、CVAT各有适用场景。单机单人标注的时候LabelImg最轻量打开一个文件夹框一个存一个不需要搭服务多人协作标注时CVAT更合适它有任务分配、审核、冲突检测这些功能还能导出YOLO格式。X-AnyLabeling的好处是带AI辅助预标注可以先用一个初始模型自动生成一批框人工再修改效率能提高很多适合数据集后续扩充。标注前最重要的事是写一份标注规范文档。我给这个项目定义了三个大类pain_face覆盖面部疼痛表情区域包括眉间收缩、眼周紧闭、口角下拉clutch_hand覆盖手部抓握、紧抓物品或按压痛处的动作tension_body覆盖躯体紧张、蜷缩、保护性体位等姿态表现。规范里明确要求每个类别的最小框范围、遮挡超过50%是否标注、两个人脸重叠时如何处理这些细节不提前定好标到后面一定返工。YOLO训练需要的是归一化后的txt标注每一行是“类别ID x_center y_center width height”所有坐标都除以图片宽高所以范围在0到1之间。LabelMe这类工具默认输出是JSON多边形坐标需要转一次。转换脚本核心逻辑就是取一个多边形外接矩形换算成中心点坐标和宽高然后写入txt文件。代码很常规但我提醒几个容易踩的点小数位数至少保留6位不然小目标的框定位误差会被放大注意检查是否有多边形坐标越界尤其是手滑点到图片外面时YOLO读取会报错类别ID必须从0开始连续不能跳号否则训练时类别映射会错位。2.3 数据集划分与类别平衡划分数据集不能图省事直接random split。面部疼痛检测这种任务同一个人的不同帧非常相似如果同一人既出现在训练集又出现在验证集模型其实是靠“认人”而不是“认表情”拿到高分的换一个新患者效果立刻打回原形。我采用按人员ID和视频片段分组的方式确保同一个人的所有帧只会落在训练、验证、测试三个集合中的一个这样评估出的mAP才有参考价值。类别平衡方面疼痛面部表情通常是最容易采集的手部抓握和躯体姿态次之分泌物等异常区域更少。我做完首轮统计pain_face的框数大约占六成clutch_hand占两成tension_body占两成。这种比例还凑合但训练时仍然要给少数类别一点优待。最简单的做法是在采样器里提高少数类图像的权重再进一步可以用复制粘贴增强把少数类目标裁出来贴到其他背景图上生成新训练样本Mixup这类图像级增强对改善类别平衡也有帮助。要注意的是验证集和测试集必须保持真实分布不能做任何重采样否则最终评估数字就失真了。3. YOLO训练实操与参数解析3.1 环境、预训练权重和训练命令训练框架我直接用的Ultralytics YOLOv8目前生态最省心pip安装即可不需要手动编译Darknet。项目目录结构建议这样pain_yolo/images/train/val/test/labels/train/val/test/pain.yaml痛苦经验之谈图片和标签的目录名要一一对应train的图片文件夹里有多少张图labels/train里就要有多少个同名txt文件任何一张图缺标签都会在训练时报错。pain.yaml内容也很简单path: /data/pain_yolo train: images/train val: images/val test: images/test names: 0: pain_face 1: clutch_hand 2: tension_body第一次训练我建议先用小模型跑通流程比如yolov8n.pt或yolov8s.pt把epochs设成5、imgsz设成320先确认数据加载、标签读取、损失函数都正常再上完整训练。有效规避“训练十几个小时后发现标签路径错了”这种惨剧。正式训练命令yolo detect train datapain.yaml modelyolov8s.pt epochs200 imgsz640 batch16 device0modelyolov8s.pt表示加载COCO预训练权重这是迁移学习的关键imgsz640是网络输入尺寸对应多数显卡的性价比batch16需要根据显存调整显存不够就降到8或4。24GB显存跑yolov8s基本没压力8GB显卡建议用yolov8n或者把imgsz降到512。3.2 关键超参与训练曲线分析很多新手把epochs拉到300就当甩手掌柜这是不对的。医疗小数据集上我最关心的三个参数是学习率、数据增强强度、输入尺寸。学习率YOLOv8默认学习率对COCO这种大数据集是合理的但2200张的医疗数据量小预训练权重不应该被大学习率破坏我会把lr0从默认的0.01降到0.005如果有轻微过拟合再降到0.002。数据增强Ultralytics默认开启Mosaic但对小目标不友好因为图像被切分后一个小表情区域可能被切掉一半尤其到了训练后期Mosaic会让模型难收敛。我的做法是把Mosaic在前30个epoch关掉使用close_mosaic30参数并在后面epoch只做轻度缩放和HSV增强。另一个常用策略是冻结骨干网络。数据量小的时候我会冻结前10层参数只训练检测部分这样能保留预训练模型学到的通用纹理特征减少过度拟合风险。做法是在model参数里指定冻结层或者直接修改train脚本里的freeze配置。训练过程中我一般盯着四张曲线图训练loss、验证loss、mAP0.5、mAP0.5:0.95。理想情况是训练loss稳步下降验证mAP同步上升。如果训练loss还在降、验证mAP却开始掉说明过拟合了优先减少增强强度、提高权重衰减而不是盲目增加epochs。3.3 评估指标怎么才算合格疼痛检测和通用目标检测的评估侧重点不太一样。通用检测榜单上大家喜欢看mAP0.5:0.95这是一个综合了不同IoU阈值下的平均分数值越接近1越好。但对医疗辅助场景我强烈建议同时关注召回率也就是“真实疼痛表现里到底找回了多少”。漏掉一个痛苦表情可能意味着患者要多忍受几个小时的疼痛而多框一个疑似区域最多是让护士多看一眼成本要低得多。所以在调阈值时我会把置信度阈值放低到0.25甚至0.2宁可输出多一些疑似框再由后端规则或人去做二次判断。在2200张这种规模的数据集上我见过不少团队的mAP0.5在0.7到0.85之间mAP0.5:0.95在0.4到0.6之间。这个数字本身不算惊艳但放在医疗小数据场景里已经足够做产品原型验证。真正重要的是测试集要按患者维度分开指标反映的是“面对没见过的病人”时的表现。我会额外看每个类别单独的平均精度如果pain_face很高但clutch_hand很低问题大概率出在数据或标注上而不是模型结构上下一步优先补那一类的数据。4. 我踩过的坑常见问题与排查技巧实录4.1 小目标漏检面部区域总是框不准疼痛表情集中在眉眼、嘴角这些局部区域在640输入尺寸下一个眉毛紧缩的区域可能只有十几个像素宽模型很难捕捉。我一开始训练完发现验证集上漏检最严重的全是小目标。解决办法有几个方向一是提高输入分辨率imgsz从640提到960或1280小目标特征明显变清晰但显存占用涨得很快只能用更小模型或更小batch找平衡二是用切图策略先跑一个通用的人脸检测器把面部区域裁下来再在裁切图上做疼痛表现检测相当于把一张大图拆成若干小图分别检测三是推理时用SAHI这类切片辅助推理框架但部署复杂度也会增加。我实测下来对疼痛表情检测最有效的是“人脸裁切主检测”双路方案。第一路人脸检测负责找到人脸位置第二路在放大的面部区域上检测疼痛细节。代价是推理耗时翻倍但在边缘设备上依然能跑到实时。小目标漏检还有可能是数据增强里的随机缩放造成的训练时图像被缩得太小原本就小的目标直接被压成噪点。我会在增广参数里限制缩放范围保证小目标在训练过程中不会频繁消失。4.2 类别不平衡引发的“选择性失明”疼痛检测数据集里pain_face样本量充足模型学得很好clutch_hand和tension_body因为样本少经常被模型忽略。最典型的症状是验证集里手部抓握动作明明很多输出的检测结果却几乎全是pain_face。这不是模型笨而是它在“模拟”训练集的先验分布少数类样本太少loss占比低学了等于没学。我的处理分两步。第一步是数据层面过采样把包含clutch_hand和tension_body的图片复制几份放进训练集复制时适当做上下翻转、亮度调整避免完全重复的样本导致过拟合。第二步是使用复制粘贴增强把少数类目标区域裁剪出来随机粘贴到有疼痛表情但没有该目标的背景图上并同步生成新的标注框。这一步对姿态类目标效果不错因为它模拟了“同一个场景里出现多种疼痛线索”的实际情况。复制粘贴增强要注意目标的边缘融合和阴影处理如果直接硬贴模型会学到“目标旁边总有条裁剪线”这种伪特征推理时反而更差。4.3 BN崩溃与训练不收敛我遇过最玄学的场景是训练跑到几十个epoch之后loss突然变成NaN验证mAP直接归零在Ultralytics界面上输出一串warning说batch normalization运行统计方差接近零。第一次遇到时我以为是数据有问题排查了半天才发现是自己把batch从16改成1来省显存BN层在batch1的时候统计量根本算不准数值崩掉是迟早的事。BN崩溃的常见原因还包括初始学习率过大、脏数据里混了全黑全白图像、标注框坐标越界变成负数。我现在的排查顺序很固定先检查标签文件有没有负数和越界坐标再确认输入图像没有损坏文件然后把batch调回8以上或用梯度累积模拟大batch最后把学习率降到原来的十分之一重新训练。数据量小的时候加载预训练权重能大幅降低BN崩溃概率。另外建议训练脚本里打开resume功能一旦发现loss异常有断点可以回滚。4.4 混淆矩阵总和为什么不是100%不少人在验证阶段看混淆矩阵发现横着加竖着加都不是100%就怀疑代码写错了其实这是概念没理顺。YOLO输出的混淆矩阵默认是“真实样本计数”矩阵里的数字表示的是“某个真实类别的样本被预测成了哪些类别”每个类别的样本总数不一样所以行和列都不是百分比。只有当矩阵做了归一化处理每一行代表该真实类别下预测结果的分布比例行和才会等于1或者100%。想查看比例用normalizeTrue或在评估工具的设置里打开归一化混淆矩阵。更重要的是怎么读混淆矩阵。我会看对角线以外的“混淆点”落在哪里比如pain_face经常被预测成背景说明面部表情区域特征不够强tension_body被预测成clutch_hand说明两类目标在画面位置或形态上太接近。这些信息比单独看mAP有用得多能直接指导下一轮数据采集和标注优化。4.5 标注缺陷引发的模型震荡有一次我把验证集指标刷到很高但一到新场景推理就疯狂误检后来发现是标注阶段埋了雷同一类目标一位标注员习惯框得紧贴边缘另一位习惯多留一圈背景模型学到的目标边界风格一会儿紧一会儿松输出框自然飘。解决方法是让两个人标注同一批图计算IoU一致性把不一致超过0.5的图全部打回重标。这种标注一致性校验在医疗项目里非常必要因为框的边界直接影响框回归的收敛质量。另一个隐蔽问题是数据泄露。我有一次把同一个视频流的相邻帧同时放进了训练集和验证集结果验证mAP高得离谱我一度以为模型已经能临床使用了直到换了一个医院的视频测试mAP直接掉了一半。从那以后我划分数据集都严格按“视频分组”同一个人的所有帧只能出现在一个集合里。吃一堑长一智评估指标只能信“跨患者”的评估任何形式的同源数据混入都会骗人。5. 从训练到部署的落地体会5.1 轻量化导出与边缘部署训练完成后导出环节不能马虎。Ultralytics里一条命令就能导出ONNX和TensorRT引擎yolo export modelbest.pt formatonnx imgsz640 dynamicTrue yolo export modelbest.pt formatengine device0ONNX格式适合先做跨平台验证TensorRT引擎适合NVIDIA显卡上的高性能推理。我部署过的场景是病房摄像头分析盒盒子上一块Jetson Orin Nano跑yolov8s量化后大概能做到30到40ms一帧同时分析一路视频完全没问题。如果目标是更低成本的嵌入式设备可以进一步做INT8量化但需要准备校准数据集校准图尽量覆盖病房常见的亮度、角度否则量化后精度损失会很明显。部署层的代码不建议直接用Ultralytics的Python推理接口太重了。我一般用ONNX Runtime或TensorRT的C/Python API加载模型输入的预处理只有resize、归一化、通道转换后处理是解码边界框、做NMS、过滤低置信度框。这一套流程在多个平台间复用起来很干净。另外我会在部署代码里加一个“灰度开关”输出检测结果但默认不弹告警只记录日志等和护理团队确认准确率达标后再开启主动提醒。5.2 时序滤波与多模态扩展思路单帧检测结果直接抖起来没法用。疼痛表情往往持续几秒甚至更久手部抓握也不是一帧就结束的但单帧推理经常出现连续几帧有检测、下一帧突然消失的情况。最简单的解法是滑窗投票记录最近15帧里每个位置区域的检测结果只有出现频率超过一半才认为是一次有效事件。更平滑的做法是加一个卡尔曼滤波或EMA对检测框中心和置信度做时间平滑能明显降低误报同时不会明显增加延迟。2200张数据集只是一个基线。要真正在医院环境里用后续还需要补三个方向的数据一是不同年龄段和肤色人群的疼痛表达现有公开数据集中年轻白人居多适用性不够二是遮挡场景比如戴口罩的患者、侧脸朝向摄像头的患者检测难度完全不同三是低光照和夜间病房场景这需要针对低光做专门的图像增强或训练数据增广。多模态方向上将YOLO检测结果与心率、血压、体动传感器信号做特征融合比纯图像判读更稳健这也是我接下来打算扩展的方向。最后再说一个我自己的习惯每次训练结束我会把预测得分在0.3到0.5之间的样本全部翻出来人工看一遍。这些低置信度样本往往最能暴露标注不一致和类别定义模糊的问题比只盯mAP数字有用得多。疼痛检测这个方向模型输出只是辅助真正决定项目价值的是能不能帮临床人员少漏掉一次痛苦的信号。