参考源于产业实践的开源深度学习平台 飞桨PaddlePaddle 的《零基础实践深度学习》 的 《目标检测YOLOv3》
根据以上资料,简化和重新梳理 YOLOv3 模型设计的基本思想
相关源码参考上述《目标检测YOLOv3》 或者 YOLOv3-PaddlePaddle
目标检测通常使用 边界框(bounding box,bbox)来表示物体的位置
边界框是正好能包含物体的矩形框
图片坐标的原点在左上角,x轴向右为正方向,y轴向下为正方向
在检测任务中,训练数据集的标签里会给出目标物体真实边界框所对应的( x 1 x_1 x1, y 1 y_1 y1, x 2 x_2 x2, y 2 y_2 y2)
这样的边界框也被称为真实框(ground truth box)
在预测过程中,模型会对目标物体可能出现的位置进行预测
由模型预测出的边界框则称为预测框(prediction box),如上图所示
锚框与物体边界框不同,是由人们假想出来的一种框
先设定好锚框的大小和形状,再以图像上某一个点为中心画出矩形框
在下图中,以像素点[300, 500]为中心可以使用下面的程序生成3个框
如图中蓝色框所示,其中锚框A1跟人像区域非常接近
在目标检测任务中,通常会以某种规则在图片上 生成一系列锚框,将这些锚框当成可能的候选区域
模型对这些候选区域是否包含物体进行预测,如果包含目标物体,则还需要进一步预测出物体所属的类别
还有更为重要的一点是,由于锚框位置是固定的,它不大可能刚好跟物体边界框重合
所以需要在锚框的基础上进行微调以形成能准确描述物体位置的预测框,模型需要预测出微调的幅度
在训练过程中,模型通过学习不断的调整参数
最终能学会如何判别出锚框所代表的候选区域 是否包含物体
,如果包含物体的话,物体属于哪个类别
,以及物体边界框相对于锚框位置需要调整的幅度
如何衡量这三个锚框跟真实框之间的关系呢?
在检测任务中,使用交并比(Intersection of Union,IoU)作为衡量指标
这一概念来源于数学中的集合,用来描述两个集合A和B之间的关系
它等于两个集合的交集里面所包含的元素个数,除以它们的并集里面所包含的元素个数
具体计算公式: I o U = A ∪ B A ∩ B IoU= \frac{A∪B}{A∩B} IoU=A∩BA∪B
交集的宽度inter_w
为AB两个集合的右边的最小值减去左边的最大值: m a x max max( m i n min min( A x m a x A_{x_{max}} Axmax, B x m a x B_{x_{max}} Bxmax) - m a x max max( A x m i n A_{x_{min}} Axmin, B x m i n B_{x_{min}} Bxmin), 0)
交集的高度inter_h
为AB两个集合的下边的最小值减去上边的最大值: m a x max max( m i n min min( A y m a x A_{y_{max}} Aymax, B y m a x B_{y_{max}} Bymax) - m a x max max( A y m i n A_{y_{min}} Aymin, B y m i n B_{y_{min}} Bymin), 0)
A ∪ B A∪B A∪B = inter_w x inter_h
A ∩ B A∩B A∩B = 面积 S A S_A SA + 面积 S B S_B SB - A ∪ B A∪B A∪B
算法的实现具体可以参考代码和资料
为了直观的展示交并比的大小跟重合程度之间的关系
下图示意了不同交并比下两个框之间的相对位置关系,从 IoU = 0.95 到 IoU = 0
按一定规则在图片上产生一系列的候选区域
根据这些候选区域与真实框之间的位置关系对候选区域进行标注正负样本
跟真实框足够接近的那些候选区域会被标注为正样本,同时将真实框的位置作为正样本的位置目标
偏离真实框较大的那些候选区域则会被标注为负样本,负样本不需要预测位置或者类别
使用卷积神经网络提取图片特征 C
使用卷积神经网络 关联图片特征C 对应候选区域的位置和类别进行预测 ,形成 特征图P
将网络预测值和标签值进行比较,就可以建立起损失函数
将每个预测框就看成是一个样本,根据真实框相对它的位置和类别进行了标注而获得标签值
将原始图片划分成 m × n m×n m×n个区域,即 均分切块
如原始图片高度H=640, 宽度W=480,如果选择小块区域的尺寸为32×32
则m和n分别为: m = H / 32 = 20 , n = W / 32 = 15 m=H/32=20,n=W/32=15 m=H/32=20,n=W/32=15
将原始图像分成了20行15列小方块区域
这里为了跟程序中的编号对应,最上面的行号是第0行,最左边的列号是第0列
为了展示方便,左图中第十行第四列的小方块位置附近画出生成3个不同尺寸的锚框
右图每个区域附近都生成3个锚框
锚框的位置都是固定好的,不可能刚好跟物体边界框重合
需要在锚框的基础上进行位置的微调以生成预测框
预测框相对于锚框会有不同的 中心位置和 大小
通过该方式生成预测框的中心坐标: b x = c x + σ ( t x ) , b y = c y + σ ( t y ) b_x=c_x+σ(t_x),b_y=c_y+σ(t_y) bx=cx+σ(tx),by=cy+σ(ty)
符号 | 含义 |
---|---|
b x , b y b_x,b_y bx,by | 预测框的中心坐标 |
c x , c y c_x,c_y cx,cy | 小方块区域左上角的位置坐标 |
σ σ σ | Sigmoid函数 |
t x , t y t_x,t_y tx,ty | 预测框的中心坐标的微调系数 |
由于Sigmoid的函数值在0∼1之间: σ ( x ) = 1 1 + e x p ( − x ) σ(x)=\frac{1}{1+exp(−x)} σ(x)=1+exp(−x)1
因此由上面公式计算出来的预测框的中心点总是落在第十行第四列的小区域内部
锚框的大小是预先设定好的,在模型中可以当作是超参数
通过该方式生成预测框的大小: b w = p w e t w , b h = p h e t h b_w=p_we^{t_w},b_h=p_he^{t_h} bw=pwetw,bh=pheth
符号 | 含义 |
---|---|
b w , b h b_w,b_h bw,bh | 预测框的宽度、高度 |
p w , p h p_w,p_h pw,ph | 锚框尺寸 |
t w , t h t_w,t_h tw,th | 预测框的大小系数 |
如果 t x = t y = 0 , t h = t w = 0 t_x=t_y=0,t_h=t_w=0 tx=ty=0,th=tw=0,则预测框跟锚框重合
将标注的预测框坐标中的 b x , b y , b h , b w b_x,b_y,b_h,b_w bx,by,bh,bw设置为真实框的位置,即可求解出 t ∗ t^∗ t∗ 的数值作为目标值
如果 t t t 是网络预测的输出值,将 t ∗ t^∗ t∗ 作为目标值
以他们之间的差距作为损失函数,则可以建立起一个回归问题
每个区域可以产生3种不同形状的锚框,每个锚框都是一个可能的候选区域
K = m × n × 3 = 20 × 15 × 3 = 900 K=m×n×3=20×15×3=900 K=m×n×3=20×15×3=900个锚
对这些候选区域需要了解如下几件事情:
锚框是否包含物体,这可以看成是一个二分类问题,使用标签objectness
来表示
当锚框包含了物体时,objectness=1,表示锚框属于正类
当锚框不包含物体时,objectness=0,表示锚框属于负类
如果锚框包含了物体,那么它对应的预测框的中心位置和大小应该是多少
即上面计算式中的 t x , t y , t h , t w t_x,t_y,t_h,t_w tx,ty,th,tw应该是多少,使用location
标签
如果锚框包含了物体,那么具体类别是什么,这里使用变量label
来表示其所属类别的标签
对于每个锚框,模型需要预测输出 ( P o b j , t x , t y , t w , t h , P 1 , P 2 , . . . , P N ) (P_{obj},t_x,t_y,t_w,t_h,P_1,P_2,...,P_N) (Pobj,tx,ty,tw,th,P1,P2,...,PN)
其中 P o b j P_{obj} Pobj是锚框是否包含物体的概率, P 1 , P 2 , . . . , P N P_1,P_2,...,P_N P1,P2,...,PN则是锚框包含的物体属于每个类别的概率
YOLOv3算法设置了一个IoU阈值 iou_threshold
当预测框的objectness不为1,但是其与某个真实框的IoU大于iou_threshold
时,就将其objectness标签设置为 -1,不参与损失函数的计算
所有其他的预测框,其objectness标签均设置为0,表示负类
通过连续使用多层卷积和池化等操作,能得到语义含义更加丰富的特征图
在检测问题中,也使用卷积神经网络逐层提取图像特征
通过最终的 输出特征图 来表示 物体位置和类别等信息
在检测任务中,将图中C0后面的平均池化、全连接层和Softmax去掉,保留从输入到C0部分的网络结构,作为检测模型的基础网络结构,也称为骨干网络
YOLOv3模型会在骨干网络的基础上,再添加检测相关的网络模块
这里将上图中 特征 C0、C1、C2 所表示的输出数据取出
指定输入数据的形状是 [1,3,640,640] 的话
查看它们的形状分别是 C2 [1,256,80,80],C1 [1,512,40,40] 和 C0 [1,1024,20,20]
对于一个预测框,网络需要输出(5+N)个实数来表示它是否包含物体、位置和形状尺寸以及属于N个类别的概率
由于在每个小方块区域都生成了 k k k个预测框
则所有预测框一共需要网络输出的预测值数目是: [ k ( 5 + N ) ] × m × n ] [k(5+N)]×m×n] [k(5+N)]×m×n]
还有更重要的一点是网络输出必须要能区分出小方块区域的位置来
不能直接将特征图连接一个输出大小为 k ( 5 + N ) ] × m × n k(5+N)]×m×n k(5+N)]×m×n 的全连接层
需要的是 建立输出特征图与预测框之间的关联
现在观察特征,经过多次卷积核池化之后,其步幅 stride=32
640×480大小的输入图片变成了20×15的特征图
而小方块区域的数目正好是20×15
也就是说可以让 特征图上每个像素点分别跟原图上一个小方块区域对应
这也是为什么最开始将小方块区域的尺寸设置为32的原因
这样可以巧妙的将小方块区域跟特征图上的像素点对应起来,解决了空间位置的对应关系
骨干网络的输出 特征C,再对特征C进行多次卷积以得到跟预测框相关的 特征图P
实际中,这几个尺寸可以随着任务数据分布的不同而调整
只要保证特征图输出尺寸(控制卷积核和下采样)和输出层尺寸(控制小方块区域的大小)相同即可
是否包含目标物体的损失函数,通过pred_objectness
和label_objectness
计算
loss_obj = paddle.nn.fucntional.binary_cross_entropy_with_logits(pred_objectness, label_objectness)
二值交叉熵:
对m个样本的损失函数求和然后除以m:
物体位置的损失函数,通过pred_location
和label_location
计算
loss_location_x = paddle.nn.fucntional.binary_cross_entropy_with_logits(pred_location_x, label_location_x)
loss_location_y = paddle.nn.fucntional.binary_cross_entropy_with_logits(pred_location_y, label_location_y)
loss_location_w = paddle.abs(pred_location_w - label_location_w)
loss_location_h = paddle.abs(pred_location_h - label_location_h)
loss_location = loss_location_x + loss_location_y + loss_location_w + loss_location_h
物体类别的损失函数,通过pred_classification
和label_classification
计算
loss_obj = paddle.nn.fucntional.binary_cross_entropy_with_logits(pred_classification, label_classification)
目前计算损失函数是在特征图P0的基础上进行的,它的步幅stride=32
特征图的尺寸比较小,像素点数目比较少,每个像素点的感受野很大,具有非常丰富的高层级语义信息,可能比较容易检测到较大的目标
为了能够检测到尺寸较小的那些目标,需要在尺寸较大的特征图上面建立预测输出
如果在C2或者C1这种层级的特征图上直接产生预测输出
可能面临新的问题,它们没有经过充分的特征提取,像素点包含的语义信息不够丰富,有可能难以提取到有效的特征模式
在目标检测中,解决这一问题的方式是,将高层级的特征图尺寸放大之后跟低层级的特征图进行融合
得到的新特征图既能包含丰富的语义信息,又具有较多的像素点,能够描述更加精细的结构
在每个区域的中心位置产生3个锚框,在3个层级的特征图上产生锚框的大小分别为
P2 [(10×13),(16×30),(33×23)],P1 [(30×61),(62×45),(59× 119)],P0[(116 × 90), (156 × 198), (373 × 326]
越往后的特征图上用到的锚框尺寸也越大,能捕捉到大尺寸目标的信息
越往前的特征图上锚框尺寸越小,能捕捉到小尺寸目标的信息
输入图片经过特征提取得到三个层级的输出特征图P0(stride=32)、P1(stride=16)和P2(stride=8)
相应的分别使用不同大小的小方块区域去生成对应的锚框和预测框,并对这些锚框进行标注
将三个层级的特征图与对应锚框之间的标签关联起来,并建立损失函数,总的损失函数等于三个层级的损失函数相加
通过极小化损失函数,可以开启端到端的训练过程
预测过程可以分为两步:
计算结果会在每个小方块区域上生成多个预测框,而这些 预测框中很多都有较大的重合度
因此需要消除重叠较大的冗余检测框
基本思想是,如果有多个预测框都对应同一个物体,则只选出得分最高的那个预测框,剩下的预测框被丢弃掉
如果两个预测框的类别一样,而且位置重合度比较大,则可以认为是在预测同一个目标
选出某个类别得分最高的预测框,然后看其余预测框跟它的IoU大于阈值,就把这些预测框给丢弃掉
这里IoU的阈值是超参数,需要提前设置,YOLOv3模型里面设置的是0.5
即丢弃与得分最高的预测框IoU较高的预测框
谢谢