很多读者在学 YOLO 系列目标检测时,都会遇到一个尴尬的阶段:网上教程刷了不少, git clone 也执行了,训练命令运气好也能跑通,但只要换成自己的数据集、自己的业务场景,马上就卡住——要么标签文件格式不对,要么类别数对不上,要么训练完的模型在部署时不知道怎么封装成接口。

本文就用两套极具代表性的深度学习实战项目来串起整条链路:一套是 YOLOv5 细胞检测 ,另一套是 YOLOv4 交通标志识别 。从数据集准备、模型训练到最终部署推理,把关键步骤和常见隐患全部过一遍。读完你会发现,这两套项目表面上一个用了 YOLOv5、一个用了 YOLOv4,但底层要掌握的“数据准备 → 训练调参 → 模型导出 → 推理部署”这条主线是完全相通的。

文章不会只停留在“跑通官方 demo”的层面,而是站在做实际项目的角度,告诉你哪些地方容易翻车、如何验收模型效果、怎么把模型接到自己的 Python 服务里。无论你是正在做毕业设计,还是刚进入视觉算法岗位,这条技术路线都值得完整走一遍。

1. 两套项目到底在解决什么问题

先摆一个判断:目标检测是计算机视觉里覆盖场景最广、落地价值最高的方向之一。而 YOLO 系列又是目标检测里工程落地最成熟的一条技术线,YOLOv5 和 YOLOv4 至今仍有大量生产环境在使用,不是简单的“过时技术”。选这两个版本作为实战项目,不是因为它们最新,而是因为它们在数据格式、训练范式和部署方式上非常典型,且资料密度大、踩坑记录多,特别适合用来建立完整的工程项目思维。

  • YOLOv5 细胞检测 :本质是一个小目标检测任务。细胞在显微图像里往往密集、尺寸小、背景复杂,对模型的特征提取能力和训练策略都有要求。这个项目能让你理解如何用 YOLOv5 处理专业领域的小目标数据,也适合医疗影像、生物实验自动化等方向的毕设选题。
  • YOLOv4 交通标志识别 :本质是一个中低分辨率目标的识别任务。交通标志类别多、颜色形状差异大,且要求较高的实时性,是 YOLOv4 这类工业级检测器的经典应用场景。做自动驾驶、辅助驾驶或智慧交通相关项目的同学,通常绕不开这个方向。

为什么要用两套项目而不是一套?

因为只看一套项目,你容易把“某个框架的用法”误当成“目标检测的通用能力”。两套项目放在一起,你才会意识到:换一个检测框架、换一种数据来源、换一个业务场景之后,核心流程依然可以复用,变的只是具体命令、配置文件和解码逻辑。这才是实战型开发者真正需要的能力。

2. YOLOv4 与 YOLOv5 的核心差异:先别盲目选型

很多初学者最容易犯的错,是听别人说“YOLOv5 更先进”,就直接忽略 YOLOv4。实际上这两个版本在技术路线和工程取舍上并不完全是迭代关系。

维度 YOLOv4 YOLOv5
官方实现 Darknet(C 语言)为主 PyTorch 官方仓库
训练生态 相对繁琐,配置偏底层 更友好,开箱即用体验好
推理速度 在 GPU 上表现优秀 导出 ONNX/TensorRT 后同样高效
数据增强 Mosaic、CutMix 等 Mosaic、MixUp、自动增强等
工程集成难度 C++ 部署资料多,但配置繁琐 Python 生态完善,适合快速原型
社区资料 论文系统和工业落地案例丰富 新手教程多,问题排查容易

仅从“好不好上手”来看,YOLOv5 无疑更适合第一次接触训练流程的人。PyTorch 动态图、官方仓库的脚本封装、完整的训练日志和可视化工具,都能极大降低入门门槛。而 YOLOv4 的 Darknet 版本意味着你需要处理编译、Makefile、CUDA 版本匹配等一系列环境问题,但这些步骤本身也是工程能力的一部分。

