# YOLOv7 拆解
###### tags: `Object Detection` `YOLO` `Paper` `deep learning` `Computer Vision` `One Stage Object Detection` `YOLO`
**本文是本人針對該篇論文的理解,若有不對之處,或是對本人在下文中提出的疑問有解答或想法的話,還請不吝賜教,非常感謝**
在2022年7月YOLOv4的作者群(王健堯博士與Alexey)悄悄在[arxiv](https://arxiv.org/abs/2207.02696)上釋出YOLOv7的論文,也在Github上提供[程式碼](https://github.com/WongKinYiu/yolov7),並且恭喜在筆者撰寫這篇文章時,該論文已經被CVPR2023收錄。此外,在差不多的時間點,還有另一版本的[YOLOv7](https://github.com/lucasjinreal/yolov7_d2),而本文只會探討這篇被YOLO之父 - Joseph Redmon所承認的論文,並將從論文與程式碼兩方面一邊分析背後的原理,一邊探討具體實現方法。

<!-- <p align="center">
<img src="https://i.imgur.com/JHvVF7o.png" width=70%> <br>
Models are trained on ImageNet-1K and deployed on iPhone 12 with CoreMLTools to get latency.
</p> -->
本文將會從top-down的角度進行拆解與說明:
1. 綜述YOLOv7提出的方法、實驗與猜想,以及貢獻
2. 拆解以及分析總體架構與模塊,並用圖片進行說明
3. 詳細分析新貢獻以及各方法與模塊(ELAN/E-ELAN, SPPCSP, RepVGG, label assignment(SimOTA, coarse-to-fine lead guided label assigner)),並且對對應的程式買進行剖析。
## 貢獻
我認為YOLOv7在以下幾個方面都提出新的貢獻:
1. 主要模型模塊優化: 將ELAN模塊進一步擴展,增強從不同特徵圖上學習特徵的能力,同時改進參數的使用量與計算量。
2. 引入並進一步分析結構重參數化: 引入丁霄漢博士提出的RepVGG,並針對RepVGG在不同結構的結果進行分析。
3. 提出新的動態標籤分配策略(dynamic label assignment strategy): lead head guided label assigner和coarse-to-fine lead head guided label assigner。
4. 為了因應ELAN-based或者說concatenation-based的模型能進行擴展與縮放,來更有效的提高參數與運算資源的利用率,而設計對應Model Scaling方案。
## 架構
\

<center>Backbone, Neck and Head</center>
\

<center>總體框架圖</center>
上圖中的模塊:
1. CBS是一組卷積模塊,$=Conv+Batch\ Norm+SiLU(激活函數)$
* 其中$SiLU$是$Sigmoid$的延伸: $SiLU(x) = x \cdot Sigmoid(x) = x \cdot \frac{1}{1+e^{-x}}$
* 
2. ELAN會在後續章節中詳細介紹,但其中的尾號4,6代表此模塊中有多少分支要在最後的Concat層concat起來。
3. RepConv也會在後面介紹,這主要將RepVGG的延伸應用。
4. SPPCSP
**注意:**
總體框架圖中,有一部分有誤:在現在標準的YOLOv7架構中,不是使用DownC模塊來做Down sampling,而是用MP(MaxPooling)模塊,在E6或E6E等較為龐大的模塊才會採用DownC。目前我已直接在圖中修改,後續針對這個部分會再重新繪製新的架構圖。
<!--  -->
來源:
1. [圖解 YOLOv7 architecture (1/2)](https://www.youtube.com/watch?v=Ot__47ItjDs)
2. [Question about the architecture of YOLOv7](https://github.com/WongKinYiu/yolov7/issues/458)
## 策略與模塊
### ELAN & E-ELAN

E(Extended)-ELAN是ELAN的拓展型,ELAN全名是Efficient Layer Aggregation Network,在YOLOv7論文中說是一篇在當時(2022/07)還未發表,但現在已經發表的論文所提出的新架構,而這篇論文([Designing Network Design Strategies Through Gradient Path Analysis](https://arxiv.org/pdf/2211.04800))也是由王建堯博士提出。在設計ELAN架構時,總結出一項結論: 通過控制最短最長的梯度路徑,可以讓更深的網絡在學習特徵與訓練時的收斂更加有效(->何解?)。
但由於ELAN的結構已經相當穩定,假設如果為了要提升模型的performance,而要在ELAN中無限制地壘加更多的計算模塊(computational block),可能會造成ELAN的穩固結構瓦解與參數的利用率下降。E-ELAN通過extend(group convolution), shuffle和merge cardinality等方式,可以在保持原本梯度路徑與transition模塊的前提下,能持續增進網絡的特徵學習能力。

<center>組卷積示意圖</center>
\
其中的Expand cardinality是來自[ResNeXt](https://openaccess.thecvf.com/content_cvpr_2017/papers/Xie_Aggregated_Residual_Transformations_CVPR_2017_paper.pdf)可以用group convolution來實現。上圖是group convolution的操作與原始卷積的比較,可以看出來計算量減少,並且有利於從稀疏矩陣中抽取特徵,此外有一個致命的問題,就是每個group之間的並沒有關聯。
針對這個問題,在E-ELAN中非常聰明的採用Shuffle cardinality來解決。而Shuffle cardinality的概念來自於一篇非常經典的論文[ShuffleNet](https://openaccess.thecvf.com/content_cvpr_2018/papers/Zhang_ShuffleNet_An_Extremely_CVPR_2018_paper.pdf)中Channel Shuffle的方法。

<center>Channel shuffle流程示意圖</center>

<center>Channel shuffle實作細節示意圖</center>
以上是ShuffleNet中shuffle cardinality(channel shuffle)的具體操作圖,實作流程如下:
1. 以上圖為例,將group convolution輸出feature的channel維度 reshape成$g \times n$, g: group數量, n: $channel\ number \div g$
2. 再轉置reshape後的特徵,得到$n \times g$
3. 最後再用Flatten攤平後作為下一層的輸入
<details>
<summary>Expand cardinality in ResNeXt</summary>
To Do
</details>
\
但根據論文跟程式碼來看,只有YOLOv7-E6E這個版本採用E-ELAN模塊,其他都是ELAN,並且雖然在論文中說用group convolution來實現cardinality這個概念,並且用channel shuffle來解決group之間不相關的缺點,但在程式碼實作上由於考量到一些邊緣設備不支援這兩種操作,等價的替代方式實現。
我一邊理解E-ELAN的概念,一邊查看程式碼中具體是如何實現的過程中,<span style="background-color: #FFFF00">發現E-ELAN的程式碼實作替代方案是先拆分成2個類ELAN分支,最後再將各自的結果加總。雖然與論文中的架構並不相同,但可以視為等價並且更為簡單。</span>
\

<center>E-ELAN概念實作模塊圖</center>
\

<center>E-ELAN實際程式碼實作模塊圖</center>
* 5.1 Experimental setup - YOLOv7 Paper
> We designed basic model for edge GPU, normal GPU, and cloud GPU, and they are respectively called YOLOv7-tiny, YOLOv7, and YOLOv7-W6. At the same time, we also use basic model for model scaling for different service requirements and get different types of models. For YOLOv7, we do stack scaling on neck, and use the proposed compound scaling method to perform scaling-up of the depth and width of the entire model, and use this to obtain YOLOv7-X. As for YOLOv7-W6, we use the newly proposed compound scaling method to obtain YOLOv7-E6 and YOLOv7-D6. In addition, **we use the proposed EELAN for YOLOv7-E6, and thereby complete YOLOv7-E6E**. Since YOLOv7-tiny is an edge GPU-oriented architecture, it will use leaky ReLU as activation function. As for other models we use SiLU as activation function. We will describe the scaling factor of each model in detail in Appendix.
<details>
<summary>YOLOv7-E6E config</summary>
```yaml=
...
# yolov7 backbone
backbone:
# [from, number, module, args],
[[-1, 1, ReOrg, []], # 0
[-1, 1, Conv, [80, 3, 1]], # 1-P1/2
[-1, 1, DownC, [160]], # 2-P2/4
[-1, 1, Conv, [64, 1, 1]], # ELAN-1
[-2, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -7, -8], 1, Concat, [1]],
[-1, 1, Conv, [160, 1, 1]], # 12
[-11, 1, Conv, [64, 1, 1]], # ELAN-2
[-12, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -7, -8], 1, Concat, [1]],
[-1, 1, Conv, [160, 1, 1]], # 22
[[-1, -11], 1, Shortcut, [1]], # 23
...
```
</details>
#### Model Scaling
在過去PlainNet或是ResNet base的網絡結構,由於輸入輸出的維度不會改變,所以可以很輕易的進行模塊或是layer的scaling,方便為了因應不同的需求(performance, inference speed)而做調整,如: Scaled-YOLOv4, YOLOv5等等。但對於concatenation-based的網絡結構來說,卻無法直接直接調整深度與寬度,在這種網絡結構中,兩者是相互影響的。

<center>Model Scaling</center>
concatenation-based網絡中若要增加深度的話,如上圖的(a)到(b),可以看得其輸出的寬度也跟著改變,會造成後續的transition或是其他layer也要一起進行調整,所以必須同時考量深度與寬度。對深度進行調整時,要去計算該模塊輸出的通道數變化量,以方便依照寬度比率調整transition layer或者說後續的layer的輸入通道數,如上圖中的圖(c)。該scaling方法可以同時維持最初模型的property與最優的結構。
* 圖片來源:
1. [YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors](https://arxiv.org/abs/2207.02696)
2. [CondenseNet: An Efficient DenseNet using Learned Group Convolutions](https://openaccess.thecvf.com/content_cvpr_2018/papers/Huang_CondenseNet_An_Efficient_CVPR_2018_paper.pd)
3. [圖解 YOLOv7 architecture (1/2)](https://www.youtube.com/watch?v=Ot__47ItjDs) 3. [圖解 YOLOv7 architecture (1/2)](https://www.youtube.com/watch?v=Ot__47ItjDs)
4. [ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile](https://openaccess.thecvf.com/content_cvpr_2018/papers/Zhang_ShuffleNet_An_Extremely_CVPR_2018_paper.pdf) 4. [ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile](https://openaccess.thecvf.com/content_cvpr_2018/papers/Zhang_ShuffleNet_An_Extremely_CVPR_2018_paper.pdf)
### Label Assignment
標籤分配(label assignment)指的是在訓練的過程中如何將ground truth上的標籤給到目標上,通常是分類任務或是其下游任務上。整個過程依照不同方面切割會有不同的任務,例如: 標籤分配的方式,或是將ground truth標籤轉換成訓練標籤的方法等。
標籤分配的方式主要分為2種方法: 靜態(fixed)和動態(dynamic)。靜態分配是過去的主流,主要過程是開始訓練前,每個grouth truth都要有一個且只能有一個對應的anchor,方法如MaxIOU等等。但靜態分配的魯棒性不足,難以應對ground truth有不同大小、形狀或是被遮擋等情況,所以後續才會有依照不同動態策略得出不同的anchor,而YOLOv7針對在分配標籤策略上,除了引用前人的方案之外,還融合其中一種方法到輔助訓練頭中,讓準確度與推論速度得到平衡。
傳統的標籤轉化方式非常簡單,就是沒有這個過程。直接把ground truth的標籤給對應的目標,稱為"**硬標籤(hard label)**"。研究人員發現這樣的做法有許多缺點,如: 泛化能力不強,容易過擬合、類間不夠分開,類內不夠聚合等。因此有了"**軟標籤(soft label)**"的產生,最簡單且泛用的就是label smoothing。在物件偵測上,軟標籤近期則是常用網絡輸出的分布與質量,跟ground truth合併計算後得到。例如: 在YOLO系列中用輸出的bounding box與ground truth計算IoU作為objectness的軟標籤。
在YOLOv7中,把網絡輸出與ground truth一起計算之後,再進行軟標籤分配的機制稱為"**label assigner**"。我認為本質上,這個問題更細部來分的話是: 標籤定義 $\rightarrow$ 標籤產生 $\rightarrow$ 標籤分配。
### 從OTA到SimOTA
#### OTA
在介紹SimOTA之前,先說明什麼是OTA(Optimal Transport Assignment)。它來自CVPR2021的一篇論文([OTA: Optimal Transport Assignment for Object Detection](https://openaccess.thecvf.com/content/CVPR2021/papers/Ge_OTA_Optimal_Transport_Assignment_for_Object_Detection_CVPR_2021_paper.pdf)),其目的在於有效地解決模糊不清的框,並認為標籤分配問題本質上可以視為一種最佳運輸問題((Optimal)Transportation Theory),那就能套用optimal transport的解決方法,如: Sinkhorn-Knopp演算法。
1. 什麼是模糊不清(ambiguous)的框?

<center>ambiguous anchor</center>
上圖是模糊不清的框,"**同一個grid cell中anchors上與多個ground truth交集,因此不確定它具體要給予哪個label(ground truth)**"。更白話一點,把anchor想像成實際物體的框,當多個物件在畫面中重疊時,而重疊的區塊中的像素歸類給誰就成了問題。而這個問題會讓模型在訓練時,引入有害的梯度,而造成訓練結果不彰。

<center>ambiguous anchor2</center>
2. 如何將標籤分配問題轉換成最佳運輸問題? 具體分配過程為何?
anchor視為只能需要一個label的需求者(demander),每個ground truth作為擁有k個正標籤的供應者(supplier)。
流程示意圖如下:

<center>OTA流程圖</center>
1. 計算每個ground truth和每個anchor的cost matrix(計算方式後續會補)
2. Dynamic k estimation: 目的是用來動態估計每個ground truth對應的positive anchor數量。對每個Ground truth分別計算與每個anchor的IOU,並各別取出Top q(=10 in YOLOv7)進行加總後,取整數得到k。但若anchor的數量大於k,則剩下的anchor都是背景。
3. 用Sinkhorn-Knopp演算法得出最佳運輸計畫(Optimal Transport Plan)$\pi^{*}$
4. 從每個anchor中,選出(與ground truth)最大的$\pi^{*}$,其對應的ground truth的label就是該anchor的label
3. 問題與缺點?
從結果來說,其實非常不錯,從全局的角度考量標籤分配,解決模糊的anchor標籤分配錯誤的問題。<span style="background-color: #FFFF00">但使用Sinkhorn-Knopp來解OT問題,會讓模型在訓練時起碼增加25%的訓練時間。</span>
#### SimOTA
SimOTA(Simplify OTA)本質上是在改進或者說簡化OTA的產物,也是在準確度與訓練速度上做出取捨的結果。
上一節最後有提到,OTA最大的問題在於使用Sinkhorn-Knopp演算法計算最優解,而產生額外大量的訓練時間。YOLOX認為既然SK演算法是罪魁禍首,那就直接捨棄該方法,用其他更快速簡易的方法替換。
<span style="background-color: #FFFF00">核心概念: 將k個最小cost的anchor選為正樣本</span>。具體作法是在第3步用SK演算法得到最佳運輸計畫做替換:
1. 每個Ground Truth取出k個最小cost的anchor
2. 若anchor有匹配到多個ground truth(ambiguous anchor),則取該anchor中最小的cost做為它的ground truth(label),其餘捨棄。
<details>
<summary>補充</summary>
從YOLOX的結果比較中可以看出,SimOTA在mAP衡量指標上有顯著的提升,但卻沒有與OTA的比較結果。我個人猜測可能是雖然改善OTA在訓練時間上的冗餘,但在準確度依然不及OTA,所以沒有放上來一起比較。我認為這可能也側面證實我一開始所說的,SimOTA是時間成本與準確度提升之間的平衡結果。
</details>
* Reference:
1. [OTA: Optimal Transport Assignment for Object Detection](https://openaccess.thecvf.com/content/CVPR2021/papers/Ge_OTA_Optimal_Transport_Assignment_for_Object_Detection_CVPR_2021_paper.pdf)
2. [圖解 YOLOv7 loss (2/2)](https://www.youtube.com/watch?v=EhXwABGhBrw)
3. [解读YOLOX(OTA / SimOTA)](https://zhuanlan.zhihu.com/p/549382358)
4. [YOLOX: Exceeding YOLO Series in 2021](https://arxiv.org/pdf/2107.08430)
#### Lead Guided Assigner and Coarse-to-fine Lead Guided assigner
Coarse-to-fine lead head guided label assigner這個策略的提出的目的是優化[輔助訓練頭](#Auxiliary-Head-輔助訓練頭)更進一步提升準確度。雖然它是要與輔助訓練頭結合再一起使用的,但我認為這項策略應該分類在label assignment的章節中,所以在編排上會與論文有所不同。所以在這個章節會先假設讀者對[輔助訓練頭](#Auxiliary-Head-輔助訓練頭)有一定的了解,如果不太了解可以先往後念面的章節去了解。
本章節將專注在標籤分配方法上,3種方法我認為可以視為是一個優化過程,本質上是在解決一個提問: "如何(更有效地)分配軟標籤到主導頭(lead head)與輔助頭(auxiliary head)?"。

* Independent Assigner
這個方法很直接,主導頭與輔助頭有各的assigner,分別計算得出soft label跟loss後,再加總或融合。
* Lead Guided Assigner
捨棄auxiliary head的label assigner,統一由lead head產生soft label後再分別兩頭的預測輸出計算loss。原因是lead head的學習能力較強,所以通過它得到的soft label應該要更能代表原始資料與目標間的分布與相關性等表徵。並且這種網絡結構也可視為一種殘差結構,讓auxiliary head直接學習lead head學習過的淺層資訊,使得lead head更加專注再學習其中的殘差。
* Coarse-to-fine Lead Guided Assigner:
結構上與lead guided assigner相同,但是用不同方法得出兩種soft label: coarse label與fine label。fine label與lead guided assigner的soft label獲取方式相同,從grid中找出3個正目標(3-NN positive)後,用prediction計算soft label;而coarse label則是從grid中找出5個正目標(5-NN positive),這麼做的理由是auxiliary head的學習能力比較差,為了避免必要學習的訊息丟失,所以提升auxiliary head在物件偵測中的招回率。實際在程式碼的實作上,使用權重的方式進行融合:
$$
iou\ loss = iou\_aux\_loss \times 0.25 + iou\_lead\_loss \times 1.0
$$
[程式碼 - ComputeLossAuxOTA](https://github.com/WongKinYiu/yolov7/blob/main/utils/loss.py#LL1176)

<center>coarse-to-fine lead guided head</center>
<details>
<summary>提問</summary>
1. SimOTA是標籤分配的方法,coarse-to-fine是label assigner,兩者都牽涉到標籤分配的動作,具體是如何結合的呢?
簡單來說,這是兩個不同過程。SimOTA不需要輔助訓練頭,並且它是"在訓練時,處理ambiguous anchor的問題",也就是把標籤分配到anchor上的過程,過程中,也需要使用到預測結果與ground truth的結果計算IoU loss。
label assigner在YOLOv7中代表得到soft label後進行標籤分配,所以在沒有使用輔助頭的情況下,SimOTA就是label assigner。而lead guided assigner系列的方法,則是在此基礎之上限縮,只有在使用輔助訓練頭的時候,才需要lead guided assigner系列的soft label assignment方法。
<!-- 在這裡有一個地方要注意,soft label不是用在類別分類的損失函數上,而是確認該預測框中是否有前景(物件)。 -->
</details>
### Trainable Bag-of-Freebies
這個概念很早就提出,但我認為是在YOLOv4出來後,在物件偵測的領域中才開始有組織並廣泛的開始使用。它的概念很簡單泛指在不增加推論速度的前提下,提高模型的performance(準確度、mAP等)。
以下將針對YOLOv7中使用的相關方法,前2項我會說明,剩下的有附相關連結:
1. Planned Re-parameterized Convolution: RepConv
2. Auxiliary Head and coarse-to-fine assigner
3. Batch normalize: fuse-conv-bn - [blog](https://nenadmarkus.com/p/fusing-batchnorm-and-conv/)
4. YOLOR: Implicit knowledge - [blog](https://learnopencv.com/yolor-paper-explanation-inference-an-in-depth-analysis/), [paper](https://arxiv.org/pdf/2105.04206)
5. EMA: [Mean teachers are better role models Weight-averaged consistency targets improve semi-supervised deep learning results](http://papers.neurips.cc/paper/6719-mean-teachers-are-better-role-models-weight-averaged-consistency-targets-improve-semi-supervised-deep-learning-results.pdf)
<details>
<summary>Bag-of-Spacial(BoS)</summary>
概念是能在增加些微推論時間成本的同時,大幅提升模型表現的即插即用(plugin)模塊與後處理方法。
</details>
#### Structural Re-parameterized: RepConv(RepVGG)
RepConv(RepVGGBlock)是丁霄漢博士在RepVGG提出的特殊卷積模塊,其中的核心概念是丁博士提出的結構重參數化。以下會先快速說明RepVGG的概念,如果想詳細了解可以參考論文([RepVGG: Making VGG-style ConvNets Great Again](https://openaccess.thecvf.com/content/CVPR2021/papers/Ding_RepVGG_Making_VGG-Style_ConvNets_Great_Again_CVPR_2021_paper.pdf))或是[程式碼](https://github.com/DingXiaoH/RepVGG)。在本節最後有結構重參數化的概略說明。

<center>RepConv</center>
RepConv最核心的概念與BoF差不多,但定義上更加狹隘,只從模型結構上著手。丁博士認為像是ResNet和Inception等模塊,能讓模型在深度與寬度上都能更有效地抽取特徵,進而建構出更準的結果。他因此提出一系列相關問題:
1. 是否能將這種結構用在VGGNet上呢?
2. 那又是否能在推論時維持VGGNet這種 PlainNet的高效運算結構,但藉由residual或是inception等結構來提升準確度呢?
最值觀的做法就是訓練與推論實採用不同架構,RepVGG就應運而生,它是VGGNet的延伸。在訓練時採用3個卷積分支(3x3,1x1,identity)組成一組卷積模塊替換原本的3x3卷積層,而在推論時則是將3個分支的權重映射到原本3x3的卷積層。
這種作法讓它在圖像分類任務中達到當時SOTA差不多performance的同時,也有更快的運行速度,並且在下游任務中(物件偵測、語意偵測等)也有非常好表現。YOLOv6基於它建構出新的模型架構,在YOLOv7的標準版網絡中,則是在輸出到Detect層之前有加入此模塊進行最後的提取與壓縮(在上述的架構圖中)。
\

<center>RepConvN</center>
<details>
<summary>結構重參數化(Structural re-parameterized)</summary>
* What: 結構重參數化是訓練與推論時的網絡結構不同,但performance相同。通常是訓練時的結構複雜,推論時的結構單一簡潔,並且不需要額外模塊去達到這一效果,而是在實現模塊時,在推論前通過公式先將訓練好的模型結構中的參數映射到推論時的模型結構中。
* 優點:
1. 在維持推論速度的前提下,提高performance。
2. 模型壓縮
3. 可直接用數學證明方法的可行性
* 相似或是延伸的概念: fuse-conv-bn, RepVGG, Diverse Branch Block(DBB), RepRes
[结构重参数化:利用参数转换解耦训练和推理结构](https://zhuanlan.zhihu.com/p/361090497)
</details>
<details>
<summary>PlainNet</summary>
雖然有以PlainNet作為名字的網絡架構,但在這的意思是泛指結構如VGGNet一般的網絡結構,沒有多分支、沒有複雜的卷積結構,甚至沒有不同大小的特徵提取器,單一、簡潔並高效。
</details>
##### 應用分析
<span style="background-color: #FFFF00">YOLOv7論文中提到將RepConv,直接應用(替換或加入)在VGGNet以外的網絡架構後,其performance不但不提升,反而有了劇烈的下降。</span>通過梯度傳播路徑(gradient flow propagation path)分析得出:
1. 如何將這個重參化的卷積結構結合到不同的網絡架構中
2. 知道performance下降的原因,並對RepConv進行微調設計出合適的重參化卷積結構(RepConvN)。
通過實驗結果分析,<span style="background-color: #FFFF00">發現RepConv中的identity分支會毀損ResNet中的殘差分支(residual)與DenseNet中的concatentation結構,為了解決此問題,直接去掉RepConv中的identity得到新的模塊RepConvN。再經過與之前一樣的實驗之後,確定RepConvN不會影響ResNet和DenseNet的結果。</span>

<details>
<summary>提問</summary>
1. 什麼是gradient flow propagation path? 又如何使用它進行模型的相關分析?
2. 我在吸收論文中對RepConv應用的分析時,去察看作者具體是如何在YOLOv7中實現的,但在[RepConv在YOLOv7中的實作](https://github.com/WongKinYiu/yolov7/blob/main/models/common.py#L463)中並沒有設計所謂RepConvN,也沒在架構中看到,因此疑惑所謂RepConvN是否真的有用? 如果有用,那為何具體實現中沒有看到?
我先回頭檢視yolov7.yml中的模型結構,以及RepVGG與YOLOv7在論文中對此模塊的具體描述與具體的程式碼實現,發現有幾個地方是造成是RepConv在YOLOv7依然可以運作良好並發揮作用的原因。
1. RepConv接在3個embedding output後,Detect layer前,不跟任何Residual或是Concatetation結構結合。
2. 原始的RepConv在論文中就提過,當input channel與output channel的數量相同時,identity分支才會啟用。在YOLOv7中,RepConv的輸入/輸出通道數不同,所以不會啟用identity。
由於我剛好正在進行YOLOv5的優化工作,其中就有將RepConv的模塊移植並應用到其中,所以也就直接針對這個改動做實驗,但結果卻不符合YOLOv7提供的分析結果,因為不管是用RepConv還是RepConvN,performance都有提升。
為了實驗的公平性,所有訓練採用同樣的參數與資料,並且都train from scratch。首先有2次主要的實驗:
1. 只在Neck stage用少量的RepConv/RepConvN替換Conv
2. 在Backbone中大量替換
| Name | mAP50 | mAP |
| -------- | -------- | -------- |
| base | 0.706 | 0.435 |
| RepConv | 0.738 | 0.483 |
| RepConvN | 0.738 | 0.48 |
所以我目前對於作者提出的RepConvN感到疑惑,因為不只在我的實驗中沒有發現準確度下降的問題,在美團的YOLOv6甚至以RepConv模塊為核心組件,建構出新的backbone,也達到非常好的效果。所以接下來若要深入探討RepConv與RepConvN的問題,可能會先從我現有實驗進行分析,以及分析YOLOv6的結構,或是直接詢問王建堯博士。
</details>
<!-- RepVGG我認為是結構重參數化被廣泛熟知的引爆點,它不只在圖像分類任務上有著能與當時SOTA模型差不多的結果,並且將VGGNet這種簡單的網絡結構再次發揚光大 -->
<!-- ## 總結 -->
\
圖片來源:
1. [YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors](https://arxiv.org/abs/2207.02696)
2. [RepVGG: Making VGG-style ConvNets Great Again](https://openaccess.thecvf.com/content/CVPR2021/papers/Ding_RepVGG_Making_VGG-Style_ConvNets_Great_Again_CVPR_2021_paper.pdf)
#### Auxiliary Head 輔助訓練頭
在上面[lead guided assigner系列](#Lead-Guided-Assigner-and-Coarse-to-fine-Lead-Guided-assigner)中有提到輔助訓練頭(Auxiliary Head),Auxiliary head其實是一種深度監督([Deep supervision](https://arxiv.org/pdf/1409.5185))的技術,就是以下圖的右邊。顧名思義,它就只能在訓練階段使用,並且目的就是輔助訓練。怎麼輔助? 輔助效果是什麼? 就是之後要探討的。

<center>一般訓練頭與輔助訓練頭</center>
* 輔助頭的目的是什麼?
用Auxiliary head有幾個目的或者說好處:
1. BoF
2. 加速模型收斂,或者說讓模型更好的收斂
3. 在某些任務下,由於學習更魯棒的特徵,所以能大幅提高performance
* 怎麼使用輔助頭?
使用的方式如上圖。將較淺層的輸出作為輔助訓練頭的輸入,並且得出第二或成為副的loss(與lead head得到的loss做區隔),用來引導lead head的訓練。
* Auxiliary head如何輔助lead head?
主要分為2種方法:
1. Multi-task learning: 這個名稱看起來很高大上,但其實概念非常簡單。它把auxiliary head視為其他任務,所以當模型正在學如何最小化loss時的loss,是將auxiliary head的loss與lead head的loss進行直接或權重加總得出,通過這種方式鼓勵網絡去學習對lead head task與auxiliary head task都有用的特徵,從而提高整體performance。
2. Knowledge distillation: 簡單來說,是用auxiliary head的輸出作為soft targets來替代老師網絡的角色,用來訓練更好的學生網絡。
由於YOLOv7是將auxiliary head的loss作為x0.25的權重,再與lead head的loss加總,所以應該可以歸類為第一種。
<!-- 程式碼 -->
<!-- <details>
<summary>Deep Supervision</summary>
</details> -->
## Reference
[1] YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors, https://arxiv.org/abs/2207.02696
[2] YOLOv7 source code, https://github.com/WongKinYiu/yolov7
[3] 丁霄漢博士, https://dingxiaohan.xyz/
[4] 圖解 YOLOv7 architecture (1/2), https://www.youtube.com/watch?v=Ot__47ItjDs
[5] 圖解 YOLOv7 loss (2/2), https://www.youtube.com/watch?v=EhXwABGhBrw
[6] YOLOv6: A Single-Stage Object Detection Framework for Industrial Applications, https://arxiv.org/abs/2209.02976
[7] 结构重参数化:利用参数转换解耦训练和推理结构, https://zhuanlan.zhihu.com/p/361090497