layer output 激活函数_深入理解YOLO v3实现细节 - 第3篇 构建v3的Loss_layer
深入理解YOLO v3實(shí)現(xiàn)細(xì)節(jié)系列文章,是本人根據(jù)自己對(duì)YOLO v3原理的理解,結(jié)合開源項(xiàng)目tensorflow-yolov3,寫的學(xué)習(xí)筆記。如有不正確的地方,請(qǐng)大佬們指出,謝謝!
目錄
第1篇 數(shù)據(jù)預(yù)處理
第2篇 backbone&network
第3篇 構(gòu)建v3的 Loss_layer
1. 解讀YOLOv3 的損失函數(shù)
在分析yolo v3的損失函數(shù)之前,先來(lái)回顧一下yolo v1的損失函數(shù)。
一般來(lái)說(shuō)系統(tǒng)設(shè)計(jì)需要平衡邊界框坐標(biāo)損失、置信度損失和分類損失。論文中設(shè)計(jì)的損失函數(shù)如下:
對(duì)于 YOLOv3 的損失函數(shù), Redmon J 在論文中并沒(méi)有進(jìn)行講解。從darknet 源代碼中的forward_yolo_layer函數(shù)中找到 l.cost ,通過(guò)解讀,總結(jié)得到 YOLOv3 的損失函數(shù)如下:
與v1 Loss類似,主要分為三大部分: 邊界框坐標(biāo)損失, 分類損失和置信度損失。
邊界框坐標(biāo)損失 表示置信度,判斷網(wǎng)格內(nèi)有無(wú)物體。與yolo v1的邊界框坐標(biāo)損失類似,v3中使用誤差平方損失函數(shù)分別計(jì)算(x, y, w, h)的Loss,然后加在一起。v1中作者對(duì)寬高(w, h)做了開根號(hào)處理,為了弱化邊界框尺寸對(duì)損失值的影響。在v3中作者沒(méi)有采取開根號(hào)的處理方式,而是增加1個(gè)與物體框大小有關(guān)的權(quán)重,權(quán)重=2 - 相對(duì)面積,取值范圍(1~2)。
分類損失 表示置信度,判斷網(wǎng)格內(nèi)有無(wú)物體。使用誤差平方損失函數(shù)計(jì)算類別class 的Loss。置信度損失使用誤差平方損失函數(shù)計(jì)算置信度conf 的Loss。
YOLO v3網(wǎng)絡(luò)輸出yolo v3三種不同尺度的輸出,一共產(chǎn)生了(13*13*3+26*26*3+52*52*3)=10647個(gè)預(yù)測(cè)框。
這個(gè)10647就是這么來(lái)的。
最終Loss采用和的形式而不是平均Loss, 主要原因?yàn)轭A(yù)測(cè)的特殊機(jī)制, 造成正負(fù)樣本比巨大, 尤其是置信度損失部分, 以一片包含一個(gè)目標(biāo)為例, 置信度部分的正負(fù)樣本比可以高達(dá)1:10646, 如果采用平均損失, 會(huì)使損失趨近于0, 網(wǎng)絡(luò)預(yù)測(cè)變?yōu)槿? 失去預(yù)測(cè)能力。
參考上述原始的損失函數(shù),加以優(yōu)化。開始動(dòng)手構(gòu)建v3的Loss_layer!
2. 邊界框損失
對(duì)IoU和GIoU不了解的讀者可以看我寫的另外一篇文章: 目標(biāo)檢測(cè)中的IOU&升級(jí)版GIOU
目前目標(biāo)檢測(cè)中主流的邊界框優(yōu)化采用的都是BBox的回歸損失(MSE loss, L1-smooth loss等),這些方式計(jì)算損失值的方式都是檢測(cè)框的“代理屬性”—— 距離,而忽略了檢測(cè)框本身最顯著的性質(zhì)——IoU。由于IOU有2個(gè)致命缺點(diǎn),導(dǎo)致它不太適合作為損失函數(shù)。GIoU延續(xù)了IoU的優(yōu)良特性,并消除了IoU的致命缺點(diǎn)。以下使用GIoU Loss作為邊界框損失。
2.1 GIoU的計(jì)算
def bbox_giou(self, boxes1, boxes2):# 將boxes[x,y,w,h]化為[x_min, y_min, x_max, y_max]的形式boxes1 = tf.concat([boxes1[..., :2] - boxes1[..., 2:] * 0.5,boxes1[..., :2] + boxes1[..., 2:] * 0.5], axis=-1)boxes2 = tf.concat([boxes2[..., :2] - boxes2[..., 2:] * 0.5,boxes2[..., :2] + boxes2[..., 2:] * 0.5], axis=-1)boxes1 = tf.concat([tf.minimum(boxes1[..., :2], boxes1[..., 2:]),tf.maximum(boxes1[..., :2], boxes1[..., 2:])], axis=-1)boxes2 = tf.concat([tf.minimum(boxes2[..., :2], boxes2[..., 2:]),tf.maximum(boxes2[..., :2], boxes2[..., 2:])], axis=-1)# 計(jì)算boxes1、boxes2的面積boxes1_area = (boxes1[..., 2] - boxes1[..., 0]) * (boxes1[..., 3] - boxes1[..., 1])boxes2_area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])# 計(jì)算boxes1和boxes2交集的左上角坐標(biāo)和右下角坐標(biāo)left_up = tf.maximum(boxes1[..., :2], boxes2[..., :2])right_down = tf.minimum(boxes1[..., 2:], boxes2[..., 2:])# 計(jì)算交集區(qū)域的寬高,如果right_down - left_up < 0,沒(méi)有交集,寬高設(shè)置為0inter_section = tf.maximum(right_down - left_up, 0.0)# 交集面積等于交集區(qū)域的寬 * 高inter_area = inter_section[..., 0] * inter_section[..., 1]# 計(jì)算并集面積union_area = boxes1_area + boxes2_area - inter_area# 計(jì)算IOUiou = inter_area / union_area# 計(jì)算最小閉合凸面 C 左上角和右下角的坐標(biāo)enclose_left_up = tf.minimum(boxes1[..., :2], boxes2[..., :2])enclose_right_down = tf.maximum(boxes1[..., 2:], boxes2[..., 2:])# 計(jì)算最小閉合凸面 C的寬高enclose = tf.maximum(enclose_right_down - enclose_left_up, 0.0)# 計(jì)算最小閉合凸面 C的面積 = 寬 * 高enclose_area = enclose[..., 0] * enclose[..., 1]# 計(jì)算GIoUgiou = iou - 1.0 * (enclose_area - union_area) / enclose_areareturn giou2.2 GIoU loss 的計(jì)算
還記得label是怎么來(lái)嗎?在 第1篇 數(shù)據(jù)預(yù)處理 的4.3章節(jié)中有詳細(xì)說(shuō)明,這里不再多說(shuō)。當(dāng)你清楚了label是什么,表示什么,respond_bbox就容易理解了。
respond_bbox = label[:, :, :, :, 4:5] # 置信度,判斷網(wǎng)格內(nèi)有無(wú)物體 ... giou = tf.expand_dims(self.bbox_giou(pred_xywh, label_xywh), axis=-1) # 2 - 相對(duì)面積 bbox_loss_scale = 2.0 - 1.0 * label_xywh[:, :, :, :, 2:3] * label_xywh[:, :, :, :, 3:4] / (input_size ** 2)giou_loss = respond_bbox * bbox_loss_scale * (1 - giou)- respond_bbox 的意思是如果網(wǎng)格單元中包含物體,那么就會(huì)計(jì)算邊界框損失;
 - box_loss_scale = 2 - 相對(duì)面積,值的范圍是(1~2),邊界框的尺寸越小,bbox_loss_scale 的值就越大。box_loss_scale可以弱化邊界框尺寸對(duì)損失值的影響;
 - 兩個(gè)邊界框之間的 GIoU 值越大,giou 的損失值就會(huì)越小, 因此網(wǎng)絡(luò)會(huì)朝著預(yù)測(cè)框與真實(shí)框重疊度較高的方向去優(yōu)化。
 
