字識別數(shù)據(jù)集:10000張圖+VOC/COCO/YOLO格式標(biāo)簽與訓(xùn)練全指南)
簡介目標(biāo)檢測是計算機視覺的基石任務(wù)而數(shù)據(jù)質(zhì)量與標(biāo)注格式往往決定模型上限。在數(shù)字識別場景中車牌、電表讀數(shù)、工業(yè)噴碼等小目標(biāo)密集且背景復(fù)雜模型對邊界框精度要求遠(yuǎn)高于通用物體檢測。面對VOC、COCO、YOLO三種主流標(biāo)注格式初學(xué)開發(fā)者常因坐標(biāo)定義差異、歸一化規(guī)則不同而陷入轉(zhuǎn)換泥潭。本文從標(biāo)注格式的底層邏輯切入解析XML、JSON與txt文件的存儲結(jié)構(gòu)與坐標(biāo)換算原理并給出可復(fù)用的轉(zhuǎn)換與劃分腳本。結(jié)合一份包含10000張圖片的數(shù)字識別數(shù)據(jù)集演示如何以預(yù)訓(xùn)練權(quán)重微調(diào)YOLOv8完成從數(shù)據(jù)校驗、目錄整理、訓(xùn)練參數(shù)設(shè)置到測試評估的完整閉環(huán)。無論你是剛?cè)腴T目標(biāo)檢測還是被數(shù)據(jù)集整理折磨過的老手都能通過這套方法快速獲得高精度數(shù)字識別模型。 做數(shù)字識別訓(xùn)練的人應(yīng)該都體會過一種尷尬模型結(jié)構(gòu)、訓(xùn)練參數(shù)這些事不難學(xué)難的是湊齊一份能用的數(shù)據(jù)。公開數(shù)據(jù)集要么背景太干凈模型一上真實場景就崩要么圖片是夠多可標(biāo)注格式五花八門得先花一兩天轉(zhuǎn)格式、寫劃分腳本才有資格點開訓(xùn)練按鈕??吹健癥OLO數(shù)字識別數(shù)據(jù)集含10000張圖片對應(yīng)voc、coco和yolo三種格式標(biāo)簽劃分腳本訓(xùn)練教程.rar”這個包時我的第一反應(yīng)是這是把從數(shù)據(jù)到訓(xùn)練的中間環(huán)節(jié)一次性補齊了。這份內(nèi)容適合誰剛接觸目標(biāo)檢測、想用YOLO做數(shù)字識別車牌、電表讀數(shù)、工業(yè)噴碼、快遞單號等的初學(xué)者也適合已經(jīng)跑通過demo、但被數(shù)據(jù)集整理折磨過的老手。下面我按實際使用的順序把這包數(shù)據(jù)從拆包到訓(xùn)練完的完整鏈路捋一遍順便把我踩過的坑都標(biāo)出來。1. 數(shù)字識別為什么值得單獨做個數(shù)據(jù)集1.1 數(shù)字檢測不等于通用目標(biāo)檢測數(shù)字識別只有10個類別0到9看起來比COCO的80類簡單多了。但數(shù)字識別有兩個特性讓它在數(shù)據(jù)上比通用檢測更挑食。第一個是“小目標(biāo)密集”。電表讀數(shù)、瓶蓋噴碼、快遞面單上的數(shù)字在整張圖里往往只占很小一塊區(qū)域而且經(jīng)常連續(xù)排列字符間距很小。模型要把每個數(shù)字當(dāng)成獨立目標(biāo)框出來對邊界框精度的要求比檢測“一個杯子”“一輛車”高得多。第二個是“字體和背景分布極不均勻”。印刷體、手寫體、LED數(shù)碼管、屏幕上渲染出來的藝術(shù)字體同一個數(shù)字在不同字體下的視覺特征差異很大。如果一個數(shù)據(jù)集只包含一種字體、一種背景模型訓(xùn)練完換到別的場景基本就是“見光死”。這也是為什么我特別關(guān)注這種數(shù)據(jù)集的數(shù)量和多樣性。10000張圖片對10類數(shù)字來說不是單純堆量而是給每個數(shù)字提供足夠多的形態(tài)變化空間。你可以把它當(dāng)作預(yù)訓(xùn)練數(shù)據(jù)先把“怎么區(qū)分?jǐn)?shù)字”這件事學(xué)扎實再在自己的業(yè)務(wù)數(shù)據(jù)上做微調(diào)。反過來如果只有幾百張圖哪怕模型結(jié)構(gòu)再強也很難學(xué)會穩(wěn)定的數(shù)字特征。1.2 10000張圖片的數(shù)據(jù)規(guī)模意味著什么先說結(jié)論10000張圖片配合預(yù)訓(xùn)練權(quán)重來微調(diào)YOLO是“夠用且舒服”的規(guī)模但如果要從零訓(xùn)練這點數(shù)據(jù)還不夠看。YOLO的常規(guī)玩法是加載在COCO上訓(xùn)練好的預(yù)訓(xùn)練權(quán)重再用自己的數(shù)據(jù)微調(diào)。模型之前已經(jīng)學(xué)會了通用物體特征比如邊緣、紋理、形狀構(gòu)成你的數(shù)據(jù)集只需要負(fù)責(zé)讓它“認(rèn)識數(shù)字”。在這個前提下每個類別平均有近千張圖足以讓模型把數(shù)字的判別特征學(xué)到位。反過來如果從隨機初始化開始訓(xùn)練模型需要同時學(xué)特征提取和類別判別10000張圖對10類目標(biāo)來說就偏少了很容易過擬合。所以拿到類似的數(shù)據(jù)包我的建議是訓(xùn)練時默認(rèn)使用modelyolov8n.pt或modelyolov8s.pt這種預(yù)訓(xùn)練權(quán)重而不是modelyolov8n.yaml。這個區(qū)別很多人會忽略直接導(dǎo)致訓(xùn)練好幾十輪精度還是上不去。2. 三種標(biāo)簽格式VOC、COCO、YOLO的底層邏輯與互相轉(zhuǎn)換2.1 為什么同一份標(biāo)注要給三份格式很多人第一次看到“voc、coco和yolo三種格式標(biāo)簽”時會想我直接用YOLO格式訓(xùn)練不就行了為什么還要給另外兩種真實原因是工具鏈不統(tǒng)一。標(biāo)注時有人用LabelImg保存的是VOC格式XML有人用Labelme或者Roboflow導(dǎo)出的COCO JSON而YOLO訓(xùn)練框架要求的是每個圖片對應(yīng)一個同名txt文件。如果數(shù)據(jù)集只給一種格式你換個訓(xùn)練框架就得寫轉(zhuǎn)換腳本。這三份標(biāo)簽相當(dāng)于把“標(biāo)注—轉(zhuǎn)換—訓(xùn)練”中間最麻煩的一段路鋪平了。比如你用MMDetectionCOCO格式直接能用用Ultralytics YOLOtxt格式直接能訓(xùn)練想用LabelImg復(fù)核標(biāo)注VOC格式最順手。我自己做項目時也經(jīng)常把數(shù)據(jù)同時保留成VOC和YOLO兩份一份用于肉眼檢查一份用于訓(xùn)練。2.2 三種格式的核心結(jié)構(gòu)對比我用自己的話把三種格式抽出來講清楚理解了底層邏輯遇到什么格式都不慌。VOC格式是一張圖片一個XML文件。文件里記錄了圖片文件名、尺寸、通道數(shù)以及每個目標(biāo)的類別名和邊界框坐標(biāo)坐標(biāo)是整數(shù)像素值格式為xmin, ymin, xmax, ymax表示左上角和右下角。它最接近人的閱讀習(xí)慣所以適合人工檢查。COCO格式是整個數(shù)據(jù)集打包成一個JSON文件。里面有幾個頂層字段images是圖片信息列表每張圖有id、file_name、width、heightannotations是標(biāo)注列表每條標(biāo)注包含image_id、category_id、bbox、area等字段categories是類別列表。注意COCO的bbox是[x, y, width, height]左上角坐標(biāo)加寬高不是右下角坐標(biāo)換算錯一位框就整個偏移。YOLO格式是一張圖片一個txt文件。每行一個目標(biāo)內(nèi)容為class_id x_center y_center width height這里的坐標(biāo)都是相對圖片寬高的歸一化浮點數(shù)取值在0到1之間。這也是YOLO訓(xùn)練時默認(rèn)讀取的格式Ultralytics要求標(biāo)簽文件放在labels/xxx.txt與images/xxx.jpg同名。我用一張表把關(guān)鍵差異列出來格式存儲方式坐標(biāo)含義歸一化適合場景VOC每圖一個XML左上角 (xmin, ymin)右下角 (xmax, ymax)否整數(shù)像素LabelImg人工檢查、Pascal VOC系列框架COCO整個數(shù)據(jù)集一個JSONbbox 為 [x, y, width, height]否像素值MMDetection、Detectron2、custom pipelineYOLO每圖一個txt目標(biāo)中心 (x_center, y_center) 和寬高是除以圖片寬高Ultralytics YOLO、Darknet2.3 三種格式轉(zhuǎn)換時最容易踩的坐標(biāo)坑格式轉(zhuǎn)換看著很簡單無非是挪坐標(biāo)但實際做一遍你會發(fā)現(xiàn)坑特別多。第一個坑是YOLO標(biāo)簽必須用歸一化坐標(biāo)而很多轉(zhuǎn)換腳本在圖片寬高取錯時會靜默出錯。比如用PIL讀的寬高順序是width, height用OpenCV的img.shape讀出來是(height, width, channels)順序反了標(biāo)簽就全錯。我檢查標(biāo)簽的對錯最常用的方法不是看數(shù)字而是把每個txt里的坐標(biāo)乘回圖片寬高畫框可視化一遍。第二個坑是VOC里可能有difficult或截斷目標(biāo)轉(zhuǎn)YOLO時這些不能直接丟給模型訓(xùn)練。轉(zhuǎn)換腳本里要處理這些屬性或者至少確認(rèn)數(shù)據(jù)包里沒有這類標(biāo)注。同樣的COCO里有些標(biāo)注帶iscrowd標(biāo)簽轉(zhuǎn)YOLO時這種實例也應(yīng)剔除。第三個坑是YOLO格式不支持“一張圖里同一個類別出現(xiàn)多次但共享同一個框”這種復(fù)雜形態(tài)。好在數(shù)字檢測基本都是獨立實例每個數(shù)字一個框不會觸發(fā)這個問題。如果你以后做的是密集人群、粘連細(xì)胞這類任務(wù)轉(zhuǎn)格式前就得想清楚實例邊界。3. 拿到壓縮包后的第一步目錄結(jié)構(gòu)與數(shù)據(jù)完整性檢查3.1 先看清單別急著解壓到訓(xùn)練目錄任何一個數(shù)據(jù)包解壓后第一件事不是直接訓(xùn)練而是先把目錄結(jié)構(gòu)看清楚。一個組織良好的數(shù)據(jù)包通常長這樣digit_dataset/ ├── images/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── labels_voc/ │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── labels_coco/ │ └── annotations.json ├── labels_yolo/ │ ├── 000001.txt │ ├── 000002.txt │ └── ... ├── split_script.py ├── data.yaml └── 訓(xùn)練教程.md當(dāng)然有些作者會把labels和images直接融合成Ultralytics風(fēng)格的images/train、labels/train結(jié)構(gòu)這也正常。關(guān)鍵是要先找到說明文件看它寫的是什么劃分方式。如果壓縮包里沒有README那就把圖片和標(biāo)簽的對應(yīng)關(guān)系先跑一遍腳本確認(rèn)。3.2 檢查圖片與標(biāo)簽是否一一對應(yīng)訓(xùn)練腳本報“l(fā)abel not found”或者“image not found”這類錯誤絕大多數(shù)情況都是數(shù)據(jù)包本身不完整。我拿到數(shù)據(jù)的第一時間會跑下面這個腳本檢查同名文件的對應(yīng)情況import os from pathlib import Path img_dir Path(images) yolo_dir Path(labels_yolo) img_stems {p.stem for p in img_dir.glob(*.jpg)} label_stems {p.stem for p in yolo_dir.glob(*.txt)} print(圖片數(shù)量:, len(img_stems)) print(標(biāo)簽數(shù)量:, len(label_stems)) print(有圖片但沒有標(biāo)簽:, sorted(img_stems - label_stems)[:10]) print(有標(biāo)簽但沒有圖片:, sorted(label_stems - img_stems)[:10])注意這里我用的是set而不是列表因為文件數(shù)量上萬時用列表做差集就是O(n*m)的災(zāi)難用set是O(1)查詢。這個細(xì)節(jié)看起來小但真等你在10000張圖前卡住時就會發(fā)現(xiàn)效率差很多。跑完腳本如果你發(fā)現(xiàn)有幾十張圖沒有標(biāo)簽先別急著刪。有些圖片里確實沒有數(shù)字目標(biāo)YOLO標(biāo)簽文件為空也是合法的只是訓(xùn)練時需要一個空的txt文件占位否則會報warning。3.3 抽查標(biāo)注質(zhì)量比看總量重要數(shù)據(jù)集質(zhì)量檢查里最直觀也最不能省的一步是可視化。隨意抽取幾十張圖把YOLO標(biāo)簽畫上去人眼掃一遍就能發(fā)現(xiàn)大部分問題。畫框代碼如下import cv2 img cv2.imread(images/000001.jpg) h, w img.shape[:2] with open(labels_yolo/000001.txt) as f: for line in f: cls, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(check_000001.jpg, img)重點看三類問題一是框是不是明顯偏離數(shù)字本體二是類別標(biāo)號是不是和真實數(shù)字一致比如把6標(biāo)成了8三是有沒有漏標(biāo)或重復(fù)框。抽查最好覆蓋不同圖片不要只看前幾十張。我習(xí)慣用random.sample抽100張出來看效率高且覆蓋度夠。提示如果可視化時發(fā)現(xiàn)大量框的尺寸都退化得特別小或者特別大優(yōu)先懷疑坐標(biāo)轉(zhuǎn)換腳本出錯而不是標(biāo)注本身的鍋。歸一化坐標(biāo)如果算錯一位畫出來的框會整體貼邊甚至超出圖片。4. 劃分腳本的底層邏輯與實操改進(jìn)4.1 為什么劃分順序這么重要很多人圖省事把數(shù)據(jù)全塞進(jìn)train跑完訓(xùn)練發(fā)現(xiàn)val精度虛高或者訓(xùn)練過程不可復(fù)現(xiàn)。數(shù)據(jù)劃分這件事看起來只是把文件分到不同文件夾實際上決定了你的模型評估是否可信。訓(xùn)練集用來學(xué)參數(shù)驗證集用來調(diào)超參、決定什么時候早停測試集用來做最終評估。三者之間如果存在數(shù)據(jù)泄漏比如同一張圖同時出現(xiàn)在train和val那val指標(biāo)就會虛高模型實際部署后表現(xiàn)會打折扣。劃分腳本存在的意義就是把這層隔離用代碼固定下來確保每次實驗可復(fù)現(xiàn)。4.2 一份可直接改用的劃分腳本這份數(shù)據(jù)包里的劃分腳本不管原作者是怎么寫的核心邏輯都應(yīng)該包含以下步驟讀取所有圖片路徑、固定隨機種子打亂、按比例分成訓(xùn)練/驗證/測試、把對應(yīng)的標(biāo)簽文件同步移動或建立軟鏈接、最后輸出一份文件清單。我自己常用的是一個偏保守的版本import random from pathlib import Path import shutil random.seed(42) img_dir Path(images) label_dir Path(labels_yolo) out_root Path(dataset) train_ratio, val_ratio 0.8, 0.1 # test_ratio 自動取剩余 0.1 imgs sorted(img_dir.glob(*.jpg)) random.shuffle(imgs) n len(imgs) n_train int(n * train_ratio) n_val int(n * val_ratio) split { train: imgs[:n_train], val: imgs[n_train:n_train n_val], test: imgs[n_train n_val:], } for split_name, img_paths in split.items(): (out_root / images / split_name).mkdir(parentsTrue, exist_okTrue) (out_root / labels / split_name).mkdir(parentsTrue, exist_okTrue) for img_path in img_paths: shutil.copy(img_path, out_root / images / split_name / img_path.name) src_label label_dir / (img_path.stem .txt) if src_label.exists(): shutil.copy(src_label, out_root / labels / split_name / (img_path.stem .txt)) else: # 沒有標(biāo)簽就用空文件占位避免后續(xù)訓(xùn)練報錯 (out_root / labels / split_name / (img_path.stem .txt)).touch() print(train:, len(split[train]), val:, len(split[val]), test:, len(split[test]))有人可能會問為什么不直接用shutil.move而是copy我的習(xí)慣是第一版盡量保留原始數(shù)據(jù)不動萬一劃分邏輯想調(diào)整、某個文件需要回頭復(fù)核原始包還在。等訓(xùn)練流程確定沒問題了再刪掉源目錄也不遲。4.3 劃分時必須處理的三個邊界情況第一同名文件沖突。如果壓縮包里的圖片本身就是000001.jpg、1.jpg這類短文件名從不同子目錄拷出來時可能撞名。建議復(fù)制時統(tǒng)一改成帶原始目錄前綴的名字或者在劃分之前先確認(rèn)全包沒有重名。第二視頻抽幀數(shù)據(jù)的時序泄漏。如果數(shù)據(jù)里的一部分圖片是從視頻里逐幀抽出來的直接把幀隨機扔進(jìn)train和val那相鄰幀高度相似val就失去評估意義。碰到這種情況應(yīng)該按視頻片段為單位劃分或者至少保證同一段視頻的幀只進(jìn)一個集合。第三類別分布不均勻。數(shù)字?jǐn)?shù)據(jù)集里如果0出現(xiàn)8000次、9只出現(xiàn)500次隨機劃分后val里可能恰好沒有9那val的mAP就不能代表模型真實能力。更穩(wěn)妥的做法是分層抽樣按每張圖片包含的類別標(biāo)簽做stratify。簡單場景下先整體shuffle再劃分通常問題不大但如果你發(fā)現(xiàn)val的混淆矩陣?yán)锬硞€類完全沒有樣本就要回頭重新切了。5. YOLO數(shù)字識別訓(xùn)練全流程環(huán)境、配置與參數(shù)5.1 環(huán)境安裝最容易出錯的是torch版本訓(xùn)練YOLO模型第一步是裝環(huán)境。當(dāng)前社區(qū)最常用的是Ultralytics生態(tài)一條命令就能裝pip install ultralytics但這里有個隱藏問題ultralytics會安裝torch依賴如果你直接pip install ultralytics它可能給你裝上最新的CPU版torch訓(xùn)練速度慢到令人發(fā)指。正確的做法是先裝好匹配CUDA版本的torch再裝ultralyticspip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralyticsCUDA版本要根據(jù)顯卡驅(qū)動來選不是越新越好。裝完后用python -c import torch; print(torch.cuda.is_available())確認(rèn)輸出True再做下一步。這個確認(rèn)步驟能幫你避免把后面所有報錯都?xì)w因到模型和數(shù)據(jù)上結(jié)果發(fā)現(xiàn)是環(huán)境沒GPU。5.2 整理成Ultralytics能直接吃的目錄結(jié)構(gòu)如果你用的是包里的labels_yolo目錄直接拿去訓(xùn)練會報錯因為Ultralytics默認(rèn)標(biāo)簽?zāi)夸洷仨毢蚷mages目錄同級并且名字是labels子目錄結(jié)構(gòu)要完全一致。經(jīng)過第4節(jié)劃分腳本處理后的結(jié)構(gòu)是這樣的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml然后寫data.yaml注意里面的路徑一定要寫對。我最??吹降膯栴}是相對路徑寫成./dataset/images/train結(jié)果訓(xùn)練時工作目錄不在項目根目錄路徑全部失效。要么用絕對路徑要么把yaml放在dataset根目錄下然后path: .path: . # 相對于本yaml文件所在的目錄 train: images/train val: images/val test: images/test nc: 10 names: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]注意names是類別名字的列表順序必須和標(biāo)簽文件里的class_id嚴(yán)格對應(yīng)。如果標(biāo)簽文件里0對應(yīng)數(shù)字0、1對應(yīng)數(shù)字1那names就從0排到9。搞反了模型也能訓(xùn)練但預(yù)測結(jié)果全是錯位這類錯誤通常到你人工驗證預(yù)測框時才會暴露排查成本很高。5.3 訓(xùn)練命令與參數(shù)選擇最普通的訓(xùn)練命令長這樣yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16 patience20參數(shù)含義不展開說了重點講幾個針對數(shù)字識別的選擇邏輯。modelyolov8n.pt而不是modelyolov8n.yaml這個前面提過再強調(diào)一次前者是加載COCO預(yù)訓(xùn)練權(quán)重進(jìn)行遷移學(xué)習(xí)后者是從零初始化。對這份10000張圖的數(shù)據(jù)集加載預(yù)訓(xùn)練權(quán)重能讓收斂速度明顯變快精度上限也更高。imgsz是訓(xùn)練分辨率。數(shù)字檢測的目標(biāo)通常偏小如果原圖很大而數(shù)字區(qū)域很小建議設(shè)成640或更高如果你的圖片本身是幾十像素的小圖強行拉到640反而會讓目標(biāo)變大、學(xué)習(xí)到不真實的特征。數(shù)據(jù)包里如果沒說明圖片分辨率建議先統(tǒng)計一下訓(xùn)練集圖片的寬高分布再定這個值。batch主要看顯存。實測顯存8GB的情況下YOLOv8n加imgsz640batch16基本是安全的換YOLOv8s就得降到8。如果訓(xùn)練時報CUDA out of memory先降batch別急著換小模型。patience20是早停參數(shù)意思是20輪內(nèi)val指標(biāo)沒提升就停止。對于數(shù)字識別這種相對簡單的任務(wù)一般20到50輪就能看到收斂沒必要硬跑200輪。保存下來的best.pt和last.pt分別在runs/detect/train/weights/下。5.4 訓(xùn)練日志里哪些指標(biāo)值得盯訓(xùn)練過程中終端會實時打印每個epoch的loss和mAP。我的習(xí)慣是盯三個東西。第一個是box_loss和cls_loss是否整體往下走。如果loss曲線像過山車一樣劇烈抖動首先看是不是學(xué)習(xí)率太高其次看標(biāo)簽有沒有錯位。第二個是mAP50它代表IoU0.5時的平均精度對數(shù)字檢測來說mAP50超過0.95算優(yōu)秀0.9左右也能用。第三個是訓(xùn)練結(jié)束時的mAP50-95這個指標(biāo)更嚴(yán)格它反映框定位的精細(xì)程度。數(shù)字檢測往往需要框盡量貼合字符所以mAP50-95同樣值得關(guān)注。如果發(fā)現(xiàn)train loss一直降、val loss不降反升那就是過擬合了。解決辦法不是繼續(xù)堆epoch而是增加數(shù)據(jù)增強、正則化或者換用更小的模型。Ultralytics默認(rèn)已經(jīng)開了mosaic、hsv增強想具體控制增強強度可以通過augmentTrue和對應(yīng)的超參配置來調(diào)整。6. 訓(xùn)練結(jié)束后的驗證、導(dǎo)出與數(shù)據(jù)迭代6.1 用測試集做一次“不被偷看”的評估訓(xùn)練過程中用的val集理論上已經(jīng)被模型間接“看過”了因為早停、調(diào)參都會參考它的指標(biāo)。所以真正能反映模型在未知數(shù)據(jù)上表現(xiàn)的是test集。跑評估的命令yolo detect val datadata.yaml modelruns/detect/train/weights/best.pt splittest這條命令會輸出test集上的mAP、Precision、Recall還有混淆矩陣和一批預(yù)測結(jié)果可視化圖。重點看混淆矩陣數(shù)字識別里常見的錯誤是8和3、5和6這類形近字混淆。如果混淆矩陣?yán)镞@類錯誤集中出現(xiàn)說明數(shù)據(jù)里對應(yīng)的字體形態(tài)覆蓋不夠下一步該有針對性地補數(shù)據(jù)而不是繼續(xù)調(diào)參。6.2 導(dǎo)出模型時容易忽略的細(xì)節(jié)訓(xùn)練完成只是第一步真要用起來一般會導(dǎo)出成ONNX或TensorRT。Ultralytics一行命令就能導(dǎo)出yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640導(dǎo)出后建議用ONNXRuntime或TensorRT做一次推理測試不要直接部署。我遇到過的一個典型問題是訓(xùn)練時imgsz640導(dǎo)出時用了動態(tài)shape部署端輸入尺寸不一致導(dǎo)致檢測框錯亂。更穩(wěn)的做法是導(dǎo)出時固定imgsz部署端預(yù)處理嚴(yán)格按照這個尺寸做resize同時記錄原始的縮放比例推理后再把框坐標(biāo)映射回原圖。另外部署時常用的conf和iou閾值也要重新調(diào)。訓(xùn)練時默認(rèn)conf0.25但真實場景下背景更復(fù)雜誤檢多就調(diào)高conf漏檢多就調(diào)低conf。這兩個參數(shù)沒有固定答案取決于你的業(yè)務(wù)容忍度。6.3 下一步從“數(shù)據(jù)集訓(xùn)練完”到“模型真的能用”最后說點真實體會。用這份數(shù)據(jù)訓(xùn)出來的模型在接近數(shù)據(jù)分布的場景下表現(xiàn)會很好但不要指望它一次就能覆蓋所有真實場景。數(shù)字識別最普遍的翻車場景是訓(xùn)練數(shù)據(jù)都是清晰印刷體上線后遇到逆光、遮擋、手寫體、LED屏刷新條紋精度立刻跳水。我的做法是把這份數(shù)據(jù)集當(dāng)成“地基”而不是終點。第一輪訓(xùn)練后專門收集模型預(yù)測錯誤的圖片人工標(biāo)注并加入訓(xùn)練集迭代兩三輪之后模型在實際場景的可用度會明顯提升。這個過程可能比調(diào)參更花時間但它才是目標(biāo)檢測項目真正值錢的部分。如果你只是交作業(yè)或者跑通流程按上面的步驟走完就能拿到一份規(guī)范的訓(xùn)練產(chǎn)物如果你要落地記得優(yōu)先收集壞例。數(shù)據(jù)集的“質(zhì)”永遠(yuǎn)比“量”更值得花時間這句話在數(shù)字識別這種看似簡單的任務(wù)上體現(xiàn)得尤其明顯。本文還有配套的精品資源點擊獲取