从项目实战的角度,我更推荐的策略是: 以 YOLOv5 跑通全流程,建立信心;再用 YOLOv4 的 Darknet 编译和训练,补足底层工程能力。 两套项目都走完,你对“算法框架”和“工程部署”的边界会清晰很多。

3. 上手前的技术准备:算法、数据格式和运行环境

在敲任何训练命令之前,先确认你对以下核心概念有基础认知。

3.1 目标检测在做什么

目标检测任务可以拆成两个核心问题:目标在哪里(定位),目标是什么(分类)。YOLO 系列的核心思路是把检测问题统一成回归问题:将输入图像划分成网格,每个网格负责预测多个候选框的位置、置信度和类别概率。理解这一点非常重要,因为后续所有的训练配置、数据标注格式都围绕这个设计展开。

3.2 YOLO 数据标注格式

YOLO 系列通用的标签格式是 .txt 文件,每行代表一个目标,内容为:

class_id x_center y_center width height

其中 x_center y_center width height 都使用归一化坐标,取值范围在 0 到 1 之间。

# 示例:一个目标的标注
0 0.515625 0.486111 0.146250 0.225000

这行表示:类别 ID 为 0,目标中心点位于图像宽度 51.5625% 的位置,高度 48.6111% 的位置,目标宽度占整张图的 14.625%,高度占 22.5%。

很多新手在准备自有数据集时,最容易翻车的地方就是把 Pascal VOC 格式(XML 坐标)和 YOLO 格式搞混,或者混淆“归一化坐标”和“绝对像素坐标”。后面我们会专门演示格式转换的脚本。

3.3 环境准备建议

两套项目都需要 GPU 环境,如果没有本地 GPU,建议优先使用云 GPU 或带 GPU 的远程服务器。

本文涉及的主要环境组件如下,版本以实际项目为准,重点是先建立正确的环境概念:

组件 作用 建议
Python 训练脚本和推理脚本的语言基础 3.8 - 3.10 均可,具体看依赖兼容
PyTorch YOLOv5 的训练和推理框架 根据 CUDA 版本选对应版本
CUDA / cuDNN GPU 加速计算库 与显卡驱动匹配即可
OpenCV 图像读取、预处理、结果绘制 由 requirements 自动安装
Darknet YOLOv4 官方训练框架 编译时注意 OpenCV 和 CUDA 选项

创建环境时,推荐使用 conda,避免污染系统 Python。

conda create -n yolov5 python=3.9 -y
conda activate yolov5

# 安装 PyTorch,这里以 CUDA 11.8 为例
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

YOLOv5 官方仓库提供完整的依赖清单:

git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt

YOLOv4 的 Darknet 版本通常需要先编译:

git clone https://github.com/AlexeyAB/darknet
cd darknet
# 修改 Makefile,打开 GPU、CUDNN、OPENCV 选项
make -j$(nproc)

编译是 YOLOv4 入门的第一道坎。如果 Makefile 里没有把 GPU=1 、 CUDNN=1 、 OPENCV=1 正确打开,训练速度会非常慢,甚至无法正常读图。

4. 数据集准备:从公开数据到 YOLO 格式

数据集是整个项目的基石。模型精度上不去的项目,绝大多数问题不是网络结构不行,而是数据本身有问题。

4.1 数据集来源与选择

细胞检测方向,常见的公开数据集包括 BCCD Dataset(血细胞检测数据集),包含白细胞、红细胞和血小板等类别;也可以使用 Blood Cell Count and Detection 等数据集。交通标志识别方向,经典公开数据集有 TT100K(腾讯交通标志数据集)或德国 GTSRB 数据集。使用这些公开数据集做项目,优点是有标注、有论文参考、结果可复现;弱点是要注意某些数据集的标注格式不是 YOLO 格式,需要额外转换。

如果是自建数据集,最核心的一条原则是: 采集的图像分布必须贴近真实部署场景 。比如交通标志识别,你要考虑白天、夜晚、雨天、反光、遮挡等实际工况;细胞检测也要考虑不同染色方式、不同显微镜倍数对图像分布的影响。

