:yolov4yolov5)
一、YOLOv41.主干网络从v3的darknet53到CSPdarknet53v3层数深计算量大反向传播慢。主要改进点就是把特征分为两部分一部分卷积一部分直接连接最后在融合。2.激活函数leakrelu改进为mishmish更平滑更稳定3.颈部结构FPN上加了PANet。v3只有FPN从上往下传递特征有深到浅v4又PAN和PANet从上往下从下往上双向融合有利于小物体和密集物体的检测。4.加入SPP模块也就是空间金字塔池化层v3中没有这个结构v4在主干网络后加入SPP用四种不同尺度池化把局部特征全局特征一次性融合。5.损失函数GIoU → CIoU检测框的更加准确。考虑到了重叠面积中心点距离宽高比。损失改进过程1IOU损失本来是IOU损失但出现下面情况所以如何进一步对比这三种情况2GIOU损失但是如果我们的预选框在真实框内那么上面损失又无法正常起到作用3DIOU4CIOUV4也不需要考虑输入图片的大小甚至不需要是32的倍数加入金字塔池化层就能对图片进行缩放二、YOLOv5从 YOLOv3 之后YOLO 系列的整体检测框架并未发生根本性改变后续版本YOLOv4、v5、v6、v7、v8 等主要是在网络结构、特征融合方式、损失函数、训练策略等方面进行优化从而提升模型的检测精度与速度。在上一篇文章中我们已经对 YOLOv3 的基本使用方法进行了介绍而后续版本虽然在细节上有所改进但核心思想、训练流程与推理逻辑基本一致遇到的差异问题也可以借助大模型快速理解与解决。现在我们需要学习的就是如何获取框架github网站这个是一个巨大的开放性开源网站这里就以下载yolov5架构为例我们在网站上搜索github来到主页在红框搜索框中搜索yolo会发现又yolov5yolov7等这里我们要下载yolov5所以点进第一个不同版本的yolov5对一些库的版本要求不一样关于库的版本要求我们可以在这些文件中找到一个requirements.txt文件里面就是对当前版本库的要求当我们把文件下载下来之后可以直接运行requirements.txt文件输入pip install requirements.txt文件路径就能一步把这些第三方库下载下来。和v3差不多也有不同我们不需要修改classes会自己识别但依旧要模仿写coco文件模型训练过程中会产生新的东西runs文件夹使我们每一次运行保存下来的信息及时运行没有成功也会存下来如果运行成功并训练好了就只需要点开runs文件夹里面最后一个exp文件夹。里面会有weights文件夹点开一个是best.pt和last.pt就是我们训练过程中产生的最好模型和最后一个模型权重可以在detect.py运行的时候使用。同时还有result.png是我们训练过程中的数据曲线图。train.py只需要修改一下参数detect.py文件只需要传入两个参数source参数为0是打开摄像头进行检测或者写图片路径视频路径对视频和图片进行目标检测。使用的时候会遇到一些问题这里我会把我遇到问题的解决方法展示修改yolov5中的一些代码首先在utils文件夹打开utils.py文件ctrlf键搜索函数def build_targets把这个函数的代码注释改为下面这个def build_targets(p, targets, model): # Build targets for compute_loss(), input targets(image,class,x,y,w,h) # 1. 优先获取Detect层兼容多卡训练 det model.module.model[-1] if type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) \ else model.model[-1] # Detect() module na, nt det.na, targets.shape[0] # number of anchors, targets tcls, tbox, indices, anch [], [], [], [] # 2. 统一设备核心修复所有张量移到模型输出p的设备 device p[0].device targets targets.to(device) # 确保targets在模型设备上 gain torch.ones(6, devicedevice) # normalized to gridspace gain off torch.tensor([[1, 0], [0, 1], [-1, 0], [0, -1]], devicedevice).float() # overlap offsets at torch.arange(na, devicedevice).view(na, 1).repeat(1, nt) # anchor tensor指定设备 g 0.5 # offset style rect4 for i in range(det.nl): anchors det.anchors[i].to(device) # 锚框移到目标设备 gain[2:] torch.tensor(p[i].shape)[[3, 2, 3, 2]].to(device) # xyxy gain指定设备 # Match targets to anchors a, t, offsets [], targets * gain, 0 if nt: # 修复计算wh比例时确保张量设备一致 r t[None, :, 4:6] / anchors[:, None] # wh ratio # 修复model.hyp可能不存在先兼容如果hyp在det里改为det.hyp anchor_t model.hyp[anchor_t] if hasattr(model, hyp) else 4.0 # 默认阈值 j torch.max(r, 1. / r).max(2)[0] anchor_t # compare # 核心修复索引张量j移到目标设备避免跨设备索引 j j.to(device) # 修复at和t的设备统一避免之前的RuntimeError a at[j].to(device) t t.repeat(na, 1, 1)[j].to(device) # filter # overlaps gxy t[:, 2:4] # grid xy z torch.zeros_like(gxy, devicedevice) # 指定设备 if style rect2: j, k ((gxy % 1. g) (gxy 1.)).T # 修复索引张量j/k移到设备 j, k j.to(device), k.to(device) a torch.cat((a, a[j], a[k]), 0) t torch.cat((t, t[j], t[k]), 0) offsets torch.cat((z, z[j] off[0], z[k] off[1]), 0) * g elif style rect4: j, k ((gxy % 1. g) (gxy 1.)).T l, m ((gxy % 1. (1 - g)) (gxy (gain[[2, 3]] - 1.))).T # 修复索引张量j/k/l/m移到设备 j, k, l, m j.to(device), k.to(device), l.to(device), m.to(device) a torch.cat((a, a[j], a[k], a[l], a[m]), 0) t torch.cat((t, t[j], t[k], t[l], t[m]), 0) offsets torch.cat((z, z[j] off[0], z[k] off[1], z[l] off[2], z[m] off[3]), 0) * g # Define b, c t[:, :2].long().T # image, class gxy t[:, 2:4] # grid xy gwh t[:, 4:6] # grid wh gij (gxy - offsets).long() gi, gj gij.T # grid xy indices # 修复限制索引范围防止越界新增 gi torch.clamp(gi, 0, p[i].shape[3] - 1) gj torch.clamp(gj, 0, p[i].shape[2] - 1) # Append indices.append((b, a, gj, gi)) # image, anchor, grid indices tbox.append(torch.cat((gxy - gij, gwh), 1)) # box anch.append(anchors[a]) # anchors已移到设备 tcls.append(c) # class return tcls, tbox, indices, anch在找到def output_to_target函数全部注释改为下面这个def output_to_target(output, width, height): # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] targets [] # 先将output移到CPU避免CUDA张量转NumPy报错 output [o.detach().cpu() for o in output] for i, o in enumerate(output): for *box, conf, cls in o.numpy(): # 核心修复给1维box增加维度变为2维 (1,4)适配xyxy2xywh box np.array(box).reshape(1, 4) # 从(4,) → (1,4) box xyxy2xywh(box) # xyxy to xywh现在能正确处理 box box[0] # 还原为1维方便后续计算 (4,) # 归一化坐标 box[[0, 2]] / width # normalize x, w box[[1, 3]] / height # normalize y, h targets.append([i, cls, *box, conf]) # 最终转为NumPy数组 return np.array(targets)在以下文件中用ctrlf找到所有torch.load一般情况下都在后面加上红框内容一定不要漏掉在yolo.py文件里添加with语句不要忘记缩进utils.py和datasets.py文件中查找np.int把所有np.int改为int。当然可能还会有其他问题可以借助大模型解决。注意这里的github网站进入会有些问题这是因为github网站是境外网站需要加速器或者翻墙这个问题需要自行解决用户注册可以用qq邮箱注册如果一直注册不成功也是因为上面原因