【论文理解】yolov3损失函数

看了很多关于yolov3的算法讲解,但是对于损失函数一直没怎么看懂,再看代码,发现完全不懂,所以决定再仔细看看yolov3的损失函数。 由于是自己总结加分析,可能存在错误,如果有错误,请告诉我~ 另外记录笔记只是为了自己学习,如果能帮助到别人很好,很开心~帮助不了,我也只是自己学习记录笔记,可以不看哦,请勿吐嘈谢谢感谢,因为不想打击 积极性啊哈~

先回顾下YOLOv1的损失函数: L o s s = λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( x i j − x ^ i j ) 2 + ( y i j − y ^ i j ) 2 ] + λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( w i j − w ^ i j ) 2 + ( h i j − h ^ i j ) 2 ] + ∑ i = 0 S 2 ∑ j = 0 B I i j o b j ( C i j − C ^ i j ) 2 + λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B I i j n o o b j ( C i j − C ^ i j ) 2 + ∑ i = 0 S 2 I i j o b j ∑ c ∈ c l a s s e s ( P i j ( c ) − P ^ i j ( c ) ) 2 Loss=lambda_{coord} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [(x_i^j-hat x_i^j)^2+ (y_i^j-hat y_i^j)^2 ] }+ \ lambda_{coord} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [ ( sqrt { w_i^j}-sqrt{hat w_i^j} )^2+ (sqrt { h_i^j}-sqrt{hat h_i^j})^2 ] }+ \ sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} (C_i^j -hat C_i^j)^2 } +\ lambda_{noobj} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{noobj} (C_i^j -hat C_i^j)^2 } +\sum_{i=0}^{S^2} { I_{ij}^{obj} } sum_{c in {classes}} (P_i^j(c) - hat P_i^j(c))^2 Loss=λcoordi=0∑S2j=0∑BIijobj[(xij−x^ij)2+(yij−y^ij)2]+λcoordi=0∑S2j=0∑BIijobj[(wij −w^ij )2+(hij −h^ij )2]+i=0∑S2j=0∑BIijobj(Cij−C^ij)2+λnoobji=0∑S2j=0∑BIijnoobj(Cij−C^ij)2+i=0∑S2Iijobjc∈classes∑(Pij(c)−P^ij(c))2

YOLOv3的损失函数: 是在yolov2基础上改动的,最大的变动是分类损失换成了二分交叉熵,这是由于yolov3中剔除了softmax改用logistic。

交叉熵

    刻画了两个概率分布之间的距离,也就是说,交叉熵值越小,两个概率分布越接近 通过 p 来表示 q 的交叉熵: H ( p , q ) = − Σ p ( x i ) l o g q ( x i ) H(p, q) = -Sigma p(x_i)logq(x_i) H(p,q)=−Σp(xi)logq(xi)p 为正确答案的分布,q 为预测的分布,这个log是以e为底的 代码示例
p = tf.constant([1.0, 0.0, 0.0])
q = tf.constant([0.88, 0.12, 0.0])
# tf.clip_by_value 函数的作用是:将元素数值限制在指定的范围内,防止一些错误运算
# 具体是:q 中的元素小于 1e-10 则用 1e-10 代替,大于 1.0 则用 1.0 代替
cross_entropy = -p * tf.log(tf.clip_by_value(q, 1e-10, 1.0))    # 逐元素相乘
sess.run(cross_entropy)
>>> array([ 0.12783338,  0.        ,  0.        ], dtype=float32)

