什么是YOLO算法?

YOLO(You Only Look Once)是一种实时物体检测算法。

它的主要特点是:
将图像分割成SxS个网格,每个网格预测B个边界框及其置信度。
每个网格同时预测C个类别的概率。
边界框包含中心坐标(x,y)、宽度(w)和高度(h)。
最后通过非极大抑制过滤边界框,输出检测结果。

YOLO v1使用GoogLeNet作为backbone,在fc7层后有两个输出,一个是边界框预测,一个是类别预测。
YOLO v2使用Darknet-19作为backbone,并增加了直通链接和更多的下采样,增加了预测的解空间。
YOLO v3在v2的基础上,使用更深的Darknet-53作为backbone,增加了FPN以提取不同尺度的特征,并通过维度聚合预测不同尺度的目标。

YOLO v1的关键代码如下:

python
import torch
import torch.nn as nn
class YOLOLayer(nn.Module):
    def __init__(self, anchor_mask, anchors, num_classes):
        super(YOLOLayer, self).__init__()
        self.anchor_mask = anchor_mask
        self.num_anchors = len(anchor_mask[0])  # 一个网格有多少个锚框
        self.num_classes = num_classes
        self.anchors = torch.tensor(anchors)
        self.grid_size = 13 # 输入图像分割成13x13的网格
    def forward(self, p, g):
        # p的维度 [bs, 255, 13, 13]
        # g的维度 [bs, 3, 13, 13]  代表网格左上角的xy坐标及网格宽度 
        # 获得锚框的宽高
        anchor_w = self.anchors[:, 0].contiguous().view(1, self.num_anchors, 1)
        anchor_h = self.anchors[:, 1].contiguous().view(1, self.num_anchors, 1)
        pred_boxes = torch.FloatTensor(p.size(0), self.num_anchors, 4) # 预测的boxes
        x = torch.sigmoid(p[..., 0])  # 物体置信度
        y = torch.sigmoid(p[..., 1])  # 框的置信度
        w = p[..., 2]  # 框的宽度
        h = p[..., 3]  # 框的高度
        # 计算每个网格左上角的xy坐标
        grid_x = torch.linspace(0, self.grid_size - 1, self.grid_size).repeat(self.grid_size, 1).repeat(
            int(p.size(0) * self.num_anchors / self.grid_size / self.grid_size), 1, 1).view(x.size()).type_as(x)
        grid_y = torch.linspace(0, self.grid_size - 1, self.grid_size).repeat(self.grid_size, 1).t().repeat(
            int(p.size(0) * self.num_anchors / self.grid_size / self.grid_size), 1, 1).view(y.size()).type_as(y)
        # 计算预测框的中心点及宽高
        pred_boxes[..., 0] = x + grid_x  # 预测框的中心x
        pred_boxes[..., 1] = y + grid_y  # 预测框的中心y
        pred_boxes[..., 2] = torch.exp(w) * anchor_w  # 预测框的宽度
        pred_boxes[..., 3] = torch.exp(h) * anchor_h  # 预测框的高度 
        # 用于训练时计算loss
        self.pred_boxes = pred_boxes
        self.conf_scores = torch.cat((x, y), -1) # 物体置信度,框置信度
        # 预测框
        pred_boxes = torch.cat((self.xy_transform(pred_boxes[..., 0:2], g[..., 0:2]),
                                torch.exp(pred_boxes[..., 2:]) * torch.cat((anchor