简介面向室内人脸检测与耳朵部位识别的YOLO目标检测数据集共209张标注图片适用于YOLOv5、YOLOv7、YOLOv8、YOLOv11、YOLOv13及YOLO26等主流系列算法。压缩包内含421个文件其中211个jpg原始图像、209个txt格式标注文件及1个data.yaml配置文件整体体积仅8.67MB轻量易用。data.yaml已预设数据集配置并划分好训练集、验证集配合已标注好的txt标签可直接用于模型训练与效果验证无需额外预处理。图片覆盖室内场景下的人脸耳朵部位适合研究耳部检测、人脸关键区域识别及YOLO系列算法迁移实践的初学者与进阶开发者快速上手。资源描述中提供了对应博文链接便于对照了解模型训练细节与参数配置。目前已有14人浏览学习可作为YOLO系列目标检测入门与耳朵检测任务的轻量级基准数据。1. 这份“YOLOv11室内人脸耳朵目标检测数据集”到底解决什么问题目标检测落到“人脸”上常见落到“耳朵”上就少见了。这份数据集一共209张室内人脸图像标注类别只有一类——耳朵打包成zip标签按YOLO格式组织能直接喂给YOLOv11训练。对正在做YOLOv11目标检测入门、人脸关键点辅助、或者遮挡场景小目标检测的人它是一个完整的最小闭环数据量小到跑一次训练只要几分钟类别单一到不用纠结多标签平衡室内场景又让光照和背景相对可控。拿到手你能在半天内把“数据集→训练→导出→推理”整条链路走通同时也能切实体会到小数据集训练的典型翻车点过拟合、标签边界抖动、左右耳互串。这份笔记基于上述标题展开讲清楚这张数据集的真实边界、落地路径和参数调整方法。2. 拆解数据集的目录与标签格式拿到zip先做三件事2.1 解压后的预期结构与常见差异这份数据集严格按YOLO数据集的通用目录组织正常解压后你会看到两个文件夹images存放JPG格式图片和labels存放同名TXT标签文件。实际使用中我一般先把images里的图片数量和labels里的TXT数量对齐209张图就对应209个TXT文件多一个少一个都说明数据有问题。# 解压并核对文件数量 unzip YOLOv11室内人脸耳朵目标检测数据集-209张-标注类别为耳朵.zip -d ear_dataset cd ear_dataset find images -type f -name *.jpg | wc -l find labels -type f -name *.txt | wc -l代码逻辑很简单unzip把压缩包解压到ear_dataset目录然后用find分别统计JPG和TXT的数量。如果两边数字不一致优先检查是否有图片文件没有对应标签这种文件在训练时会被YOLO自动跳过但会浪费一次训练batch。注意有些打包者在标签类别命名上做文章有的写成ear有的直接写0TXT内容才是唯一可靠的信息来源。接着用一条命令抽查一下TXT内容cat labels/001.txt # 预期输出形如0 0.4821 0.5633 0.2145 0.1876这个输出里有5个数字含义依次是类别id、归一化后的中心点x坐标、中心点y坐标、归一化后的框宽、归一化后的框高。这里有一个关键细节坐标全是0到1之间的浮点数除以了图片宽高不是像素值。如果你看到某个TXT里的坐标值大于1或者出现了负数这份数据的标注基本不可信需要先清洗。2.2 用五秒脚本检查标注边界是否越界YOLO格式对坐标的规范非常严格中心点坐标和宽高都必须在0到1之间越界意味着标注框超出了图片边界。这种错误在手工标注的数据集里很常见虽然YOLOv11训练时不会直接报错但损失函数计算出的边界框预测会往错误方向偏移最终表现为mAP低、检测框位置偏差。import os label_dir ear_dataset/labels for file in os.listdir(label_dir): if not file.endswith(.txt): continue with open(os.path.join(label_dir, file)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f文件 {file} 格式异常: {line}) xc, yc, w, h map(float, parts[1:]) if not (0 xc 1 and 0 yc 1 and 0 w 1 and 0 h 1): print(f文件 {file} 坐标越界: {line})这段脚本逐个TXT检查5列数据一旦发现坐标不在0到1范围立刻打印文件名和原始行。运行后如果没有输出说明这批数据在格式上是干净的。如果有输出根据越界的行定位到对应图片人工看一眼是标注手误还是图片本身就有问题不要批量直接删因为有时只是某个标签文件写错整张图还是能用的。2.3 精确到像素的可视化标注验证格式检查通过只是第一步还得验证标注框和耳朵实际位置是否对齐。最快的方式是将归一化坐标还原成像素坐标用Python的PIL或OpenCV画框到你自己的图片上肉眼逐一核对。我通常会随机抽20张做验证因为全部209张一张张看成本太高20张已能暴露绝大多数标注错位问题。import cv2 import os img_path ear_dataset/images/001.jpg label_path ear_dataset/labels/001.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: cls, xc, yc, bw, bh line.strip().split() xc, yc, bw, bh map(float, (xc, yc, bw, bh)) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, ear, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1) cv2.imwrite(check_001.jpg, img)这段代码将归一化坐标反算为像素坐标并用红色矩形框画在图片上。重点关注三类情况框是否恰好包裹住耳朵整体、左右耳是否都能被框住、以及头发遮挡时边界是否贴齐。耳朵是柔性目标标注的边界主观性较强不同标注员画出的框可能相差几个像素这种边界抖动在小数据集上会被放大。我一般会拿5到10张明显存在遮挡的图做二次校正这类图对提升模型鲁棒性帮助最直接。3. 从209张到可用模型训练配置与YOLOv11建图要点3.1 环境准备和显存门槛YOLOv11基于ultralytics组织安装方式与v8一致PyTorch环境准备好后一条pip命令就能装齐pip install ultralytics显卡方面YOLOv11n是最适合这个数据集的规格模型参数量小输入640×640分辨率下6GB显存能够顺畅训练2GB显存用batch size为2也能勉强跑不建议直接上yolov11l或yolov11x209张图不会因为你模型更大就涨点反而更容易过拟合。CPU训练就不建议尝试了哪怕只有209张图训练一个epoch也要好几分钟累计几十个epoch会相当煎熬。推理阶段CPU倒是没问题后面会提到部署时的float16转换。注意ultralytics新版本在训练时会自动从官方仓库拉取预训练权重如果你处于离线网络环境需要先在有网环境下载好yolov11n.pt放进当前目录并设置环境变量指到它。如果恰好没有这个文件而又无法联网训练会卡在下载阶段很久然后报连接错误。这是实际项目里最常见的起步卡点。3.2 写data.yaml类别名和路径要精确到能跑通训练前先建一个data.yaml让YOLOv11知道图片路径、标签类别数量和类别名# data.yaml path: ear_dataset train: images val: images names: 0: earpath指向数据集根目录train和val是相对根目录的图片文件夹路径。严格来说训练集和验证集应该分开放但这个数据集只有一个images目录所以这里val也指向同一个文件夹YOLO会自行从训练数据里划分一部分图片做验证默认比例是10%。如果你手动切好了训练集和验证集就把val改成验证集路径这样评估结果更能反映真实泛化能力。names下类别id从0开始必须和TXT标签文件里第一个数字对应。这份数据集只标注了耳朵一类那么所有TXT里的第一列数字应该是0。一旦你不小心把类别名改成了从1开始或TXT里的类别id写成了1训练时类别数会变成2loss却始终学不好。3.3 最小训练命令与三个关键参数在上述yaml准备好之后训练命令非常简洁yolo train datadata.yaml modelyolov11n.pt epochs200 imgsz640 batch16 device0epochs200是给209张图准备的底线过少会让耳朵框不收敛过多会在50个epoch后开始过拟合。batch16在6GB显存上跑yolov11n是安全的低于这个数时学习率需要等比调小。imgsz640是保底分辨率如果你追求更精准的小目标检测可以换到960但显存占用会明显上升。训练结束后runs/detect/train目录下会生成weights/best.pt和weights/last.pt。best.pt以验证集mAP为标准挑选最优权重是后续导出和推理的首选last.pt是最后一个epoch的结果通常比best差一些但如果你怀疑验证集划分不具代表性可以对照测试一下。训练过程中的日志重点看box_loss、cls_loss和mAP50-95耳朵是单类目标所以cls_loss变化不会很大box_loss才是判断收敛的主要指标。如果box_loss在前50个epoch还停留在1.5以上大概率是标注框噪声大或者学习率设置不合理。3.4 验证集划分与早停的正确用法YOLOv11训练中有一个patience参数控制早停含义是连续多少个epoch在验证集上没有提升就提前结束。小数据集训练时mAP波动幅度比大数据集大得多调patience30比较合适避免过早停下来错过后续的涨点yolo train datadata.yaml modelyolov11n.pt epochs200 imgsz640 batch16 patience30对于只有209张图的数据集验证集如果切太小验证结果随机性很强切太大训练数据不够。我的建议是手动按9:1切分用190张做训练、19张做验证。这样模型见过足够多的样本验证集又有统计意义。可以顺手写一个切分脚本把images目录里的图片按比例随机复制到train/images和val/images对应TXT也同步复制。不用做K折交叉验证这个量级的数据训练成本低但K折的边际收益不明显。4. 训练翻车实录耳朵数据集的6个常见坑和排查手段4.1 坑一准确率很高但推理框乱飘现象验证集mAP50超过0.9看起来很不错实际跑视频流时耳朵框会在脸上到处跳动甚至框到额头和眼睛上。原因209张图片对yolov11n来说太少模型把训练集的背景和噪点一起记住了属于典型的过拟合。验证集和训练集来自同一批图的随机切分风格高度接近所以指标虚高。解决第一最有效的手法是数据增强YOLOv11默认开启hsv_h、hsv_s、hsv_v、translate、scale等增强策略但flip方向等参数适合手动再调。训练命令里加fliplr0.5Mosaic增强也能补充背景多样性。第二换用带预训练权重的yolov11n.pt而不是从头训练能把特征提取底子带上。第三增加验证集和训练集的风格差异把光照变化大的图片尽量分到验证集。4.2 坑二左右耳当成一类导致的框定位偏移现象训练后推理左耳和右耳都能检测出来但很多框落在耳朵偏上或偏下的位置看起来就是没有完全包裹住耳朵形态。原因标注时把左右耳统一为ear类别而左右耳在图像中的纹理方向、遮挡情况完全不同。模型学到的特征是“近似耳朵区域”而不是精确的耳朵边界导致框的回归在左右耳间取了一个折中。解决如果使用场景对左右耳区分没有要求这类框偏移可以容忍通过提高NMS的IoU阈值能缓解一部分重叠框问题。如果业务需要区分左右耳建议把标签细化为left_ear和right_ear两个类别并重新标注对应TXT的类别id。209张图重新标注不到两个小时但模型输出会稳定很多。4.3 坑三标签类别id对不上训练时损失炸掉现象训练日志里cls_loss一直不降最终mAP为0打开预测结果全是空白框。原因TXT文件第一列类别id实际标的是1但data.yaml里names只定义了一个类别且id从0开始也就是模型期望的类别id是0。两者对不上后标签会被忽略或映射到错误类别。解决先批量扫描所有TXT的第一列取值awk {print $1} labels/*.txt | sort -u如果输出里出现了0和1说明标注不一致需要统一替换sed -i s/^1 0/0 / labels/*.txt这里要对替换逻辑保持谨慎只把首列的1替换成0不要碰坐标列。替换后重新跑一次awk确认输出只有0。4.4 坑四图片尺寸混杂Shape mismatch报错现象训练刚开始几秒就报shape mismatch或AssertionError。原因数据集里图片分辨率不统一有的横构图1280×720有的竖构图720×1280。YOLOv11本身支持多尺度训练但标签归一化坐标有时是按原图宽高算的如果图片在预处理时被resize得过于狠某些小耳朵的宽高在缩小后低于模型的最小检测尺寸训练时这些目标会直接不被匹配到正样本而且极端情况下会造成张量形状冲突。解决最简单的手段是统一图片尺寸到最接近的整数倍比如最长边缩放至1280或者把所有图片resize到640×640再训练。注意resize图片时TXT里的归一化坐标不需要改因为数据集会按这个比例再缩放。不过resize会丢失一部分小目标细节如果有条件更推荐按原始尺寸训练只把imgsz设为数据集主流分辨率。4.5 坑五训练很慢或直接OOM显存卡死现象训练到中途显存占满进程被系统杀掉日志最后出现CUDA out of memory。原因batch16在当前显卡上超出显存预算特别是开了cacheTrue时YOLOv11会尝试把整批图片载入显存。209张图总量不大但单张图尺寸如果偏大显存爆掉并不意外。解决降低batch大小是首选8或4都可以yolo train datadata.yaml modelyolov11n.pt epochs200 imgsz640 batch8也可以不开cache让图片按批次从磁盘读取代价是训练时间变长。对于这种小数据集cacheTrue其实很有用但如果爆显存就把它关掉。4.6 坑六NMS后同一个耳朵出现多个框现象推理结果里同一个耳朵被框了2到3次置信度都还不低。原因模型对同一目标预测了多个高置信度候选框NMS的IoU阈值默认是0.45低于这个阈值的框不会被合并。耳朵边缘纹理丰富相邻锚点预测出高度重叠的框放大了这个问题。解决推理或导出时把NMS的iou阈值从0.45提高至0.6或0.65。提高阈值意味着两个框重合度超过60%才合并能有效减少同目标多框。但如果阈值过高于0.8框又会开始分裂。实际项目里从0.6起步逐个测试看效果。置信度阈值建议设置在0.25到0.3之间过低会带回大量误检。5. 从训练到落地部署导出、量化与Jetson边缘设备参考5.1 导出ONNX与TensorRT引擎时锁住输入尺寸训练完成后导出是最容易出差错的环节。用以下命令把best.pt导出成ONNX格式yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640 dynamicTruedynamicTrue允许输入尺寸动态变化方便不同分辨率下测试。但如果你要部署在Jetson设备上并转成TensorRT引擎必须把输入尺寸固定下来。TensorRT对动态尺寸的推理需要额外设置profile处理起来费时费力yolo export modelruns/detect/train/weights/best.pt formatengine imgsz640 device0formatengine需要本机已安装TensorRT导出过程中会自动完成FP16量化。在Jetson Nano这类设备上我建议固定输入尺寸为480或416原因很简单耳朵目标小分辨率太低检测不到太高推理耗时明显。传感器的安装距离和视场角决定了耳朵成像大小先拍几张实际场景图量一下像素再决定用640还是480。不要凭感觉直接量。5.2 推理参数边界框输出和后处理的手动调整导出的engine文件在ultralytics里直接加载推理from ultralytics import YOLO model YOLO(best.engine) results model.predict(test.jpg, conf0.3, iou0.6, imgsz640) boxes results[0].boxes for b in boxes: print(b.xyxy.cpu().numpy(), b.conf.cpu().numpy(), b.cls.cpu().numpy())conf0.3表示置信度阈值iou0.6是NMS的IoU阈值这两个参数需要根据实际场景微调。室内固定摄像头场景下目标大小比较稳定conf可以适当调高到0.4来滤掉背景误检如果是手机拍摄的偏远小目标conf反而要降到0.2否则漏检严重。b.xyxy是像素坐标框b.cls是类别id后处理时直接就能往业务逻辑里接。5.3 Jetson Nano上的参考配置Jetson Nano 4GB的显存和算力都有限但推理单张室内人脸图还是有希望的。把engine用FP16导出imgsz设为480batch size固定为1推理耗时大约在80毫秒上下也就是12帧左右的实时性能。要跑到15帧以上往下调整输入尺寸到416或者将模型换成更轻量的变体。从实际项目角度看室内耳朵检测对帧率要求通常不高因为耳朵不会快速移动10帧足够用。外部设备读取方面用普通USB摄像头加OpenCV读帧再送入模型推理即可。如果要做边缘端实时检测建议先在地面用同一尺寸和推理模式测试一段录制视频确认耳朵检测框的稳定性再动嵌入式部署。6. 最后但最关键的一步用数据增强让209张耳多数据集尽可能逼近可用这个数据集的硬限制是209张图片太少哪怕训练阶段yolov11默认开了Mosaic增强也只是在已有图片上做裁剪拼贴不能凭空创造新的耳朵形态。想让模型真正应用到室内不同人的耳朵检测上我建议在训练前做一步离线增强把数据量扩到1500到2000张级别。离线增强不改变标签坐标值因为所有操作都是等比缩放、平移、旋转、亮度调整等保持标签语义的操作。一张耳朵图通过水平翻转、旋转15度、亮度调整、高斯噪声叠加、随机裁剪能生成8到10张新样本。水平翻转对耳朵检测特别有意义因为左右耳纹理本来就有天然对称性翻转等于免费把训练集中的耳朵种类翻了一倍。import cv2 import numpy as np import os import random src_img_dir ear_dataset/images src_lbl_dir ear_dataset/labels out_img_dir aug_dataset/images out_lbl_dir aug_dataset/labels os.makedirs(out_img_dir, exist_okTrue) os.makedirs(out_lbl_dir, exist_okTrue) for img_file in os.listdir(src_img_dir): if not img_file.endswith(.jpg): continue img_path os.path.join(src_img_dir, img_file) lbl_path os.path.join(src_lbl_dir, img_file.replace(.jpg, .txt)) img cv2.imread(img_path) h, w img.shape[:2] with open(lbl_path) as f: objs [line.strip().split() for line in f] # 水平翻转并同步翻转标注框 flip_img cv2.flip(img, 1) flip_objs [] for o in objs: cls, xc, yc, bw, bh o flip_objs.append([cls, str(1 - float(xc)), yc, bw, bh]) # 保存增强样本 save_base img_file.replace(.jpg, _flip) cv2.imwrite(os.path.join(out_img_dir, save_base .jpg), flip_img) with open(os.path.join(out_lbl_dir, save_base .txt), w) as f: for o in flip_objs: f.write( .join(o) \n) # 亮度调整与噪声保留原标注 for i, r in enumerate([0.7, 1.2, 1.5]): adjusted cv2.convertScaleAbs(img, alphar, betarandom.randint(-10, 10)) save_base img_file.replace(.jpg, f_bright{i}) cv2.imwrite(os.path.join(out_img_dir, save_base .jpg), adjusted) with open(os.path.join(out_lbl_dir, save_base .txt), w) as f: for o in objs: f.write( .join(o) \n)增强代码的核心逻辑是水平翻转时将中心点x坐标从xc改为1-xcy坐标和宽高不变亮度调整和噪声不改变目标位置所以标签文件原样复制。运行后aug_dataset里的图片数量会是原来的4倍以上。将这些增强后的图片并入训练集train路径指向新的文件夹再配合yolov11n预训练权重训练200个epoch验证集mAP通常能比只用原始数据稳定3到5个点更重要的是推理框的抖动会明显减少。增强力度要克制。耳朵检测对形态敏感旋转超过20度或严重遮挡的增强样本会让模型学到错误分布。按我自己的习惯旋转控制在±15度亮度因子在0.7到1.5之间不做随机擦除和cutout这类强增强对严重过拟合的恢复作用有限反而可能让模型对耳朵的响应变钝。另外增强后的数据集和验证集要保持严格分离不能让同一张原图的增强版本同时出现在训练和验证里否则mAP虚高部署后立刻现原形。数据增强完成后重新按第3章的流程训练并验证。如果验证集mAP稳定在0.92以上、推理框不再乱跳那份zip的价值就真正被榨出来了。我习惯在训练结束后把所有预测结果可视化到一段室内测试视频里逐帧观察这一步往往能发现mAP指标发现不了的偶发漏检。做目标检测项目被验证集指标骗过一次就会长记性209张的小样本尤其要用测试视频来兜底。希望这个从数据检查到增强训练再到部署验证的完整流程能帮你在类似小规模数据集上少走几个弯路。本文还有配套的精品资源点击获取