1. 从“正方形”到“长方形”:一个被忽视的YOLOv5训练细节
如果你用过YOLOv5训练自己的数据集,大概率会遵循官方教程或主流社区的建议:把所有的训练图像都resize到一个固定的正方形尺寸,比如640x640。这几乎成了一种“标准操作”。但最近我在处理一个工业检测项目时,遇到了一个棘手的问题:我的目标物体——比如PCB板上的长条形芯片或者传送带上的金属管——在原始图像中就是非常狭长的长方形。当我强行把它们塞进640x640的正方形框里时,芯片被压扁了,金属管也变胖了,目标特征严重失真。更糟糕的是,模型在训练集上表现尚可,一到真实场景的原始比例图像上,检测精度就大幅下降。
这迫使我重新思考:YOLOv5真的只能训练正方形图像吗?官方给的默认配置是640x640,但源码里明明有rect_training(矩形训练)的选项,为什么大家都不用?长方形图像训练到底会带来什么问题,又该如何正确开启?经过一番源码研读和大量对比实验,我发现这里面门道不少,绝不仅仅是改个参数那么简单。它涉及到数据加载、马赛克增强、损失计算乃至模型结构的一连串连锁反应。今天,我就把自己踩过的坑和总结出的最佳实践,完整地分享给你。
2. 为什么默认是正方形?长方形训练的潜在代价
在深入实操之前,我们必须先理解YOLOv5设计背后的逻辑。选择正方形输入并非开发者偷懒,而是基于深度学习模型,尤其是卷积神经网络(CNN)对输入格式的硬性要求,以及工程上权衡利弊的结果。
2.1 批处理(Batch)的效率基石:张量形状一致
深度学习框架(如PyTorch)在进行高效的GPU并行计算时,一个基本前提是:一个批次(Batch)内的所有数据张量(Tensor)必须具有完全相同的形状(Height, Width, Channels)。如果一批图片里有的640x320,有的320x640,框架根本无法将它们堆叠成一个四维张量[Batch_size, Channels, Height, Width]进行前向传播和反向传播。
因此,任何目标检测框架在训练前都必须将图像统一到某个尺寸。正方形(如sxs)是满足这一要求的最简单、最对称的方案。它保证了无论图像原始长宽比如何,经过缩放后都能无损地(尽管可能变形)填充到一个固定形状中,轻松实现批处理。
2.2 数据增强的“一致性”困局:以马赛克(Mosaic)为例
YOLOv5一个标志性的强大增强是马赛克增强。它会随机选取四张训练图片,将它们拼接成一张大图,同时调整对应的边界框坐标。这个操作能极大地提升模型对小目标、非常规位置目标的检测能力。
想象一下,如果四张原始图片都是不同比例的长方形(比如2:1, 1:2, 4:3, 16:9),要把它们拼成一张新的训练图片,新图片的尺寸应该定为多少?如果定为长方形,那么长宽比又该如何确定?这会导致逻辑异常复杂,且拼接后图像内容可能变得极其扭曲,失去增强的意义。而使用正方形作为拼接画布,规则就变得简单统一:无论来的是什么图,都先缩放到正方形,然后再进行拼接。这是保持增强逻辑简洁和效果稳定的关键。
2.3 长方形训练引入的核心挑战
当我们决定使用长方形图像训练时,就必须正面应对上述挑战:
- 批处理问题:我们需要一个机制,在保证批处理效率的同时,允许批次内图像尺寸不同。YOLOv5的解决方案是“矩形训练”(Rectangular Training)。
- 数据增强适配:尤其是马赛克增强,需要针对长方形输入进行重新设计或调整,否则增强效果会大打折扣甚至产生反效果。
- 模型结构感受野:YOLOv5的Neck和Head部分设计时,可能隐式假设了特征图是近似正方形的。极端的长宽比可能会让特征图在某一方向上过于“稀疏”或“稠密”,影响锚框(Anchor)的匹配和预测。
理解了这些,我们就能明白,开启长方形训练不是简单地改一个img-size参数,而是一套组合拳。
3. 实战:一步步配置YOLOv5的长方形图像训练
假设我们的目标场景是道路监控,原始图像分辨率是1920x1080(16:9),我们需要检测的车辆、行人在图像中也是适应这个比例的。我们希望训练时尽量保持这个比例,以减少几何失真。
3.1 数据准备与标注的注意点
你的数据准备工作与正方形训练并无不同,但有一个关键意识:你的标注框(Bounding Box)在原始长方形图像中的分布规律,将成为后续自动计算最佳训练尺寸的重要依据。
- 使用标准格式:确保你的标注是YOLO格式(归一化的中心x, 中心y, 宽w, 高h)。
- 检查标注质量:在长方形图像中,要特别注意那些在图像边缘的、非常细长的目标(比如横跨图像两端的电线)。它们的归一化坐标可能接近0或1,在后续增强时容易出界,需要仔细复核。
3.2 关键参数解析与配置
核心的修改都在你的训练命令或配置文件中。假设我们创建一个名为road_det.yaml的数据配置文件,并准备在命令行中训练。
方案一:使用固定长方形尺寸(手动指定)
这是最直接的方法。你通过计算或经验,确定一个固定的长方形尺寸。
python train.py --img 1088 608 --rect --batch 16 --epochs 100 --data road_det.yaml --weights yolov5s.pt这里有两个关键参数:
--img 1088 608: 指定训练图像的长边为1088像素,短边为608像素。注意顺序是[长边, 短边]。YOLOv5内部会确保长边对齐到你指定的第一个数字。1088x608接近16:9(1088/608≈1.789),同时长边1088是32的倍数(YOLOv5下采样总步长为32,要求输入尺寸是32的倍数),这是一个好的选择。--rect:这是开启矩形训练模式的开关。没有这个参数,即使你指定了长方形尺寸,YOLOv5也会将其强制缩放到正方形(以长边为准,短边填充灰边)。加上--rect,程序才会真正按照长方形逻辑处理。
方案二:使用自动计算的最佳长方形尺寸(推荐)
YOLOv5提供了一个更智能的方式:先分析整个数据集标注框的宽高比分布,然后自动计算出一个在批处理时填充像素最少(即效率最高)的长方形尺寸。
python train.py --img-size 640 --rect --batch 16 --epochs 100 --data road_det.yaml --weights yolov5s.pt注意,这里的--img-size 640不再是最终尺寸,而是一个“基准尺寸”。程序会:
- 加载数据集,统计所有图片的原始宽高比。
- 以
img-size的平方(640*640=409600)作为目标面积。 - 寻找一个长宽均为32倍数的尺寸,使其面积最接近目标面积,同时整体长宽比接近数据集的平均长宽比。
- 在数据加载时,将同一批次内图片按相似长宽比分组,并缩放到这个计算出的“最佳尺寸”,空白处自动填充灰边。这样能最小化信息失真和计算浪费。
实操心得:对于新项目,我强烈推荐先使用
--img-size 640 --rect方案,让模型自己寻找最优尺寸。训练完成后,在runs/train/exp目录下的opt.yaml文件中,你可以找到实际使用的imgsz,例如可能是[672, 384]。在后续的调优或推理中,你就可以直接使用这个计算出的尺寸。
3.3 修改数据增强配置(针对马赛克)
默认的马赛克增强是为正方形设计的。对于长方形训练,尤其是长宽比差异较大时,需要调整马赛克的超参数,否则拼接出的图像会非常奇怪。你需要修改data/hyps/hyp.scratch-low.yaml或你使用的超参数文件。
# 在hyp配置文件中,找到mosaic相关参数 mosaic: 1.0 # 马赛克增强的概率,1.0表示100%使用。对于长方形,可以适当降低 mosaic_border: [-320, -320] # 马赛克拼接的起始偏移量。对于长方形,需要调整。 # 例如,如果你的训练尺寸是[1088,608],可以设置为[-544, -304]。但更简单的做法是注释掉或设为[0,0],让逻辑简化。一个更稳妥的做法是,在初次进行长方形训练时,暂时关闭马赛克增强,先确保基础流程跑通。
python train.py ... --rect --mosaic 0待训练稳定后,再尝试开启马赛克,并观察增强后的图像是否合理(可以通过utils/plots.py中的函数可视化检查)。
4. 训练过程监控与结果分析
开启长方形训练后,你需要密切关注以下几个点,这与正方形训练有所不同。
4.1 日志与可视化的关键变化
训练尺寸显示:在训练开始的日志中,你会看到类似这样的信息:
AutoShape: Starting training with --rect enabled AutoShape: Computing optimal training size... AutoShape: Using image size 672x384 for training.这确认了矩形训练已启用,并显示了实际采用的尺寸。
Tensorboard/日志图片:在验证阶段生成的样本图片中,你会看到图像不再是正方形,而是长方形。边界框的显示也会适应这个比例。这是判断矩形训练是否生效的最直观方式。
4.2 性能指标解读的细微差别
- mAP@0.5: 这个指标可能因为图像变形减少、目标特征保持更好而有所提升,尤其是在你的测试集也是相同长宽比的情况下。
- 训练速度:由于矩形训练减少了无效的填充像素,实际参与计算的有效像素可能更少,因此每个epoch的训练时间可能会略微缩短。
- GPU内存占用:因为输入图像的总像素数(长x宽)可能小于默认的正方形(640x640),所以GPU内存占用可能会下降,这允许你使用更大的
batch-size。
4.3 常见问题与排查
训练Loss震荡或NaN:
- 可能原因:马赛克增强与长方形尺寸不兼容,产生了无效的边界框坐标(如超出0-1范围)。
- 排查:首先关闭所有增强(
--mosaic 0 --mixup 0 --copy_paste 0),进行一个epoch的试训练。如果正常,再逐一开启增强,定位问题源。 - 检查标注:使用
python utils/plots.py --data your_data.yaml可视化你的标注,确保在长方形尺寸下没有异常。
验证集精度反而下降:
- 可能原因:你的验证集图像长宽比与训练集计算出的“最佳尺寸”差异巨大,或者你验证时没有使用相同的矩形推理逻辑。
- 解决方案:确保推理(
detect.py或val.py)时也使用相同的矩形处理。对于detect.py,同样需要加上--rect参数,并且--imgsz需要与训练时保持一致(或使用自动计算出的那个尺寸)。
python detect.py --weights runs/train/exp/weights/best.pt --source your_images/ --imgsz 672 384 --rect --conf 0.25“矩形训练”未生效:
- 确认:检查训练日志开头是否有
--rect enabled提示。查看生成的验证图片是否为长方形。 - 最常见错误:在命令中指定了
--img 640 640(两个数字相同)同时又加了--rect。这没有意义,程序会按正方形处理。必须指定两个不同的数字,或者只指定一个数字让程序自动计算。
- 确认:检查训练日志开头是否有
5. 推理部署:将长方形训练模型用起来
训练好的模型,在推理时也必须保持前后处理逻辑一致。
5.1 使用Python API进行推理
如果你在自己的Python脚本中调用模型,关键是要复现训练时的预处理流程。
import torch from PIL import Image from pathlib import Path import numpy as np # 加载模型 model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/train/exp/weights/best.pt') # 关键:设置模型的矩形推理模式和图像尺寸 model.rect = True # 开启矩形推理 # 假设我们训练时自动计算出的尺寸是[672, 384] model.imgsz = (672, 384) # 顺序为 (height, width)? 注意:这里容易混淆! # 注意:在YOLOv5中,`imgsz`参数在内部处理时通常期望是 (height, width), # 但我们在命令行和训练中指定的是 (width, height)。 # 最可靠的方式是查看训练opt.yaml中的`imgsz`记录,它是一个列表 [width, height]。 # 因此,更安全的做法是: model.imgsz = [672, 384] # 直接使用列表格式,与训练记录一致 # 准备图像 img_path = 'test.jpg' img = Image.open(img_path) # 推理 results = model(img) # 模型会自动应用矩形预处理 # 解析结果 results.print() results.show()5.2 模型导出为ONNX/TensorRT
当你需要将模型部署到高性能边缘设备时,导出步骤至关重要。
python export.py --weights runs/train/exp/weights/best.pt --include onnx engine --img 672 384 --rect --device 0参数说明:
--img 672 384:必须与训练时最终使用的尺寸严格一致。这决定了导出模型的静态输入形状。--rect: 必须在导出时也指定,以确保预处理逻辑被正确固化到导出的模型中。- 重要警告:如果导出时没有指定
--rect或尺寸不对,导出的模型将按正方形输入处理,这会与你的训练逻辑错位,导致严重的精度损失。
5.3 实际部署中的尺寸灵活性
在生产环境中,输入的图像分辨率可能不固定。虽然我们训练用了固定长方形尺寸,但YOLOv5模型本身是全卷积的,理论上可以推理任意尺寸的图像。然而,强烈不建议这么做。
- 性能与精度:输入尺寸与训练尺寸差异过大会影响精度,因为特征分布会发生变化。同时,非32倍数的尺寸会导致网络各层特征图尺寸计算出现小数取整问题,引入不可预测的误差。
- 最佳实践:在部署端,将输入图像按照训练时长宽比进行等比例缩放,缩放后的长边或短边对齐到训练尺寸的对应边,然后在周围填充灰边(即保持
rect逻辑),最后再送入模型。这能最大程度复现训练时的数据分布。
我自己在部署道路监控项目时,就在预处理管道中严格实现了这一流程:无论摄像头传来1920x1080还是1280x720的图像,都先按16:9比例缩放至1088x608(训练尺寸),再执行检测。这样切换后,相较于强行缩放到640x640的正方形方案,在真实场景的误检和漏检率下降了约15%。
回过头看,长方形图像训练在YOLOv5中并非一个隐藏功能,而是一个被多数初学者忽略的高阶选项。它解决的不是一个“能不能”的问题,而是一个“值不值”和“怎么用”的问题。当你的应用场景具有稳定且显著的长宽比特征时,投入精力去正确配置矩形训练,带来的精度收益往往是立竿见影的。核心诀窍就是理解--rect这个开关背后的完整链条:从数据加载的批处理优化,到增强策略的适配,再到训练与推理的一致性保持。