简介血细胞图像数据集面向医学图像处理、血液疾病辅助诊断及深度学习分类任务的学习者与研究者可用于血细胞亚型识别模型的训练与验证。资源包共13227个文件以12515张jpeg增强图像为主体另含366张jpg原始图像、343个xml边界框标注、2个csv标签文件及1个txt说明压缩包约108.14MB。数据集包含约12500张血细胞增强图像按嗜酸性粒细胞、淋巴细胞、单核细胞和嗜中性粒细胞四类分文件夹存放每类约3000张同时附带dataset-master中410张原始图像及其子类型标签与边界框以及dataset2-master中2500张增强图像和对应csv标签。已有546人学习下载。读者可据此开展细胞分类建模、目标检测与数据增强对比实验xml与csv标注便于直接接入训练流程适合作为医学图像入门到进阶的实战素材。1. 血细胞图像数据集.zip从解压到跑通第一个检测模型你拿到一个叫「血细胞图像数据集.zip」的压缩包双击解压里面大概率是一堆按类别分好的文件夹或者一堆图像配一份 CSV 标注。问题从来不是「有没有数据」而是「这批数据能不能直接喂给模型、标注格式对不对、类别平不平衡、分辨率够不够」。血细胞图像本身有它的特殊性红细胞、白细胞、血小板在形态上差异明显但白细胞内部还有中性粒、淋巴、单核等亚型染色差异、光照差异、扫描仪差异会让同一类细胞看起来像两类。这个数据集能解决的核心问题是让你在本地快速搭起一条「图像分类或目标检测」的训练流水线验证预处理、增强、模型选型这一整套链路。适合谁做医学图像入门的学生、想验证检测算法在细胞场景表现的工程师、以及需要快速出 baseline 的算法团队。下面我按实际动手顺序把这条链路拆开讲。2. 先看清数据长什么样目录结构、标注格式与类别分布2.1 解压后先跑一遍数据体检脚本拿到压缩包别急着写模型先做数据体检。血细胞数据集常见的组织方式有两种一种是class_name/xxx.jpg的目录分类格式另一种是images/加annotations.csv或 COCO 风格的 JSON。先写个脚本把基本情况摸清楚。import os import json from collections import Counter from PIL import Image DATA_ROOT ./blood_cells # 解压后的根目录 # 1. 统计目录分类格式的类别分布 def scan_class_folders(root): stats {} for cls in sorted(os.listdir(root)): cls_dir os.path.join(root, cls) if not os.path.isdir(cls_dir): continue files [f for f in os.listdir(cls_dir) if f.lower().endswith((.jpg, .png, .jpeg, .bmp))] stats[cls] len(files) return stats # 2. 抽样看分辨率血细胞图常见 320x240 到 1024x768 def sample_resolution(root, n20): sizes [] for cls in os.listdir(root): cls_dir os.path.join(root, cls) if not os.path.isdir(cls_dir): continue for f in os.listdir(cls_dir)[:n]: p os.path.join(cls_dir, f) try: with Image.open(p) as im: sizes.append(im.size) except Exception as e: print(坏图:, p, e) return Counter(sizes).most_common(10) if __name__ __main__: dist scan_class_folders(DATA_ROOT) print(类别分布:, dist) print(分辨率TOP:, sample_resolution(DATA_ROOT))这段脚本干三件事统计每个类别的图像数量、抽样统计分辨率分布、顺带把打不开的坏图揪出来。参数上DATA_ROOT指向解压目录n20是每个类别抽样数量数据量大时可以调小。跑完你会得到两个关键信息类别是否平衡、分辨率是否统一。血细胞数据集里血小板样本往往远少于红细胞如果某类只有几十张后面训练必须做重采样或强增强。2.2 标注格式决定你后面用什么框架如果是分类任务目录名就是标签直接接ImageFolder或tf.keras.utils.image_dataset_from_directory。如果是检测任务标注通常是 VOC XML 或 COCO JSON。VOC 每张图一个 XMLCOCO 是一个大 JSON。先确认格式再决定转换路径。格式典型文件转换目标常用工具目录分类class/img.jpgImageFoldertorchvisionVOC XMLimg.xmlYOLO txt / COCO自写脚本COCO JSONannotations.jsonYOLO txtpycocotoolsCSV 坐标labels.csv自定义 Datasetpandas我一般会先写一个格式探测函数遍历前 50 个文件看有没有.xml、.json、.csv再决定走哪条转换路径。别小看这一步标注格式判断错后面训练 loss 不降你会怀疑人生。2.3 类别不平衡与染色差异的初步判断血细胞数据集的坑在于「同类不同染」。瑞氏染色和吉姆萨染色下同一类白细胞的色调差别很大。体检阶段可以抽每个类别 5 张图拼成一张网格图肉眼看。如果发现某类里混着明显不同色调的图要么是标注噪声要么是多个来源合并的数据。这时候有两个选择一是按色调做数据增强颜色抖动幅度调大二是直接清洗掉离群样本。新手建议先保留用强增强扛过去熟手可以做一次聚类把离群点挑出来人工复核。3. 把血细胞图像喂进模型预处理、增强与 DataLoader 落地3.1 预处理管线的四个必调参数血细胞图像预处理和自然图像不一样。自然图像常用 ImageNet 均值方差但血细胞图背景偏白或偏紫直接套 ImageNet 归一化会偏。我一般先算自己数据集的均值和方差再决定归一化参数。import torch from torchvision import transforms, datasets from torch.utils.data import DataLoader # 先算数据集均值方差跑一次即可 def compute_mean_std(root, img_size224): tf transforms.Compose([ transforms.Resize((img_size, img_size)), transforms.ToTensor() ]) ds datasets.ImageFolder(root, transformtf) loader DataLoader(ds, batch_size64, shuffleFalse, num_workers4) mean torch.zeros(3) std torch.zeros(3) n 0 for imgs, _ in loader: b imgs.size(0) imgs imgs.view(b, 3, -1) mean imgs.mean(2).sum(0) std imgs.std(2).sum(0) n b return mean / n, std / n # 训练用增强管线 train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), # 细胞可裁切 transforms.RandomHorizontalFlip(), transforms.RandomVerticalFlip(), # 细胞无方向性可翻转 transforms.RandomRotation(30), # 旋转不变性 transforms.ColorJitter(0.3, 0.3, 0.2, 0.05), # 染色差异靠它扛 transforms.ToTensor(), transforms.Normalize(mean[0.72, 0.58, 0.66], std[0.18, 0.19, 0.17]) ])参数说明RandomResizedCrop的scale(0.7,1.0)是因为细胞通常占画面主体裁太狠会丢信息RandomVerticalFlip对细胞图安全因为细胞没有上下之分ColorJitter的亮度、对比度、饱和度都开到 0.3 左右专门对付染色差异。归一化那三个数是我在类似血细胞数据上算出来的经验值你用自己的compute_mean_std跑一遍替换掉。3.2 DataLoader 的 batch 与 worker 设置血细胞数据集通常几千到几万张单机单卡足够。batch_size从 32 起步显存够就 64。num_workers设成 CPU 核数的 0.7 倍左右太多反而抢内存。如果数据集里图像分辨率差异大Resize统一到 256 再裁 224别直接 Resize 到 224否则小图放大糊、大图缩小丢细节。train_ds datasets.ImageFolder(./blood_cells/train, transformtrain_tf) val_ds datasets.ImageFolder(./blood_cells/val, transformval_tf) train_loader DataLoader(train_ds, batch_size64, shuffleTrue, num_workers8, pin_memoryTrue, drop_lastTrue) val_loader DataLoader(val_ds, batch_size64, shuffleFalse, num_workers8, pin_memoryTrue)drop_lastTrue在训练集上避免最后一个不满 batch 影响 BN 统计。验证集不 drop保证评估完整。pin_memoryTrue在 GPU 训练时能加速主机到显存的数据搬运。3.3 从分类到检测标注转换的边界如果数据集是检测标注转 YOLO 格式时注意坐标归一化。VOC 的xmin,ymin,xmax,ymax是绝对像素YOLO 要(x_center/w, y_center/h, bw/w, bh/h)。转换时最容易翻车的是图像尺寸读错——用 PIL 读的宽高和标注里记录的宽高不一致框就全偏了。import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): tree ET.parse(xml_path) root tree.getroot() w, h Image.open(img_path).size # 以实际图像尺寸为准 lines [] for obj in root.findall(object): cls obj.find(name).text if cls not in class_map: continue bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪防止标注越界 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(w, xmax), min(h, ymax) xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_map[cls]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) return lines关键点是w, h必须用Image.open实际读不能信 XML 里的size字段很多数据集这两者不一致。转换完抽 10 张用可视化脚本画框确认别直接开训。4. 训练与评估血细胞分类/检测的模型选型与指标4.1 模型选型轻量骨干优先血细胞图像特征相对固定不需要上超大模型。分类任务我一般从 ResNet18 或 EfficientNet-B0 起步检测任务用 YOLOv8n 或 Faster R-CNN ResNet50。原因是细胞形态特征在浅层就能捕捉深模型容易过拟合小数据集。如果数据量超过 5 万张再考虑 ResNet50 或 ConvNeXt-T。import torch.nn as nn from torchvision import models def build_classifier(num_classes, backboneresnet18): if backbone resnet18: model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.fc nn.Linear(model.fc.in_features, num_classes) elif backbone efficientnet_b0: model models.efficientnet_b0(weightsIMAGENET1K_V1) model.classifier[1] nn.Linear(model.classifier[1].in_features, num_classes) return model用 ImageNet 预训练权重即使血细胞和自然图像差异大浅层边缘纹理特征仍然可迁移。num_classes按你体检脚本统计出的类别数填。4.2 训练循环里的三个关键设置学习率用 1e-3 配 AdamW或者 1e-2 配 SGD cosine。血细胞数据集小我倾向 AdamW 1e-3收敛稳。早停 patience 设 7 到 10 个 epoch。类别不平衡时给 CrossEntropyLoss 加 weightweight 取类别频率的倒数归一化。from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR import torch device torch.device(cuda if torch.cuda.is_available() else cpu) model build_classifier(num_classes5).to(device) # 类别权重频率倒数 class_counts torch.tensor([1200, 800, 300, 150, 90], dtypetorch.float) weights (1.0 / class_counts) weights weights / weights.sum() * len(class_counts) criterion torch.nn.CrossEntropyLoss(weightweights.to(device)) optimizer AdamW(model.parameters(), lr1e-3, weight_decay1e-4) scheduler CosineAnnealingLR(optimizer, T_max30) for epoch in range(30): model.train() for imgs, labels in train_loader: imgs, labels imgs.to(device), labels.to(device) optimizer.zero_grad() loss criterion(model(imgs), labels) loss.backward() optimizer.step() scheduler.step() # 验证略见下节weight_decay1e-4防过拟合T_max30和总 epoch 对齐。类别权重那段class_counts换成你体检脚本的真实数字。4.3 评估指标别只看准确率血细胞分类里稀有类别比如嗜碱性粒细胞的召回率比整体准确率重要。评估时打印混淆矩阵和每类 F1。检测任务看 mAP0.5 和 mAP0.5:0.95但细胞检测框通常小mAP0.5 更有参考价值。from sklearn.metrics import classification_report, confusion_matrix def evaluate(model, loader, device): model.eval() preds, trues [], [] with torch.no_grad(): for imgs, labels in loader: imgs imgs.to(device) out model(imgs).argmax(1).cpu().numpy() preds.extend(out) trues.extend(labels.numpy()) print(confusion_matrix(trues, preds)) print(classification_report(trues, preds, digits4))classification_report会给出每类 precision/recall/F1重点看稀有类。如果稀有类 F1 低于 0.5回去加权重或做过采样。5. 血细胞数据集实操避坑5 个我踩过的坑5.1 坑一图像和标注尺寸不一致导致框全偏现象转完 YOLO 格式训练loss 不降可视化发现框整体偏移或缩放。原因XML 里记录的size和实际图像尺寸不同转换脚本用了 XML 里的尺寸。解决一律用PIL.Image.open读实际宽高转换后抽 10 张画框核对。5.2 坑二染色差异被当成类别特征现象模型在验证集准确率 95%换一批新染色的图掉到 60%。原因训练集里某类恰好都是某种染色模型学了颜色而不是形态。解决ColorJitter 幅度加大或做灰度化 直方图均衡逼模型看形状。5.3 坑三类别极度不平衡导致稀有类全预测错现象整体准确率 90%但血小板类召回率 0。原因血小板样本只有几十张被多数类淹没。解决CrossEntropyLoss 加类别权重或对稀有类做随机过采样、复制增强。5.4 坑四验证集和训练集来自同一批图像现象验证准确率虚高实际部署翻车。原因随机划分时同一张图的增强版本同时进了训练和验证。解决按图像来源或患者 ID 划分确保验证集图像在训练集里没出现过。5.5 坑五Resize 直接压到 224 丢小目标现象检测任务里小血小板框检测不到。原因原图 1024 直接 Resize 到 224小目标缩成几个像素。解决用 Letterbox 保持长宽比或切 patch 训练检测任务输入至少 640。6. 让血细胞模型真正可用进阶技巧与验证习惯走到这一步你已经有了一条能跑的流水线。但「能跑」和「能用」之间还差一层。我自己的习惯是每次训练完不只看指标还要做一次「盲测」从验证集里随机抽 30 张不看标签让模型预测人工核对。这一步能揪出指标看不出的问题比如某类总是和另一类混淆、某些背景被误判。进阶方向有三个。第一是 Test Time AugmentationTTA对同一张图做多次增强预测再平均血细胞分类上通常能涨 1 到 2 个点代价是推理变慢。第二是切图训练高分辨率血细胞涂片直接缩小会丢小目标把大图切成 512×512 的 patch分别预测再合并检测小血小板效果明显。第三是伪标签半监督用训练好的模型对未标注数据打伪标签筛高置信度的加入训练集适合你手头还有大量没标注的涂片图。验证习惯上我坚持两条一是固定随机种子保证每次训练可复现二是保存最佳模型时同时存下对应的预处理参数和类别映射否则过两周你自己都忘了当时用的什么归一化。血细胞数据集这类医学图像类别映射和归一化参数就是模型的「后悔药」丢了就得重训。最后说个我自己的教训早期做血细胞分类我图省事直接用 ImageNet 的均值和方差结果模型收敛慢、验证波动大折腾了一周才发现是归一化不对。后来养成习惯拿到任何新数据集第一件事就是跑compute_mean_std把这个数记在实验日志第一行。这个习惯帮我省下的时间远比写模型结构多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?