4.2 目录结构规范

YOLOv5 和 YOLOv4 的数据集目录结构很相似,建议按下面的方式组织:

datasets/
├── cell_dataset/
│   ├── images/
│   │   ├── train/
│   │   ├── val/
│   │   └── test/
│   └── labels/
│       ├── train/
│       ├── val/
│       └── test/
└── traffic_sign_dataset/
    ├── images/
    │   ├── train/
    │   ├── val/
    │   └── test/
    └── labels/
        ├── train/
        ├── val/
        └── test/

图片和标签的文件名需要一一对应,比如 img_001.jpg 对应 img_001.txt 。这是 YOLO 系列最基础的文件组织约定。

4.3 数据集划分

训练集、验证集、测试集的比例一般建议是 7:2:1 或 8:1:1。关键是保证三个集合之间的数据分布一致,不能训练集都是白天图片,验证集全是夜晚图片。划分数据集的脚本可以参考以下逻辑:

import os
import random
from shutil import copyfile

random.seed(42)

image_dir = "raw_images"
label_dir = "raw_labels"
train_ratio, val_ratio = 0.8, 0.1

images = [f for f in os.listdir(image_dir) if f.endswith(('.jpg', '.png'))]
random.shuffle(images)

train_split = int(len(images) * train_ratio)
val_split = int(len(images) * (train_ratio + val_ratio))

splits = {
    "train": images[:train_split],
    "val": images[train_split:val_split],
    "test": images[val_split:],
}

for split_name, split_images in splits.items():
    os.makedirs(f"datasets/cell_dataset/images/{split_name}", exist_ok=True)
    os.makedirs(f"datasets/cell_dataset/labels/{split_name}", exist_ok=True)
    for img in split_images:
        src_img = os.path.join(image_dir, img)
        src_label = os.path.join(label_dir, img.replace(".jpg", ".txt").replace(".png", ".txt"))
        copyfile(src_img, f"datasets/cell_dataset/images/{split_name}/{img}")
        copyfile(src_label, f"datasets/cell_dataset/labels/{split_name}/{img.replace('.jpg', '.txt').replace('.png', '.txt')}")

如果你手上的标签是 Pascal VOC 的 XML 格式,还需要做格式转换:

import xml.etree.ElementTree as ET

def convert_voc_to_yolo(xml_file, output_txt, class_names):
    tree = ET.parse(xml_file)
    root = tree.getroot()
    
    img_width = int(root.find("size/width").text)
    img_height = int(root.find("size/height").text)
    
    lines = []
    for obj in root.findall("object"):
        class_name = obj.find("name").text
        class_id = class_names.index(class_name)
        bbox = obj.find("bndbox")
        x_min = int(bbox.find("xmin").text)
        y_min = int(bbox.find("ymin").text)
        x_max = int(bbox.find("xmax").text)
        y_max = int(bbox.find("ymax").text)
        
        x_center = (x_min + x_max) / 2 / img_width
        y_center = (y_min + y_max) / 2 / img_height
        width = (x_max - x_min) / img_width
        height = (y_max - y_min) / img_height
        
        lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
    
    with open(output_txt, "w") as f:
        f.write("\n".join(lines))

这段代码的核心逻辑是拿到 XML 里的绝对像素坐标,再除以图像宽高,得到归一化坐标。很多框架自带类似的转换脚本,但自己写一遍能更清楚地理解格式含义。

4.4 数据配置文件

YOLOv5 需要使用 YAML 文件描述数据集信息:

# 文件路径:yolov5/data/cell.yaml
train: ../datasets/cell_dataset/images/train
val: ../datasets/cell_dataset/images/val
test: ../datasets/cell_dataset/images/test

nc: 3
names: ['WBC', 'RBC', 'Platelet']
  • train/val/test :图片目录路径,训练时会根据同名机制自动寻找 labels 目录。
  • nc :类别总数。
  • names :类别名称列表,顺序必须与标注文件中的 class_id 一致。

