1. 为什么选 Ultralytics 库跑 YOLO 模型预测
如果你接触过计算机视觉或者目标检测,那对 YOLO 这个名字一定不陌生。从最初的开山之作,到后来社区里百花齐放的各个版本,YOLO 系列一直是实时目标检测领域绕不开的标杆。而现在,Ultralytics 这个官方团队维护的 Python 库,几乎成了跑 YOLO 模型的首选方式。我自己从最早期用 Darknet 框架跑模型,到后来转用 Ultralytics,最直观的感受就是:这个库把过去繁琐的推理流程压缩到了几行代码,让“加载模型做预测”这件事变得异常顺手。
1.1 Ultralytics 库到底解决了什么问题
先说一个最常见的痛点。以前想跑一个 YOLO 模型做预测,你得先把模型权重从某个犄角旮旯的下载链接里弄下来,然后配置对应的深度学习框架环境,再写一堆预处理代码,把图像缩放、转成张量、归一化,把结果解析出来,最后画框还得自己调 OpenCV 的 API。这一套流程下来,光是环境配置就够折腾半天。
Ultralytics 库做的事情,就是把这整条链路打包成了统一接口。你只需要安装一个库,加载一个.pt权重文件,调用一句model.predict(),它就会自动处理好图像预处理、模型推理、后处理、结果可视化这些环节。对于绝大多数业务场景来说,你根本不需要关心底层卷积怎么算的、张量维度怎么变换的,拿来就能用。这种“开箱即用”的体验,在过去的目标检测生态里是相当稀缺的。
1.2 各版本 YOLO 模型怎么选
Ultralytics 库目前支持多个版本的 YOLO 模型,包括 YOLOv5、YOLOv8,以及后续迭代版本。这些模型各有各的侧重点,选择逻辑也不一样。我这里总结一下我实际使用下来的经验。
如果你要部署到边缘设备,比如树莓派、手机端或者嵌入式设备,那么yolov8n(nano 版本)或者yolov8s(small 版本)是优先考虑的。它们的参数量小、计算量低,在 CPU 上都能跑出不错的速度。如果是做高精度的离线检测任务,比如缺陷检测、医学影像分析,那yolov8m、yolov8l甚至yolov8x会更合适,精度有明显提升,代价就是推理速度变慢、显存占用变大。
另外一个选择是带-seg、-pose、-cls后缀的变体。带-seg的是实例分割模型,不仅给出目标框,还能给出像素级的分割掩码;带-pose的是关键点检测模型,专门用于人体姿态估计;带-cls的是图像分类模型,输出的是整张图片的类别概率。这个库最方便的地方就在这里,统一 API 风格覆盖了检测、分割、姿态、分类四类任务,切换成本极低。
提示:如果你只是在学习阶段,建议先跑
yolov8n.pt或yolov8s.pt。这两个模型小,下载快,CPU 也能流畅运行,先把整个预测流程跑通,再去研究大模型的效果差异。
2. 环境准备与核心概念梳理
在你动手写第一行预测代码之前,需要先把基础环境搭好。这一步看似简单,但很多初学者会在这里踩坑,尤其是 Python 版本、依赖冲突、CUDA 版本对不上的问题,一旦出现就会让人很头疼。
2.1 Python 环境和安装步骤
Ultralytics 库对 Python 版本有明确要求,理论上 3.8 以上都能装,但我建议直接用 Python 3.10 或者 3.11,这两个版本相对稳定,各种依赖库的兼容性也最好。安装最省心的方式是使用pip:
pip install ultralytics这条命令会自动帮你安装核心依赖,主要包括torch、torchvision、opencv-python、numpy、matplotlib等。如果你是在国内网络环境下安装,注意把 pip 源换成国内镜像,不然下载速度会非常感人。我通常用清华源:
pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple如果你想用 GPU 推理,还需要单独安装对应版本的 PyTorch。这个坑比较常见:直接用pip install ultralytics拉下来的 PyTorch 默认是 CPU 版本,即使你的机器有独立显卡也不会被利用。正确做法是先去 PyTorch 官网查一下适配你 CUDA 版本的安装命令,比如 CUDA 11.8 对应的是:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118先装好 GPU 版 PyTorch,再装 Ultralytics,这样就能自动识别你的显卡了。
注意:不要盲目追求最新版本。我遇到过几次因为 PyTorch 版本过新,导致某些旧模型权重兼容性出问题的情况。稳定压倒一切,如果你的业务代码已经跑得好好的,别频繁升级核心依赖。
2.2 模型推理背后的几个关键概念
在真正上手写预测代码之前,有几个核心概念必须弄明白,不然你连结果都看不懂。
首先是置信度(Confidence)。每个检测框都会附带一个 0 到 1 之间的分数,代表模型认为这个框里确实是目标的把握有多大。通常我们会设置一个阈值,低于这个阈值的框直接丢弃。在 Ultralytics 库中,对应的参数就是conf。
其次是IoU 与非极大值抑制(NMS)。目标检测的流程往往会生成大量重叠的候选框,NMS 的作用就是从这些重叠框里挑出“最好”的那一个。IoU 衡量的是两个框之间的重叠程度,iou参数就是用来控制 NMS 的严格程度的。这个值设得太高,会导致很多重叠的目标被合并成同一个;设得太低,又会让同一目标周围出现多个重复框。经验值是设 0.4 到 0.5 之间。
然后是输入尺寸(imgsz)。模型训练时用的是固定尺寸的输入,推理时也需要把图像缩放到这个尺寸。这个参数直接影响推理速度和精度。增大imgsz通常会提升对小目标的检测能力,但也会显著增加计算量。我用yolov8n模型实测过,imgsz从 640 提到 1280,推理耗时大概增加了 3 到 4 倍,精度提升却并不总是成正比。
3. 完整实操:从加载模型到输出结果
接下来进入正题,我按实际编写的顺序,把完整流程一步步拆开讲清楚。这一段内容适合你对照着代码边看边敲,跑通一个完整的预测 Demo。
3.1 加载模型的两种方式
Ultralytics 库中加载模型的核心入口是YOLO类。它的用法非常直观:
from ultralytics import YOLO # 方式一:加载本地权重文件 model = YOLO("yolov8n.pt") # 方式二:直接传入模型配置,加载预训练权重 model = YOLO("yolov8n.yaml").load("yolov8n.pt")方式一在实例化时会自动去官方服务器下载对应的预训练权重,前提是你的机器有网络。如果你本地已经有了权重文件,也可以直接传入路径,比如YOLO("/path/to/your/model.pt"),它就不会再去下载了。
方式二一般用于训练场景,比如你想修改网络的配置结构,然后加载预训练权重作为初始参数,再微调训练。我们这里只做预测的话,用方式一就够了。
很多人会疑惑yolov8n.pt这串名字代表什么意思。yolov8是模型系列名,n是型号缩写,对应 nano,也就是最小版本。后面的字母还有s(small)、m(medium)、l(large)、x(extra large),体型和精度依次递增。官方还有一个按输入尺寸区分的版本,比如yolov8n-640,表示 640 分辨率下的优化版本,但通常直接使用基础版本就行,推理时通过参数控制输入尺寸。
3.2 单张图像预测的核心代码
加载好模型之后,最基础的任务就是给一张图片做预测。直接用model.predict()方法:
from ultralytics import YOLO model = YOLO("yolov8n.pt") results = model.predict( source="path/to/your/image.jpg", conf=0.25, iou=0.45, imgsz=640, )就这么几行,预测就完成了。返回的results是一个列表,列表里每个元素对应一个预测结果对象。如果你传入的是单张图片路径,这个列表的长度就是 1。
predict()里的参数我逐一说一下,它们影响整个预测结果:
source:数据来源,可以是单张图片路径、图片文件夹路径、视频文件路径,甚至摄像头设备 ID。conf:置信度阈值,低于这个值的预测框会被过滤掉。默认是 0.25,但实际使用中我会根据场景微调。如果是高精度筛选场景,比如工业缺陷检测,我会把阈值调到 0.5 以上,降低误报;如果是想尽量不漏掉目标,可以适当调低。iou:NMS 的 IoU 阈值,控制重叠框的合并策略。默认 0.45,我用下来这个值大部分场景够用。imgsz:推理输入尺寸,默认 640。对大多数公开数据集训练的模型来说,640 是性能和速度的平衡点。
如果你想直接看到可视化结果,在参数里加上save=True,模型会自动把画好框的图片保存到默认目录runs/detect/predict/下:
results = model.predict( source="path/to/your/image.jpg", conf=0.25, save=True, )3.3 深入理解预测结果的结构
很多初学者跑通代码后,看着results这个对象一脸茫然,不知道该从哪里拿坐标、哪里拿类别。我来拆开讲一下。
每个result对象里最核心的属性是boxes,它包含了所有检测框的信息。通过results[0].boxes可以访问:
# 取第一个预测结果 result = results[0] # 打印所有检测框的坐标(xyxy 格式:左上角 x1, y1, 右下角 x2, y2) print(result.boxes.xyxy) # 打印置信度 print(result.boxes.conf) # 打印类别 ID print(result.boxes.cls) # 打印类别名称 for cls_id in result.boxes.cls: print(result.names[int(cls_id)])result.names是一个字典,把类别 ID 映射到类别名称。比如 COCO 数据集上训练的官方模型,会把 0 映射到person,1 映射到bicycle,以此类推。
如果你需要把这些框在原图上画出来,可以用plot()方法:
visualized_img = result.plot() # 此时 visualized_img 是已经画好边框和标签的 BGR 图像再配合 OpenCV 做显示或者保存,就非常顺手了。这一小段代码几乎是我所有项目里复用率最高的工具代码,建议直接存成工具函数。
提示:
result.plot()返回的是 numpy 数组格式的图像,颜色通道是 BGR,和 OpenCV 一致,如果你后面用 matplotlib 显示,记得先转成 RGB。
3.4 批量预测文件夹中的图片
实际工作中,极少时候只有一张图需要预测。更多情况是给一个文件夹,里面有几百张图片,要全部跑一遍。predict()的source参数直接传入文件夹路径,它就会自动遍历处理目录下所有图片:
results = model.predict( source="path/to/image_folder", conf=0.25, save=True, save_txt=True, )这里我加了save_txt=True,这个参数非常实用,它会把每个检测框的坐标、置信度、类别 ID 写入独立的.txt文件,格式类似:
0 0.5234 0.6214 0.8231 0.9412每一行分别代表类别 ID、中心点 x 坐标(归一化)、中心点 y 坐标(归一化)、框宽度(归一化)、框高度(归一化)。这种格式和 YOLO 训练的标签格式完全一致,方便你后续做数据分析、可视化或者训练自己的模型。
处理完一批图片后,在runs/detect/predict/目录下,你会看到两个子目录:一个存放画好框的结果图,一个存放标签 txt 文件。整体流程非常省心。
3.5 视频流和实时摄像头预测
视频预测和图片预测在 API 层面基本没有区别,还是同一个predict()方法:
results = model.predict( source="path/to/video.mp4", conf=0.25, save=True, )只要传入的是视频文件路径,它就会自动逐帧推理,保存成带检测框的结果视频。如果想用摄像头实时检测,把source换成摄像头设备 ID 就行,比如 0 代表第一个摄像头:
results = model.predict( source=0, conf=0.25, stream=True, )stream=True是实时流场景下的推荐写法,它会启用生成器逐帧返回结果,避免一次性占用过多内存。这里要注意,用stream=True时,results是一个生成器,需要遍历它来获取每一帧的结果:
for result in model.predict(source=0, stream=True): frame = result.plot() # 这里可以直接用 cv2.imshow 显示我平时做摄像头实时检测时,还会顺手用cv2.resize调整显示窗口大小,不然窗口太大非常占屏幕。
4. 常见问题与排查技巧实录
实操过程中免不了遇到各种报错和异常结果,这里我把最常踩的坑整理成一个速查表,基本覆盖了初学者阶段的大部分问题。
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 安装时提示依赖冲突 | 环境中旧版本 numpy / opencv 冲突 | 新建干净的虚拟环境,在虚拟环境中重新安装 |
| 加载模型后推理速度极慢 | 实际在使用 CPU,GPU 没被识别 | 检查 CUDA 版本,重装匹配的 GPU 版 PyTorch |
| 预测结果为空 | 置信度阈值过高或图像尺寸异常 | 调低conf参数,检查imgsz是否过小 |
| 视频预测内存持续增长 | 未释放之前的帧结果 | 改用stream=True生成器方式逐帧处理 |
| 中文标签无法显示 | OpenCV 默认字体不支持中文 | 使用 PIL 在图像上绘制中文文本 |
4.1 安装和环境配置的坑
关于安装,最大的坑就是前文提到的 PyTorch 版本问题。很多人跑完pip install ultralytics就直接用了,结果不管什么模型都慢得离谱,原因就是装的是 CPU 版 PyTorch。验证是否用上 GPU 的方法很简单:
import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU")如果输出是 False,说明显卡根本没有参与计算。解决办法是卸载掉当前的 torch,再装对应 CUDA 版本的 GPU 版。
还有一个坑在虚拟环境。我见过不少初学者在系统级 Python 环境里直接安装各种深度学习库,结果把系统环境搞得一团糟。建议用conda创建独立环境:
conda create -n yolo_env python=3.10 conda activate yolo_env这样即使环境搞坏了,删掉重来也很快,不用影响系统其他项目的运行。
4.2 推理结果不理想怎么办
预测出来一堆空结果,或者检测框明显不准,这种问题多半不是代码的锅,而是参数和模型的选择有问题。
首先要自查conf参数。如果你设了 0.5 以上,而当前模型对某些目标本身的置信度输出就是 0.3 到 0.5 之间,那所有框都会被过滤掉。我建议调试阶段先把conf设为 0.1,把能检出来的目标先全部展示出来,再根据实际效果逐级上调。
其次是imgsz设置。如果你的目标在图像里占比很小,默认的 640 尺寸可能会丢失细节。可以试试imgsz=1280,代价是推理时间变长。这个参数需要根据你的实际图像分辨率灵活调整,没有绝对正确的固定值。
最后再考虑模型本身。用小模型yolov8n做高难度检测任务,效果不好是正常的,并不是代码错了。这种情况下换成yolov8m或者yolov8x,大概率能压出更高的精度。
4.3 从预测到部署的路径调整
predict()方法虽然好用,但要部署到生产环境,还有几个细节值得留意。
- 如果调用频率很高,频繁加载模型权重会浪费大量时间。正确做法是在服务启动时初始化一次模型,后续直接复用,不要每来一个请求就
YOLO("yolov8n.pt")一次。 - 高并发场景下,单模型实例同时推理多个请求会显存溢出。可以引入任务队列或者线程池,控制同时推理的任务数量。
- 对于追求极致速度的场景,建议把模型导出成 ONNX 或者 TensorRT 格式。这一步不需要重写业务代码,Ultralytics 提供了导出接口,确实能做到显著加速。
注意:生产环境建议把
verbose=False加进predict()方法,否则每一帧的推理信息都会刷屏日志,影响系统性能。
5. 进阶扩展:用一个模型玩转更多任务
YOLOv8 系列真正厉害的地方在于,同一个YOLO类,通过加载不同的权重文件,可以完成完全不同的视觉任务。这里分享几个我实际用过的扩展方向,能帮你把技能面拓宽不少。
5.1 自定义数据集上的模型预测
很多同学学会跑通官方权重以后,下一步就是训练自己的模型,比如检测某种特定设备、某种缺陷、或者某种肤色。训练部分这里不展开,只讲预测环节的注意点。
用自己训练的模型做预测,API 完全一样:
model = YOLO("best.pt") results = model.predict(source="test.jpg", conf=0.3)关键区别在result.names的映射关系变成你的自定义标签类别了。训练时你如果定义了["正常", "破损", "污渍"]三个类别,那么预测时names字典就是{0: "正常", 1: "破损", 2: "污渍"}。
在自定义模型上,conf阈值的调节尤其重要。因为你的训练数据和官方的 COCO 数据分布差异很大,置信度输出也可能整体偏高或偏低。我习惯先在验证集上跑一圈,画出置信度分布图,再根据分布规律确定适合的阈值,而不是直接套默认值。
5.2 导出模型格式与部署优化
如果要把模型部署到服务器上,用 PyTorch 权重直接跑推理虽然简单,但效率不是最优。Ultralytics 提供了方便的导出接口:
model.export(format="onnx") model.export(format="tensorrt")导出的 ONNX 文件在 CPU 上的推理速度通常比原生 PyTorch 快不少。而 TensorRT 导出则针对英伟达 GPU 做了深度优化,如果你手头有 NVIDIA 显卡,我非常推荐试一下 TensorRT。我用标配显卡实测,同一个模型导出 TensorRT 后,推理延迟可以缩短到原来的二分之一甚至三分之一。
导出后再用推理引擎加载,比如 ONNX Runtime:
import onnxruntime as ort session = ort.InferenceSession("yolov8n.onnx")这个方案的好处是部署环境可以不装 PyTorch,依赖大幅减少,这对服务器环境约束严格的场景尤其适用。
提示:导出 ONNX 时如果遇到动态维度相关的问题,可以在
export()参数里加上dynamic=True,给输入输出加上动态轴,灵活性会更高。
5.3 从预测走向跟踪和计数
预测解决的是“每帧里有什么目标”的问题,但在很多实际业务场景里,我们还要回答“目标往哪里走”或者“一共有多少个目标经过”。这时候就需要目标跟踪的加持。
Ultralytics 库同样提供了跟踪接口:
from ultralytics import YOLO model = YOLO("yolov8n.pt") results = model.track( source="video.mp4", conf=0.25, persist=True, )track()和predict()的唯一区别是,它会在检测框的基础上补充id属性,就藏在results[0].boxes.id里,代表每个目标的唯一编号。有了这个编号,你就能统计某个目标在视频里出现过的帧数、计算运动轨迹,甚至画一个虚拟围栏做越界报警。很多安防、零售、交通场景的核心能力都是建立在“检测加跟踪”这条链路之上的。
学会了预测之后,花点时间研究一下跟踪其实是非常好的学习路径,因为你会开始接触更完整的工程化思路,而不是停留在单帧的静态检测上。
6. 踩坑记录与真实项目经验总结
最后这部分,我把自己在实际项目里反复踩过、后来彻底记住的几条经验分享出来。有些细节你可能看文档看不出来,但真正做项目的时候特别关键。
第一,不要把predict()和train()的输入输出格式搞混。预测时传入的是图像路径或者图像数组,训练时传入的是数据集 YAML 配置路径。这个看起来很简单,但我在带人的时候见过太多次了。
第二,在处理视频时,save参数保存出来的视频文件体积可能相当大,如果视频分辨率高、时延长,可能直接把磁盘吃满。我建议在追求效率的时候,不要用save=True保存视频,而是自己用 OpenCV 的VideoWriter来控制编码格式和码率,这样文件大小会可控很多。
第三,关于批量预测的速度问题。如果你要对一个大文件夹执行预测,4 个线程并行推 CPU 是不用想了,GPU 才是硬道理。如果只有 CPU,建议调小imgsz和控制单批处理量,batch参数默认是 1,在 GPU 上可以加大这个值提高吞吐量。我曾在大规模图片数据集上把batch从 1 调到 16,GPU 利用率明显提升,总耗时缩短了将近 60%。
第四,现实项目里图像质量千奇百怪,旋转、模糊、低亮度、过曝都是常态。如果发现检测效果差,不要第一时间怪模型,先检查你的图像输入是不是异常的。我做过一个项目,监控摄像头拍摄的画面带严重鱼眼畸变,一开始检测率低得离谱,后来加了一个畸变校正的预处理步骤,指标立刻回归正常。
说到底,Ultralytics 库把目标检测的工程门槛拉得很低,但真正用到业务中,还是会考验你处理真实数据、优化性能、排查问题的能力。我个人觉得,最好的学习方式就是拿自己手边的图片和视频,跑通这套预测流程,然后不断调整参数、比较结果,慢慢你就知道每个参数实际导致什么样的变化了。