医学图像分类数据集实战:19类器官细胞与yolov5训练指南
发布时间:2026/9/28 8:14:58来源:尧图网络
简介医学图像分类数据集面向医学影像分析与深度学习分类任务涵盖肾上腺、子宫、甲状腺、食道等19种器官细胞图像训练集2100张、测试集500张已按类别分文件夹保存并附带类别字典JSON文件可直接用于CNN分类网络或YOLOv5分类模型训练与评估。资源包共2000个文件以1998张PNG图片为主另有1个类别字典文件和1个Python可视化脚本压缩包约260.22MB。目前已有176人学习使用。数据目录结构清晰训练集与测试集独立存放便于完成加载、训练和精度对比show脚本可快速预览样本图像class_indices.json提供类别索引映射免去手工整理标签的麻烦。分类类别丰富、样本划分完整适合医学图像分类入门、课程设计以及分类算法验证配套相关CSDN专栏还可帮助进一步理解分类网络和YOLOv5分类实现。1. 医学图像分类数据集19类器官细胞拿到手就能训练做医学图像分类最烦的不是搭模型而是找一份能直接用的数据。这份数据集给到了19类器官/细胞图片训练集2100张、测试集500张目录按data/train和data/test分好每个类别一个文件夹还附带class_indices.json类别字典和可视化脚本。解压之后不需要再写划分代码直接能喂给yolov5分类项目或者自己写CNN分类网络。我拆过不少所谓医学数据集很多都是只有原始图、标签要自己从XML里抠这份起码把数据源头理顺了。适合做细胞病理识别、器官影像分类的从业者或者拿真实医学图做baseline的算法工程师尤其是需要快速验证分类思路、又不想花一星期整理标注的人。2. 数据集目录结构与类别字典先看懂 json 再动手拿到数据集的第一步不是训练而是把目录和映射文件搞清楚。这套数据本身组织得很规整train和test各自内部按类别建文件夹同一类图片放在同一个目录里。这种组织方式在PyTorch的ImageFolder、Keras的flow_from_directory、yolov5的datasets里都是天然支持的不需要额外写映射表。2.1 train/test 划分与文件命名规律解压后你会看到data目录下有两个子目录训练集、测试集。每个子目录内部再按类别建文件夹图片命名形如img_Uterus_1_01061.png、img_Pancreatic_1_02328.png。命名结构可以拆成三段img是固定前缀中间是类别英文名后面是序号和编号。这种命名的好处是后期如果发现某张图有问题你能直接从文件名反查类别不用打开图片看。我建议先跑一段脚本统计每个文件夹的图片数量确认和描述一致训练集总量2100测试集总量500。如果数量对不上先检查是不是下载过程丢包或者解压时有文件被系统拦截。import os data_root data for split in [train, test]: split_path os.path.join(data_root, split) print(f {split} ) for cls in sorted(os.listdir(split_path)): cls_path os.path.join(split_path, cls) if os.path.isdir(cls_path): count len([f for f in os.listdir(cls_path) if f.lower().endswith(.png)]) print(f{cls}: {count})这段代码遍历train/test两个目录统计每个类别下png图片的数量。注意我加了endswith(.png)过滤防止目录里混入DS_Store之类的隐藏文件导致计数虚高。如果你后续要把数据转成其他格式记得同步改后缀。跑完这个脚本你就能得到一个19类的数量分布表立刻看出有没有类别特别少、样本特别不均衡的情况。类别名都是英文标识比如Uterus是子宫、Skin是皮肤、Pancreatic是胰腺、Kidney是肾脏。数据集说明里提到的肾上腺、甲状腺、食道等具体文件夹叫什么、有多少个类别请以json文件为准。千万不要凭文件名猜类别总数19个类别的实际英文标识很可能和你预想的不一样。如果后续需要重新划分数据集建议在复制文件时保留原始文件名因为文件名里已经携带了类别信息重命名会在数据清洗时增加不必要的麻烦。2.2 class_indices.json 的读取与映射class_indices.json是整个数据集里最值得先读的文件。它本质上是类别名到索引编号的映射训练时模型输出的softmax维度顺序就是按这个json的键值顺序来的。如果这个映射搞错你训练出来的模型预测结果和真实的类别名会对不上部署时会出大问题。用下面的代码直接加载并打印同时确认json的键值结构import json with open(class_indices.json, r, encodingutf-8) as f: class_indices json.load(f) print(类别总数:, len(class_indices)) print(映射内容:) for k, v in class_indices.items(): print(f{v}: {k})这里强制指定了utf-8编码因为json里如果包含中文类别名在Windows默认的gbk环境下不指定编码会直接抛异常。输出结果是索引到类别名的对应关系。注意有的json是{类名: 索引}有的是{索引: 类名}打印出来先确认结构不要想当然地拿v当类别名用。这个json文件在两类场景下必须引用。第一类是训练时如果使用PyTorch的ImageFolder它会按照文件夹名的字母顺序自动生成标签索引这个索引顺序可能和class_indices.json不一致。所以你需要手动调整数据集类的类别顺序或者直接用json里的映射重新组织训练数据。第二类是推理时模型输出的是索引你必须用这个json把索引翻译回类别名才能得到Uterus而不是3这样的结果。我一般会写一个包装函数把类别映射加载成一个list按索引顺序存放类别名这样推理时直接按索引取值import json def load_class_names(json_path): with open(json_path, r, encodingutf-8) as f: mapping json.load(f) # 兼容 {类名: 索引} 和 {索引: 类名} first_key list(mapping.keys())[0] if isinstance(first_key, int): class_names [mapping[i] for i in sorted(mapping.keys())] else: class_names [None] * len(mapping) for name, idx in mapping.items(): class_names[idx] name return class_names names load_class_names(class_indices.json) print(names)这个函数的逻辑是先看看key是整数还是字符串如果key是整数直接按key排序取值否则按value作为索引填到对应位置。这样不管json作者用什么风格你都能得到一份索引有序的类别名list。注意如果json里类别数和实际文件夹数不一致函数返回的list长度也会不对训练前人工核对一遍最稳妥。3. 用内置 show 脚本可视化验证图片与标签是否对齐数据集的干净程度直接决定训练效率。光看目录结构和json还不够图片和文件夹名对不对得上必须用肉眼确认。好在资源里带了一个show脚本专门干这个事。3.1 show 脚本用法与依赖show脚本就是一段Python程序依赖matplotlib和Pillow。先把环境装好pip install matplotlib pillow然后运行脚本。多数这类脚本会读取指定目录下的图片以网格形式展示常见用法python show.py --data data/train --num 8参数--data指定要可视化的目录--num表示每类显示几张图。不同脚本参数名可能不一样比如--split或--classdir先跑一下python show.py --help看看支持什么参数不要硬猜。如果脚本没有命令行参数那就直接改脚本里的路径变量。可视化主要解决三类问题图片是否损坏加载时抛异常或显示空白图片内容和文件夹类别是否匹配比如Uterus文件夹里混入一张皮肤图肉眼一眼能看出来样本是否过于相似或重复同一个文件夹下很多张图几乎一样说明原始采集存在重复采样会影响模型泛化。3.2 结果怎么看先对类别后对细节跑完show脚本屏幕上会显示一个大图包含多个子图每张子图左上角通常标着类别名和文件名。先快速扫一遍每个类别是否都是对应器官或细胞的图片确认大类没问题再放大看细节。医学图像的标志性结构比较明显比如皮肤组织的角质层、肾脏的肾小球结构如果你熟悉这些特征能很快判断分类是否合理。如果发现某个类别的图片明显不对比如文件夹叫Uterus但图片都是肝脏组织大概率是原始数据打包时放错了。解决方法是打开class_indices.json确认类别名和文件夹名字一一对应再把对应的子目录整体检查一遍。图片少就一张张看图片多就随机抽样看。这里有个经验不要只检查一个类要每类都抽几张尤其是样本数量少的类往往出错率更高。如果你觉得matplotlib默认显示窗口太小看细节费劲可以把figure的size调大plt.figure(figsize(12, 12))在脚本里找到plt.figure这一行把figsize参数改大。如果脚本用subplot方式可以调整子图的排列让每张图更大一点。用PIL单独看单张图也行但效率低不推荐作为主流程。4. 直接喂给 yolov5 分类模型数据组织与训练命令这套数据集最常见的用途就是做yolov5分类训练。yolov5从某版本开始集成了分类训练脚本classify/train.py它要求的数据目录结构是根目录/类别文件夹/图片。这份数据集本身结构就满足要求只需要把data目录指定给--data参数即可。4.1 yolov5 分类数据集目录要求yolov5分类训练时--data参数可以是一个目录路径该目录下每个子文件夹对应一个类别。比如python classify/train.py --model yolov5s-cls.pt --data data/ --epochs 50 --batch-size 32 --img 224注意这里的--data是你自己的data目录它下面必须有train和test两个子目录。yolov5会自动读取train和test并按照文件夹名称自动生成类别映射。如果你想要单独的验证集就把测试集当作验证集用或者自己从train里分出部分图片建一个val目录。这里有个关键坑yolov5自动生成的类别顺序是按照文件夹名的字母顺序排列的可能和class_indices.json里的顺序不一致。如果你训练完成后直接输出类别名做部署最好在训练前把class_indices.json的映射替换成yolov5生成的映射。怎么得到yolov5的映射训练时yolov5会把类别名写进训练日志或者在训练结束后打开runs目录下的结果文件查看。我更推荐的做法开始训练前手动检查数据目录下的类别文件夹列表按字母排序后和json对照。用下面的命令输出文件夹顺序ls -1 data/train/把输出的顺序记录下来和class_indices.json比对。如果顺序不一致优先以文件夹顺序为准因为yolov5内部就是按文件夹名排序的。然后写一个小脚本按排序后的文件夹名重新生成json覆盖掉原来的class_indices.json这样训练和推理用的是同一套映射。4.2 训练参数设置与结果验证yolov5分类训练有自己的一套参数直接套用目标检测的训练参数经常翻车。关键参数有这么几个--img决定输入图片尺寸。医学图像很多是显微镜下的细胞图分辨率高但内容相对简单用224或256就够了过大反而增加显存压力。--epochs建议50起步医学分类数据集小过拟合风险高50个epoch足够观察趋势。--batch-size根据显存调整常见8或16显存紧张就降到4。训练命令示例python classify/train.py \ --model yolov5s-cls.pt \ --data ./data \ --epochs 50 \ --batch-size 32 \ --img 224 \ --project runs/classify \ --name med19--project和--name用来指定输出目录跑完会在runs/classify/med19下生成训练曲线和最佳权重。训练完成后用验证脚本看准确率python classify/val.py --data ./data --weights runs/classify/med19/weights/best.pt --img 224这个命令会输出每类的准确率、混淆矩阵等信息。医学图像分类最怕所有类准确率都高但某一类医学上关键的类别偶尔漏检所以建议多看confusion matrix而不是只看总的acc。如果发现某一类的召回率明显低于其他类回第2章统计样本分布优先处理类别不平衡。5. 避坑医学图像分类数据集的五个常见问题整理一下我实际拆分和训练这套数据时踩过的坑每条按现象、原因、解决三步写。5.1 训练损失不降准确率一直低位徘徊现象loss前几个epoch有下降但后面一直震荡acc卡在10%左右甚至接近随机猜测的概率1/19≈5.26%。数据集看起来没问题网络却学不动。原因最常见的有两个。第一是类别不平衡比如某个类别有800张另一个只有50张模型偏向学大样本类。第二是学习率设置过高导致loss在最优解附近反复横跳小数据集尤其敏感。解决先跑统计脚本看每类数量如果差异超过3倍就需要重采样。常见做法是使用PyTorch的WeightedRandomSampler给样本少的类别更高的采样权重。学习率方面yolov5的默认学习率是针对ImageNet级别的数据量医学小数据集建议降低一个数量级比如把lr从0.01降到0.001或者用余弦退火调度。5.2 训练过程中报错提示图片尺寸不一致现象某个epoch报错Expected 3D or 4D tensor或者size mismatch检查代码发现是模型输入尺寸和图片实际尺寸不匹配。原因数据集内部图片分辨率不一定统一。有的图片是1024x1024有的是512x768如果数据加载器没有统一resize而模型默认输入是224x224就会在维度拼接时报错。解决在数据加载时强制统一resize。用PyTorch的transforms.Resize((224, 224))最省事但要注意医学图像的长宽比被改变可能影响诊断特征更推荐做长边缩放到224后再pad到正方形。在yolov5里直接设置--img 224它会自动做resize和letterbox处理。5.3 预测时类别标签对不上现象训练完测试模型输出索引3按class_indices.json查是甲状腺但实际图片看起来像食道。或者混淆矩阵里某一类互相错位严重。原因训练时yolov5按文件夹字母序生成索引而class_indices.json的索引顺序不是字母序。推理时用了json里的映射两者对不上。解决训练前先确认yolov5的类别顺序。以文件夹排序为准重新生成json。写一个脚本遍历train目录下的文件夹名按排序输出映射覆盖掉class_indices.json。这样训练和推理用的是同一个映射就不会错位。我一般会在训练完成后把模型输出的类别索引和实际文件夹名再核对一遍用几张图片做盲测。5.4 测试集和训练集存在重复图片准确率虚高现象测试准确率接近100%但拿到新图预测准确率骤降。怀疑过拟合但重训后仍然如此。原因数据划分时没有做去重。原始图像可能有相同细胞的不同切片或者同一张图被重复保存了多次只是文件名不同。这种重复样本既出现在train又出现在test会让模型记住图片而不是学泛化特征。解决对全部图片计算感知哈希pHash找出重复项。常用库是imagehash代码如下from PIL import Image import imagehash import os def deduplicate(root_dir): hashes {} dupes [] for split in [train, test]: split_path os.path.join(root_dir, split) for cls in os.listdir(split_path): cls_path os.path.join(split_path, cls) for fname in os.listdir(cls_path): if not fname.lower().endswith(.png): continue path os.path.join(cls_path, fname) try: h imagehash.phash(Image.open(path)) except Exception: continue if h in hashes: dupes.append((path, hashes[h])) else: hashes[h] path return dupes dupes deduplicate(data) print(重复对数量:, len(dupes)) for d in dupes[:10]: print(d)这里用哈希值为键如果两张图哈希相同说明视觉内容高度相似。跑完把重复的测试图像从test中剔除或者把重复样本全部只保留一份。对于医学图像完全相同的图很少但非常相似的切片会很多所以阈值可能需要调高。imagehash的phash默认是64位先用它扫一遍如果发现没有重复再换用dhash等其他方法。5.5 读取class_indices.json乱码或者键值顺序错乱现象在Windows下用Python读json打印出来中文类别名变成乱码或者键值顺序和预期不一致。原因json文件可能是UTF-8编码但Windows默认控制台编码是GBK直接print中文就会乱码。键值顺序错乱则是因为旧版本Python中dict不保证插入顺序或者手动排序时搞混了。解决读取时强制指定encodingutf-8打印时先设置环境变量PYTHONIOENCODINGutf-8。如果不想改环境变量就在代码里不要依赖字典顺序而是按照索引遍历。第2章给出的load_class_names函数已经兼容了两种映射风格建议直接复制使用。这些坑看起来零碎但任何一个都能让你在训练后多花两三天排错。数据集本身是干净的问题往往出在数据加载和标签映射环节所以每次新拿一个数据集我都会先跑一遍去重和映射检查再上模型。6. 最后一个技巧写一个轻量数据加载器把数据集接进自定义CNN如果你不用yolov5而是想自己搭一个CNN分类网络PyTorch的数据集类怎么写也很关键。这里给出一个可以直接套用的torch Dataset实现它同时处理了标签映射、图片读取、数据增强三个问题。import torch from torch.utils.data import Dataset from PIL import Image import os class OrganCellDataset(Dataset): def __init__(self, root_dir, class_indices, transformNone): self.samples [] self.class_indices class_indices # {类名: 索引} self.transform transform for cls_name, cls_idx in class_indices.items(): cls_path os.path.join(root_dir, cls_name) if not os.path.isdir(cls_path): continue for fname in os.listdir(cls_path): if not fname.lower().endswith(.png): continue self.samples.append((os.path.join(cls_path, fname), cls_idx)) def __len__(self): return len(self.samples) def __getitem__(self, idx): path, label self.samples[idx] image Image.open(path).convert(RGB) if self.transform: image self.transform(image) return image, label这个加载器的逻辑是从json里拿类别名到索引的映射然后去root_dir下找对应的文件夹。好处是标签顺序完全由json决定不会出现yolov5那种按字母序排序的问题。transform参数留出来你在外面定义自己的预处理和增强链比如from torchvision import transforms transform_train transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.RandomRotation(15), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) dataset OrganCellDataset(data/train, class_indices, transformtransform_train)这里用了ImageNet的mean和std做归一化对医学图像来说虽然不是最精确的统计值但因为迁移学习用的预训练权重大多在ImageNet上训练沿用这组参数能保持特征分布一致性。如果从零训练建议先统计自己数据的mean和std再归一化能略微提升收敛速度。数据增强里我只用了水平翻转和随机旋转没有用随机裁剪因为医学图像里细胞的位置和形态本身有诊断意义过度随机的crop可能把关键区域截掉。如果要做更激进的数据增强建议用albumentations的弹性形变对细胞图像来说更符合真实变形情况但不要同时叠加旋转加裁剪容易破坏结构。验证模型时我养成了一个习惯每次训练完挑5张训练图、5张测试图用模型预测并打印对应类别名人工看一眼预测结果。这个动作看着糙但能一次性发现标签映射错位、数据增强过头、过拟合三个问题。从那以后我每次新拿到分类数据集都强制走一遍查数量→看json→跑show脚本→去重→小步训练盲测这个流程省掉了后面反复返工的几小时。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网