YOLOv4 的 Darknet 则需要两个文件。第一个是类别名称文件:

# 文件路径:darknet/data/traffic.names
speed_limit
stop
crosswalk

第二个是数据配置文件:

# 文件路径:darknet/data/traffic.data
classes=3
train=darknet/data/traffic_train.txt
valid=darknet/data/traffic_val.txt
names=darknet/data/traffic.names
backup=darknet/backup/

train.txt 和 val.txt 里每一行是一张训练图片的绝对路径,这种“路径列表”的方式和 YOLOv5 的“目录自动查找”方式不同,属于框架差异,换框架时要注意。

5. 训练流程:细胞检测与交通标志识别的完整命令

数据准备好之后,进入整个项目最核心,也最容易出问题的训练环节。

5.1 YOLOv5 细胞检测训练

YOLOv5 官方仓库封装得非常完整,最小训练命令如下:

cd yolov5
python train.py \
    --data data/cell.yaml \
    --weights yolov5s.pt \
    --img 640 \
    --batch-size 16 \
    --epochs 100 \
    --device 0

参数含义:

参数 作用 建议
--weights 预训练权重 首次训练建议用 yolov5s.pt ,迁移学习效果好
--img 训练输入尺寸 小目标密集场景可以尝试 640 或更高
--batch-size 批大小 根据显存调整,显存不足时报错时降低
--epochs 训练轮数 先跑 100 轮观察收敛情况
--device 使用的 GPU 编号 多卡可用 0,1,2,3

如果训练时显存不足,优先降低 batch-size ,而不是降低 img 尺寸,因为输入分辨率对检测小目标影响极大。细胞检测这类小目标任务,如果条件允许,把 --img 1280 也纳入对比实验。

5.2 YOLOv4 交通标志识别训练

YOLOv4 使用 Darknet 框架,训练前需要准备网络配置文件。一般以官方提供的 yolov4-custom.cfg 为基础,修改以下几个关键参数:

# 文件路径:darknet/cfg/yolov4-traffic.cfg
batch=64
subdivisions=16

width=608
height=608

max_batches=6000
steps=4800,5400

同时在文件的末尾,找到三个 [yolo] 层,修改:

classes=3
filters=24

filters 的计算公式是 (classes + 5) * 3 ,对应 YOLO 每个网格预测 3 个 anchor 框,每个框有 4 个坐标值、1 个置信度和 classes 个类别概率。

完成配置后执行训练命令:

cd darknet
./darknet detector train \
    data/traffic.data \
    cfg/yolov4-traffic.cfg \
    yolov4.conv.137 \
    -map

yolov4.conv.137 是官方提供的预训练卷积权重,不属于完整模型权重,它的作用是让模型在训练初期更快收敛。 -map 参数让训练过程中实时计算并打印 mAP 指标,方便观察效果。

5.3 训练过程中的关键监控点

训练不是敲完命令就结束的。我见过太多人训练过程中完全不看日志,训练结束直接拿权重去测试,结果效果很差也不知道问题出在哪。

训练期间一定要盯住几个信号:

信号 正常表现 异常表现
loss 下降趋势 前 20 轮快速下降,后逐渐平缓 剧烈波动或完全不降
验证集 mAP 随训练轮次稳步提升 长期为 0 或反复横跳
训练集 loss 和验证集 loss 的关系 两者差距不大,验证 loss 同步下降 训练 loss 很低但验证 loss 高,过拟合了
输出示例图片 目标框位置合理,置信度较高 目标框偏移、重复框多、漏检明显

有一个训练细节值得单独提醒: 训练中断后不要盲目从头开始 。YOLOv5 会自动保存 last.pt ,你可以从断点恢复:

python train.py \
    --data data/cell.yaml \
    --weights runs/train/exp/weights/last.pt \
    --epochs 200 \
    --img 640 \
    --batch-size 16 \
    --device 0

