简介:面向脑肿瘤医学影像分类与分割任务的数据集,可用于训练和评估深度学习模型,也为相关竞赛预训练提供支撑。数据分为两个独立部分:分类部分涵盖神经胶质瘤、脑膜瘤、垂体瘤和无肿瘤四种类别,并做好训练与测试分离;分割部分则针对肿瘤存在与否进行标注,且给出对应的区域坐标,方便完成病灶定位与分割实验。压缩包内含2000个文件,以1849张JPG图像为主,配合150个TXT标签文件与1个YAML配置文件,整体大小约92MB,目录组织清晰,能够直接用于主流深度学习框架的数据加载。已有526人学习下载,既适合医学影像初学者理解分类与分割任务的基本流程,也可作为竞赛预训练或科研基线的重要数据来源。
1. 脑肿瘤MRI数据集:拿到手先别急着训练,先迈过这四道坎
做医学影像分类的同行应该都有体会:脑肿瘤MRI数据集难的不是下载,而是下载完之后那一串看不见的坑——标签错位、文件损坏、归一化翻车、患者切片泄露。四样里面随便踩中一样,模型训出来的准确率都是虚的。这份资源把三类脑肿瘤MRI(脑膜瘤、胶质瘤、垂体瘤)的切片数据连同预处理和校验脚本打包整理好了,核心价值在于你不需要自己从头去爬取、清洗、对齐标签,拿到后直接按文里的流程跑一遍就能进入训练环节。适合正在做医学影像分类或者刚接触MRI数据准备上手深度学习的工程师,也适合需要一份干净基准数据做算法对比的团队。
2. 数据集选型与下载:三类标签、T1增强序列与目录核对
2.1 标签体系:脑膜瘤、胶质瘤、垂体瘤的分类逻辑
这个数据集的核心标签就三类:脑膜瘤(meningioma)、胶质瘤(glioma)、垂体瘤(pituitary adenoma)。这三类是颅内最常见的原发性肿瘤,分类任务的区分度适中,不会像二分类那样容易过拟合,也不像多分类那样需要太深的网络,是验证预处理流程和模型架构的好选择。
标签的组织方式一般有两种:一种是用文件夹名区分,比如train/meningioma/、train/glioma/、train/pituitary/;另一种是维护一个 CSV 标注文件,每一行是文件名,类别。这份资源默认按文件夹方式组织,我拿到手的第一件事就是跑一个统计脚本确认三类样本量是否均衡,因为后续的加权采样、数据增强策略都取决于这个数字。
2.2 T1增强序列:为什么它是默认选项而不是T2或FLAIR
MRI 有多个序列:T1加权、T2加权、FLAIR、DWI 等,脑肿瘤MRI数据集里最常见的切片来自 T1 增强扫描序列。原因是注射对比剂后,肿瘤血脑屏障破坏区域会明显强化,边界比 T2 和 FLAIR 清晰得多,做分类任务时模型能依靠的纹理和边缘特征更集中,不需要额外的多序列融合处理。
如果你后续想扩展到分割任务,T1增强序列同样是最容易出效果的起点。但要注意:数据集的切片虽然是灰度图,但很多源文件在采集时就是彩色预览图,或者带有扫描仪的文字标注框,这两类干扰必须在预处理阶段清掉,后面我会专门说。
2.3 下载与解压:用脚本核对目录结构
下载完成后不要急着写训练代码,先做一次目录结构核对。常见的压缩包解压后会有内层嵌套,比如brain_tumor_dataset.zip解压出来是一个同名文件夹,里面才是train/和test/,路径写错一处模型训练直接报FileNotFoundError。
# 1. 解压,注意区分大小写 unzip brain_tumor_dataset.zip -d ./dataset # 2. 查看顶层结构 find ./dataset -maxdepth 2 -type d | sort # 3. 统计每个类别的样本数,确认没有空的类别目录 for cls in meningioma glioma pituitary; do echo "$cls: $(find ./dataset/train/$cls -type f | wc -l)" done # 4. 抽查图片真实尺寸与格式,防止混入异常文件 file ./dataset/train/meningioma/*.jpg | head -5这里的find加maxdepth 2是为了避免递归太深把隐藏文件也扫进来;file命令能快速识别出哪些文件根本不是有效图片。我见过有人把 MRI 的 DICOM 文件和 JPG 切片混放在同一个目录里,训练时图像解码失败,报错却指向了数据加载器的缓存问题,排查了一整天才发现是文件格式不统一。
3. 预处理流水线:把原始切片清洗成模型能吃的输入
3.1 数据清洗:剔除损坏样本与重复切片
很多下载来的脑肿瘤MRI数据集里会混入 CSRF 下载失败产生的 0 字节文件、macOS 的._开头的元数据文件,以及采集端生成的缩略图。这些文件一旦进入训练集,轻则损失一部分样本,重则在torchvision.datasets.ImageFolder加载时直接抛异常。我一般会用一段独立脚本先做清洗,而不是等训练时报错再回头查。
from PIL import Image from pathlib import Path root = Path("./dataset/train") removed = [] for img_path in root.rglob("*.jpg"): # 跳过隐藏文件和系统文件 if img_path.name.startswith("._") or img_path.name.startswith("."): removed.append(img_path) img_path.unlink() continue try: with Image.open(img_path) as im: im.load() # 过滤掉过小的缩略图,脑肿瘤切片正常尺寸不小于 200x200 if im.size[0] < 200 or im.size[1] < 200: removed.append(img_path) img_path.unlink() except Exception as e: # 打不开的一律删除,避免训练时解码报错 removed.append(img_path) img_path.unlink() print(f"removed {len(removed)} files")逻辑说明:先按文件名规则过滤隐藏文件,再用Image.open配合load()强制解码,能暴露损坏的图片;最后按尺寸阈值过滤缩略图。删除操作直接unlink,不进入回收站,所以跑之前确认 root 路径是对的,别把原始备份删了。
参数说明:尺寸阈值 200×200 是经验值,如果数据集本身就有小尺寸切片,可以降到 128。关键在于im.load()这行,Image.open是惰性的,不加load()时文件打不开也不会报错,这是最常见的坑。
3.2 灰度归一化与尺寸统一:参数怎么设才不会翻车
MRI 切片是灰度图,但有些源文件保存成了 RGB 三通道的 JPG。如果直接用三通道喂给预训练模型,通道数对得上,但语义上相当于复制了三份灰度,会浪费近一半的计算量;如果转成单通道,又要改模型输入层的in_channels。我倾向于全部统一成单通道灰度,然后用 1%–99% 分位数截断再线性映射到[0,1],而不是直接(x - min) / (max - min)。
import numpy as np from PIL import Image def normalize_mri(img_array: np.ndarray) -> np.ndarray: # 裁剪到 1% 和 99% 分位数,避免个别高亮噪点拉伸整个图像的对比度 lo, hi = np.percentile(img_array, (1, 99)) img_array = np.clip(img_array, lo, hi) img_array = (img_array - lo) / (hi - lo + 1e-6) return img_array.astype(np.float32) img = Image.open("./dataset/train/meningioma/001.jpg").convert("L").resize((224, 224)) arr = np.array(img) arr = normalize_mri(arr)我一般在连续切片测试后固定用 1% 和 99% 分位数。直接用 min-max 归一化的问题是 MRI 图像里常有极亮噪声点,比如扫描仪标记线,min 和 max 会被这些离群点占住,导致正常组织的灰度范围被压缩到很小一段,模型看到的对比度极低,训练 loss 下降得异常缓慢。
3.3 按患者划分数据:同源泄露会让验证准确率虚高
这是脑肿瘤MRI数据集里最隐蔽的问题。同一个患者的多个切片在相邻层之间极其相似,如果只是按文件随机划分训练集和验证集,同一个患者的不同切片会被分到两边,验证集里就会出现和训练集几乎一样的图像,模型准确率虚高到 98% 以上,部署到真实数据上立刻掉到 70%。
import re from sklearn.model_selection import GroupShuffleSplit # 假设文件命名包含患者ID,例如 "ID001_slice12_meningioma.jpg" def extract_patient_id(filename: str) -> str: match = re.search(r"ID(\d+)", filename) return match.group(1) if match else filename filenames = [p.name for p in root.rglob("*.jpg")] patient_ids = [extract_patient_id(name) for name in filenames] splitter = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42) train_idx, val_idx = next(splitter.split(filenames, groups=patient_ids))核心点是GroupShuffleSplit按groups参数划分,保证同一个患者 ID 的所有切片只会落在同一侧。常见误用是直接用train_test_split,它不认识患者 ID 这个分组概念。划分完以后,建议把分配结果落盘成 CSV,方便后续每次训练都沿用同一份划分,否则随机种子一变,实验结果就没法对比了。
4. 避坑与常见问题:下载和预处理中最容易翻车的五个细节
4.1 解压后文件统计数量不对,多了一堆隐藏文件
现象:按 2.1 节的脚本统计样本数,发现 meningioma 目录下比正常多出几十个文件,训练时总报路径找不到。
原因:压缩包是从数据源站直接拉取的,里面混入了 macOS 的._元数据文件和 Windows 的Thumbs.db。这些文件在解压后被find -type f计算在内,但不属于有效图片。
解决:清洗脚本里已经用startswith("._")过滤了。我后来改成先解压到临时目录,统计完有效文件数再移动到工作目录,这样能避免污染原始数据。
4.2 归一化后图像整体偏暗,模型训练不收敛
现象:预处理完预览图像,发现整张图灰蒙蒙一片,几乎看不清肿瘤边界,模型 loss 一直在 0.7 左右打转。
原因:直接用(x - min) / (max - min)归一化,而图像里恰好有几个高亮噪点,把 max 值拉得很大,正常组织的灰度范围被压缩。
解决:换成 1%–99% 分位数截断后再归一化,也就是 3.2 节的写法。注意(hi - lo + 1e-6)里的1e-6是防止lo == hi时除零。
4.3 患者切片泄露到验证集,指标好看但部署翻车
现象:训练时验证集准确率 98%,模型在真实采集的新数据上只有 75%,一度怀疑是代码 bug。
原因:按文件随机划分数据集,同一个患者的不同切片被分到了训练集和验证集两侧,验证集包含了训练集的近重复样本。
解决:改用GroupShuffleSplit按患者 ID 划分,并在实验记录里标明划分方式。从那以后我每份数据集都会先检查文件名能不能提取患者 ID,提取不了就先补标注,绝不硬训。
4.4 数据增强时翻转方向设错,模型学到错误解剖结构
现象:增强后的样本看起来和原图差不多,但验证集表现持续偏低,网上查资料才发现垂直翻转有可能让解剖结构上下颠倒。
原因:脑部 MRI 虽然视觉上大致对称,但严格来说脑干位置、脑室形态都有上下语义差异,垂直翻转会改变这些结构的方向,相当于引入错误标签。
解决:增强只保留水平翻转和不超过 15° 的旋转,不设垂直翻转。这个参数我现在是写死在配置里的,训练脚本不做任何方向上的自由发挥。
4.5 CSV 标注文件里文件名和切片对不上
现象:加载 CSV 后按行索引图片,发现显示出来的图像和文件名标注的类别不符。
原因:部分标注文件是手工整理的,行序和实际目录顺序不一致,或者文件名里包含多余的空格和转义字符。
解决:加载标注时强制按文件名排序,然后把文件名和标签做字典映射再取值,不要依赖行号对应。校验方式见第 6 章的可视化脚本。
5. 数据增强与类别平衡:提升模型泛化性的三个实用技巧
5.1 增强参数配置:旋转、翻转、对比度怎么搭配
脑肿瘤MRI的样本量通常在几百到几千张,离训练一个深度卷积网络还差得远,数据增强是必须的。我用的是torchvision.transforms,配置如下:
import torchvision.transforms as T train_transforms = T.Compose([ T.Resize((240, 240)), T.RandomRotation(degrees=15, fill=0), T.RandomHorizontalFlip(p=0.5), ttransforms.ColorJitter(brightness=0.2, contrast=0.2), T.CenterCrop(224), T.ToTensor(), ])逻辑说明:先放大到 240 再做随机裁剪回 224,相当于引入了随机平移效果;fill=0让旋转产生的边角填充为黑色,对 MRI 灰图比较自然;水平翻转只对左右方向做。
参数说明:旋转角度 15° 是我实测比较稳的值,超过 30° 肿瘤区域的形状会被过度扭曲;brightness和contrast的幅度 0.2 也不会让图像灰度过曝。验证集和测试集只做Resize和CenterCrop,不做任何随机增强。
5.2 增强后标签同步:分类场景也不能只盯着图像
增强虽然作用于图像,但分类任务的标签是跟随文件名的,只要增强在一个Dataset内部完成,标签一般不会错位。真正的坑出在「离线增强」——如果你把增强后的图片保存到磁盘,再把新旧文件混在一起训练,就必须保证文件名里写清楚类别来源。
# 离线增强保存时,把类别写进文件名,避免后续加载错乱 out_path = save_dir / f"{label}_{idx}_rot15.jpg"我早期做过一次离线增强,把增强后的图片平铺到一个文件夹,结果加载时类别全部变成了上一个文件夹的末尾类别,准确率直接崩到三分之一,后来全靠文件名前缀才定位到问题。现在除非是数据量特别小需要手工查看,否则我都用在线增强。
5.3 类别不平衡:加权采样比简单复制更有效
三类肿瘤的样本量往往不均衡,脑膜瘤和胶质瘤偏多,垂体瘤偏少。处理方式有两种:一种是少数类复制,简单但容易过拟合;另一种是加权采样,每次迭代按类别概率补足少数类。
from torch.utils.data import WeightedRandomSampler labels = [0, 0, 1, 1, 1, 2, 2, ...] # 全部训练样本的类别 class_counts = torch.bincount(torch.tensor(labels)) weights = 1.0 / class_counts[labels].float() sampler = WeightedRandomSampler( weights=weights, num_samples=len(weights), replacement=True )WeightedRandomSampler会根据每个样本的权重决定采样概率,权重低的多数类被抽到的次数减少,权重高的少数类被反复抽到。相比直接复制样本,它不会增加模型见过的样本总量,只是让每个 batch 的类别分布更均匀,泛化性更好。num_samples保持和原始样本数一致,让每个 epoch 的总迭代步数不变。
6. 训练前最后一道工序:批量可视化验证切片与标签对应关系
在正式启动训练之前,我会强制走一遍批量可视化抽查。很多人觉得数据已经整理完了,直接开训,结果跑了几个小时发现标签错位,白白浪费算力。可视化抽查只需要几十行代码,能把「图像内容」和「标注标签」直接对应起来看。
import matplotlib.pyplot as plt import random from PIL import Image def visualize_batch(image_paths, labels, class_names, grid=(4, 4)): fig, axes = plt.subplots(grid[0], grid[1], figsize=(12, 12)) idxs = random.sample(range(len(image_paths)), grid[0] * grid[1]) for ax, idx in zip(axes.flat, idxs): img = Image.open(image_paths[idx]).convert("L") ax.imshow(img, cmap="gray") ax.set_title(f"{class_names[labels[idx]]}\n{image_paths[idx].name}", fontsize=9) ax.axis("off") plt.tight_layout() plt.savefig("preview_grid.png", dpi=150)我用它抽查三类里各取几十张,重点看两件事:一是图像内容是不是脑部 MRI 切片,有没有混入扫描仪 LOGO 或文字水印;二是标题显示的类别和图像里的肿瘤形态是否一致。脑膜瘤通常呈现均匀强化的脑外肿块,胶质瘤边界不规则且强化不均匀,垂体瘤位于蝶鞍区域。如果某一张图看起来明显不属于标注类别,那就要回头检查标注文件。
从那以后我每次拿到新数据集都强制走一遍这套流程:先统计目录和类别分布,再清洗异常文件,然后按患者划分数据,跑一遍可视化抽查,最后才允许进入训练环节。三分钟的抽查,省下的是一整晚的翻车排查。希望帮到你。
本文还有配套的精品资源,点击获取