練全流程:從數(shù)據(jù)標(biāo)注到模型部署實(shí)戰(zhàn)指南)
1. 項(xiàng)目概述從零開始掌握YOLOv3模型訓(xùn)練想自己動(dòng)手訓(xùn)練一個(gè)能識別特定物體的AI模型嗎比如讓電腦自動(dòng)識別你花園里的不同花卉或者從監(jiān)控視頻里快速找出你的寵物貓。YOLOv3You Only Look Once version 3就是一個(gè)絕佳的起點(diǎn)。它不像一些復(fù)雜的模型那樣需要龐大的計(jì)算資源和海量數(shù)據(jù)對于個(gè)人開發(fā)者、學(xué)生或者中小型項(xiàng)目來說YOLOv3在精度和速度之間取得了非常好的平衡至今依然是許多實(shí)際場景下的首選。很多朋友在入門目標(biāo)檢測時(shí)會(huì)被官方代碼、復(fù)雜的配置和環(huán)境依賴搞得暈頭轉(zhuǎn)向最終卡在“跑通第一個(gè)訓(xùn)練”這一步。這篇文章我就以一個(gè)過來人的身份手把手帶你走一遍使用YOLOv3訓(xùn)練自己模型的完整流程把那些容易踩的坑、關(guān)鍵的參數(shù)調(diào)整和私藏的調(diào)試技巧都攤開來講清楚。我們的目標(biāo)很明確讓你用自己準(zhǔn)備的數(shù)據(jù)集成功訓(xùn)練出一個(gè)能用的模型并理解其中每一個(gè)步驟背后的“為什么”。2. 核心思路與準(zhǔn)備工作為什么是YOLOv3與數(shù)據(jù)為王2.1 為什么選擇YOLOv3進(jìn)行自定義訓(xùn)練在開始動(dòng)手之前我們得先搞清楚為什么選它。YOLO系列的核心思想是“單次檢測”即把目標(biāo)檢測問題當(dāng)作一個(gè)回歸問題來處理只需“看”一次圖像就能預(yù)測出所有邊界框和類別。YOLOv3作為該系列的經(jīng)典之作有幾個(gè)難以替代的優(yōu)勢速度與精度的良好權(quán)衡相比更早的版本YOLOv3引入了多尺度預(yù)測3種不同尺寸的特征圖和更優(yōu)的主干網(wǎng)絡(luò)Darknet-53對小物體的檢測能力顯著提升同時(shí)保持了較快的推理速度。對于需要實(shí)時(shí)或準(zhǔn)實(shí)時(shí)處理的應(yīng)用如視頻分析它依然能打。成熟的生態(tài)與社區(qū)支持YOLOv3的代碼實(shí)現(xiàn)如Darknet框架非常經(jīng)典網(wǎng)上有海量的教程、問題解答和預(yù)訓(xùn)練模型。這意味著你遇到的大多數(shù)問題很可能已經(jīng)有人解決過了。對硬件要求相對友好雖然訓(xùn)練深度學(xué)習(xí)模型離不開GPU但YOLOv3對顯存的要求不像一些超大模型那樣苛刻。在RTX 306012GB甚至更早的GTX 1080Ti11GB上你完全可以進(jìn)行有效的訓(xùn)練。易于理解和修改其網(wǎng)絡(luò)結(jié)構(gòu)、損失函數(shù)相對清晰配置文件.cfg是純文本格式調(diào)整起來直觀。這對于想要深入理解目標(biāo)檢測原理并進(jìn)行定制化修改如修改錨框、調(diào)整網(wǎng)絡(luò)層的學(xué)習(xí)者來說是很好的練手項(xiàng)目。當(dāng)然它也有局限比如在極高精度要求的場景下可能不如最新的模型但對于絕大多數(shù)自定義物體檢測的需求工業(yè)零件檢測、特定商品識別、安全帽檢測等YOLOv3完全夠用且性價(jià)比極高。2.2 訓(xùn)練自己的模型數(shù)據(jù)是地基模型訓(xùn)練七分靠數(shù)據(jù)三分靠調(diào)參。在敲下任何代碼之前你的主要精力應(yīng)該放在數(shù)據(jù)上。你需要準(zhǔn)備什么圖像數(shù)據(jù)包含你希望模型識別物體的圖片。數(shù)量上每個(gè)類別至少準(zhǔn)備200-300張圖片是一個(gè)比較穩(wěn)妥的起點(diǎn)。圖片應(yīng)盡可能多樣化不同的光照條件、拍攝角度、背景、遮擋情況。圖片格式通常為JPG或PNG。標(biāo)注信息每張圖片中你需要用矩形框標(biāo)出目標(biāo)物體并告訴模型這個(gè)框里是什么。這就是“標(biāo)注”。標(biāo)注會(huì)生成一個(gè)與圖片同名的文本文件如image001.jpg對應(yīng)image001.txt里面記錄了物體類別和邊界框坐標(biāo)。標(biāo)注的實(shí)操要點(diǎn)工具選擇推薦使用LabelImg或CVAT。LabelImg簡單易用適合快速啟動(dòng)CVAT功能更強(qiáng)大支持團(tuán)隊(duì)協(xié)作和視頻標(biāo)注。標(biāo)注格式Y(jié)OLO使用的是一種歸一化的坐標(biāo)格式(class_id, x_center, y_center, width, height)。所有坐標(biāo)值都是相對于圖片寬度和高度的比例范圍在0到1之間。class_id是類別的整數(shù)索引從0開始。x_center, y_center是邊界框中心點(diǎn)的坐標(biāo)。width, height是邊界框的寬度和高度。 例如0 0.5 0.5 0.32 0.48表示圖片中心有一個(gè)類別0的物體其寬度占圖寬的32%高度占圖高的48%。標(biāo)注質(zhì)量框要準(zhǔn)邊界框應(yīng)緊密貼合物體邊緣。類別要對確保標(biāo)注的類別與預(yù)定義的類別列表一致。不要漏標(biāo)特別是目標(biāo)物體較小或被部分遮擋時(shí)。處理遮擋如果物體被嚴(yán)重遮擋以至于人眼都難以辨認(rèn)其完整輪廓可以不標(biāo)或只標(biāo)可見部分取決于你的業(yè)務(wù)需求。注意標(biāo)注是一項(xiàng)耗時(shí)但至關(guān)重要的工作。前期在數(shù)據(jù)清洗和標(biāo)注上多花一小時(shí)可能比后期調(diào)參折騰一天效果更明顯。建議先標(biāo)注一個(gè)小批量如50張跑通流程再大規(guī)模標(biāo)注。3. 環(huán)境搭建與代碼部署打造穩(wěn)定的訓(xùn)練工作站3.1 基礎(chǔ)環(huán)境配置我們通常選擇Linux系統(tǒng)如Ubuntu 20.04/22.04進(jìn)行訓(xùn)練因?yàn)槠鋵ι疃葘W(xué)習(xí)框架的支持最友好。Windows也可以但可能會(huì)遇到更多依賴問題。步驟1安裝Python與必備工具確保系統(tǒng)已安裝Python 3.8或3.9與后續(xù)庫的兼容性最好。使用pip作為包管理工具。sudo apt update sudo apt install python3-pip python3-dev -y步驟2安裝PyTorch或DarknetYOLOv3最流行的實(shí)現(xiàn)有兩個(gè)原版DarknetC語言和PyTorch版本。我強(qiáng)烈推薦PyTorch版本因?yàn)樗子谩⒄{(diào)試更方便且與Python生態(tài)結(jié)合緊密。訪問 PyTorch官網(wǎng) 根據(jù)你的CUDA版本通過nvidia-smi命令查看選擇安裝命令。例如對于CUDA 11.8pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118步驟3克隆YOLOv3代碼庫我們將使用一個(gè)維護(hù)良好的PyTorch版YOLOv3實(shí)現(xiàn)例如ultralytics/yolov3的舊版本分支或者eriklindernoren/PyTorch-YOLOv3。這里以后者為例git clone https://github.com/eriklindernoren/PyTorch-YOLOv3.git cd PyTorch-YOLOv3 pip3 install -r requirements.txtrequirements.txt會(huì)自動(dòng)安裝numpy,opencv-python,matplotlib,tqdm等依賴。3.2 數(shù)據(jù)集的規(guī)范整理代碼倉庫克隆好后我們需要按照其要求組織數(shù)據(jù)集。通常結(jié)構(gòu)如下PyTorch-YOLOv3/ ├── data/ │ └── custom/ # 我們自定義的數(shù)據(jù)集目錄 │ ├── images/ │ │ ├── train/ # 訓(xùn)練集圖片 │ │ │ ├── image001.jpg │ │ │ └── ... │ │ └── val/ # 驗(yàn)證集圖片 │ │ ├── image101.jpg │ │ └── ... │ └── labels/ │ ├── train/ # 訓(xùn)練集標(biāo)簽與圖片同名.txt │ │ ├── image001.txt │ │ └── ... │ └── val/ # 驗(yàn)證集標(biāo)簽 │ ├── image101.txt │ └── ...關(guān)鍵操作劃分訓(xùn)練集和驗(yàn)證集通常按 8:2 或 9:1 的比例隨機(jī)劃分。驗(yàn)證集用于在訓(xùn)練過程中評估模型性能防止過擬合。可以使用腳本隨機(jī)分割。創(chuàng)建數(shù)據(jù)集配置文件在data/目錄下創(chuàng)建一個(gè)custom.data文件內(nèi)容如下classes2 # 你的物體類別數(shù)例如2表示有‘貓’和‘狗’兩類 traindata/custom/train.txt # 訓(xùn)練集圖片路徑列表文件 validdata/custom/val.txt # 驗(yàn)證集圖片路徑列表文件 namesdata/custom/names.names # 類別名稱文件 backupbackup/ # 訓(xùn)練過程中模型權(quán)重保存的目錄創(chuàng)建路徑列表文件train.txt和val.txt里面每行是圖片的絕對路徑或相對于項(xiàng)目根目錄的相對路徑。例如/home/user/PyTorch-YOLOv3/data/custom/images/train/image001.jpg /home/user/PyTorch-YOLOv3/data/custom/images/train/image002.jpg同樣需要生成names.names文件每行一個(gè)類別名cat dog實(shí)操心得路徑錯(cuò)誤是新手最常遇到的問題之一。建議在生成train.txt后用Python簡單讀幾行檢查一下路徑是否能正常打開圖片。可以使用os.path.join來構(gòu)建跨平臺兼容的路徑。4. 模型配置與訓(xùn)練啟動(dòng)調(diào)參的藝術(shù)4.1 理解與修改配置文件YOLOv3的網(wǎng)絡(luò)結(jié)構(gòu)由.cfg文件定義。在代碼倉庫的config/目錄下通常會(huì)有yolov3.cfg。我們不需要從頭寫而是復(fù)制一份進(jìn)行修改例如yolov3-custom.cfg。需要修改的關(guān)鍵位置有三處對應(yīng)三個(gè)不同尺度的檢測層YOLO層搜索三個(gè)[yolo]層。在每個(gè)[yolo]層上方緊鄰的[convolutional]層中修改filters參數(shù)。計(jì)算公式為filters (classes 5) * 3。其中classes是你的類別數(shù)5代表4個(gè)坐標(biāo)值x,y,w,h加1個(gè)置信度3代表每個(gè)網(wǎng)格預(yù)測3個(gè)錨框anchor boxes。例如你有2個(gè)類別則filters (25)*3 21。在每個(gè)[yolo]層中修改classes參數(shù)為你的類別數(shù)例如2。可選修改[yolo]層中的anchors。通常建議使用針對你自己數(shù)據(jù)集重新聚類的錨框尺寸這能提升模型收斂速度和精度。但初次訓(xùn)練可以先用默認(rèn)的COCO數(shù)據(jù)集錨框。4.2 啟動(dòng)訓(xùn)練命令與核心參數(shù)解析一切就緒可以開始訓(xùn)練了。訓(xùn)練命令的基本格式如下python train.py \ --model-def config/yolov3-custom.cfg \ --data-config data/custom.data \ --pretrained-weights weights/darknet53.conv.74 \ --epochs 100 \ --batch-size 8 \ --gradient-accumulations 2 \ --img-size 416讓我們拆解這些核心參數(shù)--model-def: 指定我們修改后的網(wǎng)絡(luò)配置文件路徑。--data-config: 指定數(shù)據(jù)集配置文件custom.data路徑。--pretrained-weights:強(qiáng)烈建議使用預(yù)訓(xùn)練權(quán)重。這里加載的是在ImageNet上預(yù)訓(xùn)練的Darknet-53主干網(wǎng)絡(luò)權(quán)重不包含檢測頭。這能極大加速收斂并提升最終性能。相當(dāng)于讓模型先學(xué)會(huì)“看”圖片的基本特征。--epochs: 訓(xùn)練輪數(shù)。對于小型數(shù)據(jù)集100-200輪可能足夠。需要觀察損失曲線決定是否早停。--batch-size: 批大小。這是指一次迭代送入模型的圖片數(shù)量。它受限于你的GPU顯存。RTX 3060 12GB上img-size416時(shí)batch-size8或16通常是安全的起點(diǎn)。如果出現(xiàn)CUDA out of memory錯(cuò)誤就減小它。--gradient-accumulations: 梯度累積步數(shù)。當(dāng)顯存不足以支持大的batch-size時(shí)可以通過這個(gè)小技巧來模擬大批次訓(xùn)練的效果。例如batch-size4且gradient-accumulations4效果上近似于batch-size16但每4個(gè)批次才更新一次模型權(quán)重。--img-size: 輸入圖片的尺寸。YOLOv3要求是32的倍數(shù)常用416x416。更大的尺寸如608可能提升精度但會(huì)顯著增加顯存消耗和訓(xùn)練時(shí)間。--multiscale-training: 可選多尺度訓(xùn)練。開啟后每隔幾個(gè)批次會(huì)隨機(jī)改變輸入圖片的尺寸在img-size的±50%范圍內(nèi)這能提升模型對不同尺度目標(biāo)的魯棒性。對于小數(shù)據(jù)集這是一個(gè)非常有效的防過擬合技巧。--checkpoint-interval: 每隔多少輪保存一次中間權(quán)重。建議設(shè)置一個(gè)值如5或10方便回退到性能最好的模型。4.3 訓(xùn)練過程監(jiān)控與解讀啟動(dòng)訓(xùn)練后控制臺會(huì)打印日志。你需要重點(diǎn)關(guān)注以下幾個(gè)指標(biāo)損失Loss總損失由邊界框坐標(biāo)損失、置信度損失和分類損失組成。你會(huì)看到Loss: x.xxxx。理想情況下這個(gè)值應(yīng)該隨著訓(xùn)練輪數(shù)Epoch增加而穩(wěn)步下降最終趨于平緩。如果損失劇烈震蕩或很早就停止下降可能是學(xué)習(xí)率過大、數(shù)據(jù)有問題或模型配置錯(cuò)誤。驗(yàn)證集指標(biāo)每隔一定輪數(shù)模型會(huì)在驗(yàn)證集上評估并打印如下指標(biāo)Precision精確率模型預(yù)測為正的樣本中真正為正的比例。越高越好。Recall召回率所有真實(shí)為正的樣本中被模型正確預(yù)測出來的比例。越高越好。mAP0.5平均精度均值這是核心評估指標(biāo)。它計(jì)算了在不同召回率下的平均精確率取IoU交并比閾值為0.5。這個(gè)值直接反映了模型的綜合檢測性能。訓(xùn)練的目標(biāo)就是讓這個(gè)值在驗(yàn)證集上不斷提升。Tensorboard可視化大多數(shù)訓(xùn)練腳本支持Tensorboard。在另一個(gè)終端運(yùn)行tensorboard --logdirlogs然后在瀏覽器打開提示的地址。你可以在這里看到損失曲線、mAP曲線、權(quán)重分布等這是分析訓(xùn)練過程最直觀的工具。注意事項(xiàng)訓(xùn)練初期損失可能很高幾十甚至上百這是正常的因?yàn)闄?quán)重是隨機(jī)初始化的。如果使用了預(yù)訓(xùn)練權(quán)重初始損失會(huì)低很多。務(wù)必關(guān)注驗(yàn)證集的mAP而不是一味追求訓(xùn)練集損失的降低。如果訓(xùn)練集損失持續(xù)下降但驗(yàn)證集mAP停滯不前甚至下降那就是過擬合的典型信號。5. 模型評估、測試與部署從訓(xùn)練到應(yīng)用5.1 模型評估與選擇最佳權(quán)重訓(xùn)練結(jié)束后在checkpoints/或backup/目錄下會(huì)保存多個(gè)權(quán)重文件。你需要選擇在驗(yàn)證集上性能最好的那個(gè)而不是最后一個(gè)last.pt。如何選擇查看日志找到驗(yàn)證集mAP0.5最高的那個(gè)Epoch對應(yīng)的權(quán)重文件。使用評估腳本通常代碼庫會(huì)提供test.py或evaluate.py腳本。用它來系統(tǒng)性地評估各個(gè)保存的權(quán)重在驗(yàn)證集上的性能生成詳細(xì)的報(bào)告。python test.py --weights-path checkpoints/yolov3_ckpt_95.pth --model-def config/yolov3-custom.cfg --data-config data/custom.data --img-size 416這個(gè)命令會(huì)輸出精確率、召回率、mAP等指標(biāo)的最終值。5.2 使用訓(xùn)練好的模型進(jìn)行推理預(yù)測現(xiàn)在你可以用自己訓(xùn)練的模型來檢測新圖片或視頻了。通常會(huì)有detect.py或類似的腳本。單張圖片檢測python detect.py \ --image-path data/samples/test_image.jpg \ --weights-path checkpoints/best_weights.pth \ --model-def config/yolov3-custom.cfg \ --conf-thres 0.5 \ --nms-thres 0.4 \ --output-path output/--conf-thres置信度閾值。只顯示置信度高于此值的預(yù)測框。調(diào)高它會(huì)減少誤報(bào)但可能漏檢調(diào)低則相反。--nms-thres非極大值抑制閾值。用于合并重疊的預(yù)測框。值越小合并越嚴(yán)格留下的框越少。視頻流或攝像頭檢測python detect.py --video-path 0 --weights-path checkpoints/best_weights.pth ... # 0代表攝像頭 python detect.py --video-path path/to/video.mp4 --weights-path checkpoints/best_weights.pth ...5.3 模型優(yōu)化與常見問題排查訓(xùn)練很少有一次就完美的。下面是一些常見問題及排查思路問題現(xiàn)象可能原因排查與解決思路損失不下降Nan學(xué)習(xí)率過大數(shù)據(jù)標(biāo)注有嚴(yán)重錯(cuò)誤如坐標(biāo)超出0-1梯度爆炸。1. 大幅降低學(xué)習(xí)率如乘以0.1。2. 檢查標(biāo)注文件格式和數(shù)值范圍。3. 使用梯度裁剪--gradient_clip。驗(yàn)證集mAP很低訓(xùn)練集損失正常嚴(yán)重過擬合驗(yàn)證集和訓(xùn)練集數(shù)據(jù)分布差異大。1. 增加數(shù)據(jù)增強(qiáng)隨機(jī)翻轉(zhuǎn)、裁剪、色彩抖動(dòng)。2. 使用更小的模型或添加正則化如權(quán)重衰減。3. 檢查驗(yàn)證集圖片和標(biāo)注是否正常。4. 確保訓(xùn)練/驗(yàn)證集劃分是隨機(jī)的。模型只檢測到部分類別或漏檢嚴(yán)重類別不平衡某些類別的樣本太少或質(zhì)量差錨框尺寸不合適。1. 對樣本少的類別進(jìn)行過采樣或數(shù)據(jù)增強(qiáng)。2. 檢查漏檢類別的圖片看是否目標(biāo)太小、太模糊。3. 針對你的數(shù)據(jù)集重新聚類生成錨框使用tools/目錄下的腳本。推理速度很慢輸入圖片尺寸過大未在GPU上運(yùn)行模型未轉(zhuǎn)換為推理優(yōu)化模式。1. 嘗試減小--img-size如從608降到416。2. 確認(rèn)PyTorch使用了CUDA (torch.cuda.is_available())。3. 在推理前調(diào)用model.eval()并可能使用torch.no_grad()。預(yù)測框位置不準(zhǔn)邊界框回歸損失權(quán)重可能不合適數(shù)據(jù)標(biāo)注的框不精確。1. 在配置文件中調(diào)整coord_scale坐標(biāo)損失權(quán)重。2. 回頭檢查并修正訓(xùn)練數(shù)據(jù)的標(biāo)注框。一個(gè)關(guān)鍵的優(yōu)化技巧學(xué)習(xí)率調(diào)度Learning Rate Schedule不要使用固定學(xué)習(xí)率。采用熱身Warmup和余弦退火Cosine Annealing或步進(jìn)衰減Step Decay策略能顯著提升模型性能和穩(wěn)定性。例如在PyTorch中可以這樣設(shè)置optimizer torch.optim.Adam(model.parameters(), lr1e-4, weight_decay1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_010, T_mult2)這會(huì)在訓(xùn)練中周期性地重啟學(xué)習(xí)率有助于跳出局部最優(yōu)。5.4 模型轉(zhuǎn)換與輕量化部署思考訓(xùn)練出的PyTorch模型.pth文件可以直接用于Python環(huán)境。但如果需要在其他平臺部署如C環(huán)境、移動(dòng)端、邊緣設(shè)備就需要進(jìn)行模型轉(zhuǎn)換。轉(zhuǎn)換為ONNX格式ONNX是一種開放的模型交換格式。PyTorch提供了torch.onnx.export函數(shù)可以將模型轉(zhuǎn)換為ONNX。轉(zhuǎn)換后你可以使用ONNX Runtime進(jìn)行高性能推理或者進(jìn)一步轉(zhuǎn)換為其他格式。轉(zhuǎn)換為TensorRT引擎如果你在NVIDIA的GPU上追求極致推理速度TensorRT是不二之選。它會(huì)對模型進(jìn)行層融合、精度校準(zhǔn)FP16/INT8等深度優(yōu)化。這個(gè)過程相對復(fù)雜需要先轉(zhuǎn)ONNX再用TensorRT的解析器構(gòu)建引擎。轉(zhuǎn)換為其他框架如需在手機(jī)端使用可考慮轉(zhuǎn)換為TFLiteTensorFlow Lite或Core ML蘋果生態(tài)。對于資源受限的設(shè)備你可能還需要考慮模型剪枝、量化等后處理技術(shù)來壓縮模型大小、提升速度。不過對于初次訓(xùn)練成功而言先能穩(wěn)定地跑通從數(shù)據(jù)到推理的全流程比過早追求極致優(yōu)化更重要。訓(xùn)練自己的YOLOv3模型就像教一個(gè)孩子認(rèn)識新事物。數(shù)據(jù)是你給他的“教材”標(biāo)注是“講解”訓(xùn)練過程是“反復(fù)練習(xí)”而調(diào)參則是“因材施教”。這個(gè)過程難免會(huì)遇到各種報(bào)錯(cuò)和效果不佳的情況但每一次排查和嘗試都會(huì)讓你對模型的工作原理有更深的理解。我的建議是先從一個(gè)小而精的數(shù)據(jù)集開始快速走完整個(gè)流程獲得第一個(gè)能跑的模型建立信心。然后再去迭代數(shù)據(jù)質(zhì)量、嘗試更復(fù)雜的增強(qiáng)和調(diào)參策略。記住在深度學(xué)習(xí)的實(shí)踐中動(dòng)手做和有效復(fù)盤比讀十篇理論文章都管用。當(dāng)你第一次看到模型準(zhǔn)確框出你標(biāo)注的物體時(shí)那種成就感就是繼續(xù)探索下去的最大動(dòng)力。