YOLOv4 只需要在训练命令中指定 -clear 之前使用已有的 backup 权重路径继续训练:

./darknet detector train \
    data/traffic.data \
    cfg/yolov4-traffic.cfg \
    backup/yolov4-traffic_last.weights \
    -map

6. 模型评估与推理部署

训练结束不等于项目结束。把模型用起来,才算完成闭环。

6.1 评估指标怎么看

YOLOv5 训练结束后会在 runs/train/exp/ 目录下生成丰富的评估结果,包括 results.png 、 confusion_matrix.png 、 PR_curve.png 等。

核心指标不需要全部搞清楚,但必须理解这几个:

指标 简单理解 什么时候特别关注
Precision 预测为正样本的结果里,真正正确的比例 假检代价高的场景,比如医疗场景误报会引发后续复核成本
Recall 所有真实目标里被找回的比例 漏检代价高的场景,比如安全监控漏掉一个目标可能更严重
mAP@0.5 IoU 阈值为 0.5 时各类别 AP 的平均值 最常用的模型精度指标,也是论文里最常报的指标
mAP@0.5:0.95 多个 IoU 阈值下的平均 更严格的指标,小目标检测对它的影响更大

YOLOv5 提供官方评估命令:

python val.py \
    --data data/cell.yaml \
    --weights runs/train/exp/weights/best.pt \
    --img 640 \
    --task val \
    --verbose

YOLOv4 评估命令:

./darknet detector map \
    data/traffic.data \
    cfg/yolov4-traffic.cfg \
    backup/yolov4-traffic_best.weights

6.2 部署推理:单张图片与批量预测

YOLOv5 官方自带推理脚本:

python detect.py \
    --weights runs/train/exp/weights/best.pt \
    --source data/images/test.jpg \
    --conf-thres 0.5 \
    --iou-thres 0.45 \
    --project runs/detect \
    --name test_result

--source 支持图片路径、视频路径、摄像头 ID 或目录,实际项目中非常方便。

但真实业务系统不会直接调命令行,你需要把模型封装成 Python 推理类。这里给出一个最小可用的 YOLOv5 推理封装示例:

import cv2
import torch

class YOLOv5Detector:
    def __init__(self, weights_path, device="cpu", conf_thres=0.5, iou_thres=0.45):
        self.model = torch.hub.load("ultralytics/yolov5", "custom", path=weights_path, force_reload=False)
        self.model.conf = conf_thres
        self.model.iou = iou_thres
        self.model.to(device)
    
    def predict(self, image):
        """
        image: BGR numpy array (OpenCV 读取格式)
        return: list of dict, 每个 dict 包含 bbox、置信度、类别
        """
        results = self.model(image)
        detections = []
        for *xyxy, conf, cls in results.xyxy[0].tolist():
            detections.append({
                "bbox": [int(v) for v in xyxy],
                "confidence": conf,
                "class_id": int(cls),
                "class_name": self.model.names[int(cls)]
            })
        return detections

    def predict_image_file(self, image_path):
        image = cv2.imread(image_path)
        return self.predict(image)

if __name__ == "__main__":
    detector = YOLOv5Detector("runs/train/exp/weights/best.pt", device="0")
    img = cv2.imread("test.jpg")
    dets = detector.predict(img)
    for d in dets:
        print(d)

这个封装类可以很方便地嵌入 FastAPI、Flask 服务或 ROS 节点中。关键是理解 results.xyxy[0] 的结构:每行包含 [x1, y1, x2, y2, confidence, class_id] ,其中 x1, y1, x2, y2 是目标框左上角和右下角的绝对像素坐标。

YOLOv4 的 Python 部署通常使用 pybind11 或直接调用 darknet.py 提供的辅助函数。这里给出一段基于 OpenCV 和 darknet 库的简化推理流程:

import cv2
import darknet

# 加载网络
net = darknet.load_network(
    b"cfg/yolov4-traffic.cfg",
    b"data/traffic.data",
    b"backup/yolov4-traffic_best.weights",
    batch_size=1
)

