Yolov10:詳解、部署、應用一站式齊全!
一、前言
在過去的幾年里,YOLOs由于其在計算成本和檢測性能之間的有效平衡,已成為實時目標檢測領域的主導范式。研究人員探索了YOLO的架構設計、優化目標、數據擴充策略等,取得了顯著進展。然而,依賴非極大值抑制(NMS)進行后處理阻礙了YOLO的端到端部署,并對推理延遲產生不利影響。
此外,YOLOs中各種組件的設計缺乏全面徹底的檢查,導致明顯的計算冗余,限制了模型的能力。它提供了次優的效率,以及相當大的性能改進潛力。在這項工作中,目標是從后處理和模型架構兩個方面進一步提高YOLO的性能效率邊界。為此,首先提出了YOLOs無NMS訓練的一致雙重分配,它同時帶來了有競爭力的性能和低推理延遲。此外還介紹了YOLO的整體效率精度驅動模型設計策略。
從效率和精度兩個角度對YOLO的各個組件進行了全面優化,大大減少了計算開銷,增強了能力。工作成果是新一代用于實時端到端目標檢測的YOLO系列,稱為YOLOv10。大量實驗表明,YOLOv10在各種模型尺度上都達到了最先進的性能和效率。例如,在COCO上的類似AP下,YOLOv10-Sis1.8比RT-DETR-R18快1.8倍,同時享受的參數和FLOP數量少2.8倍。與YOLOv9-C相比,在相同的性能下,YOLOv10-B的延遲減少了46%,參數減少了25%。
二、背景
實時物體檢測一直是計算機視覺領域的研究熱點,其目的是在低延遲下準確預測圖像中物體的類別和位置。它被廣泛應用于各種實際應用,包括自動駕駛、機器人導航和物體跟蹤等。近年來,研究人員專注于設計基于CNN的物體檢測器,以實現實時檢測。
其中,YOLOs由于其在性能和效率之間的巧妙平衡而越來越受歡迎。YOLO的檢測流水線由兩部分組成:模型前向處理和NMS后處理。然而,這兩種方法仍然存在不足,導致準確性和延遲邊界不理想。具體而言,YOLO通常在訓練期間采用一對多標簽分配策略,其中一個基本事實對象對應于多個正樣本。盡管產生了優越的性能,但這種方法需要NMS在推理過程中選擇最佳的正預測。這降低了推理速度,并使性能對NMS的超參數敏感,從而阻止YOLO實現最佳的端到端部署。解決這個問題的一條途徑是采用最近引入的端到端DETR架構。例如,RT-DETR提供了一種高效的混合編碼器和不確定性最小的查詢選擇,將DETR推向了實時應用領域。然而,部署DETR的固有復雜性阻礙了其實現精度和速度之間最佳平衡的能力。另一條線是探索基于CNN的檢測器的端到端檢測,它通常利用一對一的分配策略來抑制冗余預測。
然而,它們通常會引入額外的推理開銷或實現次優性能。此外,模型架構設計仍然是YOLO面臨的一個基本挑戰,它對準確性和速度有著重要影響。為了實現更高效、更有效的模型架構,研究人員探索了不同的設計策略。為增強特征提取能力,為主干提供了各種主要計算單元,包括DarkNet、CSPNet、EfficientRep和ELAN等。對于頸部,探索了PAN、BiC、GD和RepGFPN等,以增強多尺度特征融合。此外,還研究了模型縮放策略和重新參數化技術。盡管這些努力取得了顯著進展,但仍然缺乏從效率和準確性角度對YOLO中的各種組件進行全面檢查。因此,YOLO中仍然存在相當大的計算冗余,導致參數利用效率低下和效率次優。此外,由此產生的約束模型能力也導致較差的性能,為精度改進留下了充足的空間。
三、新技術
Consistent Dual Assignments for NMS-free Training
在訓練期間,YOLOs通常利用TAL為每個實例分配多個陽性樣本。一對多分配的采用產生了豐富的監控信號,有助于優化并實現卓越的性能。然而,YOLO必須依賴NMS后處理,這導致部署的推理效率不理想。雖然以前的工作探索一對一匹配來抑制冗余預測,但它們通常會引入額外的推理開銷或產生次優性能。在這項工作中,為YOLO提供了一種無NMS的訓練策略,該策略具有雙標簽分配和一致的匹配度量,實現了高效率和有競爭力的性能。
- Dual label assignments
與一對多分配不同,一對一匹配只為每個地面實況分配一個預測,避免了NMS的后處理。然而,它導致監督不力,從而導致精度和收斂速度不理想。幸運的是,這種不足可以通過一對多分配來彌補。為了實現這一點,為YOLO引入了雙重標簽分配,以結合兩種策略中的最佳策略。具體而言,如下圖(a)所示。
為YOLO引入了另一個一對一的頭。它保留了與原始一對多分支相同的結構并采用了相同的優化目標,但利用一對一匹配來獲得標簽分配。在訓練過程中,兩個頭部與模型共同優化,讓骨干和頸部享受到一對多任務提供的豐富監督。在推理過程中,丟棄一對多的頭,并利用一對一的頭進行預測。這使得YOLO能夠進行端到端部署,而不會產生任何額外的推理成本。此外,在一對一的匹配中,采用了前一名的選擇,在較少的額外訓練時間下實現了與Hungarian matching相同的性能。
- Consistent matching metric
在分配過程中,一對一和一對多方法都利用一個指標來定量評估預測和實例之間的一致性水平。為了實現兩個分支的預測感知匹配,使用統一的匹配度量:
在雙標簽分配中,一對多分支比一對一分支提供更豐富的監控信號。直觀地說,如果能夠將一對一頭部的監管與一對多頭部的監管相協調,就可以朝著一對多的頭部優化的方向對一對一的頭部進行優化。因此,一對一頭部可以在推理過程中提供改進的樣本質量,從而獲得更好的性能。為此,首先分析了兩個之間的監管差距。由于訓練過程中的隨機性,一開始就用兩個用相同值初始化的頭開始檢查,并產生相同的預測,即一對一的頭和一對多的頭為每個預測實例對生成相同的p和IoU。注意到兩個分支的回歸目標。
當to2m,i=u*時,它達到最小值,即,i是中的最佳正樣本?, 如上圖(a)所示。為了實現這一點,提出了一致的匹配度量,即αo2o=r·αo2m和βo2o=r·βo2m,這意味著mo2o=mro2m。因此,一對多頭部的最佳陽性樣本也是一對一頭部的最佳樣本。因此,兩個頭部可以一致且和諧地進行優化。為了簡單起見,默認取r=1,即αo2o=αo2m和βo2o=βo2m。為了驗證改進的監督對齊,在訓練后計算一對多結果的前1/5/10內的一對一匹配對的數量。如上圖(b),在一致匹配方法下,對準得到改善。
由于篇幅有限,YOLOv10 的一大創新點便是引入了一種雙重標簽分配策略,其核心思想便是在訓練階段使用一對多的檢測頭提供更多的正樣本來豐富模型的訓練;而在推理階段則通過梯度截斷的方式,切換為一對一的檢測頭,如此一來便不在需要 NMS 后處理,在保持性能的同時減少了推理開銷。原理其實不難,可以看下代碼理解下:
#https://github.com/THU-MIG/yolov10/blob/main/ultralytics/nn/modules/head.py
class v10Detect(Detect):
max_det = -1
def __init__(self, nc=80, ch=()):
super().__init__(nc, ch)
c3 = max(ch[0], min(self.nc, 100)) # channels
self.cv3 = nn.ModuleList(nn.Sequential(nn.Sequential(Conv(x, x, 3, g=x), Conv(x, c3, 1)), \
nn.Sequential(Conv(c3, c3, 3, g=c3), Conv(c3, c3, 1)), \
nn.Conv2d(c3, self.nc, 1)) for i, x in enumerate(ch))
self.one2one_cv2 = copy.deepcopy(self.cv2)
self.one2one_cv3 = copy.deepcopy(self.cv3)
def forward(self, x):
one2one = self.forward_feat([xi.detach() for xi in x], self.one2one_cv2, self.one2one_cv3)
if not self.export:
one2many = super().forward(x)
if not self.training:
one2one = self.inference(one2one)
if not self.export:
return {'one2many': one2many, 'one2one': one2one}
else:
assert(self.max_det != -1)
boxes, scores, labels = ops.v10postprocess(one2one.permute(0, 2, 1), self.max_det, self.nc)
return torch.cat([boxes, scores.unsqueeze(-1), labels.unsqueeze(-1)], dim=-1)
else:
return {'one2many': one2many, 'one2one': one2one}
def bias_init(self):
super().bias_init()
'''Initialize Detect() biases, WARNING: requires stride availability.'''
m = self # self.model[-1] # Detect() module
# cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1
# ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency
for a, b, s in zip(m.one2one_cv2, m.one2one_cv3, m.stride): # from
a[-1].bias.data[:] = 1.0 # box
b[-1].bias.data[: m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (.01 objects, 80 classes, 640 img)
Holistic Efficiency-Accuracy Driven Model Design
架構改進:
- Backbone & Neck:使用了先進的結構如 CSPNet 作為骨干網絡,和 PAN 作為頸部網絡,優化了特征提取和多尺度特征融合。
- 大卷積核與分區自注意力:這些技術用于增強模型從大范圍上下文中學習的能力,提高檢測準確性而不顯著增加計算成本。
- 整體效率:引入空間-通道解耦下采樣和基于秩引導的模塊設計,減少計算冗余,提高整體模型效率。
四、實驗
與最先進的比較。潛伏性是通過官方預訓練的模型來測量的。潛在的基因測試在具有前處理的模型的前處理中保持了潛在性。?是指YOLOv10的結果,其本身對許多訓練NMS來說都是如此。以下是所有結果,無需添加先進的訓練技術,如知識提取或PGI或公平比較:
五、部署測試
首先,按照官方主頁將環境配置好,注意這里 python 版本至少需要 3.9 及以上,torch 版本可以根據自己本地機器安裝合適的版本,默認下載的是 2.0.1:
conda create -n yolov10 pythnotallow=3.9
conda activate yolov10
pip install -r requirements.txt
pip install -e .
安裝完成之后,我們簡單執行下推理命令測試下效果:
yolo predict model=yolov10s.pt source=ultralytics/assets/bus.jpg
讓我們嘗試部署一下,譬如先導出個 onnx 模型出來看看:
yolo export model=yolov10s.pt format=onnx opset=13 simplify
好了,接下來通過執行 pip install netron 安裝個可視化工具來看看導出的節點信息:
# run python fisrt
import netron
netron.start('/path/to/yolov10s.onnx')
先直接通過 Ultralytics 框架預測一個測試下能否正常推理:
yolo predict model=yolov10s.onnx source=ultralytics/assets/bus.jpg
大家可以對比下上面的運行結果,可以看出 performance 是有些許的下降。問題不大,讓我們基于 onnxruntime 寫一個簡單的推理腳本,代碼地址如下,有興趣的可以自行查看:
# 推理腳本
https://github.com/CVHub520/X-AnyLabeling/blob/main/tools/export_yolov10_onnx.py
# onnx 模型權重
https://github.com/CVHub520/X-AnyLabeling/releases/tag/v2.3.6