关于YOLO的损失函数,采用sum-squared error整合localization error(bboxes的坐标误差)和classification error,如果这两者的权值一致,会导致模型不稳定,训练发散。其中classification error包括两部分,一部分是没有包含object的box的confidence loss权值,另一部分则是有包含object的box的confidence loss权值。因此在损失函数计算的过程中,将提高localization error 的权值,降低没有包含object的box的confidence loss的权重。至于有包含object的box,它的confidence loss始终为1。
直接上图吧。
loss函数是分为三个部分的,即坐标预测,也就是我们上面所说的localization error,一部分是box的confidence预测,还有一部分是来自于类别的预测,后两部分就是classification error。
损失函数分为三个部分:
代表cell中含有真实物体的中心。 pr(object) = 1
损失函数分为三个部分:
def loss_layer(self,predicts,labels,scope='loss'):
''' predicts的shape是[batch,7*7*(20+5*2)]
labels的shape是[batch,7,7,(5+20)]
'''
with tf.variable_scope(scope):
#预测种类,boxes置信度,boxes坐标[x_center,y_center,w,h],坐标都除以image_size归一化,中心点坐标为偏移量,
#w,h归一化后又开方,目的是使变化更平缓
predict_classes=tf.reshape(predicts[:,:self.boundary1],
[self.batch_size,self.cell_size,self.cell_size,self.num_classes])
predict_scales=tf.reshape(predicts[:,self.boundary1:self.boundary2],
[self.batch_size,self.cell_size,self.cell_size,self.box_per_cell])
predict_boxes=tf.reshape(predicts[:,self.boundary2:],
[self.batch_size,self.cell_size,self.cell_size,self.box_per_cell,4])
#是否有目标的置信度
response=tf.reshape(labels[:,:,:,0],
[self.batch_size,self.cell_size,self.cell_size,1])
#boxes坐标处理变成[batch,7,7,2,4],两个box最终只选一个最高的,为了使预测更准确
boxes=tf.reshape(labels[:,:,:,1:5],
[self.batch_size,self.cell_size,self.cell_size,1,4])
boxes=tf.tile(boxes,[1,1,1,self.box_per_cell,1])/self.image_size
classes=labels[:,:,:,5:]
#offset形如[[[0,0],[1,1]...[6,6]],[[0,0]...[6,6]]...]与偏移量x相加
#offset转置形如[[0,0,[0,0]...],[[1,1],[1,1]...],[[6,6]...]]与偏移量y相加
#组成中心点坐标shpe[batch,7,7,2]是归一化后的值
offset=tf.constant(self.offset,dtype=tf.float32)
offset=tf.reshape(offset,[1,self.cell_size,self.cell_size,self.box_per_cell])
offset=tf.tile(offset,[self.batch_size,1,1,1])
predict_boxes_tran=tf.stack([(predict_boxes[:,:,:,:,0]+offset)/self.cell_size,
(predict_boxes[:,:,:,:,1]+tf.transpose(offset,(0,2,1,3)))/self.cell_size,
tf.square(predict_boxes[:,:,:,:,2]),
tf.square(predict_boxes[:,:,:,:,3])],axis=-1)
#iou的shape是[batch,7,7,2]
iou_predict_truth=self.cal_iou(predict_boxes_tran,boxes)
#两个预选框中iou最大的
object_mask=tf.reduce_max(iou_predict_truth,3,keep_dims=True)
#真实图中有预选框,并且值在两个预选框中最大的遮罩
object_mask=tf.cast((iou_predict_truth>=object_mask),tf.float32)*response
#无预选框遮罩
noobject_mask=tf.ones_like(object_mask,dtype=tf.float32)-object_mask
#真实boxes的偏移量
boxes_tran=tf.stack([boxes[:,:,:,:,0]*self.cell_size-offset,
boxes[:,:,:,:,1]*self.cell_size-tf.transpose(offset,(0,2,1,3)),
tf.sqrt(boxes[:,:,:,:,2]),
tf.sqrt(boxes[:,:,:,:,3])],axis=-1)
#=================================================================================================================================
#分类损失
class_delta=response*(predict_classes-classes)
class_loss=tf.reduce_mean(tf.reduce_sum(tf.square(class_delta),axis=[1,2,3]),name='clss_loss')*self.class_scale
#有目标损失(IOU)
object_delta=object_mask*(predict_scales-iou_predict_truth) #这里iou_predict_truth应该为1
object_loss=tf.reduce_mean(tf.reduce_sum(tf.square(object_delta),axis=[1,2,3]),name='object_loss')*self.object_scale
#无目标损失(IOU)
noobject_delta=noobject_mask*predict_scales #这里减0
noobject_loss=tf.reduce_mean(tf.reduce_sum(tf.square(noobject_delta),axis=[1,2,3]),name='noobject_loss')*self.no_object_scale
#选框损失(坐标)
coord_mask=tf.expand_dims(object_mask,4)
boxes_delta=coord_mask*(predict_boxes-boxes_tran)
coord_loss=tf.reduce_mean(tf.reduce_sum(tf.square(boxes_delta),axis=[1,2,3,4]),name='coord_loss')*self.coord_scale
tf.losses.add_loss(class_loss)
tf.losses.add_loss(object_loss)
tf.losses.add_loss(noobject_loss)
tf.losses.add_loss(coord_loss)
————————————————
YOLO V2:
YOLO V3:
YOLOv3不使用Softmax对每个框进行分类,而使用多个logistic分类器,因为Softmax不适用于多标签分类,用独立的多个logistic分类器准确率也不会下降。
分类损失采用binary cross-entropy loss.