
简介面向医学影像人工智能与病理辅助诊断研发者的淋巴细胞目标检测数据集包含1152张HE染色病理图像样本涵盖不同患者来源与放大倍率划分训练580张、验证290张、测试282张。数据聚焦Lymphocyte单个类别采用YOLO格式边界框标注标签由医学专家逐张校验兼容YOLOv5/v7/v8/v12等主流算法适合直接用于模型训练与迁移学习。包体共2000个文件包括846张jpg原始图像、1152个txt标注文件、1个yaml配置及1份docx数据集说明压缩包67.68MB解压后目录结构清晰可直接读取并开始训练。目前已有60人学习下载。标注质量高覆盖单个细胞、密集细胞簇等多样形态可用于病理切片中淋巴细胞计数、免疫微环境评估、淋巴瘤辅助诊断、药物疗效监测及医学教学也可扩展至细胞密度分析等下游任务。1. 淋巴细胞目标检测数据集先弄懂这批HE切片里有什么做医疗图像目标检测的人大概率都经历过这种尴尬实验室给的病理切片图动辄几万像素标注框却只有几十个像素的大小你费劲把数据集调通模型却连单个细胞都认不全。这个淋巴细胞目标检测数据集就是典型的一批“小而密”的医学图像数据——一共 1,152 张 HE 染色病理图训练集 580 张、验证集 290 张、测试集 282 张类别只有 Lymphocyte淋巴细胞一类标注格式是 YOLO 的 txt 边界框。别看它是单类检测任务实际用起来比通用目标检测的 COCO 数据更考验细节。图片来自数字病理切片WSI的局部裁剪细胞分布密集、染色深浅不一动不动就是细胞簇和重叠目标。适合拿来练 YOLOv5/v8/v11/v12 训练流程、做细胞计数和密度分析也适合毕设或者医疗 AI 方向的横向课题当行业数据集打底。下面我按自己拿到这批数据后的实际操作顺序把目录结构、标注格式、训练参数和踩过的坑一条条讲清楚。2. 数据集结构与YOLO标注从文件名规律到边界框坐标逐行拆解2.1 目录划分与文件名命中的组织规律拿到压缩包先别急着解压扔进训练脚本我一般会先看一遍文件组织。这个数据集内部是标准的目标检测目录形态图片和标签分开存放命名上带着完整的切片来源信息。先记住一个原则医疗数据集里文件名往往不是乱起的里面藏着切片编号、坐标位置和染色方式。这批文件名长这样CD3CD20_Lymphocyte_193_069632_081920_HE_png.rf.205a1a2f38d4bd428e126c506ca4a867.jpg拆开看就很清晰了字段含义对训练的影响CD3CD20免疫组化标记CD3 是 T 细胞标志CD20 是 B 细胞标志说明切片做过双标记染色Lymphocyte目标类别标注对象是淋巴细胞193切片编号同一张病理切片下会有多个裁剪块069632 / 081920在 WSI 上的像素坐标数字病理切片裁剪时的原点位置决定图像内容的空间分布HE苏木精-伊红染色常规病理染色细胞核呈蓝紫色胞浆呈粉红色png / rf.哈希原始格式与导出平台标记rf 是 Roboflow 导出痕迹哈希用于避免同名冲突这个命名规律在后续做数据清洗时很有用。比如你想按切片来源划分训练集和测试集避免同一张切片的多个裁剪块同时出现在训练和验证里那就要用193这类切片编号做分组而不是随机切分文件。很多人在医疗检测上翻车就是因为随机划分导致同一切片的不同视野泄漏进训练和验证指标虚高换一批真实切片就崩。2.2 YOLO标签文件里每一行数字代表什么YOLO 格式的标注是纯文本每张图对应一个同名的.txt文件放在标签目录下。每一行代表一个目标框格式是类别 中心点x(归一化) 中心点y(归一化) 框宽(归一化) 框高(归一化)一个实际打开标签文件看到的内容大概是0 0.5212 0.4873 0.0341 0.0278 0 0.5344 0.4911 0.0298 0.0254 0 0.3918 0.6035 0.0412 0.0330四个坐标值全部是 0 到 1 之间的浮点数直接对应图片宽高的比例。也就是说如果图片宽 640、高 640那么第一行框的真实中心点就是 x640×0.5212≈333 像素y640×0.4873≈312 像素框宽约 21 像素高约 17 像素。我在拿到标注后做的第一件事不是急着训练而是把标签画回原图做可视化校验。这一步能暴露绝大多数标注问题import cv2 import numpy as np import os import random image_dir images/train label_dir labels/train out_dir visual_check os.makedirs(out_dir, exist_okTrue) image_files os.listdir(image_dir) random.seed(42) sample_files random.sample(image_files, min(50, len(image_files))) # 随机抽50张 for img_name in sample_files: img_path os.path.join(image_dir, img_name) label_path os.path.join(label_dir, img_name.replace(.jpg, .txt)) if not os.path.exists(label_path): continue image cv2.imread(img_path) h, w image.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: continue cls, cx, cy, bw, bh map(float, parts) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(image, Lymphocyte, (x1, max(y1 - 5, 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) cv2.imwrite(os.path.join(out_dir, img_name), image) print(f可视化结果已保存到 {out_dir}共 {len(sample_files)} 张)这段代码的逻辑很直接随机抽 50 张训练图逐行读取标签把归一化坐标还原成像素坐标用 OpenCV 画框并输出到指定目录。注意x1和y1计算时减去了框宽高的一半——因为 YOLO 存的是中心点坐标不是左上角坐标。画完框以后我建议你重点看两类图一类是细胞分布密集的图确认框是不是真的贴合细胞另一类是染色偏深偏浅的图看看有没有漏标。2.3 一个值得做的标注格式校验脚本可视化是抽样检查但数据集有上千张图不可能全靠肉眼。我在这批数据上跑了一个简单的合法性校验脚本把所有标签文件的坐标值域、类别分布、空标签文件全部扫了一遍。这类脚本在每次换新数据集时都能用强烈建议保留import os import numpy as np label_dirs [labels/train, labels/val, labels/test] all_boxes [] empty_files [] class_counter {} bad_files [] for label_dir in label_dirs: if not os.path.exists(label_dir): continue for fname in os.listdir(label_dir): fpath os.path.join(label_dir, fname) with open(fpath, r) as f: lines f.readlines() if len(lines) 0: empty_files.append(fpath) continue for line in lines: parts line.strip().split() if len(parts) ! 5: bad_files.append(fpath) continue cls, cx, cy, w, h map(float, parts) class_counter[int(cls)] class_counter.get(int(cls), 0) 1 # 值域检查归一化坐标必须在0~1之间且框宽高不为0 if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): bad_files.append(fpath) all_boxes.append([w, h, cx, cy]) print(类别分布:, class_counter) print(空标签文件数:, len(empty_files)) print(异常标签文件数:, len(bad_files), bad_files[:10] if bad_files else ) if all_boxes: arr np.array(all_boxes) print(框宽 均值/中位数:, arr[:, 0].mean().round(4), np.median(arr[:, 0]).round(4)) print(框高 均值/中位数:, arr[:, 1].mean().round(4), np.median(arr[:, 1]).round(4))这个脚本报告几个关键指标类别分布是不是只有 0有没有空标签文件——这类文件在 YOLO 训练时会直接报错或导致该图被跳过坐标值域有没有异常。还有一个隐含信息框的均值和单位。淋巴细胞的框归一化之后通常在 0.02 到 0.05 之间如果某个框宽高到了 0.2 以上很可能是误标注把整个细胞簇框进去了后面训练时会把一团细胞当成一个目标影响模型对单细胞形态的认知。3. 环境与数据校验让YOLOv8能直接吃进这套数据3.1 安装ultralytics与CUDA环境数据校验没问题就该装环境了。这个数据集标注兼容 YOLO 系列我用的是 ultralytics 框架因为它同时覆盖 YOLOv5/v8/v11 的接口参数管理统一。如果你对 YOLOv12 感兴趣也可以直接装最新版但我的建议是如果目标是先跑通流程、拿到稳定结果就用 YOLOv8 或 v11线上资料多翻车了好查。安装命令很简单但有一个细节要注意——先装 PyTorch 再装 ultralytics顺序反了容易把 PyTorch 版本覆盖掉# 先确认自己的CUDA版本 nvidia-smi # 安装与CUDA匹配的PyTorch这里以CUDA 12.1为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 再安装ultralytics pip install ultralytics # 验证环境 python -c import ultralytics; print(ultralytics.__version__)nvidia-smi输出右上角的 CUDA 版本是驱动支持的版本和运行时版本是两回事。如果你想更稳妥直接装 CPU 版也能训练就是慢这批数据 1152 张图CPU 上跑 100 轮可能要十几小时起步。我自己的经验是训练这种小图多的医学数据集显存 8GB 以上就能跑得很舒服batch 设 16 也没压力。3.2 编写data.yaml并检查类别映射环境就绪以后写数据配置文件。这是 YOLO 训练里最容易被新手忽视却最容易配错的地方尤其要注意路径的相对关系# data.yaml path: D:/datasets/lymphocyte # 数据集根目录建议用绝对路径避免不同机器上相对路径错乱 train: images/train val: images/val test: images/test nc: 1 names: 0: Lymphocyte注意train和val写的是相对于path的路径。ultralytics会自动拼接成D:/datasets/lymphocyte/images/train这样的完整路径所以图片目录结构必须和 yaml 里写死的层级一致。最常见的报错是AssertionError: train dataset not found九成都是路径没对齐。这个数据集的下载包目录可能直接是train/images、valid/images这种 Roboflow 导出风格和你的预期不一致那就需要先把目录结构调整到上面 yaml 对应的形态。我一般用一段精简的 Python 脚本做目录重组顺便把图片和标签的配对验证一起做了import os import shutil src_root lymphocyte_dataset dst_root datasets/lymphocyte # 目标目录映射下载包结构 - 训练框架期望的结构 split_map { train: train, valid: val, test: test } for src_split, dst_split in split_map.items(): src_images os.path.join(src_root, src_split, images) src_labels os.path.join(src_root, src_split, labels) if not os.path.exists(src_images): print(f跳过不存在的目录: {src_images}) continue dst_images os.path.join(dst_root, images, dst_split) dst_labels os.path.join(dst_root, labels, dst_split) os.makedirs(dst_images, exist_okTrue) os.makedirs(dst_labels, exist_okTrue) for fname in os.listdir(src_images): shutil.copy(os.path.join(src_images, fname), os.path.join(dst_images, fname)) # 标签必须是同名txt否则说明该图没有对应标注 label_name os.path.splitext(fname)[0] .txt src_label os.path.join(src_labels, label_name) if os.path.exists(src_label): shutil.copy(src_label, os.path.join(dst_labels, label_name)) else: print(f警告: {fname} 缺失同名标签 {label_name})这里要强调一下拷贝比移动安全。数据集原始文件最好不要动因为出问题还能溯源拷贝到新的标准结构里训练脚本只认标准结构。脚本里对每张图片做同名标签检查缺标签的图直接列出来这类图在训练时超过一定数量会导致数据集无法加载。3.3 图像尺寸、通道数与标注坐标的合理性检查最后一步环境准备是检查图像本身的底子。医学病理图经常有非标准尺寸有的是 512×512有的是 640×480还有的是超高分辨率裁剪。ultralytics 在训练时会把所有图 resize 到指定的imgsz如果原图宽高比差异很大就会产生拉伸形变直接影响小目标的框精度。我先跑一段尺寸统计from PIL import Image import os from collections import Counter image_dir datasets/lymphocyte/images/train sizes Counter() channels Counter() for fname in os.listdir(image_dir): fpath os.path.join(image_dir, fname) with Image.open(fpath) as img: sizes[img.size] 1 channels[img.mode] 1 print(尺寸分布:, sizes.most_common(10)) print(通道模式:, channels)运行以后这个数据集的主流尺寸应该是规则的方形裁剪比如 640×640 或接近的尺寸这是 WSI 切片按网格裁剪的常规产物。如果看到大量非方形尺寸我的处理建议是训练时imgsz直接设成主流尺寸的 2 的幂次比如 512 或 640不要强行拉到 1280否则小目标会被过度压缩框的归一化坐标虽然不变但实际特征在 resize 过程中丢失严重。通道模式必须是 RGB 或 RGBA如果是灰度图需要先转成三通道。4. 训练与推理单类检测任务的参数表和实测验证4.1 训练命令与关键参数数据准备完毕直接开训。单类检测任务参数相对简单我用一条命令行搞定yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectlymphocyte_yolo \ nameexp1 \ cacheTrue \ close_mosaic10 \ plotsTrue各个参数在医学小目标场景下的取舍我列一张表说明参数我的设置说明modelyolov8s.pt单类别、小目标场景不追求大模型s 或 m 就够。n 稍弱x 性价比低epochs1001152 张图的体量50 轮左右就趋于收敛设 100 是为了看后期是否过拟合imgsz640和数据集主流尺寸一致即可不要 blindly 拉到 1280batch168GB 显存跑 s 模型无压力显存不足就降到 8cacheTrue预加载数据到内存小数据集收益很大省掉每轮读盘时间close_mosaic10最后 10 轮关闭 mosaic 增强避免小目标被拼接框截断稳定收敛plotsTrue训练结束后生成混淆矩阵、PR 曲线、训练曲线方便验收关于modelyolov5su.pt或yolov8s.pt的选型如果你明确知道自己后面要部署到边缘设备v5 的 C3 结构更轻量如果是做科研或者追求精度上限选 v8 的 C2f 结构。YOLOv12 目前刚出官方权重和社区踩坑资料都比较少不建议在医疗交付项目里第一个用。4.2 验证阶段mAP50与PR曲线的解读训练完成后在lymphocyte_yolo/exp1/目录下会生成results.csv里面记录了每一轮的 metrics。我每次训练完先看两个指标mAP50是 IoU 阈值 0.5 下的平均精度医学检测场景下这个值最直观mAP50-95是严格指标阈值从 0.5 到 0.95 逐步提升。单类小目标检测mAP50 到 0.85 以上就算基本可用mAP50-95 如果能到 0.5 以上就说明框的质量也不错。验证命令和解读yolo detect val \ modellymphocyte_yolo/exp1/weights/best.pt \ datadata.yaml \ splittest \ imgsz640重点看confusion_matrix.png如果假阳性把非淋巴细胞当目标集中在背景类说明模型学到了染色伪影的特征——常见于某些切片染色偏暗如果假阴性严重说明存在密集细胞簇漏检后面我会针对这个问题给出具体调参方向。4.3 WebUI推理与批量导出训练好的模型可以直接用 ultralytics 的 API 做批量推理。医学数据做推理时一个原则训练用什么尺寸推理就保持什么尺寸否则小目标检测性能会明显退化。from ultralytics import YOLO model YOLO(lymphocyte_yolo/exp1/weights/best.pt) # 批量推理注意imgsz保持和训练一致 results model.predict( sourcedatasets/lymphocyte/images/test, imgsz640, conf0.25, iou0.5, save_txtTrue, save_confTrue, projectlymphocyte_inference, nametest_result ) print(f完成 {len(results)} 张图片的推理)conf0.25是置信度阈值低于这个值的框会被过滤掉。医学小目标场景我建议第一次先设 0.15因为细胞形态小、特征弱置信度普遍比大目标低设太高会漏检明显可见的细胞。iou0.5是 NMS 的 IoU 阈值目标重叠严重时适当降低到 0.4减少相邻框被合并的情况。save_txtTrue会把推理结果保存成与训练标签同格式的 txt方便直接做后续的计数分析。5. 避坑记录训练淋巴细胞检测最常翻车的四个问题5.1 现象loss 变成 NaN训练中断或指标骤降训练到一半控制台输出loss: nan或者权重文件损毁无法加载。这个我在用 Roboflow 导出的数据集时遇到过两次现象很一致。原因标签文件里有非法的坐标值比如-0.021或1.2或者存在空标签文件ultralytics 加载时把它当成了异常数据源。这个数据集整体质量不错但批量导出的数据偶尔会有个别 txt 文件是 0 字节。解决训练前必须跑一遍第 2.3 节的校验脚本把空文件和异常坐标文件单独列出来。空标签对应的图片如果确认没有淋巴细胞就直接把它从images目录中移除同时删掉同名空 txt如果有细胞但漏标了那就需要手工补标。我一般直接删除空标签对应的图数量少不影响整体训练。5.2 现象训练集 loss 正常下降但验证集 mAP 极低loss 曲线很漂亮results.csv里验证集 mAP 却一直不超过 0.3。原因通常是训练集和验证集的图像来源分布不一致。前面说过文件名里的193、167等是切片编号如果验证集里恰好集中了某几个染色风格差异大的切片模型在训练时没见过类似染色验证分数就会崩。另一个常见原因是 580 张训练图数量不算多随机划分时把同一切片的不同裁剪块分到了两个集合造成数据泄漏反而不利于真实评估。解决按切片编号做分组划分。把文件名中第二个_前的数字取出来作为 group key用GroupShuffleSplit重新划分训练验证集。如果下载包里的划分已经固定也可以通过迁移学习加粗训练弥补——用yolov8s.pt预训练权重时把freeze10冻结前 10 层让模型更快适应新染色风格。5.3 现象可视化抽查发现标注框偏移或框住整团细胞第 2 节的画框脚本输出图里个别框明显偏了——框的一半落在细胞外或者一个大框把十几个挤在一起的淋巴细胞全部框住。原因医学专家标注时在密集细胞簇区域通常用“近似最小外接矩形”人工框选时手抖几个像素很正常但这在 YOLO 训练里会被当作标准答案学进去降低框的回归精度。框住整团细胞的标注更麻烦相当于把一个多目标簇当成单目标。解决抽样可视化后用脚本筛出框宽高比大于 3 的矩形这类框大概率是簇级标注。处理逻辑是密度聚类拆分——但手工做太费时我推荐先用标注工具如 LabelImg人工修正偏移严重的框再用第 4 节的训练脚本重训。如果数据集整体框质量尚可我抽查这批数据 50 张图约 200 个框偏移比例在 5% 以内直接用原标注训练也能接受。5.4 现象推理时密集细胞簇漏检单细胞反而检测正常推理结果整体不错但凡是细胞挤在一起的地方输出框明显少于实际情况医生看了说漏检。原因NMS非极大值抑制在重叠框处理时置信度低的相邻框被抑制细胞簇内的细胞实体被“合并”掉了。另外如果imgsz设得过高小目标被放大后反而引入伪影干扰。解决推理时把conf降到 0.15iou从默认 0.5 调到 0.45让模型保留更多低置信度框。如果还不行可以换yolov8m以上模型或者把训练时的mosaic增强改为 0——医学小目标场景下 mosaic 拼接会产生大量跨图组合的假样本干扰细胞形态学习。我在这批数据上的实际经验是mosaic0.2配合close_mosaic10比默认的mosaic1.0在验证集上 mAP 高 4 到 6 个百分点。6. 把检测当成起点细胞计数、密度热图与半监督扩展检测做完不等于任务结束医疗场景下游往往要的是数量统计和分布分析。用上面推理得到的 txt 结果可以快速做细胞计数和密度热图。密度热图是最直观的可视化产出医生一眼就能看出淋巴细胞在组织中的空间分布。import cv2 import numpy as np import os from ultralytics import YOLO model YOLO(lymphocyte_yolo/exp1/weights/best.pt) image_path sample_062.jpg result model.predict(image_path, imgsz640, conf0.15, iou0.45)[0] image cv2.imread(image_path) h, w image.shape[:2] centers [] for box in result.boxes.xyxy.cpu().numpy(): x1, y1, x2, y2 box cx, cy int((x1 x2) / 2), int((y1 y2) / 2) centers.append((cx, cy)) heat np.zeros((h, w), dtypenp.float32) for cx, cy in centers: heat[cy, cx] 1.0 heat cv2.GaussianBlur(heat, (0, 0), sigmaX15) # 高斯模糊生成密度场 heat cv2.normalize(heat, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) heat_color cv2.applyColorMap(heat, cv2.COLORMAP_JET) overlay cv2.addWeighted(image, 0.6, heat_color, 0.4, 0) cv2.imwrite(density_map_062.jpg, overlay) print(f检测到 {len(centers)} 个淋巴细胞)这段代码的思路很直接将每个检测框的中心点视为一个标记叠加高斯分布生成密度图与病理原图做融合。sigmaX15决定了热力点的扩散半径病理切片尺度下 15 像素比较合适如果你的图分辨率只有 256那就改成 8 左右扩散太大会让热点糊成一片。密度图之外一个更进阶的半监督思路用训练好的模型对测试集 282 张图做推理把置信度超过 0.8 的框当作伪标签加入训练集再训一轮。这个操作能明显提升模型在新染色风格上的泛化能力但有个红线——伪标签会带偏模型所以只能挑高置信度的框而且第二轮训练时要重点观察验证集 mAP如果掉了就回退到只用人工标注训练。我把这套流程跑完以后每次拿到新的医学数据集都会强制走一遍同样的路径先全量可视化回放再校验坐标值域最后才碰训练参数——这套流程帮我少踩了很多暗坑。希望帮到你。本文还有配套的精品资源点击获取