学习来源于博客https://blog.paperspace.com/how-to-implement-a-yolo-object-detector-in-pytorch/
YOLO只使用了卷积层,使其成为一个全卷积网络(FCN)。它有75个卷积层,有跳跃连接和上采样层没有使用池的形式,
使用一个带有stride=2的卷积层对特征图进行降采样。这有助于防止通常归因于池的低级功能的丢失。
作为一个FCN, YOLO对输入图像的大小是不变的。然而,在实践中,我们可能希望保持恒定的输入大小
该网络通过一个称为网络步长的因素对图像进行下采样。例如,如果网络的步长为32,那么大小为416 x 416的输入图像将产生大小为13 x 13的输出。
通常,(就像所有对象检测器的情况一样)卷积层学习到的特征被传递到一个分类器/回归器上,由分类器/回归器进行检测预测(包围盒的坐标、类标签)。等等)。
特征图的深度为(B x (5 + C))
B表示每个单元格可以预测的边界框数。每一个边界框都可以专门检测某一类对象。每个边界框都有5 +C属性,用于描述每个边界框的中心坐标、大小、对象得分和C类的置信度。YOLO v3预测每个单元格有3个包围框。
如果中心的预测是(0.4,0.7),那么这意味着中心位于(6.4,6.7)在13 x 13 feature map上。(因为红色细胞的左上坐标是(6,6))。
预测bw和bh,是由图像的高度和宽度归一化的。如果包含狗的盒子的预测bx和by为(0.3,0.8),那么13 x 13特征图上的实际宽度和高度为(13 x 0.3, 13 x 0.8)。
object score
object score表示一个对象被包含在一个边界框中的概率。
class confidences
class confidences表示被检测对象属于某个特定类(狗、猫、香蕉、汽车等)的概率。
YOLO v3在3个不同的尺度上进行预测。检测层用于对三种不同尺寸的特征图进行检测,步长分别为32、16、8步。这意味着,在输入416 x 416的情况下,我们在13 x 13、26 x 26和52 x 52的scale进行探测。
该网络将输入图像向下采样,一直到第一个检测层,其中使用stride 32的层特征图进行检测。此外,将层向上采样2倍,并将具有相同大小的前一层的特征映射连接起来。另一个检测现在是stride为16的层。重复相同的上采样过程,最后在stride 8层进行检测。
在每个尺度上,每个单元格预测3个使用3个锚点的边界框,使得使用9个锚点的总数。(不同尺度的锚不同)
输出处理
对于大小为416 x 416的图像,YOLO预测((52 x 52) + (26 x 26) + 13 x 13)) x 3 = 10647个边界框。
然而,在我们的图像中,只有一只狗。我们如何把10647的边界框减少到1个?
Thresholding by Object Confidence
首先,我们根据box的object confidence对它们进行筛选。通常,object confidence低于阈值的框将被忽略。
Non-maximum Suppression
将所有框的得分排序,选中最高分及其对应的框:
遍历其余的框,如果和当前最高分框的重叠面积(IOU)大于一定阈值,我们就将框删除。
从未处理的框中继续选一个得分最高的,重复上述过程。
parse_cfg 读取配置文件信息
create_modules 创建相应的块
Darket 定义网络,实现forward方法
YOLO(DetectionLayer)层,对三个特征图进行检测
predict_transform 在forward中使用到这个函数。
# 经过predict_transform函数之后输出的是相较于cfg中的input_size
# (batch_size, grid*grid*3, 5+num_classes)
write_result返回(D*8)的tensor,D是真实检测到的物体,8分别代表图片的索引,4个角点坐标,objectness score, the score of class with maximum confidence, and the index of that class.
pred_image在这个函数里面用到了letterbox_image函数,这个函数的作用是将待检测图片的大小转化为网络需要的大小,即(416*416),
接着将Opencv读取的numpy转化为pytorch输入格式
yolov3检测算法主要流程:
Darket中的构造方法中用到了
parse_cfg,读取配置文件。
create_modules创建相应的块,注意配置文件中的YOLO层,对应的是DetectionLayer,该层的作用是对三个特征图进行检测,输出我们所需要的结果。
在Darket中实现forward方法,对每个modules进行相应的操作,如卷积,上采样,shotcoming,检测等等。通过使用predict_transform将检测的结果进行变化,变为(batch_size, grid*grid*3, 5+num_classes)的格式,5代表每个边界框的中心坐标、大小、对象得分,
再将每个特征图的检测结果cat连接起来。第三个特征图检测连接完成之后,detections的shape为(batch_size, 10647, 5 + num_classses)
10647 = ((52 x 52) + (26 x 26) + 13 x 13)) x 3,三个特征图,每个点预测三个边框。
detections也是Darket网络中forward函数返回的结果。
第三部分为detect.py函数,用来检测图片的。
将需要检测的图片,先经过pred_image函数,将待检测图片的大小转化为网络需要的大小,即(416*416),同时将Opencv读取的numpy转化为pytorch输入格式。使用网络前向传播之后,得到的detections,经过write_result函数之后,得到(D*8)的tensor,D是真实检测到的物体,8分别代表图片的索引,4个角点坐标,objectness score, the score of class with maximum confidence, and the index of that class.再将检测到的角点的尺寸转化成相对于原始图片大小。最后用了一个write函数,在原始图片上画出bounding box