---
# System prepended metadata

title: YOLOv3實作整理
tags: [YOLO, DeepLearning, YOLOv3]

---

# YOLOv3實作整理
###### tags: `YOLOv3` `YOLO` `DeepLearning`
相關模型可參考在下的[github](https://github.com/shaoeChen/deeplearning/tree/master/tf2)

YOLOv3，現在都已經v8了，我可能才剛整理好v3，因為我個人習慣上是盡可能的希望可以自己硬寫一發，神經網路可能是黑盒子無法解釋，但是方法本身如果是可解釋的我就盡可能的去瞭解，不過還是有一些小細節沒有很完整，但至少我有信心看完我寫的資料之後你也可以絕大部份的掌握YOLOv3，這對你再往後延伸閱讀很有幫助。

物體偵測的資料格式與一般分類任務的標記有很大的不同，也因此我們在實作之前一定要先能夠處理資料的轉變。舉例來說，如果是分類任務的話，那一張照片也許就是一個類別，但如果是物體偵測的話，那也許一張照片上面就有四五個物體標記資訊了。

也因此，我們就先需要做些資料處理的前置動作，這部份你可以參考[Arch_YOLO_dataset_preprocess_1.ipynb](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLO_dataset_preprocess_1.ipynb)以及[Arch_YOLO_dataset_preprocess_2_data_for_yolov3.ipynb](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLO_dataset_preprocess_2_data_for_yolov3.ipynb)

這兩份文件主要在說明資料的前置處理，以及產生模型中計算loss所需要的資料格式。

整理好訓練資料之後就可以開始著手處理模型，我們知道，YOLOv3採用Darknet-53做為骨幹，這意謂著它有53層，骨幹的意思就是最主要的模型架構，但這是骨幹，YOLOv3的輸出跟Darknet-53是不一樣的，一個是做為物體偵測，一個是做為分類任務。

下圖給出YOLOv3的完整架構：

![image alt](https://hackmd.io/_uploads/rJJwnl5pq.png "YOLOv3" =750x1200)

可以看的出來主要是將不同大小的feature map做結合，讓大小資訊可以結合在一起做為輸出預測，這樣子不同尺寸的ancbor box就可以有比較豐富的資訊。

針對Darknet與YOLOv3的模型說明可以參考[Arch_YOLOv3_1_Darknet-53_structure.ipynb](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_1_Darknet-53_structure.ipynb)與[Arch_YOLOv3_2_YOLOv3_structure.ipynb](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_2_YOLOv3_structure.ipynb)的說明。這兩篇文章中對於架構的部份有著較為詳細的說明，可以更直觀的瞭解到模型中特徵圖(feature map)的變化。

接下來要處理的就是loss function，自己手寫過一次就會有一種，『啊，原來還可以這樣處理』的感覺出現。如下圖所示：
![](https://hackmd.io/_uploads/HyaUu33ao.png)

loss function的部份大致分為三個部份：
1. 框的好不好
2. 有沒有信心
3. 框到什麼

詳細的細節可以參考[Arch_YOLOv3_3_loss_function](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_3_loss_function.ipynb)。框的好不好可以用IoU來判斷，有沒有信心跟框到什麼就是用cross_entropy，這很標準。不過或許是因為我沒有先用影像分類的任務來做預訓練，訓練起來有點不順利，也因此loss function的部份我在實作上是有做些許調整的。

在[Arch_YOLOv3_3_loss_function](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_3_loss_function.ipynb)裡面有一個函數，decoder，這主要是拿來調整模型得到的feature map，整個資料流大致如下：
![](https://hackmd.io/_uploads/BJs41a3ai.png)

現在我們已經可以進入訓練的步驟了，有一些說不上來的細節，像是AP50之類的計算我還沒有實作上，所以目前來看是沒有這一個數值可以提供參考的，唯一有的就是loss。正如上面提到的，或許是因為我沒有先做預訓練，所以訓練過程中常常會造成梯度的消失或是爆炸等問題。也因此整個訓練過程真的很長，常常早上看的時候發現loss又nan，我把我的訓練過程通通寫在[Arch_YOLOv3_4_training](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_4_training.ipynb)，算是幫自己做個過程中記錄：
![](https://hackmd.io/_uploads/H1IcvT26s.png)

訓練之後我們需要做個推論測試，所以拿了張照片就看看它的原始狀態，再用我們訓練完成的模型看看推論出來的狀態，這可以參考[Arch_YOLOv3_5_predict](https://github.com/shaoeChen/deeplearning/blob/master/tf2/Arch_YOLOv3_5_predict.ipynb)。得到的推論結果如下：
![](https://hackmd.io/_uploads/SJB6QsTps.png)

上圖左是原始框的資料，然後上圖右是訓練後模型推論得到的資料，結果看似不錯，不過中間還是存在置信度的問題就是了，或許還需要更次的迭代。

以上就差不多是整個模型的處理過程了，前陣子已經看到發表YOLOv8了，我的v4才正要開始動手，有點慢，不過相信有這個基礎在可以很快速的推進才是。