YOLO V1損失函數理解:
(結構圖)
首先是理論部分,YOLO網絡的實現這里就不贅述,這里主要解析YOLO損失函數這一部分。
損失函數分為三個部分:
代表cell中含有真實物體的中心。 pr(object) = 1
① 坐標誤差
為什么寬和高要帶根號???
對不同大小的bbox預測中,相比於大bbox預測偏一點,小box預測偏一點更不能忍受。作者用了一個比較取巧的辦法,就是將box的width和height取平方根代替原本的height和width
(主要為了平衡小目標檢測預測的偏移)
② IOU誤差(很多人不知道代表什么)
其實這里的分別表示 1 和 0
=
③ 分類誤差
這個很容易理解(激活函數的輸出)。
下面給出TensorFlow的Loss代碼:
1 def loss_layer(self,predicts,labels,scope='loss'): 2 ''' predicts的shape是[batch,7*7*(20+5*2)] 3 labels的shape是[batch,7,7,(5+20)] 4 ''' 5 with tf.variable_scope(scope): 6 #預測種類,boxes置信度,boxes坐標[x_center,y_center,w,h],坐標都除以image_size歸一化,中心點坐標為偏移量, 7 #w,h歸一化后又開方,目的是使變化更平緩 8 predict_classes=tf.reshape(predicts[:,:self.boundary1], 9 [self.batch_size,self.cell_size,self.cell_size,self.num_classes]) 10 predict_scales=tf.reshape(predicts[:,self.boundary1:self.boundary2], 11 [self.batch_size,self.cell_size,self.cell_size,self.box_per_cell]) 12 predict_boxes=tf.reshape(predicts[:,self.boundary2:], 13 [self.batch_size,self.cell_size,self.cell_size,self.box_per_cell,4]) 14 #是否有目標的置信度 15 response=tf.reshape(labels[:,:,:,0], 16 [self.batch_size,self.cell_size,self.cell_size,1]) 17 #boxes坐標處理變成[batch,7,7,2,4],兩個box最終只選一個最高的,為了使預測更准確 18 boxes=tf.reshape(labels[:,:,:,1:5], 19 [self.batch_size,self.cell_size,self.cell_size,1,4]) 20 boxes=tf.tile(boxes,[1,1,1,self.box_per_cell,1])/self.image_size 21 classes=labels[:,:,:,5:] 22 #offset形如[[[0,0],[1,1]...[6,6]],[[0,0]...[6,6]]...]與偏移量x相加 23 #offset轉置形如[[0,0,[0,0]...],[[1,1],[1,1]...],[[6,6]...]]與偏移量y相加 24 #組成中心點坐標shpe[batch,7,7,2]是歸一化后的值 25 offset=tf.constant(self.offset,dtype=tf.float32) 26 offset=tf.reshape(offset,[1,self.cell_size,self.cell_size,self.box_per_cell]) 27 offset=tf.tile(offset,[self.batch_size,1,1,1]) 28 29 predict_boxes_tran=tf.stack([(predict_boxes[:,:,:,:,0]+offset)/self.cell_size, 30 (predict_boxes[:,:,:,:,1]+tf.transpose(offset,(0,2,1,3)))/self.cell_size, 31 tf.square(predict_boxes[:,:,:,:,2]), 32 tf.square(predict_boxes[:,:,:,:,3])],axis=-1) 33 #iou的shape是[batch,7,7,2] 34 iou_predict_truth=self.cal_iou(predict_boxes_tran,boxes) 35 #兩個預選框中iou最大的 36 object_mask=tf.reduce_max(iou_predict_truth,3,keep_dims=True) 37 #真實圖中有預選框,並且值在兩個預選框中最大的遮罩 38 object_mask=tf.cast((iou_predict_truth>=object_mask),tf.float32)*response 39 #無預選框遮罩 40 noobject_mask=tf.ones_like(object_mask,dtype=tf.float32)-object_mask 41 #真實boxes的偏移量 42 boxes_tran=tf.stack([boxes[:,:,:,:,0]*self.cell_size-offset, 43 boxes[:,:,:,:,1]*self.cell_size-tf.transpose(offset,(0,2,1,3)), 44 tf.sqrt(boxes[:,:,:,:,2]), 45 tf.sqrt(boxes[:,:,:,:,3])],axis=-1)
#================================================================================================================================= 46 #分類損失 47 class_delta=response*(predict_classes-classes) 48 class_loss=tf.reduce_mean(tf.reduce_sum(tf.square(class_delta),axis=[1,2,3]),name='clss_loss')*self.class_scale 49 #有目標損失(IOU) 50 object_delta=object_mask*(predict_scales-iou_predict_truth) #這里iou_predict_truth應該為1 51 object_loss=tf.reduce_mean(tf.reduce_sum(tf.square(object_delta),axis=[1,2,3]),name='object_loss')*self.object_scale 52 #無目標損失(IOU) 53 noobject_delta=noobject_mask*predict_scales #這里減0 54 noobject_loss=tf.reduce_mean(tf.reduce_sum(tf.square(noobject_delta),axis=[1,2,3]),name='noobject_loss')*self.no_object_scale 55 #選框損失(坐標) 56 coord_mask=tf.expand_dims(object_mask,4) 57 boxes_delta=coord_mask*(predict_boxes-boxes_tran) 58 coord_loss=tf.reduce_mean(tf.reduce_sum(tf.square(boxes_delta),axis=[1,2,3,4]),name='coord_loss')*self.coord_scale 59 tf.losses.add_loss(class_loss) 60 tf.losses.add_loss(object_loss) 61 tf.losses.add_loss(noobject_loss) 62 tf.losses.add_loss(coord_loss)
YOLO V2:
YOLO V3:
YOLOv3不使用Softmax對每個框進行分類,而使用多個logistic分類器,因為Softmax不適用於多標簽分類,用獨立的多個logistic分類器准確率也不會下降。
分類損失采用binary cross-entropy loss.