
疼痛检测这个概念在医疗圈里已经讨论了很多年但在计算机视觉领域真正把它当作目标检测任务来做的人相对还是少数。我最近整理完成了一套2200张图像的疼痛检测数据集全部按YOLO格式标注专为医疗健康场景下的疼痛表情识别设计可以直接拿来训练yolov5、yolov8这些主流型号。这篇文章就从数据集的设计初衷说起一路讲到标注格式、训练配置、评估指标和部署落地把整条链路完整走一遍也会把我在整理和训练中踩过的坑一并摆出来给准备做同类项目的朋友一个参考。1. 疼痛检测到底在解决什么问题1.1 医疗场景中疼痛评估的困境疼痛评估是所有临床科室都躲不开的环节但对它的评估方式医疗行业其实一直处于“形而上”的状态。成年患者能开口说“我疼疼在刀口上程度大概七分”这是主观报告是目前最常用的手段但到了ICU、术后恢复室、新生儿科、认知障碍病房这些场景里这个手段就彻底失效了——患者无法表达、不愿表达或者表达不准确。于是临床上衍生出了FLACC量表和CPOT量表这类观察式评估工具。操作流程大致是护士观察患者的面部表情、肢体动作、肌张力、是否发声逐项打分加总。这套方法不是不好而是重度依赖观察者的经验不同护士给同一个患者打分经常差出两三分。更麻烦的是疼痛是动态变化的一次评估只能反映当下那一分钟的状态护士不可能全天候盯着每一位患者看突发剧烈疼痛未必能在第一时间被记录。这就给计算机视觉留出了非常明确的切入点能不能用摄像头做连续的面部表情捕捉用模型来判断画面中的疼痛特征把“每时每刻都有一位观察员”这件事自动化。这恰好是本次疼痛检测数据集的核心定位——不停留在替代人工评估这个层面而是做“连续监测的辅助工具”把医护人员从高强度的观察工作中解放出来。1.2 为什么这张数据集选择YOLO路线做疼痛检测很多人第一反应是“这不就是表情分类吗给一个ResNet或者Vision Transformer不就行了”。理论上是但不是最优解。真实医疗场景里摄像头拍到的是整个病房或床单元画面人脸在整个画面中可能只占很小一块区域而且脸的角度、遮挡、运动模糊都是变量。直接把整张图送进分类网络网络会花大量计算资源去扫描根本没有信息的背景效率低精度也顶不上去。YOLO这类目标检测模型天然适合这个结构——它先把人脸区域框出来然后在框内判断是否是疼痛相关表情。检测和分类一步完成推理速度快对嵌入式设备友好训练生态也足够成熟。YOLO的另一个优势在数据层面。市面上绝大多数开源表情识别数据集使用的是裁剪好的单人脸图这种格式没法直接落地到一个完整的监测系统中。而YOLO格式的txt标注文件每一行记录一个目标的类别和归一化坐标灵活性极高。我做这个数据集时全程按YOLO的标注规范来组织同时对图像内容做了大量扩充保证它既能在学术上复现实验也能在实际病房画面里跑起来。2. 厚积薄发2200张图像的数据集解剖2.1 数据构成与合规处理逻辑先交代底细。这套数据集由多个可再分发的专业表情相关公开资源整合而成涵盖欧洲和东亚人群的多种面部样本。我在采集后做了三件事统一图像尺寸与格式、重新标注并人工审核每一张图、对全部样本进行匿名化处理。医疗数据无小事涉及人脸的数据更是如此——出于用户隐私保护所有原始来源均被剥离去标识化处理仅保留本文所述的任务标注内容。这里多提一句合规问题。医疗健康类数据集和普通街景数据集最大的区别在于身份敏感属性。做这类项目时数据来源是否获得明确授权、是否允许二次加工和分发是必须先确认的红线。如果你打算从某个论文附带的数据集出发自己整理务必仔细读清楚许可条款。有的数据集只允许学术研究不允许商业使用有的要求在使用时引用原作者的论文还有的明确禁止再分发。这些都必须在项目启动前明确别等模型都训好了才发现授权不合法那就太被动了。2.2 类别体系与YOLO标注文件结构这套数据集的类别体系只有两类normal_face和pain_face。前者代表非疼痛面部表情包括中性表情、自然状态、微笑等后者代表有明确疼痛特征的表情包括皱眉、眯眼、口周紧张、鼻唇沟加深等面部动作组合。这里解释一个容易混淆的点这套数据集监听的到底是谁答案是“人脸”。每张图上把所有清晰可见的人脸都打了框框内的表情决定这个框归属哪个类别。这样的设计是为了让模型在真实病房环境中能同时完成两件事——发现人脸并给出疼痛判别。如果你自己打算在此基础上修改比如增加一个person类来做人脸与身体的关联也是完全可行的YOLO格式对多类别的扩展非常友好。每个标注对象在txt文件里是一行五列的记录# 依次为类别ID 归一化中心x 归一化中心y 归一化宽度 归一化高度 0 0.4821 0.3556 0.2184 0.2877 1 0.1244 0.7119 0.1053 0.1711类别ID从0开始编号0对应normal_face1对应pain_face。归一化坐标是关键——所有坐标值必须除以图片实际宽度和高度保持在0到1之间。这个约定是YOLO全系模型的通用标准从yolov5到yolov8再到最新版本都适用。2.3 数据分布与不均衡处理的思考放个统计数据在这里2200张图像中共标注约5400个人脸框其中pain_face框约1700个normal_face框约3700个。从框数量看两类比例约1比2.2有差异但没有到灾难性不均衡的程度。我们在实际训练时没有做大幅度的类别加权而是通过数据增强策略让模型在保持正常表情识别能力的同时把疼痛表情的召回率做上去。原因后面我会细讲——在医疗场景中漏检一个疼痛表情的代价往往大于误报一次。光照方面数据集里我刻意保留了室内日光、暖色病房灯、冷色荧光灯等不同色温条件下的样本。这么做不是随意为之而是因为颜色域偏移会影响人脸检测的稳定性。同一个人的面部在暖黄灯光和冷白灯光下像素分布差异非常大如果训练集只用了一种光源模型部署到另一环境时很容易出现精度断崖式下跌。3. 模型训练实操从拿到数据集到跑通检测3.1 训练前的数据集检查与结构划分拿到任何数据集第一步不是急着开train而是先检查数据质量。这个习惯我吃了很多次亏才养成。具体检查什么有三件事必备。一是检查标注框有没有越界、有没有宽高为0这种明显异常。YOLO格式虽然简单但标注工具导出的文件偶尔会有小数点精度问题某些框的坐标可能出现负值或者坐标超出图像范围。在训练前写一段简单的校验脚本遍历所有txt文件检测坐标是否在合理范围内能帮你省掉后面大量的训练排查时间。二是检查图像和标签文件是否一一对应。有些数据在整理过程中会出现图像丢失但标签还在、或者标签缺失但图像还在的情况。最常见的现象是训练到一半突然报FileNotFoundError。直接写个脚本统计两个目录下的同名文件数量几分钟就能查清楚。三是做分层划分。我把数据集按8比1比1的比例拆成训练集、验证集、测试集划分时按图像粒度随机打散但保证同一个来源的连续帧尽量分到同一集合避免训练集和验证集之间出现信息泄漏。这个细节直接影响评估结果的真实性——如果同一个人的不同表情图片同时出现在训练集和测试集里模型相当于提前“见过答案”mAP会虚高部署到新人群时立马现原形。3.2 关键训练参数与模型选择我在多个YOLO版本上反复试过结论是基于yolov5n和yolov8n做了完整对比实验。参数配置在高层次上是一致的这里给出一份经过验证的参考配置# dataset.yaml train: ./pain_dataset/train/images val: ./pain_dataset/val/images test: ./pain_dataset/test/images nc: 2 names: [normal_face, pain_face]训练启动命令以yolov8为例yolo detect train \ datapain_dataset.yaml \ modelyolov8n.pt \ epochs120 \ imgsz640 \ batch32 \ lr00.01 \ patience20 \ augmentTrue几个参数背后的逻辑必须说明白。imgsz用640是YOLO系列的默认值适合大多数人脸占画面中等比例的图像。但如果你处理的是高清摄像头下的人脸特写可以试试把imgsz提高到960或1280代价是训练和推理时间翻倍。epochs设120并不是越多越好我在实际训练中观察到到80轮左右验证集loss就开始进入平台期靠patience20的早停机制卡住能自动在最优位置结束训练。预训练权重这里有个很有用的策略。直接用yolov8n.pt在COCO上预训练过的权重作为起点比从零训练收敛快得多。因为COCO数据里本身就包含person这个大类模型对人脸附近的边缘纹理特征已经有了一定的基础表征能力。如果你希望模型更偏好人脸检测可以在训练前用一批含人脸但不含疼痛表情的普通图像先微调几步再切到疼痛检测数据集上正式训练。这个二次迁移的技巧能让小样本数据集的收敛更稳。3.3 评估指标怎么看才不翻车训练结束后大多数人第一眼会去看mAP0.5但医疗场景里只盯这一个数字是危险的。mAP0.5是类别平均精度在IoU阈值0.5下的均值它反映的是模型整体检测质量但对“漏检”和“误检”的区分不够直观。我建议重点看两张图Precision-Recall曲线和混淆矩阵。集中在Confusion Matrix上pain_face这一行的Recall值才是医疗场景的性命指标。简单解释一个患者术后回到病房如果模型把他真实的术后疼痛表情判成了正常表情这就是一次漏检可能导致医护人员错过干预窗口。反之把微笑错判成疼痛顶多让护士多跑一趟腿。两害相权模型设计必须偏重Recall宁多勿漏。如果发现pain_face的Recall过低最直接的办法是调整置信度阈值YOLO默认的conf阈值是0.25在实际部署时我会把它降到0.15左右来提升敏感度。当然了阈值降低意味着误检增加这个平衡需要根据具体病房的容忍度来调节没有一个固定答案。4. 从训练成果到真实落地4.1 模型导出与推理加速方案训练完了模型文件best.pt还不是最终交付形态。在真实医疗监测场景中我们通常把模型导出为ONNX格式再进一步转换成TensorRT engine部署在终端设备上。ONNX是各个推理框架通用的中间格式YOLO官方仓库已经内置了导出脚本命令也很简单yolo export modelbest.pt formatonnx opset12有了ONNX文件就可以用ONNX Runtime在CPU上做推理也可以用TensorRT在NVIDIA GPU上做极致加速。很多笔记本级GPU和嵌入式工控机上用TensorRT以后推理时间能压到20毫秒内人脸检测的实时性完全不是问题。我在实际测试中用TensorRT FP16精度跑一遍完整的tensored确实比直接跑PyTorch模型快了不少几乎感觉不出来延迟。需要提醒的是精度和速度的平衡在部署阶段要重新审视。FP16推理会损失少量精度如果这个模型被用在高危场景建议保留一份FP32精度的备份在医院实际部署前用测试集做一次A/B对比确认精度损失在可接受范围之内再切FP16。4.2 边缘设备选型与摄像头布点做视觉检测项目硬件选型往往是决定成败的隐形因素。疼痛检测要部署在病房不可能扛一台台式机放床头所以边缘设备是必然选择。根据团队不同预算有两条路线。一条是高性能路线选用带Tensor Core的嵌入式GPU设备配合TensorRT跑4路摄像头视频流单路延迟可以控制在30毫秒以内。另一条是低成本路线用单板ARM设备在CPU上跑yolov5n。yolov5n是YOLO系列里最轻量的一个变体模型参数量小CPU推理也能保持在每帧100毫秒左右的水平。谈出结论之前我先亲自试了CPU部署发现夜晚低照度场景时延迟会明显上升到了170毫秒左右台阶感比较明显。所以如果预算允许别在CPU上死磕加一块小GPU或者选用带NPU的异构平台体验完全不同。摄像头布点上也有一些值得注意的细节。面部表情识别对拍摄角度的敏感度比人体检测高得多正脸角度下的疼痛表情特征最完整侧面超过30度时皱眉和口周紧张这些关键特征会被部分遮挡。所以部署时摄像头最好正对患者面部避免逆光夜间模式的红外补光会影响色彩纹理需要重新评估模型在对应模式下的表现。4.3 隐私保护与伦理合规的现实约束这套系统不是纯机器自动判读而是辅助决策工具这个定位在隐私和伦理层面都很关键。病房监控涉及患者隐私数据采集必须事先取得患者或其监护人知情同意并且在医院信息科的授权下进行。图像数据在传输和存储时必须加密模型推理建议做本地化处理只输出脱敏后的状态标签和置信度数值不传出原始图像。这种“端侧推理、结果上报”的架构不仅是为了流速也是医疗机构接受这套系统的底线逻辑。我在项目落地的过程中体会很深技术方案做得再完美如果隐私流程没走通临床科室是不敢用的。反过来把数据合规性做在前面医护人员的接受度会大幅提升。5. 常见问题与排查技巧实录5.1 标注标准不一致导致训练loss异常波动这是我整理这套数据集时遇到的最棘手问题。最初一批样本来自不同标注人员的协同作业有人把微笑但带一点皱眉的样本标成pain_face有人则标成normal_face结果训练时loss曲线震荡得非常厉害mAP最高也只到0.6出头。排查思路是先看标注分布。我把所有pain_face类别对应图像做了一遍聚类抽查发现疑似被误标的样本集中在某一批来源里。重新检查后我统一了口径只有至少两个标准疼痛特征同时出现的样本才标pain_face单一模棱两可的特征一律归normal_face。重标后重新训练mAP立刻有可感知的提升。这个教训说明一个问题数据集质量的最大决定因素不是数量是标准的一致性。5.2 痛vs笑的混淆问题疼痛表情和某些表情的视觉特征有很大重叠。嘴部张开、眉头微蹙、眼周肌肉收紧这些特征在极度痛苦和部分假笑里可能同时出现。模型初期经常把嘴角上扬的疼痛表情判成normal_face或者把极度不自然的笑判成pain_face。缓解办法有两个维度。数据层面加大训练集里各种混合表情的数量尤其是疼痛伴随发声和身体动作的样本模型层面可以在顶部接一个小型的时序模块利用前后几帧的表情变化趋势来辅助判别。疼痛表情通常有一个快速出现、缓慢消退的过程而社交性微笑往往快速出现又快速消失。用连续几帧做判断比单帧判别的置信度高很多。5.3 小脸目标检测效果不佳病房场景里有时候人脸只占画面的一小部分比如广角监控下多个病床的画面。在640分辨率下小于32×32像素的人脸框很容易被模型漏检或检测不准。针对这个问题的优化思路有两层。一是训练时将输入分辨率提高到960或1280这让小脸目标的像素占比更大二是利用YOLO的多尺度检测特性在部署时同时跑两个尺度的推理把结果做融合。如果条件允许直接用YOLO官方针对小目标改进的P5/P6模型结构也能提升小脸召回。5.4 模型在不同医院的通用性下降训练集里的人群特征和部署现场的人群特征通常有分布差异。A医院的患者以中老年为主B医院可能以青壮年为主。我拿在A医院场景上训练的模型直接部署到B医院时pain_face的精准率掉了不少。解决这个问题最直接的办法是引入少量现场数据做微调。采集10到20个典型病例的脱敏样本手工标注后对模型做低学习率微调效果非常立竿见影。这里有个经验值微调时把学习率设置成原训练的十分之一到二十分之一epoch控制在20以内避免模型对原数据集产生灾难性遗忘。5.5 trainer和部署端精度不一致一个容易被忽略的坑训练时因为开了一堆数据增强模型看到的图像和部署时看到的真实图像分布不一致。尤其像Mosaic增强把四张图拼在一起训练短期能明显提升模型鲁棒性但训练最后阶段如果还开着很强的Mosaic模型可能适应了拼接图的分布实际部署时表现反而打折。我建议的做法是训练最后10到20个epoch把Mosaic关闭只用轻量级增强过渡收尾。这个做法在多个项目里都验证过能有效减小训练和部署之间的gap。这次整理疼痛检测数据集的过程让我更加确信一件事医疗健康类的视觉项目真正的难点往往不在模型结构而在于数据是否能真实反映临床现场的复杂情况。疼痛表情不像行人检测那样有清晰的边界它本身就是模糊的、连续的、因人而异的。做这套数据集的时候我一遍遍翻看那些疼痛样本里的细节特征逐渐建立起一个具体而微的认知眉头的肌肉走向、鼻翼扩张幅度、上唇和鼻唇沟的联动关系这些微小线索都在传递疼痛信号。把这些信号转化成YOLO能学会的标注框再用模型去自动发现它们这就是这套数据的价值。后续我自己也计划在时序模型和疼痛强度分级两个方向继续扩展结合这次积累的标注经验和踩坑记录把疼痛检测这套链路做得更完整。