拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于YOLOv5的直肠息肉检测:数据准备、模型训练与GUI部署实践

简介基于YOLOv5的直肠息肉检测系统实现方案以1个docx文档形式打包面向医学影像分析人员、机器学习开发人员及疾病筛查工程师旨在借助自动检测技术辅助直肠息肉的早期筛查与诊断。压缩包体积仅41KB但文档内容相对完整从环境准备、数据准备、创建数据集配置文件到模型训练、导出ONNX模型、性能评估、评估指标可视化再到搭建GUI界面、整合所有代码覆盖了系统落地的全部关键环节且目录编排清晰。评估环节专门涉及精确度、召回率、F1分数等多个指标的可视化分析便于客观衡量模型效果。文档还梳理了项目特点、参考资料、未来改进方向如多类别息肉检测、数据增强、集成学习、云部署以及数据质量、硬件要求、模型监控等注意事项既适合医疗影像分析新手系统学习YOLOv5的实践流程也能为机器学习开发者在医疗检测项目二次开发时提供可复用的思路与基础模板。目前已有120人学习/下载。1. 基于YOLOv5的直肠息肉检测为什么医疗影像场景选这套技术栈YOLOv5这套目标检测框架在医学影像落地最常见的一个场景就是内镜息肉筛查检查视频一放就是半小时医生盯着屏幕一帧帧找漏检几乎不可避免。这套基于YOLOv5的直肠息肉检测系统把数据准备、模型训练、ONNX导出、性能评估和GUI实时检测串成了一条完整可跑的链路数据是现成的YOLO格式代码从train.py到export.py全部串好训练完的best.pt能直接接进Tkinter界面。对医学影像分析人员、机器学习开发人员和疾病筛查方向的研发工程师来说它的价值在于不用从零趟一遍环境配置和标签格式的坑拿到就能跑通基线再换成自己的数据集。核心模型固定选YOLOv5理由很朴素生态成熟、文档多、部署资料齐全后面要换backbone或者做多类扩展社区方案都现成。2. 环境配置与数据准备YOLO格式数据集落地的三个关键点2.1 从零安装依赖版本选型与验证方法先把原理说清楚。YOLOv5的训练和推理都跑在PyTorch上所以torch和torchvision是骨架opencv-python负责图像读写和摄像头的视频帧采集matplotlib用来画训练过程的loss曲线和精确度曲线tkinter是Python自带的GUI库做检测界面不额外引框架onnx是导出模型格式用的。装的时候顺序很重要先把torch装对再装其余包因为torch的版本会影响后面opencv、numpy的对齐。pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113 pip install opencv-python matplotlib tkinter onnx第一行里的cu113对应CUDA 11.3适合显存不太旧的NVIDIA显卡。如果你的驱动版本低或者只有CPU机器把--extra-index-url去掉默认装CPU版训练速度会慢不少但至少能跑通流程。装完先验证一下torch能不能调起GPUpython -c import torch; print(torch.__version__, torch.cuda.is_available())看到True说明CUDA可用。我在实际项目里碰到过最蠢的情况就是torch装了CPU版还浑然不觉训练了三个小时才反应过来速度不对所以这一步验证别省。接下来克隆YOLOv5官方仓库git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txtrequirements.txt里各依赖版本是官方锁过的一般不会出大问题但有两个细节值得注意第一如果系统里之前装过高版本numpy安装opencv时可能会触发numpy降级降级后有些旧代码的API会变建议装完后统一pip list | grep numpy看一眼第二Linux下tkinter经常是缺失的直接pip install tkinter装不上要用sudo apt-get install python3-tk。Windows用户一般没这个问题但macOS的python安装包需要勾选额外组件否则import tkinter会报ModuleNotFoundError。2.2 数据准备目录结构、标签格式与命名规范YOLO格式的数据集和分类任务那种「文件夹即类别」完全不同它是一张图片配一个同名txt文件txt里每行代表一个目标框。整个目录结构按官方惯例分成images和labels两个大目录各自再拆train和valpolyp_data/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/images/train里放的是jpg或png内镜图像labels/train里放的是同名txt。我习惯把图像和标注文件都命名为001.jpg、001.txt这种纯数字递增避免出现中文名和空格否则后面训练脚本读路径会玄学报错。标签文件里每一行的格式是固定的0 0.520312 0.498512 0.0812 0.0673第一个数字是类别ID这个项目只有息肉一类所以恒为0后面四个数字依次是目标框中心点的x坐标、y坐标、框的宽度、框的高度全部做了归一化范围在0到1之间。归一化的换算关系是cx (x_left x_right) / 2 / img_w cy (y_top y_bottom) / 2 / img_h w (x_right - x_left) / img_w h (y_bottom - y_top) / img_h初学者最容易翻车的地方就是这里直接用像素值写进txt忘了除以图像宽高训练时loss怎么都降不下去因为目标框的坐标动辄几百上千模型学到的梯度是乱的。还有一个坑是txt里写了小数但类别ID写成了1而配置文件的names里只有一个polyp类别ID必须从0开始。数据划分我一般按8:2或者9:1train和val之间不能有图像重叠否则评估结果虚高mAP看着漂亮但换新图就露馅。划分完后记得检查一下val目录里是否有0字节的txt空标注文件会导致训练时警告不断最好直接把没有目标的图片从数据集里剔掉。3. 模型训练与超参数调优从train.py到ONNX导出的实操细节3.1 创建polyp.yaml配置文件与启动训练YOLOv5的训练入口是train.py但数据集的路径和类别信息要用一个yaml文件告诉它。把下面这个文件放到yolov5目录下命名polyp.yamltrain: ../polyp_data/images/train val: ../polyp_data/images/val nc: 1 names: [polyp]train和val路径建议用绝对路径相对路径的参照点是当前工作目录如果不在yolov5目录下启动训练很容器路径错乱。nc是类别数量单类息肉就是1names列表的顺序就决定了标签文件里类别ID对应的含义列表第一个元素对应ID 0。这个顺序一旦训练开始就固定住了中途改名字不会影响权重但推理结果的显示名会变。配置文件就绪后开始训练python train.py --img 640 --batch 16 --epochs 50 --data polyp.yaml --weights yolov5s.pt这条命令是整套流程的核心。逐项说明参数逻辑--img 640是把输入图像resize成640×640再送进网络内镜图像原始分辨率一般不高640是均衡检测速度和精度的常见取值显存不够就降到480或320小目标检测能力会下降但息肉在画面里占比通常不小影响不大。--batch 16是批量大小16G显存跑yolov5s比较稳显存吃紧就减到8或4减batch的同时最好把epochs往上加因为每个epoch看到的样本变少了。--epochs 50是训练轮数医学小数据集我一般从50开始看loss曲线再决定要不要续跑。--weights yolov5s.pt表示从官方s规模的预训练权重开始第一次训练会自动下载如果没有网络或者下载失败可以手动下载后放到yolov5目录下。从预训练权重起步和从零训练差距非常大尤其在数据集只有几千张图的情况下收敛速度快一倍不止这是迁移学习的红利别浪费。3.2 训练过程的loss观察与超参数调整策略训练一启动yolov5会自动创建runs/train/exp目录里面除了每轮的权重文件外还有一个results.csv记录了每个epoch的train loss、val loss、precision、recall、mAP等全部指标。我训练时基本每隔几个epoch就扫一眼loss的趋势而不是等全部跑完才去看。判断标准很简单train_loss持续下降是正常信号train_loss降但val_loss不降甚至回升就是过拟合了需要增大数据增强强度或者提前停止train_loss从头到尾纹丝不动先别急着调参大概率是数据处理出了问题回来检查标签的归一化坐标。超参数的选择有几个实际经验。--lr默认是0.01如果数据集只有几百张图0.01偏大我一般改成0.001epochs建议先跑50轮看趋势如果val_loss到第40轮还在降就接着跑100轮不用一次把epochs设得很大浪费时间。batch和img的关系是显存决定的如果启动时报CUDA out of memory把batch降到8、img降到480是最快的解法。超参数建议值说明img640图像resize尺寸显存不足降到480或320batch16显存不足降到8或4同时适当增加epochsepochs50起步看loss曲线决定是否续训过拟合就提前停weightsyolov5s.pt预训练权重小数据集别从零训练lr0.01默认小数据集改0.001收敛更稳3.3 导出ONNX模型部署前必须做的一步训练完成后最佳权重在runs/train/exp/weights/best.pt这是PyTorch格式只能在PyTorch环境里加载。真要落地到实际检测流程里我一般会先导成ONNX格式这样后续推理可以不依赖完整的YOLOv5训练代码用ONNX Runtime或OpenCV DNN就能跑。导出命令python export.py --weights runs/train/exp/weights/best.pt --img-size 640 --batch-size 1 --device 0 --include onnx--img-size必须和训练时的--img一致否则导出的模型输入尺寸和训练尺寸对不上推理时图像resize会错乱。--batch-size 1是导出时的batch数推理场景固定为1导出更干净。--device 0指定用GPU导出CPU机器换成--device cpu。命令跑完best.pt同目录下会出现best.onnx。我习惯导出后顺手用ONNX Runtime加载跑一遍验证确保模型文件能正常推理而不是只看到导出成功就完事。这个验证步骤成本极低但能提前暴露算子兼容问题别留到部署阶段才炸。4. 性能评估与指标可视化让训练结果不再停留在黑匣子里4.1 用val.py评估模型在验证集上的真实表现训练的mAP是train阶段算出来的只能看到趋势不能作为最终结论。真正要信的是在模型没见过的验证集上跑的评估结果。YOLOv5自带val.py直接复用训练时的配置python val.py --weights runs/train/exp/weights/best.pt --data polyp.yaml --img 640--weights换成best.pt而不是last.pt因为last是最后一轮的权重通常不如best稳定。这条命令跑完后会输出一列指标表重点看几项mAP0.5是所有类别在IoU阈值0.5下的平均精确度模型综合能力的直观体现mAP0.5:0.95是IoU从0.5到0.95逐档计算的均值更严格也会更低Precision和Recall分别对应「框出来的目标里有多少是对的」和「所有真实目标里有多少被框出来了」。在息肉检测这个场景里我特别强调recall的参考价值。漏掉一个息肉比误检一个的代价高得多因为漏检意味着患者可能错过早期干预。如果recall偏低而precision很高说明模型偏保守可以调低置信度阈值让更多低分框进入输出或者加大训练集中的阳性样本占比。最怕的情况是训练时mAP高但val的mAP明显低这种落差基本是数据划分泄漏或者标注风格不一致造成的比如train里标注得仔细而val里有些目标漏标了模型学到的分布和验证分布对不上。4.2 用Matplotlib绘制损失与精确度曲线results.csv里的数据是逐epoch记录的直接用Excel看也行但画成曲线图更容易看出训练趋势的拐点。下面这段代码从results.csv读数据并绘制loss和precision两条曲线import matplotlib.pyplot as plt import pandas as pd # 训练过程中每个 epoch 的指标全部记录在 results.csv data pd.read_csv(runs/train/exp/results.csv) plt.figure(figsize(12, 6)) # 左侧子图损失随 epoch 的变化 plt.subplot(1, 2, 1) plt.plot(data[epoch], data[loss], labelLoss, colorblue) plt.title(Loss over Epochs) plt.xlabel(Epoch) plt.ylabel(Loss) plt.grid() # 右侧子图精确度随 epoch 的变化 plt.subplot(1, 2, 2) plt.plot(data[epoch], data[precision], labelPrecision, colorgreen) plt.title(Precision over Epochs) plt.xlabel(Epoch) plt.ylabel(Precision) plt.grid() plt.tight_layout() plt.show()pd.read_csv直接读results.csv默认第一行是列名所以后续能用data[epoch]这种方式取整列数据。代码里用的loss和precision列名在官方YOLOv5里都存在但不同版本列名有差异——老版本叫val_loss新版本拆成了train/box_loss、train/obj_loss、train/cls_loss这种带分组前缀的写法。如果画图时报KeyError先print(data.columns)打印所有列名把列名换成实际存在的。我的习惯是把loss列换成train/box_loss再加一条val_loss两线对比才能看出来是否过拟合。曲线的横轴是epoch纵轴是数值loss曲线在20轮以后稳步向下、precision曲线向上抬升说明模型还在学如果loss曲线在第40轮开始反弹说明已经过拟合早停就好。看不清微小波动时可以加plt.ylim()把纵轴范围收窄比默认的自动缩放更直观。5. 常见问题与避坑指南GUI整合过程中踩过的五个坑5.1 Tkinter GUI与实时检测的实现思路GUI部分是全项目的交付门面。用Tkinter做界面的理由很直接它是Python标准库的一部分不需要额外装框架功能虽然朴素但做一个「选图/开摄像头→显示检测结果」的界面完全够用。核心是把摄像头采集到的帧喂给加载好的YOLOv5模型拿到检测结果后渲染画框再通过Tkinter的Label组件显示出来。下面是一段能跑的完整界面代码import cv2 import tkinter as tk from PIL import Image, ImageTk import torch def detect_from_camera(): # 打开默认摄像头0 表示第一个摄像头设备 cap cv2.VideoCapture(0) # 加载本地训练好的 YOLOv5 权重sourcelocal 表示不联网拉取源码 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/exp/weights/best.pt, sourcelocal) while True: ret, frame cap.read() if not ret: break # 模型推理并渲染检测框 results model(frame) frame results.render()[0] # 将 OpenCV 的 BGR 帧转成 Tkinter 可显示的 PhotoImage img Image.fromarray(frame) img ImageTk.PhotoImage(imageimg) panel.imgtk img panel.config(imageimg) # 按 q 键退出实时检测 if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows() # 创建主窗口 root tk.Tk() root.title(Rectal Polyp Detection System) root.geometry(800x600) # Label 组件用于显示视频帧 panel tk.Label(root) panel.pack() start_button tk.Button(root, textStart Detection, commanddetect_from_camera) start_button.pack() root.mainloop()torch.hub.load这里有个关键参数sourcelocal意思是直接用本地yolov5目录里的源码不联网去GitHub拉取。我一开始没加这个参数结果每次都试图访问外网网络受限时直接报错。results.render()会在每帧图像上画出边界框和类别置信度返回的是numpy数组需要转成PIL的Image对象再转成PhotoImage才能在Tkinter里显示。有个小技巧panel.imgtk img这一行必须保留否则图像对象会被Python垃圾回收掉界面显示会闪烁或者干脆黑屏。整个循环跑在Tkinter的主线程里如果视频流卡顿多半是这个原因。5.2 五个真实踩坑记录坑一torch.hub.load加载本地权重报错提示找不到模型源码现象运行GUI时报ModuleNotFoundError或者网络超时。 原因没加sourcelocaltorch.hub默认从GitHub下载yolov5源码网络环境不允许就挂了。 解决显式加sourcelocal并确保当前路径下有yolov5的源码目录或者用torch.hub.set_dir(./)指定本地缓存目录。坑二训练中途CUDA out of memory现象train.py跑了几分钟突然崩掉报CUDA out of memory。 原因batch和img尺寸超出了显存容量。 解决batch从16降到8或4img从640降到480如果还崩检查是否有其他进程占用显存用nvidia-smi看一眼。我自己的习惯是训练前先停掉所有浏览器Chrome的GPU进程经常白占几百兆显存。坑三loss降不下去反复震荡现象训练到第10轮loss始终在2附近晃完全没有下降趋势。 原因标签txt里的坐标是用像素值直接写的没做归一化最大误差到达几百模型梯度彻底乱掉。 解决把标签文件重新换算成归一化坐标并用下面这段代码画框预览做可视化校验确认标注框确实贴着真实目标。import cv2 # 读取图像和标签验证归一化坐标换算是否准确 img cv2.imread(polyp_data/images/train/001.jpg) h, w img.shape[:2] with open(polyp_data/labels/train/001.txt, r) as f: line f.readline().strip().split() cls_id, cx, cy, bw, bh int(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4]) # 将归一化坐标还原成像素坐标 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(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow(check, img) cv2.waitKey(0)坑四GUI界面点击Start Detection后卡死按钮无响应现象视频画面出不来整个窗口转圈。 原因while True循环里不断读摄像头和推理把Tkinter的事件循环堵死了。 解决把视频循环放到独立线程里执行用threading.Thread(targetdetect_from_camera, daemonTrue)启动如果需要把数据显示回主窗口用队列传帧别直接操作控件的引用。坑五eval的mAP很高但GUI实测误检一堆现象val.py评估mAP0.5到了0.9但实际跑视频时非息肉区域画出一堆框。 原因验证集里阴性样本太少模型没充分见过非息肉的背景纹理置信度阈值默认偏低。 解决训练时保证val里有一定比例的阴性图片不强行把每张图都标注成有目标推理时调高置信度阈值比如从默认的0.25提高到0.4误检明显减少。6. 进阶验证与部署技巧多类扩展与单帧推理耗时优化6.1 多类检测扩展这套系统目前只有polyp一个类别但内镜场景里常见的问题不止一种。要扩展到多类数据改动很小标签文件里第一个数字按类别顺序递增polyp.yaml里的nc改成实际类别数names列表按同样顺序写全。比如要区分腺瘤性息肉和炎性息肉names写成[adenomatous, inflammatory]标注时分别标0和1重新训练一遍即可。YOLOv5的多类别训练逻辑是完全自动的不需要改网络结构。6.2 单帧推理耗时验证部署到实际流程前我强烈建议先测一下推理速度和稳定性。下面这段代码用time模块打印每帧耗时并统计FPSimport time import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/exp/weights/best.pt, sourcelocal) model.conf 0.4 # 置信度阈值实测阶段调高可降低误检 cap cv2.VideoCapture(0) fps 0 while True: ret, frame cap.read() if not ret: break start time.time() results model(frame) infer_time time.time() - start fps 1 / infer_time # 打印每秒处理帧数低于 10 就说明推理太慢 print(finfer_time: {infer_time:.3f}s, FPS: {fps:.1f}) cap.release()model.conf可以独立于权重文件设置它控制的是后处理阶段保留检测框的置信度下限不需要重新训练。调高到0.4后误检会减少但过高的置信度阈值也可能把真正的小息肉滤掉得根据验证集的recall曲线来定。如果FPS低于10优先确认GPU是否真的在工作torch.cuda.is_available()返回True不代表当前模型一定跑在GPU上其次考虑把输入尺寸从640降到512推理速度能提升约三分之一。我从这个项目里沉淀下来的一个习惯是每次换数据集训练完先抽出一张没见过的图像跑一次单张推理把结果框和原始标注重叠画出来看一遍再谈mAP和部署。这套流程走完一遍基本能排除八成以上的数据问题和模型问题。希望这些踩坑记录和参数经验能帮你在医疗图像检测这条路上少绕点弯顺利把自己的数据集跑通。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门