当前位置:   article > 正文

yolov8检测头

yolov8检测头

1.检测头原理检测

1.1检测头

在图中的Detect就是yolov8的检测头部分.我们可以发现有两个分支

第一个是

第二个是

分别通过2个3x3的卷积和一个1x1的卷积来提取信息,最后分别结算Bbox.loss和CLs.loss

对应代码部分是cv2和cv3

可以发现,3层卷积之后有一个for循环,来遍历所有的通道数(3通道),这也是大大加大计算量的原因

1.2检测头的计算量

yolov8中的检测头是yolov8中检测目标的关键,它几乎占了计算量的1/5

从图中可以看到检测头部分的时间为125.37ms约为564.40ms的1/5

因此我们想要减少模型的计算量就可以对yolov8的检测头进行改进

1.3文件中的head.py

首先我们需要查看yolov8中的ultralytics/nn/modules/head.py

  1. class Detect(nn.Module):
  2. """YOLOv8 Detect head for detection models."""
  3. dynamic = False # force grid reconstruction
  4. export = False # export mode
  5. shape = None
  6. anchors = torch.empty(0) # init
  7. strides = torch.empty(0) # init
  8. def __init__(self, nc=80, ch=()): # detection layer
  9. super().__init__()
  10. self.nc = nc # number of classes
  11. self.nl = len(ch) # number of detection layers
  12. self.reg_max = 16 # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x)
  13. self.no = nc + self.reg_max * 4 # number of outputs per anchor
  14. self.stride = torch.zeros(self.nl) # strides computed during build
  15. c2, c3 = max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], self.nc) # channels
  16. self.cv2 = nn.ModuleList(
  17. nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)
  18. self.cv3 = nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
  19. self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()
  20. def forward(self, x):
  21. """Concatenates and returns predicted bounding boxes and class probabilities."""
  22. shape = x[0].shape # BCHW
  23. for i in range(self.nl):
  24. x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
  25. if self.training:
  26. return x
  27. elif self.dynamic or self.shape != shape:
  28. self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
  29. self.shape = shape
  30. x_cat = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)
  31. if self.export and self.format in ('saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs'): # avoid TF FlexSplitV ops
  32. box = x_cat[:, :self.reg_max * 4]
  33. cls = x_cat[:, self.reg_max * 4:]
  34. else:
  35. box, cls = x_cat.split((self.reg_max * 4, self.nc), 1)
  36. dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
  37. y = torch.cat((dbox, cls.sigmoid()), 1)
  38. return y if self.export else (y, x)
  39. def bias_init(self):
  40. """Initialize Detect() biases, WARNING: requires stride availability."""
  41. m = self # self.model[-1] # Detect() module
  42. # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1
  43. # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency
  44. for a, b, s in zip(m.cv2, m.cv3, m.stride): # from
  45. a[-1].bias.data[:] = 1.0 # box
  46. b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (.01 objects, 80 classes, 640 img)

代码中的各个参数的含义为:

nc: 整数,表示图像分类问题中的类别数;
nl: 整数,表示检测模型中使用的检测层数;
reg_max: 整数,表示每个锚点输出的通道数;
no: 整数,表示每个锚点的输出数量,其中包括类别数和位置信息;
stride: 一个形状为(nl,)的张量,表示每个检测层的步长(stride);
cv2: 一个 nn.ModuleList 对象,包含多个卷积层,用于预测每个锚点的位置信息;
cv3: 一个 nn.ModuleList 对象,包含多个卷积层,用于预测每个锚点的类别信息;
dfl:  DFL(Distribution Focal Loss)


具体的检测流程可以查看,以下的连接(作者以后理解了更新)







yolov8的Detect层详解(输出维度改动)_yolov8中detect.py在哪-CSDN博客

2.检测头的更改

检测头的更改方案可以分为两种

一种是轻量化

轻量化,主要是更改卷积层来实现

举例,我们可以把两个检测头前面的两次卷积合在一起

一种是增加检测的精度

检测精度可以在检测头中增加注意力机制来实现

随着学习,更新
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/361399?site
推荐阅读
相关标签
  

闽ICP备14008679号