
简介面向医学影像与深度学习初学者的肺病X光片分类数据集整合了细菌性肺炎、新冠病毒、正常肺、结核和病毒性肺炎五类样本所有图片已基于YOLOv8完成标注可直接用于目标检测或分类模型的训练与验证。压缩包共1601个文件包含800张JPG原始影像、800个TXT格式的YOLO标注文件记录目标框坐标与类别标签及1个YAML数据集配置文件整体大小仅25.51MB结构紧凑便于快速下载与解压使用。目前已有419人学习/下载该数据集适合作为课程设计、算法对比或科研验证的基准数据。使用者无需手动标注即可直接划分训练集和验证集配合YOLOv8系列模型可快速搭建肺病识别流程也可借助YAML文件灵活调整类别与路径配置节省数据准备时间专注模型调优与结果分析。1. 800张X光片和五类肺病标签为什么拿到zip先别急着训练一个zip压缩包800张原始X光片用YOLOv8格式标好了细菌性肺炎、新冠病毒、正常肺、结核、病毒性肺炎五类目标——听起来像是一条可以直接开工的检测产线但真实情况往往没这么顺。这个X光片肺病数据集最大的价值不是“能直接训出一个高分模型”而是给你一套带标注的医学影像起步素材让你有机会把数据验收、格式转换、类别不均衡处理、训练调参这一整条链路走通。适合刚啃完YOLOv8文档、手里缺干净医疗数据的从业者拿来练手也适合做迁移学习基线。下文从解压开始把这800张图一步步变成能出指标的检测模型。2. 拆开这个“肺病数据集”zip目录组织、标签格式与五类目标核对2.1 五类的医学影像差异决定了YOLOv8学什么做目标检测和做分类不一样YOLOv8学的是“框内区域的特征”所以标签框画在哪、画多大直接决定了模型能不能区分这五类。肺病X光片里细菌性肺炎的典型表现是肺实变病灶区域密度增高常出现在中下肺野结核则偏爱锁骨下区和上肺野可见结节、空洞和播散灶新冠病毒肺炎的特征是外周带磨玻璃影往往双侧分布病毒性肺炎更多表现为间质纹理增粗呈网格状正常肺纹理清晰没有局灶性高密度影。这里要提一个关键点细菌性肺炎和结核在很多X光片上看起来非常像都是局灶性高密度影如果标注时框的边界画得松模型就会把两者的纹理特征混在一起。常见做法是单个病灶画一个框框紧贴病灶边缘宁可框小一点也不要圈进大半个肺野。YOLOv8的anchor和特征图尺度是固定的框的宽高比如果严重偏离常见分布训练时收敛会很慢。2.2 解压与文件核验unzip、统计脚本和zip隐藏坑拿到zip后第一件事不是打开训练脚本而是先解压并核对文件结构。解压时我习惯用unzip命令而不是图形化工具因为命令行能把文件数、目录层级这些信息一次性暴露出来。unzip -q Xray_Lung_Dataset.zip -d lung_data find lung_data -type f | wc -l find lung_data -type f -name *.jpg | wc -l find lung_data -type f -name *.txt | wc -l find lung_data -type f | head -30第一条命令里-q是静默解压-d lung_data指定解压目标目录避免压缩包把文件直接散在当前文件夹。后三条命令分别统计总文件数、图片数和标签数正常情况下图片数和标签数应该一致都是800。最后一条head -30是看前30个文件的路径用来确认zip内部是否嵌套了一层同名目录——这种情况非常常见解压后实际路径变成lung_data/Xray_Lung_Dataset/images/...后面写data.yaml时极容易路径错误。如果发现标签数少于图片数先别急着补标注检查是不是有图片真的没有对应目标还是漏标了。还有一种压缩包特有的坑叫zip伪加密文件头里加了加密标记双击解压时提示要密码但直接用unzip或7-Zip打开却能正常解出来这是旧式压缩工具的产物不是真的加密不用找密码换个解压工具绕过去就行。2.3 LabelMe的JSON转YOLO的TXT坐标换算与格式校验很多医学影像数据集是用LabelMe标注的导出的是JSON文件里面存的是像素坐标系下的多边形或矩形坐标而YOLOv8的标签格式是归一化中心点加宽高每一行一个目标。如果拿到手的是JSON需要自己写转换脚本。import json import os def labelme_to_yolo(json_path, out_dir, class_map): with open(json_path, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] x1, y1 shape[points][0] x2, y2 shape[points][1] cx ((x1 x2) / 2) / img_w cy ((y1 y2) / 2) / img_h bw abs(x2 - x1) / img_w bh abs(y2 - y1) / img_h lines.append(f{class_map[label]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, os.path.basename(json_path).replace(.json, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) class_map { bacterial_pneumonia: 0, covid: 1, normal: 2, tuberculosis: 3, viral_pneumonia: 4 }这段脚本的核心是坐标换算LabelMe的坐标原点是图片左上角单位是像素YOLO格式要求把中心点x和y分别除以图片宽高宽高也做同样的归一化。class_map把标签名映射成整数idid从0开始连续编号这个顺序必须和后面data.yaml里的names顺序完全一致错一位整个训练都是错的。转换后需要抽样验证三个边界情况坐标被截断到0或1、宽高为0、类别id越界。一条正常训练标签应该长这样3 0.4825 0.6183 0.2104 0.2841里面的数全是0到1之间的小数。如果看到1.024或-0.003这种值基本可以断定换算时用了错误的图片尺寸。3. 把X光片肺病数据集喂给YOLOv8数据YAML、训练命令与必调参数3.1 数据YAML的写法决定成败绝对路径、类别顺序不能错Ultralytics YOLOv8的训练入口是yolo detect train命令它需要一个数据配置文件来告诉模型“去哪里找图片、图片里有哪些类别”。这个YAML写错是新手最常翻车的点而且报错信息往往模棱两可。path: /home/user/lung_data train: images/train val: images/val names: 0: bacterial_pneumonia 1: covid 2: normal 3: tuberculosis 4: viral_pneumoniapath是数据集根目录train和val是相对path的子目录指向存放图片的文件夹。这里有个容易绕晕的地方YOLOv8读取标签时会自动把images替换成labels也就是说如果图片在images/train下标签就必须在labels/train下目录名必须是这个对应关系不能自己改成annotations。names里的id顺序要和标签txt里的第一个数字对应之前转换脚本里定的class_map是什么顺序这里就写什么顺序。我一般建议path写绝对路径尤其是刚上手时。相对路径在不同机器上解析结果不一致换一台电脑就跑不通排查起来很费时间。还有一个隐藏问题路径里不要带中文和空格Ultralytics对路径的解析在Windows上特别容易出问题数据集文件夹命名用lung_data这种全小写加下划线的风格最稳。3.2 从最小训练命令开始epochs、imgsz、batch、patience四参数怎么定数据和配置就位后第一次训练不要一上来就堆大参数。800张图的数据集规模不大重点是先把训练流程跑通再关注指标。yolo detect train \ datalung.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ device0 \ projectlung_exp \ namerun1modelyolov8s.pt会从官方权重仓库下载预训练模型第一次运行需要联网。yolov8s在800张图的小数据集上比yolov8n更稳精度上限更高如果显存紧张再退回yolov8n。epochs100是个合理的起点训练过程中用patience20做早停——连续20轮验证集指标不再提升就自动停止省时间且防止过拟合。imgsz640是YOLOv8的通行配置但X光片原始分辨率通常超过1024如果最终部署环境对分辨率不敏感可以提到768或832。batch16要看显存后文会专门讲。project和name指定输出目录训练结果会落在lung_exp/run1/下包括weights权重、results.png损失曲线和混淆矩阵。3.3 CPU和低显存GPU怎么跑先用小模型验证pipeline再上完整训练不少人是先在CPU机器上搭环境跑通代码再切换到GPU服务器。Ubuntu 20.04上搭建CPU版YOLOv8环境并不复杂装好Python和pip install ultralytics就能跑但CPU训练800张图会非常慢所以策略要调整先用yolov8n.pt、imgsz416、epochs5跑一个微型训练目的不是出精度而是确认数据路径、标签读取、训练循环没有报错。这五轮跑完看results.png里loss是不是在下降如果loss正常下降说明数据链路是通的。显卡是GTX 1660 Ti这种6GB显存时yolov8s加batch16加imgsz640大概率会OOM。实际处理时把batch降到8同时确认ampTrue——Ultralytics默认开启混合精度训练能省不少显存。Windows用户还要注意一个特定问题DataLoader的workers默认值在Windows上偶尔会导致训练卡死或报错显式设置workers0可以规避。如果CPU训练时看到进度条不走多半也是这个问题。4. 训练前先验货把800张图的标注框画回去验证标签是能用的4.1 可视化巡检脚本一张图看清框的松紧和出界标注文件是人标的人就会出错。最直接的校验方式是把标签框画回原图用肉眼检查框和病灶的关系。写一个简单的巡检脚本随机抽几十张图输出到临时目录。import cv2 import glob for txt_path in glob.glob(lung_data/labels/train/*.txt)[:20]: img_path txt_path.replace(labels, images).replace(.txt, .jpg) img cv2.imread(img_path) h, w img.shape[:2] with open(txt_path) as f: for line in f: cls, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) color (0, 255, 0) if int(cls) 2 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite(visual_check/ txt_path.split(/)[-1] .jpg, img)这段代码的关键是把归一化坐标还原成像素坐标中心点减去一半宽高得到左上角加上一半宽高得到右下角。别小看这一步坐标还原后框和病灶的位置是否吻合直接暴露标注质量。重点看三种情况框是不是完全在图片内如果坐标换算错了框会出界框是不是紧贴病灶如果整个肺叶都被圈进去模型会学到错误纹理同一张图上多个框是否覆盖了所有可见病灶。实际操作中400张训练图全看一遍不现实抽20到30张足够发现问题。巡检时如果发现某类图片大面积错标回头修标注的成本远低于训练后返工。4.2 统计每个类和每张图的标签数类别不均衡会误导后续调参800张图看着不少分到五类里可能严重不均。训练前先统计一下每个类别的框数量这一步能避免后续看到mAP时误判模型能力。from collections import Counter import glob counter Counter() images_with_targets 0 empty_files 0 for txt_path in glob.glob(lung_data/labels/train/*.txt): with open(txt_path) as f: lines f.readlines() if len(lines) 0: empty_files 1 else: images_with_targets 1 for line in lines: counter[int(line.split()[0])] 1 print(类别统计:, counter) print(有目标的图片数:, images_with_targets) print(空标签文件数:, empty_files)统计结果会直接影响训练策略。如果某一类占比极低比如结核只有几十个框YOLOv8会把这类当成稀有前景mAP会被其他类别拉平而且val集里这类样本太少评估结果方差巨大。常见做法是先看数据分布再决定要不要加权而不是盲目调loss。如果五类大致均匀800张图完全可以直接训练如果严重不均后续要考虑类别权重或过采样。还有一个容易被忽略的指标空标签文件数。如果一张X光片确实没有病灶空标签是正常的这类是hard negative对模型有价值但如果有几十个空文件很可能有一部分是漏标需要回到图片里人工确认。4.3 分层划分train/val别让某一类全跑进验证集随机划分看起来公平但在小数据集上容易出问题类别分布不均匀时可能某一类在训练集里有100个框在验证集里只有3个验证指标随机性极大。更稳妥的做法是分层抽样。import random from pathlib import Path random.seed(42) label_files list(Path(lung_data/labels).glob(*.txt)) label_files [f for f in label_files if f.stat().st_size 0] random.shuffle(label_files) val_count int(len(label_files) * 0.2) val_files set(label_files[:val_count]) train_files [f for f in label_files if f not in val_files] for f in train_files: img str(f).replace(labels, images).replace(.txt, .jpg) dst_img lung_data/images/train/ Path(img).name Path(img).rename(dst_img) Path(str(f)).rename(lung_data/labels/train/ f.name) # 同理处理val_files这段脚本按20%比例切出验证集代码里random.seed(42)固定随机种子保证每次跑结果一致可复现。更精细的分层做法是先把文件按类别分组再从每个类别里分别抽20%确保验证集的类别比例和总体一致。Path对象在Windows和Linux上的路径拼接都比较安全避免手写字符串路径踩斜杠坑。划分完成后还要做一道自检统计train和val里每个类别的框数比例应该接近4比1。如果发现某个类别在val里缺失回到划分步骤重跑别嫌麻烦——小数据集上val泄漏或分布失衡导致的虚高指标会误导你对模型真实能力的判断。5. YOLOv8训练避坑实录X光片肺病数据集踩过的五个坑5.1 标签文件是空的exif旋转、漏存json与空txt现象训练过程没有报错但某些类别recall一直为0打开对应txt文件发现是0KB。原因两种情况最常碰到。一是LabelMe标注后没有逐张保存部分json文件内容为空转换脚本没报错但产出了空txt二是智能手机或部分医疗设备拍摄的X光片照片带有exif旋转信息图像实际显示方向和像素存储方向不一致画框时看着是正的转成YOLO坐标后框错位甚至因为坐标计算得到负值被判定为空。解决先统计空文件数量如果比例不高把空标签保留作为负样本如果比例高回到标注源头补标。exif问题用PIL.ImageOps.exif_transpose处理一遍再转换或者用mogrify -auto-orient批量修正。这类问题跑训练才发现的话浪费时间且难以定位。5.2 “No labels found”路径、缓存和同名配对问题现象训练命令执行后几秒钟就报错提示找不到标签文件退出训练。原因三种可能。data.yaml里的path指向了错误的根目录图片在images/train而标签被放到了train_labels这种自定义目录里YOLOv8默认只认labels/train还有一个很隐蔽的情况——Ultralytics会把数据集信息缓存到cache文件里如果之前跑过一次错误路径的训练缓存记录了旧路径改好数据后不删缓存仍然报错。解决删掉数据集根目录下生成的*.cache文件检查path是否为绝对路径确认图片和标签目录的对应关系。命令行下用ls lung_data/labels/train/ | head快速看一眼标签是否存在比翻报错日志更直接。5.3 val泄漏导致mAP虚高划分前先查病历现象训练曲线很漂亮val loss低于train lossmAP50超过0.9但拿到新图上推理效果平平。原因随机划分时没有考虑数据来源。医学影像数据集里同一个病人的多张X光片可能被分到了train和val两边模型其实“见过”同一病人的影像特征val指标虚高。800张图虽然不大但这类情况在真实采集数据里经常发生。解决划分前先看文件名常见的命名规则里有患者ID或检查序列号。如果有患者信息按患者分组后再划分保证同一个患者的片子只出现在一个集合里。只按文件名随机shuffle在这种数据集上是不可靠的。5.4 结核和细菌性肺炎互相误判关注框内纹理与肺野位置现象训练完成后看混淆矩阵结核和细菌性肺炎两个类别之间有很大的误判块。原因这两个类别在X光片上的局部纹理非常接近都是局灶性实变影密度和形状没有明显边界。YOLOv8默认的640输入尺寸下框内特征可能丢失了能区分它们的细节。如果标注的框画得太松把正常肺纹理也圈进去区分难度更大。解决先检查标注边界确认框是否紧贴病灶然后尝试提高imgsz到768或832保留更多纹理细节。还有一个实用策略不只看框内纹理也关注病灶在肺野里的位置结核常见上肺野细菌性肺炎多在中下肺野。YOLOv8不会显式使用位置先验但它能隐式学到前提是标注框的位置是一致的——所以别为了好看把框画得横跨整侧肺野那样等于把位置信息抹掉了。5.5 CUDA OOM总在最后一步显存预算的计算与自救现象训练开始时没问题跑了几轮到某个节点突然报CUDA out of memory或者整个进程被kill看起来像训练卡死。原因显存占用是动态的loss计算、梯度累积和验证阶段的峰值比平均占用高。X光片虽然是灰度图但读取时被转成三通道批量加载时的显存开销比预期大一截。6GB显存的卡跑yolov8s加batch16加imgsz640正好卡在峰值边缘随时可能爆。解决训练时用nvidia-smi -l 1盯着显存变化。爆了就按三个顺序调整先降batch到8这是影响最小的手段再不行降imgsz到480最后才换yolov8n。Ultralytics开启ampTrue能省约30%的显存默认是开的别在配置里关掉。另外validate阶段也会占显存把batch8同时传给train和val命令避免出现训练不爆验证爆的诡异情况。6. 从指标到部署用confusion_matrix和ONNX验证这个模型真的能用6.1 混淆矩阵告诉你的第一件事谁和谁分不开训练完成后lung_exp/run1/目录下会生成confusion_matrix.png和results.png。看指标时别只盯着mAP——直接看混淆矩阵对角线以外的高亮块。X光片肺病检测里如果结核被大量识别成细菌性肺炎说明框内特征的区分度不够这时再调分类头或加数据增强收益有限不如回标注侧检查是不是某些框的边界有问题。6.2 灰度图与CLAHEX光片预处理的小技巧X光片本质是灰度图训练时可以直接以灰度图输入也可以转成三通道让加载器兼容二者对精度影响不大。但对比度对检测效果影响明显肺纹理不清晰的病例上预处理阶段做一次CLAHE对比度自适应增强比多训50轮epoch更有效。import cv2 img cv2.imread(xray.jpg, cv2.IMREAD_GRAYSCALE) clahe cv2.createCLAHE(clipLimit3.0, tileGridSize(8, 8)) enhanced clahe.apply(img)clipLimit控制对比度限制幅度过大会把噪点同步放大一般取2到3之间tileGridSize取8×8针对胸片这种大尺寸图像是个稳妥起点。增强后的数据作为另一个实验分支跑和原始图对比mAP。6.3 导出ONNX并做一次本地推理自检训练完成后第一步不是急着上板子而是导出ONNX在本地跑一次推理确认权重在脱离PyTorch环境后依然能给出正确结果。yolo export modellung_exp/run1/weights/best.pt formatonnx imgsz640导出的best.onnx用onnxruntime做一次单图推理输入先用6.2的预处理逻辑做灰度归一化输出是一个[1, 5, 8400]的张量按置信度阈值筛出框再复现出yolov8的坐标解码逻辑确认框能落在病灶上。这一步走通了后面不管是往RK3588还是其他板端迁移剩下的工作都是针对推理框架做算子适配数据这个源头已经没有问题。医疗影像模型最终要面对的是新图上未知病例的考验。我现在每训完一版都会单独留出自己肉眼见过但不参与训练的片子做一次“盲测”确认模型不是背了数据集的题。这个习惯救过我太多次也建议你保留。希望帮到你。本文还有配套的精品资源点击获取