3. 置信度損失
3.1 引入Focal Loss
論文發(fā)現(xiàn),密集檢測(cè)器訓(xùn)練過(guò)程中,所遇到的極端前景背景類別不均衡(extreme foreground-background class imbalance)是核心原因。為了解決 one-stage 目標(biāo)檢測(cè)器在訓(xùn)練過(guò)程中出現(xiàn)的極端前景背景類不均衡的問(wèn)題,引入Focal Loss。Focal Loss, 通過(guò)修改標(biāo)準(zhǔn)的交叉熵?fù)p失函數(shù),降低對(duì)能夠很好分類樣本的權(quán)重(down-weights the loss assigned to well-classified examples),解決類別不均衡問(wèn)題.
Focal Loss的計(jì)算公式:
是不同類別的分類概率, 權(quán)重因子 是個(gè)[0,1]間的小數(shù),縮放因子 是個(gè)大于0的值。 和都是固定值,不參與訓(xùn)練。 和 的最優(yōu)值是相互影響的,所以在評(píng)估準(zhǔn)確度時(shí)需要把兩者組合起來(lái)調(diào)節(jié)。作者在論文中給出 = 0.25 (即正負(fù)樣本比例為1:3)、 = 2 時(shí)性能最佳。此外,實(shí)驗(yàn)結(jié)果表面在計(jì)算 時(shí)用sigmoid方法比softmax準(zhǔn)確度更高。講了這么多,我們來(lái)看代碼吧!
先定義權(quán)重因子
和縮放因子 。target分為前景類和背景類,當(dāng)target是前景類時(shí)為1,背景類時(shí)為0。 def focal(self, target, actual, alpha=0.25, gamma=2):focal_loss = tf.abs(alpha + target - 1) * tf.pow(tf.abs(target - actual), gamma)return focal_loss鑒于論文實(shí)驗(yàn)結(jié)果表明sigmoid方法比softmax準(zhǔn)確度更高,下面選用sigmoid_cross_entropy交叉熵來(lái)計(jì)算置信度損失
3.2 計(jì)算置信度損失
conf_loss的計(jì)算公式:
計(jì)算置信度損失必須清楚conv_raw_conf和pred_conf是怎么來(lái)的。還記得上一篇文章提到的邊界框預(yù)測(cè)decode函數(shù)嗎?對(duì),就是從那來(lái)的。
def decode(self, conv_output, anchors, stride):"""return tensor of shape [batch_size, output_size, output_size, anchor_per_scale, 5 + num_classes]contains (x, y, w, h, score, probability)""" conv_shape = tf.shape(conv_output)batch_size = conv_shape[0]output_size = conv_shape[1]anchor_per_scale = len(anchors) # 3# 將v3網(wǎng)絡(luò)最終輸出的255維特征向量的形狀變?yōu)閍nchor_per_scale, x + y + w + h + score + num_classconv_output = tf.reshape(conv_output, (batch_size, output_size, output_size, anchor_per_scale, 5 + self.num_class))# v3網(wǎng)絡(luò)輸出的scoreconv_raw_conf = conv_output[:, :, :, :, 4:5]# 計(jì)算預(yù)測(cè)框里object的置信度pred_conf = tf.sigmoid(conv_raw_conf)conv_raw_conf 對(duì)應(yīng)計(jì)算公式中的
, pred_conf 對(duì)應(yīng)公式中的 。nice,開始動(dòng)手構(gòu)建conf_loss!
iou = bbox_iou(pred_xywh[:, :, :, :, np.newaxis, :], bboxes[:, np.newaxis, np.newaxis, np.newaxis, :, :]) # 找出與真實(shí)框 iou 值最大的預(yù)測(cè)框 max_iou = tf.expand_dims(tf.reduce_max(iou, axis=-1), axis=-1) # 如果最大的 iou 小于閾值,那么認(rèn)為該預(yù)測(cè)框不包含物體,則為背景框 respond_bgd = (1.0 - respond_bbox) * tf.cast( max_iou < IOU_LOSS_THRESH, tf.float32 )conf_focal = self.focal(respond_bbox, pred_conf) # 計(jì)算置信度的損失(我們希望假如該網(wǎng)格中包含物體,那么網(wǎng)絡(luò)輸出的預(yù)測(cè)框置信度為 1,無(wú)物體時(shí)則為 0) conf_loss = conf_focal * (respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf)+respond_bgd * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf))4.分類損失
這里分類損失采用的是二分類的交叉熵,即把所有類別的分類問(wèn)題歸結(jié)為是否屬于這個(gè)類別,這樣就把多分類看做是二分類問(wèn)題。
prob_loss = respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=label_prob, logits=conv_raw_prob)5. 最終Loss計(jì)算
將各部分損失值的和,除以均值,累加,作為最終的圖片損失值。
giou_loss = tf.reduce_mean(tf.reduce_sum(giou_loss, axis=[1,2,3,4]))conf_loss = tf.reduce_mean(tf.reduce_sum(conf_loss, axis=[1,2,3,4]))prob_loss = tf.reduce_mean(tf.reduce_sum(prob_loss, axis=[1,2,3,4]))return giou_loss, conf_loss, prob_loss補(bǔ)充
tf.pow函數(shù)具體使用方法:
TensorFlow冪值計(jì)算函數(shù):tf.pow_w3cschool?www.w3cschool.cntf.nn.sigmoid_cross_entropy_with_logits函數(shù)使用方法:
TensorFlow函數(shù)教程:tf.nn.sigmoid_cross_entropy_with_logits_w3cschool?www.w3cschool.cntf.expand_dims函數(shù)使用方法:
TensorFlow函數(shù)教程:tf.keras.backend.expand_dims_w3cschool?www.w3cschool.cnFocal Loss詳細(xì)講解和公式推導(dǎo)過(guò)程可以參考這篇文章:
Focal Loss 論文理解及公式推導(dǎo)?www.aiuai.cnsoftmax_cross_entropy和sigmoid_cross_entropy之間的區(qū)別可以參考這篇文章:
損失函數(shù)softmax_cross_entropy、binary_cross_entropy、sigmoid_cross_entropy之間的區(qū)別與聯(lián)系?www.jianshu.com謝謝觀看,覺(jué)得好就點(diǎn)個(gè)贊唄!
總結(jié)
以上是生活随笔為你收集整理的layer output 激活函数_深入理解YOLO v3实现细节 - 第3篇 构建v3的Loss_layer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: aspose.words 表格内容水平居
 - 下一篇: 矩形变弧度角_在上海做下颌角整形这些医生