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

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

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ù)測種類,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最終只選一個最高的,為了使預(yù)測更準確
? ? ? ? ? ? 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相加
? ? ? ? ? ? #組成中心點坐標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)
? ? ? ? ? ? #兩個預(yù)選框中iou最大的
? ? ? ? ? ? object_mask=tf.reduce_max(iou_predict_truth,3,keep_dims=True)
? ? ? ? ? ? #真實圖中有預(yù)選框,并且值在兩個預(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
? ? ? ? ? ? #真實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應(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
? ? ? ? ? ? #無目標損失(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.