所以yolov3中损失函数为: L o s s = λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( x i − x ^ i j ) 2 + ( y i − y ^ i j ) 2 ] + λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( w i j − w ^ i j ) 2 + ( h i j − h ^ i j ) 2 ] − ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ C ^ i j log ⁡ ( C i j ) + ( 1 − C ^ i j ) log ⁡ ( 1 − C i j ) ] − λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B I i j n o o b j [ C ^ i j log ⁡ ( C i j ) + ( 1 − C ^ i j ) log ⁡ ( 1 − C i j ) ] − ∑ i = 0 S 2 I i j o b j ∑ c ∈ c l a s s e s ( [ P ^ i j log ⁡ ( P i j ) + ( 1 − P ^ i j ) log ⁡ ( 1 − P i j ) ] Loss=lambda_{coord} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [(x_i-hat x_i^j)^2+ (y_i-hat y_i^j)^2 ] }+ \ lambda_{coord} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [ ( sqrt { w_i^j}-sqrt{hat w_i^j} )^2+ (sqrt { h_i^j}-sqrt{hat h_i^j})^2 ] }- \ sum_{i=0}^{S^2} sum_{j=0}^B { I_{ij}^{obj} [ hat C_i^{j} log (C_i^{j}) + (1- hat C_i^{j}) log(1-C_i^{j}) ]} -\ lambda_{noobj} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{noobj} [ hat C_i^{j} log (C_i^{j}) + (1- hat C_i^{j}) log(1-C_i^{j}) ] } -\sum_{i=0}^{S^2} { I_{ij}^{obj} } sum_{c in {classes}} ([ hat P_i^{j} log (P_i^{j}) + (1- hat P_i^{j}) log(1-P_i^{j}) ] Loss=λcoordi=0∑S2j=0∑BIijobj[(xi−x^ij)2+(yi−y^ij)2]+λcoordi=0∑S2j=0∑BIijobj[(wij −w^ij )2+(hij −h^ij )2]−i=0∑S2j=0∑BIijobj[C^ijlog(Cij)+(1−C^ij)log(1−Cij)]−λnoobji=0∑S2j=0∑BIijnoobj[C^ijlog(Cij)+(1−C^ij)log(1−Cij)]−i=0∑S2Iijobjc∈classes∑([P^ijlog(Pij)+(1−P^ij)log(1−Pij)]

网格一共是 S ∗ S S*S S∗S个,每个网格产生 B B B个候选框anchor box,每个候选框会经过网络最终得到相应的bounding box。最终会得到 S ∗ S ∗ B S*S*B S∗S∗B个bounding box,那么哪些bounding box会用来计算误差更新权重?又是如何计算误差?需要仔细了解公式。
    参数 I i j o b j I_{ij}^{obj} Iijobj I i j o b j I_{ij}^{obj} Iijobj表示:第 i i i个网格的第 j j j个anchor box是否负责这个object, 如果负责那么 I i j o b j = 1 I_{ij}^{obj}=1 Iijobj=1,否则为0。 那么什么叫做负责呢? 那第 i i i个网格的 B B B个anchor box中与该对象的ground truth box的IOU在所有的anchor box(与一个grid cell中所有bounding box对应,COCO数据集中是9个)与ground truth box的IOU中最大,那它就负责预测这个对象,因为这个形状、尺寸最符合当前这个对象,此时 I i j o b j = 1 I_{ij}^{obj}=1 Iijobj=1。 I i j n o o b j I_{ij}^{noobj} Iijnoobj表示 i i i个网格的第 j j j个anchor box不负责该目标。 论文中是这么规定正负样本的,但是我看代码是,只要目标所在网格产生的9个anchor中和目标的真实框的iou大于阈值的就为正样本,如果都小于阈值,那么和目标iou最大的为正样本。 参数置信度 C ^ i j hat C_{i}^{j} C^ij 训练中, C ^ i j hat C_{i}^{j} C^ij表示真实值, C ^ i j hat C_{i}^{j} C^ij的取值是由grid cell的bounding box有没有负责预测某个对象决定的。如果负责,那么 C ^ i j = 1 hat C_{i}^{j}=1 C^ij=1,否则, C ^ i j = 0 hat C_{i}^{j}=0 C^ij=0。 下面我们来说明如何确定某个grid cell的bounding box是否负责预测该grid cell中的对象:前面在说明anchor box的时候提到每个bounding box负责预测的形状是依据与其对应的anchor box相关的,那这个anchor box与该对象的ground truth box的IOU在所有的anchor box(与一个grid cell中所有bounding box对应,COCO数据集中是9个)与ground truth box的IOU中最大,那它就负责预测这个对象,因为这个形状、尺寸最符合当前这个对象,这时 C ^ i j = 1 hat C_{i}^{j}=1 C^ij=1,其他情况下 C ^ i j = 0 hat C_{i}^{j}=0 C^ij=0。注意,你没有看错,就是所有anchor box与某个ground truth box的IOU最大的那个anchor box对应的bounding box负责预测该对象,与该bounding box预测的box没有关系。

一项一项分析损失函数:

    中心坐标误差 ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( x i j − x ^ i j ) 2 + ( y i j − y ^ i j ) 2 ] sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [(x_i^j-hat x_i^j)^2+ (y_i^j-hat y_i^j)^2 ] } i=0∑S2j=0∑BIijobj[(xij−x^ij)2+(yij−y^ij)2]首先,通过我们可以知道,实际上,网络输出的应当是 t x t_x tx和 t y t_y ty,然后通过 σ ( t x ) sigma(t_x) σ(tx)和 σ ( t y ) sigma(t_y) σ(ty),再乘以步长,就映射到了 416 ∗ 416 416*416 416∗416大小的图上的目标了,所以在计算误差的时候,其实也是用的这一项 σ ( t x ) ∗ s t r i d e sigma(t_x)*stride σ(tx)∗stride和 σ ( t y ) ∗ s t r i d e sigma(t_y)*stride σ(ty)∗stride和真实目标经过resize到 416 ∗ 416 416*416 416∗416上的目标的大小,去计算误差。 整个这一项表示的是:当第 i i i个网格的第 j j j个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box就应该去和真实目标的box去比较,计算得到中心坐标误差。 宽高坐标误差: ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ ( w i j − w ^ i j ) 2 + ( h i j − h ^ i j ) 2 ] sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{obj} [ ( sqrt { w_i^j}-sqrt{hat w_i^j} )^2+ (sqrt { h_i^j}-sqrt{hat h_i^j})^2 ] } i=0∑S2j=0∑BIijobj[(wij −w^ij )2+(hij −h^ij )2]首先,通过我们可以知道,实际上,网络输出的应当是 ( t w ) (t_w) (tw)和 ( t h ) (t_h) (th),所以在计算误差的时候,其实也是用的这一项 ( t w ) ∗ s t r i d e (t_w)*stride (tw)∗stride和 ( t h ) ∗ s t r i d e (t_h)*stride (th)∗stride和真实目标经过resize之后的值,去计算误差的。所以可以认为公式里的 w i w_i wi就是 ( t w ) ∗ s t r i d e (t_w)*stride (tw)∗stride等等。 整个这一项表示的是:当第 i i i个网格的第 j j j个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box就应该去和真实目标的box去比较,计算得到宽高的误差。 置信度误差 − ∑ i = 0 S 2 ∑ j = 0 B I i j o b j [ C ^ i j log ⁡ ( C i j ) + ( 1 − C ^ i j ) log ⁡ ( 1 − C i j ) ] − λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B I i j n o o b j [ C ^ i j log ⁡ ( C i j ) + ( 1 − C ^ i j ) log ⁡ ( 1 − C i j ) ] - sum_{i=0}^{S^2} sum_{j=0}^B { I_{ij}^{obj} [ hat C_i^{j} log (C_i^{j}) + (1- hat C_i^{j}) log(1-C_i^{j}) ]} \ -lambda_{noobj} sum_{i=0}^{S^2} sum_{j=0}^B {I_{ij}^{noobj} [ hat C_i^{j} log (C_i^{j}) + (1- hat C_i^{j}) log(1-C_i^{j}) ] } −i=0∑S2j=0∑BIijobj[C^ijlog(Cij)+(1−C^ij)log(1−Cij)]−λnoobji=0∑S2j=0∑BIijnoobj[C^ijlog(Cij)+(1−C^ij)log(1−Cij)]首先需要知道,置信度误差使用交叉熵来表示。另外需要清楚不管anchor box是否负责某个目标,都会计算置信度误差。因为置信度表示:框出的box内确实有物体的自信程度和框出的box将整个物体的所有特征都包括进来的自信程度。具体可以参考。 损失函数分为两部分:有物体,没有物体,其中没有物体损失部分还增加了权重系数。添加权重系数的原因是,对于一幅图像,一般而言大部分内容是不包含待检测物体的,这样会导致没有物体的计算部分贡献会大于有物体的计算部分,这会导致网络倾向于预测单元格不含有物体。因此,我们要减少没有物体计算部分的贡献权重,比如取值为:0.5。
