代码地址
在17届省赛结束后,因为担心国赛场地光照影响较大,写了这个目标检测算法。但因为时间以及实力不足,算法仅有了个雏形,没能成功部署,非常遗憾。
今年寒假终于有时间将其完善,也算对自己的锻炼。正好在18届的比赛中有无边框图片,发现该算法在无边框定位上也有较好效果,所以将这个算法开源,希望能对大家有所帮助与启发。
因为能力有限,算法还有许多优化空间。这里仅是抛砖引玉,期待大家的完善。
在art上部署目标检测,最需要解决的问题是如何保证art那点可怜的算力能流畅运行目标检测模型。所以我们的重点是如何将模型简化。
本算法借鉴了SSD网络的一些思想,在经典的one-stage目标检测网络架构上进行了修改。
严格意义上来说,本算法不是目标检测网络,其仅完成了目标板定位的功能,并没有对目标板进行分类。也就是说,网络仅对背景与目标板两个类别进行分类。
这样做的原因如下:
所以,我们索性删掉进行分类的部分,专注于进行定位,让其起到与art的find_rect函数相同的作用。
为了使得模型更加轻量化,从以下方面简化网络。
首先给出两个前提:
我们可以根据以上前提,对经典的目标检测网络作出如下改变:
通过以上简化,我们的网络在量化后仅有38KB。经过朋友测试,在art连接电脑的情况下可以达到12帧,勉强可以满足定位的需求。
预测特征层只有一个:4x3
在4x3的先验格子中,不会出现两个目标的中心落在一个格子的情况
正样本:4x3格子中有目标的格子
负样本:4x3格子中无目标的格子
d x = c x − x 0 w d_x = \frac{c_x-x_0}{w} dx=wcx−x0
d y = c y − y 0 h d_y = \frac{c_y-y_0}{h} dy=hcy−y0
d x , d y 为目标中心相对于先验格子中心偏移量的归一化值。 c x , c y 为目标的中心坐标。 d_x,d_y为目标中心相对于先验格子中心偏移量的归一化值。c_x,c_y为目标的中心坐标。 dx,dy为目标中心相对于先验格子中心偏移量的归一化值。cx,cy为目标的中心坐标。
x 0 , y 0 为先验格子的中心坐标。 w , h 为先验格子的宽和高。 x_0,y_0为先验格子的中心坐标。w,h为先验格子的宽和高。 x0,y0为先验格子的中心坐标。w,h为先验格子的宽和高。
编码后的label长度为36,其中前24项为12个先验格子中的回归坐标偏移量,剩下的12项为12个格子中是否有目标的置信度。
相邻的两个格子中心的距离为32,一个格子的大小为40。也就是说,相邻两个格子会有相交的区域。
对于目标与先验格子的匹配,遵循以下两条原则:
第一原则保证了每个目标都能与先验格子进行匹配,第二原则增加了正样本数,且避免了边界效应。
注意:上述所有具体数值可以根据模型输入大小已经模型结构等因素进行调整,比如输入为(48,64,3)的模型只要将上述的参数全部除以2就行。
解码就是对模型输出做编码的逆运算,这样会得出一个坐标序列。然后对坐标做非极大值抑制。
将总体的目标损失函数定义为 定位损失(loc)和置信度损失(conf)的加权和:
L ( x , c , l , g ) = 1 N ( L c o n f ( x , c ) + α L l o c ( x , l , g ) ) \begin{equation} L(x,c,l,g) = \frac{1}{N}(L_{conf}(x,c)+\alpha L_{loc} (x,l,g)) \end{equation} L(x,c,l,g)=N1(Lconf(x,c)+αLloc(x,l,g))
其中 N 为真实值中有目标的格子数,如果 N = 0 ,则将损失设为 0 ; 其中N为真实值中有目标的格子数,如果N=0,则将损失设为0; 其中N为真实值中有目标的格子数,如果N=0,则将损失设为0;
而 α 参数用于调整置信度损失和定位损失之间的比例,默认 α = 1 。 而 α 参数用于调整置信度损失和定位损失之间的比例,默认 α=1。 而α参数用于调整置信度损失和定位损失之间的比例,默认α=1。
因为为sigmoid激活后的二分类任务,使用交叉熵损失函数
L c o n f ( x , c ) = − ∑ ( y l o g ( c i ^ ) + ( 1 − y ) l o g ( c i ^ ) ) \begin{equation} % L_{conf}(x,c) = -\sum_{i \in Pos}^N log(\hat{c}_{i}) - \sum_{i \in Neg}^M log(\hat{c}_{i}) L_{conf}(x,c) = -\sum (\ ylog(\hat{c_i}) +(1-y)log(\hat{c_i}) \ ) \end{equation} Lconf(x,c)=−∑( ylog(ci^)+(1−y)log(ci^) )
c i ^ = S i g m o i d ( c i ) \hat{c_i} = Sigmoid(c_i) ci^=Sigmoid(ci)
y = { 1 , 0 } , 当标签上有目标时为 1 ,无目标时为零。其实就是 B i n a r y C r o s s e n t r o p y 损失。 y=\left\{1,0\right\},当标签上有目标时为1,无目标时为零。其实就是Binary \ Crossentropy 损失。 y={1,0},当标签上有目标时为1,无目标时为零。其实就是Binary Crossentropy损失。
当且仅当预测与真实图片在某个格子内有目标时才进行计算(回归结果不在格子内也算,这就体现出Smooth L1 的价值了)。
偏差为与格子中心进行归一化后的偏差(除以格子的边长)。
使用Smooth L1 loss
生成的标签为目标中心相对于格子中心的偏差。
L l o c ( x , l , g ) = ∑ i ∈ P o s N ∑ m ∈ { c x , c y } x i s m o o t h L 1 ( l i m − g ^ i m ) \begin{equation} L_{loc}(x,l,g) = \sum_{i \in Pos }^N \sum_{m \in \left\{c_x,c_y\right\}} x_i smooth_{L1}(l_i^{m}- \hat{g}_i^{m}) \end{equation} Lloc(x,l,g)=i∈Pos∑Nm∈{cx,cy}∑xismoothL1(lim−g^im)
其中 l 为预测值的回归偏移量归一化值, g ^ 为真实值的回归偏移量归一化值。 其中l为预测值的回归偏移量归一化值,\hat{g}为真实值的回归偏移量归一化值。 其中l为预测值的回归偏移量归一化值,g^为真实值的回归偏移量归一化值。
x i = { 1 , 0 } ,当且仅当标签与预测都有目标时为 1 。 x_i=\left\{1,0\right\},当且仅当标签与预测都有目标时为1。 xi={1,0},当且仅当标签与预测都有目标时为1。
ssd中利用Hard negative mining方法得到1:3的正负样本比例。这里为了方便,直接利用数据生成器生产1:3正负样本比例的数据集,暂时不在损失函数部分实现Hard negative mining。
模型的部署不需要标签文件,但需要后处理函数。后处理包括解码以及非极大值抑制。因为现在手上没有art,所以这里暂时不提供脚本。可以参考utils.target_utils下的target_decoder类进行改写。