關(guān)于YOLO的損失函數(shù),采用sum-squared error整合localization error(bboxes的坐標(biāo)誤差)和classification error,如果這兩者的權(quán)值一致,會(huì)導(dǎo)致模型不穩(wěn)定,訓(xùn)練發(fā)散。其中classification error包括兩部分,一部分是沒有包含object的box的confidence loss權(quán)值,另一部分則是有包含object的box的confidence loss權(quán)值。因此在損失函數(shù)計(jì)算的過程中,將提高localization error 的權(quán)值,降低沒有包含object的box的confidence loss的權(quán)重。至于有包含object的box,它的confidence loss始終為1。
直接上圖吧。

loss函數(shù)是分為三個(gè)部分的,即坐標(biāo)預(yù)測(cè),也就是我們上面所說的localization error,一部分是box的confidence預(yù)測(cè),還有一部分是來自于類別的預(yù)測(cè),后兩部分就是classification error。
損失函數(shù)分為三個(gè)部分:
代表cell中含有真實(shí)物體的中心。 pr(object) = 1
損失函數(shù)分為三個(gè)部分:

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):
? ? ? ? ? ? #預(yù)測(cè)種類,boxes置信度,boxes坐標(biāo)[x_center,y_center,w,h],坐標(biāo)都除以image_size歸一化,中心點(diǎn)坐標(biāo)為偏移量,
? ? ? ? ? ? #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])
? ? ? ? ? ? #是否有目標(biāo)的置信度
? ? ? ? ? ? response=tf.reshape(labels[:,:,:,0],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self.batch_size,self.cell_size,self.cell_size,1])
? ? ? ? ? ? #boxes坐標(biāo)處理變成[batch,7,7,2,4],兩個(gè)box最終只選一個(gè)最高的,為了使預(yù)測(cè)更準(zhǔn)確
? ? ? ? ? ? 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轉(zhuǎn)置形如[[0,0,[0,0]...],[[1,1],[1,1]...],[[6,6]...]]與偏移量y相加
? ? ? ? ? ? #組成中心點(diǎn)坐標(biāo)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)
? ? ? ? ? ? #兩個(gè)預(yù)選框中iou最大的
? ? ? ? ? ? object_mask=tf.reduce_max(iou_predict_truth,3,keep_dims=True)
? ? ? ? ? ? #真實(shí)圖中有預(yù)選框,并且值在兩個(gè)預(yù)選框中最大的遮罩
? ? ? ? ? ? object_mask=tf.cast((iou_predict_truth>=object_mask),tf.float32)*response
? ? ? ? ? ? #無預(yù)選框遮罩
? ? ? ? ? ? noobject_mask=tf.ones_like(object_mask,dtype=tf.float32)-object_mask
? ? ? ? ? ? #真實(shí)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
? ? ? ? ? ? #有目標(biāo)損失(IOU)
? ? ? ? ? ? object_delta=object_mask*(predict_scales-iou_predict_truth)? #這里iou_predict_truth應(yīng)該為1
? ? ? ? ? ? object_loss=tf.reduce_mean(tf.reduce_sum(tf.square(object_delta),axis=[1,2,3]),name='object_loss')*self.object_scale
? ? ? ? ? ? #無目標(biāo)損失(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
? ? ? ? ? ? #選框損失(坐標(biāo))
? ? ? ? ? ? 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對(duì)每個(gè)框進(jìn)行分類,而使用多個(gè)logistic分類器,因?yàn)镾oftmax不適用于多標(biāo)簽分類,用獨(dú)立的多個(gè)logistic分類器準(zhǔn)確率也不會(huì)下降。
分類損失采用binary cross-entropy loss.