下面我们来说明如何确定某个grid cell的bounding box是否负责预测该grid cell中的对象:前面在说明anchor box的时候提到每个bounding box负责预测的形状是依据与其对应的anchor box(bounding box prior)相关的,那这个anchor box与该对象的ground truth box的IOU在所有的anchor box(与一个grid cell中所有bounding box对应,COCO数据集中是9个)与ground truth box的IOU中最大,那它就负责预测这个对象.
    第一项是:存在对象的bounding box的置信度误差。带有 I i j o b j I_{ij}^{obj} Iijobj意味着只有"负责"(IOU比较大)预测的那个bounding box的置信度才会计入误差。
另外,这里有个例外,当某个bounding box不负责对应grid cell中ground truth box的预测,但是又与该ground truth box的IOU大于设定的阈值时(论文中是0.5,darknet中针对COCO数据集使用的是0.7),忽略该bounding box所有输出的对loss的误差贡献,包括置信度误差。其他情况(负责某个对象即IOU最大的,不负责对象即IOU不是最大,而且IOU<0.5)要计算置信度误差。
    第二项是:不存在对象的bounding box的置信度误差。因为不存在对象的bounding box应该老老实实的说"我这里没有对象",也就是输出尽量低的置信度。如果它不恰当的输出较高的置信度,会与真正"负责"该对象预测的那个bounding box产生混淆。其实就像对象分类一样,正确的对象概率最好是1,所有其它对象的概率最好是0。 分类误差 − ∑ i = 0 S 2 I i j o b j ∑ c ∈ c l a s s e s ( [ P ^ i j log ⁡ ( P i j ) + ( 1 − P ^ i j ) log ⁡ ( 1 − P i j ) ] - sum_{i=0}^{S^2} { I_{ij}^{obj} } sum_{c in {classes}} ([ hat P_i^{j} log (P_i^{j}) + (1- hat P_i^{j}) log(1-P_i^{j}) ] −i=0∑S2Iijobjc∈classes∑([P^ijlog(Pij)+(1−P^ij)log(1−Pij)]首先需要知道分类误差也是选择了交叉熵作为损失函数。当第 i i i个网格的第 j j j个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box才会去计算分类损失函数。
训练的时候,我们是知道某一图片中目标的真实框的 x , y , w , h x,y,w,h x,y,w,h,以及置信度confidence(1或0)和分类概率 P ( i ) P(i) P(i)([1,0,0,0,0…]、[0,1,0,0,0…])。 当第 i i i个网格的第 j j j个anchor box负责某一真实目标时,我们需要对这个anchor box产生的bounding box进行 求中心坐标误差,求宽高误差,求置信度误差,求分类误差。(因为这个anchor box负责了某一个目标,那么这个anchor box产生的bounding box自然很重要,计算所有的损失函数,用来更新权重) 其他的不对真实目标负责的anchor box所产生的bounding box,只需要求一个置信度误差就可以了。 (因为这个anchor box不负责目标,那么这个anchor box产生的bounding box的坐标,宽高,分类都不重要,也就不需要计算坐标,宽高,分类的损失函数,但是置信度仍然重要,因为置信度还可以表示这个anchor box产生的bounding box中并不包含对象,所以仍然需要计算置信度损失函数的。)

参考:

经验分享 程序员 微信小程序 职场和发展