YOLOv8从零复现:环境配置、自定义训练与推理脚本实践

发布时间:2026/10/18 8:35:51
YOLOv8从零复现:环境配置、自定义训练与推理脚本实践
YOLOv8 这种开源视觉模型网上复现教程多得快能按斤称了但真正自己动手从零跑通的数量其实没有想象中多。最近我刚好把环境搭建、权重推理、自定义数据集训练、测试脚本验证这条路完整走了一遍全程没有用现成镜像容器纯手动装包、调参、debug最终把 yolov8n 和一个小批量自建数据集的模型都跑通了。这篇文章就把整个过程拆成模块来讲重点不是背参数而是说清楚每个环节“为什么这么弄”以及“实操时容易在哪里翻车”。不管你手头是 NVIDIA 显卡还是只能用 CPU 调试照着下面的顺序走一遍基本都能复现出来。1. 复现前先弄清的三件事1.1 复现不等于 pip install ultralytics很多人一上来就pip install ultralytics然后发现一个包能装但模型跑不动、GPU 用不上、各种导入报错。原因很简单YOLOv8 不是一个孤立的库它背后挂着一整套与版本强相关的 Python 生态至少包括 Python 解释器、PyTorch、CUDA、cuDNN、OpenCV、Pillow、NumPy。其中最容易出问题的就是 PyTorch 的 CUDA 版本。PyTorch 安装包内部其实自带了一部分 CUDA 运行时库但能否真正调用显卡还取决于你机器的 NVIDIA 驱动是不是够新。很多时候torch.cuda.is_available()返回 False不是因为你没装 CUDA而是因为你装的 PyTorch 版本要求的 CUDA 运行时和你本机的驱动不兼容。所以复现的第一步不是急着下载模型而是先把环境版本的对应关系理顺。这也是我觉得整个流程里最值得花时间的地方。环境一旦对了后面基本是顺水推舟。1.2 模型规格怎么选n、s、m、l、xYOLOv8 官方提供了一串不同尺寸的预训练模型文件名后缀区分了模型大小。第一次复现时强烈建议从yolov8n开始因为它最小、最快、占显存最少用来确认环境和流程是最合适的。我把几个常用规格的参数和定位整理了一下方便你对照选型模型参数量约典型用途显存需求参考yolov8n3.2M移动端、边缘设备、快速验证2GB 左右yolov8s11.2M中等精度需求、边缘计算4GB 左右yolov8m25.9M服务器端常规任务8GB 左右yolov8l43.7M高精度检测任务12GB 左右yolov8x68.2M对精度要求极高的场景16GB 以上显存需求只是一个粗略参考实际占用还跟训练图片尺寸、batch size、有没有开启 cache 等有直接关系。推理阶段占用会明显低于训练阶段2GB 显存跑 yolov8n 推理完全没问题甚至可以 CPU 跑只是慢一点。复现阶段先用小模型把链路打通后面再换大模型这不会浪费你做的工作。1.3 版本配套的大致规则我这次用的环境组合是 Python 3.10 PyTorch 2.1 CUDA 12.1 对应的 torch 预编译包。如果你手头是 CUDA 11.8也可以选 cu118 对应版本。关键规则是换 CUDA 版本不如换 torch 对应的预编译版本因为 torch 官方针对不同 CUDA 版本都发布了编译好的 wheel直接装就能匹配比自己装 CUDA 再编译简单得多。Python 版本也是硬约束。老项目用 Python 3.6 或 3.7 可能会碰上某些新版本依赖装不上的问题新版本库又可能因为 Python 太新而缺少预编译 wheel。实际体验下来Python 3.9 或 3.10 兼容性最好踩坑最少。如果你用的不巧是 Python 3.12 或更高遇到编译报错时别硬刚退回 3.10 通常能解决。2. 环境搭建与依赖安装实战2.1 创建独立的 Python 虚拟环境复现这种项目第一件事永远是建虚拟环境别把依赖直接装进系统环境。身边有朋友图省事直接在 base 环境里装 ultralytics结果后来做另一个项目时一pip install就冲突到怀疑人生。用虚拟环境隔离后面随意折腾都不怕污染其他项目。我这里用的是 conda你也可以用 Python 自带的 venv但 conda 对依赖解析和 Python 版本切换更省心。conda create -n yolov8 python3.10 -y conda activate yolov8激活之后看到命令提示符前面出现(yolov8)就说明环境切换成功了。这一步是最简单的但也最容易忽略尤其是 Windows 上如果在 PowerShell 里没运行 conda 初始化脚本可能直接卡在找不到 conda 命令。2.2 安装 PyTorch 和 ultralytics如果你确定要使用 GPU建议不要直接pip install torch因为默认可能装到 CPU 版本等你训练时才发现用的是 CPU白白浪费时间。先到 PyTorch 官方安装页面选一个和你的 CUDA 版本匹配的命令然后手动指定 index-url 安装。以 CUDA 12.1 为例pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121如果只是 CPU 调试直接pip install torch torchvision然后安装 ultralyticspip install ultralytics它会自动把 opencv-python、numpy、pillow、matplotlib、pandas 这些常见依赖拉下来。我实际测试时发现只要网络正常这套安装非常稳定基本不会出现缺依赖的问题。2.3 安装完别急着跑模型先验证装完之后打开 Python 交互式环境或者写一个临时脚本确认显卡和包都能正常工作import torch print(torch.__version__) print(torch.cuda.is_available()) if torch.cuda.is_available(): print(torch.cuda.get_device_name(0)) else: print(current device: cpu)如果你前面装的是带 CUDA 的 PyTorch且驱动也正常这里torch.cuda.is_available()应该输出 True。如果输出 False先别往下走回到第 2.2 节确认一下你是否装对了版本。这一步多花两分钟能省掉后面大半天的排查时间。再验证一下 YOLO 能正常初始化from ultralytics import YOLO model YOLO(yolov8n.pt) print(model)首次运行如果本地没有权重文件会自动联网下载下载完会打印模型结构信息。如果你看到一堆网络层结构输出来那说明 ultralytics 本身已经没问题了。这里有个小细节权重下载是到当前工作目录如果你后面换目录运行它又会再下一次。提前知道这一点免得以为模型每次都自动下了一遍。3. 用官方预训练权重把推理跑通3.1 权重下载卡住怎么办官方权重默认是从 GitHub Release 下载的。国内网络环境不稳定时最常见的问题就是权重下载卡在几分钟都不动。解决办法很简单手动下载对应权重文件放到当前目录或者放到项目根目录让程序检测到本地文件后跳过下载。文件名要严格对照官网的命名比如yolov8n.pt、yolov8s.pt、yolov8m.pt。注意权重文件不能改名因为模型加载时会根据文件内容识别架构而不是只认文件名。如果你下载了某个版本的权重放到程序能找到的路径下再运行YOLO(yolov8n.pt)就不会去网络请求了。还有个细节别把权重下载放到项目根目录后又在另一台机器上换个路径运行程序会去和当前路径对比找不到就需要重新下载。所以项目目录结构最好固定下来。3.2 一条命令快速验证推理环境没问题之后先随便找一张测试图片比如一张包含猫狗的图放在工作目录下。然后运行yolo predict modelyolov8n.pt sourcedemo.jpg conf0.25 imgsz640 saveTrueconf0.25表示只保留置信度大于等于 0.25 的检测框imgsz640是输入图片缩放尺寸saveTrue表示把画好检测框的图片保存下来。运行完后会在runs/detect/predict目录下生成一张标注过的图包含类名、置信度和边界框。如果你用的是官方预训练权重识别的是 COCO 数据集里的 80 类目标比如人、车、猫、狗、杯子、椅子等。看到图上出现带类别名称的方框就说明官方推理链路已经跑通了。3.3 CLI 和 Python 接口怎么对应命令行模式用起来方便但实际项目里更多是嵌入到 Python 脚本中这里把最常用的几个场景对照列出来方便你切换功能CLI 方式Python 方式检测yolo detect predict ...model.predict(...)分割yolo segment predict ...YOLO(yolov8n-seg.pt).predict(...)分类yolo classify predict ...YOLO(yolov8n-cls.pt).predict(...)训练yolo detect train ...model.train(...)验证yolo detect val ...model.val()核心参数在两边的名字是一样的比如conf、imgsz、device、save。CLI 只是把这些参数变成命令行字符串底层调用的还是同一套 Python 接口。你自己写脚本时直接以 Python 接口为准就行。4. 送出的测试脚本拿来直接跑4.1 脚本的设计思路说好的送测试脚本这里直接给你一份我在复现过程中整理的版本。它比单纯敲命令行更接近真实使用场景支持指定图片、文件夹、摄像头支持把检测结果保存成图片和标签文本还能打印出每个目标的类别和置信度。脚本里所有参数都用 argparse 接收方便你不改代码就能换参数。这个脚本的核心逻辑就是调用model.predict()让 ultralytics 内部去处理图片预处理、推理、后处理和可视化。你只需要关心传入什么路径、存到哪里、过滤阈值是多少。4.2 完整的 Python 测试脚本import argparse from pathlib import Path from ultralytics import YOLO def parse_args(): parser argparse.ArgumentParser(descriptionYOLOv8 test runner) parser.add_argument(--weights, typestr, defaultyolov8n.pt) parser.add_argument(--source, typestr, defaultdemo.jpg) parser.add_argument(--conf, typefloat, default0.25) parser.add_argument(--imgsz, typeint, default640) parser.add_argument(--project, typestr, defaultruns/detect) parser.add_argument(--name, typestr, defaulttest) parser.add_argument(--device, typestr, default0) parser.add_argument(--save-txt, actionstore_true, help同时保存检测结果的 txt 文件) return parser.parse_args() def main(): args parse_args() model YOLO(args.weights) results model.predict( sourceargs.source, confargs.conf, imgszargs.imgsz, projectargs.project, nameargs.name, saveTrue, save_txtargs.save_txt, deviceargs.device, exist_okTrue, verboseTrue, ) for idx, r in enumerate(results): print(fresult {idx}: {r.path}) if r.boxes is not None: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy [round(float(x), 2) for x in box.xyxy[0]] print(f category{r.names[cls_id]} conf{conf:.3f} box{xyxy}) if __name__ __main__: main()保存成test_yolov8.py然后运行python test_yolov8.py --source ./images --conf 0.3 --save-txt如果--source给的是一个文件夹路径程序会把文件夹下所有图片依次推理完保存的结果会放在runs/detect/test下。--device默认写的是0表示使用第一张显卡如果你只有 CPU改成--device cpu就行。4.3 怎么读结果对象脚本里results是一个列表数量对应输入源的数量比如输入一个文件夹里有 10 张图那结果就有 10 个元素。每个元素都包含检测框、类别、置信度、原始图像路径等信息。r.boxes检测框对象包含坐标和置信度box.cls类别索引例如 0 代表 data.yaml 里第一个类别box.conf置信度0 到 1 之间box.xyxy检测框左上角和右下角坐标格式是[x1, y1, x2, y2]r.names类别索引到类别名的映射字典如果你处理的是视频或摄像头实时画面predict方法内部仍会逐帧处理。但对实时视频流更推荐model(sourcestream_path, streamTrue)这种生成器写法避免一次性把所有帧结果全部载入内存细节先不展开等有需求时再单独说。5. 训练自己的数据集5.1 数据集目录怎么摆推理通了接下来通常就是训练自己的数据集。这里我不讲从零构造大规模数据的完整工程只讲最基础、最常用的目录结构。YOLOv8 的训练接口对数据目录的要求很直接建议用以下方式组织dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/images和labels必须在同一个父目录下。图片和标签的文件名保持一致比如001.jpg对应001.txt一张图对应一个同名 txt 文件。val 目录不是必须的但强烈建议准备因为训练过程要靠它做验证和早期停止。5.2 标注文件的 YOLO 格式YOLO 的标签文本格式非常简洁每行代表一个目标class_id x_center y_center width height注意坐标是归一化到 0 到 1 之间的值不是像素值。x_center和y_center是目标框中心点相对图片宽度和高度的比例width和height是目标框宽高占图片宽高的比例。类别索引从 0 开始比如你只有猫和狗两类那猫是 0狗是 1。很多新手踩的坑是把坐标写成像素值或者类别索引从 1 开始这样训练出来的模型要么完全学不到东西要么所有检测框都偏掉。格式这个东西没有技巧就是字段顺序和归一化两个点写完后自己写个小脚本确认一下数值范围是否都在 0 到 1 之间能省很多事。如果你想自己标注数据可以用开源标注工具导出 YOLO 格式时会自动生成同名 txt 文件。拿到 txt 后不要急着训练先随机抽几张图打印对应的标注内容人工对照一下确保标签和图像内容真的匹配。5.3 编写 data.yaml 配置YOLOv8 训练时通过一个 YAML 文件告诉模型数据集在哪、有哪些类别。我这里给一个最典型的写法path: ./dataset train: images/train val: images/val nc: 2 names: 0: cat 1: dogpath是数据集根目录最好用绝对路径或相对于当前工作目录的清晰相对路径。train和val是相对这个根目录的图片目录路径。nc是类别数量names是类别索引到名称的映射。注意names的顺序必须和标注文件里的类别索引一致否则训练出来的模型类别会错乱检测结果的含义也会完全对不上。5.4 训练命令与关键参数训练的核心命令很简单yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0这里modelyolov8n.pt很关键它表示在官方预训练权重基础上继续微调也就是迁移学习。对于自制小数据集来说用预训练权重比随机初始化收敛更快精度也更高。如果你想从零训练也可以只给模型架构文件yolov8n.yaml但实际应用里大多数人不会这么做。几个参数的选取逻辑说一下epochs训练轮数。小数据集 100 轮起步如果验证集 loss 还在持续下降可以加大到 200。batch批大小。这个值受限于显存显存不够就减小。比如 8GB 显存跑 yolov8n 训练batch 16 通常没问题但如果同时开cacheTrue把图片全部预加载进显存就可能显存爆掉。imgsz输入图片尺寸。官方默认 640显存小可以降到 416 甚至 320但精度会有所下降。device指定训练设备0是首张 GPUcpu是 CPU。训练过程中会看到 mAP50、mAP50-95、loss 等指标随轮次变化。不用太在意每个 epoch 的震荡重点看整体趋势。训练结束后最优权重保存在runs/detect/train/weights/best.pt最后一个 epoch 的权重在last.pt一般直接使用best.pt。5.5 训练完怎么验证模型效果训练结束后不要直接用best.pt去猜效果先用验证集跑一遍指标yolo detect val modelruns/detect/train/weights/best.pt datadataset/data.yaml它会输出 mAP50、mAP50-95 等数值。mAP50 是 IoU 阈值大于等于 0.5 时的平均精度mAP50-95 是在多个 IoU 阈值下的平均值后者更严格也更接近真实难度。对一个类别很少的小数据集来说mAP50 能到 0.9 以上通常已经相当好了。如果你更习惯用脚本评估from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datadataset/data.yaml) print(metrics.box.map50, metrics.box.map)最后再用第 4 节那个测试脚本把--weights换成best.pt路径跑几张没参与过训练的图片看看确认实际检测框位置和类别标签是否符合预期。这一步能直观反映模型在真实环境里的表现。6. 复现过程中最常见的问题与排查6.1 环境层面的高发问题复现过程中环境相关的报错是出现频率最高的。我把几类常见信息整理成一个速查表遇到可以直接对照报错关键信息常见原因解决思路torch.cuda.is_available()返回 FalsePyTorch 与驱动不匹配重装对应 CUDA 版本的 PyTorch或升级驱动AttributeError: module PIL.Image has no attribute ResamplingPillow 版本过旧pip install -U pillow升级 PillowImportError: libGL.so.1OpenCV 缺少系统图形库安装 opencv-python-headless或在系统层补齐图形库OMP: Error #15OpenMP 重复加载检查有没有在多个环境里混用库必要时设置相关线程环境变量CUDA out of memorybatch 或 imgsz 太大减小 batch、imgsz关闭 cacheNo labels found in ...标签目录路径或格式错误检查 data.yaml 路径确认存在同名 txt 文件环境类问题最忌讳的就是反复重装越急越容易把环境搞得乱七八糟。我的建议是报错先看前三行如果是依赖缺失直接补对应依赖如果是 CUDA 相关问题先单独写个脚本测试torch.cuda.is_available()再决定要不要重装。6.2 数据准备阶段的典型错误数据阶段最常见的错误有几种。第一种是标签文件和图片文件名不一致。YOLOv8 是按文件名前缀匹配图片和标签的比如001.jpg必须对应001.txt。如果你从别的数据集转换过来文件名规则对不上就会疯狂报“No labels found”。第二种是类别索引错位。训练数据里标注的是0 cat、1 dog但 data.yaml 里names写反了模型训练时会把猫和狗的标签互相混淆导致最终检测结果完全错误。这种错误在指标上往往不明显因为整体 mAP 可能看起来不低但实际语义完全乱了。第三种是标签数据没有归一化。YOLO 格式要求坐标都归一化到 0 到 1如果写成像素坐标训练会非常不稳定甚至出现 loss 为 NaN。建议拿到任何数据集后先写一段几行的脚本统计一下所有标签文本的数值范围如果超出 0 到 1就要先处理数据再训练。6.3 几条避坑经验总结这部分是我自己跑完几轮实验之后的体会。第一个经验不要一上来就用大模型和全量数据。先用 yolov8n 加几十张图把整个训练流程跑通确认数据格式和代码链路都没问题再上大模型和大数据量。这样即便出错每次迭代周期也只有几分钟而不是几小时。第二个经验每次实验单独建目录。我习惯在runs/detect下给不同实验起不同 name比如train_baseline、train_aug这样权重和日志都隔离不会因为覆盖而丢失历史结果。对比实验时也能快速找到哪一份权重是哪个配置训出来的。第三个经验善用exist_okTrue。如果是自己写脚本调用 train 或 predict加这个参数可以让程序重复写同一目录时直接覆盖而不是每次创建新的序号目录。我在自动化跑批量测试时经常因为忘加这个参数结果生成一堆无意义的目录。第四个经验CPU 也能跑但要接受速度差距。如果实在没有 GPU训练时把imgsz降到 320、batch设为 4 或 8还是能跑通的只是时间慢很多。推理阶段 CPU 也不至于完全不可用拿几张小图测一批效果完全没问题。说真的YOLOv8 复现的难点不在模型本身而在环境版本匹配和数据格式对齐。跑通一个最小 demo 之后再一句一句改自己的脚本改一步跑一步别一口气照着别人的完整工程全量粘贴。把我上面这个测试脚本和训练流程搭起来你就能从“会跑官方权重”顺利过渡到“训练自己的数据集”。后面再想扩展模型量化、导出 ONNX、接入摄像头实时检测都可以在这个基础上慢慢加。