# 读取图片并做 letterbox resize
image = cv2.imread("test.jpg")
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
resized, ratio, pad = darknet.letterbox_image(image_rgb, (608, 608))

# 推理
detections = darknet.detect_image(net, resized)

# detections 中每项是 (class_name, confidence, bbox)
# bbox 格式为 (center_x, center_y, width, height)

YOLOv4 的 bbox 解码结果是中心点加宽高格式,必须自己转换成角点坐标才能用 OpenCV 绘制。这也是很多人从 YOLOv5 切到 YOLOv4 时容易困惑的点。

6.3 导出 ONNX 与跨平台部署

YOLOv5 可以实现一次训练、多处部署,核心途径是导出 ONNX 格式。ONNX 是一种开放的模型交换格式,可以转到 TensorRT、OpenVINO、ONNX Runtime 等推理引擎,覆盖 GPU 服务器、CPU 服务器、边缘设备等场景。

python export.py \
    --weights runs/train/exp/weights/best.pt \
    --img 640 \
    --batch 1 \
    --include onnx \
    --dynamic

导出后用 ONNX Runtime 推理示例:

import cv2
import numpy as np
import onnxruntime as ort

session = ort.InferenceSession("best.onnx")
input_name = session.get_inputs()[0].name

# 预处理:letterbox + 归一化
image = cv2.imread("test.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
h, w = image.shape[:2]
scale = min(640 / w, 640 / h)
nw, nh = int(w * scale), int(h * scale)
resized = cv2.resize(image, (nw, nh))
canvas = np.full((640, 640, 3), 114, dtype=np.uint8)
canvas[(640 - nh) // 2:(640 - nh) // 2 + nh, (640 - nw) // 2:(640 - nw) // 2 + nw] = resized

input_tensor = canvas.astype(np.float32) / 255.0
input_tensor = np.transpose(input_tensor, (2, 0, 1))[None]

# 推理
outputs = session.run(None, {input_name: input_tensor})[0]

YOLOv5 导出的 ONNX 输出需要做 NMS 后处理,这也是和直接使用 PyTorch 模型最大的区别:PyTorch 模型内部已经集成了 NMS,而 ONNX 默认只输出原始预测框。实际项目中建议导出时加入 --nms 参数让模型自带 NMS,或在外部代码中实现 NMS,否则会出现大量重叠框。

7. 常见问题与排查方法

两套项目走下来,有几类问题几乎必踩。这里整理成排查对照表,建议收藏后用。

问题现象 可能原因 排查方式 解决方案
训练 loss 始终不下降 学习率设置不合理、数据标注错乱、标签类别与配置不一致 先看 loss 曲线;随机挑几张训练图叠加标签可视化 降低学习率;修复标签;核对 names 顺序
显存不足(CUDA out of memory) batch-size 过大、输入分辨率过高 查看 GPU 显存占用 降低 batch-size 或 subdivisions;减小输入尺寸
模型 mAP 为 0 标签文件为空、类别 ID 越界、数据划分有问题 统计训练集中有效标签数量;检查类别索引 修复标签文件;重新划分数据集
验证时大量误检 置信度阈值过低、数据不平衡 查看 PR 曲线 提高 conf-thres;增加负样本或困难样本
YOLOv4 训练很慢 Makefile 未开启 GPU/CUDNN 选项 ./darknet 运行日志查看是否使用 GPU 重编译 darknet;确认 CUDA 版本
推理时框的位置偏移 预处理时未使用 letterbox 或未还原坐标 核对预处理代码 统一推理时的 resize 方式和坐标还原
训练中断后无法恢复 没有保存断点权重或恢复参数写错 查看权重目录 使用 last.pt 或 darknet 的 last.weights

在这些问题中, 标签可视化 是效率最高的排查手段。很多人标注完数据后直接开训,直到模型效果差才开始怀疑数据,其实应该在训练前就把标注结果叠加到图片上,肉眼核对一遍。

YOLOv5 里可以用下面的命令快速检查:

import cv2

image_path = "datasets/cell_dataset/images/train/img_001.jpg"
label_path = "datasets/cell_dataset/labels/train/img_001.txt"

img = cv2.imread(image_path)
h, w = img.shape[:2]

with open(label_path) as f:
    for line in f.readlines():
        cls, x_center, y_center, bw, bh = line.strip().split()
        x_center, y_center, bw, bh = map(float, (x_center, y_center, bw, bh))
        x1 = int((x_center - bw / 2) * w)
        y1 = int((y_center - bh / 2) * h)
        x2 = int((x_center + bw / 2) * w)
        y2 = int((y_center + bh / 2) * h)
        cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

cv2.imwrite("check_annotation.jpg", img)

如果这个脚本画出来的框位置不对,说明标签转换环节出了问题,需要回到数据准备阶段修,而不是改模型参数硬调。

8. 工程化最佳实践与避坑建议

把训练和部署跑通,是项目的及格线。要做到接近生产环境的质量,还需要注意下面这些工程问题。

8.1 数据管理:版本化与备份

数据集不是一次准备好的,后续大概率会不断补充坏例、修正错标。建议给数据集加上版本号,或者在 Git LFS 中管理原始数据集。任何修改标注的操作前先备份原始标注,避免批量操作失误导致不可逆损失。

8.2 实验记录:别靠记忆管理模型

训练几次之后, runs/train/ 目录下会积累大量 exp 文件夹。如果不记录每次实验的数据配置、超参数、训练集组成和评估指标,两周之后你根本分不清哪个模型对应哪次实验。建议每次训练前固定一个实验备注,或在训练命令后补充 --name exp_cell_v2_lr001 这样的命名。

8.3 超参数调整:先收敛再优化

很多初学者一上来就追求“最好的超参数”,这其实是本末倒置。先把一组常规参数训练收敛,拿到一个可以工作的基准模型,再针对性地调参。YOLOv5 也提供了超参数进化工具,但那是后面的优化步骤,不应该在第一步就用。

8.4 部署安全:受控环境与权限意识

医疗影像、交通监控这类场景涉及敏感数据,部署模型的服务必须做到数据最小化访问、日志脱敏、模型文件权限受控。进行模型替换或回滚操作前,先在测试环境验证,再切生产流量,同时保留上一版本的模型权重和配置文件。

8.5 性能优化:从模型自身出发

如果部署端推理速度不达标,先分析瓶颈在哪里。GPU 推理场景,优先考虑 TensorRT 半精度加速;CPU 推理场景,优先尝试 ONNX Runtime 的 CPU 优化版本,或者换更小的模型结构如 yolov5n 。盲目堆硬件是最贵的优化方式,而模型导出后的后处理优化往往能省下大量时间。

9. 总结与下一步

两套项目走完,你实际上掌握的不只是两个检测模型,而是一条可复制到很多场景的标准流水线:理解 YOLO 算法原理、准备 YOLO 格式数据集、配置训练环境、监控训练过程、评估模型效果、导出并封装推理服务。这个方法论的适用范围远超细胞检测和交通标志识别,换到工业质检、安防监控、农业视觉等场景,主线逻辑完全一致。

  • 如果你还没有动手:先选一套项目,把“数据集 → 训练 → 推理”跑通,再换另一套对比学习。
  • 如果你已经能跑通官方 demo:下一步去运营自己的真实数据,积累处理脏数据的经验。
  • 如果你已经完成训练:建议优先研究 ONNX 导出和 TensorRT 加速,这是模型真正进入生产环境的必经环节。

最有价值的动作是:现在就打开你的数据集标注工具,检查一遍标签中是否有漏标或错标,然后跑一次完整的训练和评估。等你亲手踩过数据、训练、部署这条链路上的每一个坑,才算真正入了深度学习的门。

Logo

聚焦RDK与具身智能,汇集机器人开发教程、开源案例和技术交流

更多推荐