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