注數(shù)據(jù)集:YOLO目標(biāo)檢測(cè)訓(xùn)練實(shí)踐)
簡(jiǎn)介面向醫(yī)學(xué)影像AI與計(jì)算機(jī)視覺(jué)學(xué)習(xí)者這份數(shù)據(jù)集基于X胸透光片構(gòu)建采用COCO格式對(duì)1765張?jiān)紙D片完成標(biāo)注覆蓋新冠肺炎、正常、肺炎三種類別可直接用于目標(biāo)檢測(cè)、圖像分類、語(yǔ)義分割等任務(wù)的模型訓(xùn)練與效果驗(yàn)證。壓縮包共1770個(gè)文件包括1765張jpg原圖、3個(gè)json標(biāo)注文件以及2個(gè)txt說(shuō)明文件整體約61.41MB目錄結(jié)構(gòu)清晰便于導(dǎo)入MMDetection、Detectron2等主流框架。目前已有906人在CSDN學(xué)習(xí)或下載適合醫(yī)療影像診斷研究、高校深度學(xué)習(xí)課程設(shè)計(jì)以及算法對(duì)比實(shí)驗(yàn)等場(chǎng)景。借助完整的標(biāo)注信息使用者可快速完成數(shù)據(jù)劃分、樣本平衡與模型微調(diào)免去人工標(biāo)注的繁雜流程把精力集中在檢測(cè)網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì)、損失函數(shù)優(yōu)化與性能評(píng)估上。1. 新冠肺炎檢測(cè)數(shù)據(jù)集先看這份COCO標(biāo)注的X光胸透能用在哪影像AI項(xiàng)目里最難的不是模型而是標(biāo)注干凈的數(shù)據(jù)。這份名為“新冠肺炎檢測(cè)數(shù)據(jù)集”的資源包含1765張?jiān)糥光胸透圖片已經(jīng)用COCO格式完成了目標(biāo)檢測(cè)標(biāo)注能區(qū)分新冠肺炎、正常、肺炎三種狀態(tài)。對(duì)做醫(yī)療影像檢測(cè)、想快速驗(yàn)證YOLO系列或MMDetection流程的開發(fā)者來(lái)說(shuō)它省掉了收集圖片和數(shù)據(jù)標(biāo)注兩件最耗時(shí)的事。拿到手就能直接轉(zhuǎn)格式、訓(xùn)練、出指標(biāo)適合正在做肺部X光檢測(cè)實(shí)驗(yàn)、需要一份帶bbox標(biāo)注的醫(yī)學(xué)圖像數(shù)據(jù)集來(lái)跑通訓(xùn)練管線的從業(yè)者。2. 數(shù)據(jù)集結(jié)構(gòu)與COCO JSON1765張圖、三分類標(biāo)簽是這樣組織的數(shù)據(jù)集的可靠程度決定了后面訓(xùn)練順不順利。拿到壓縮包后建議先別急著訓(xùn)練把目錄結(jié)構(gòu)和標(biāo)注文件拆開看一遍摸清圖片和標(biāo)注的對(duì)應(yīng)關(guān)系。這一章我把這份數(shù)據(jù)集的目錄特征、COCO JSON的字段含義、類別分布逐一拆開講清楚。2.1 目錄與文件命名從文件名反推數(shù)據(jù)集來(lái)源解壓后你會(huì)發(fā)現(xiàn)圖片文件名長(zhǎng)這樣COVID19-8-_jpg.rf.d1e42a6f39394fad7a82891eb20d0f82.jpg COVID19-260-_jpg.rf.f73c9b0edecb542528268295e0214e45.jpg COVID19-175-_jpg.rf.a23ef5f24b9e58a4fd42ac52775d81eb.jpg這里有個(gè)關(guān)鍵信息文件名里的rf是Roboflow平臺(tái)導(dǎo)出時(shí)留下的標(biāo)記。常見(jiàn)做法是Roboflow導(dǎo)出的數(shù)據(jù)集會(huì)自帶train、valid、test三個(gè)子目錄COCO標(biāo)注文件通常以_annotations.coco.json的形式存放在各目錄下例如train/_annotations.coco.json。這個(gè)數(shù)據(jù)集之所以叫“1765張?jiān)紙D片”是因?yàn)閳D片內(nèi)容未做裁剪增強(qiáng)保留了原始胸片的畫面范圍。文件名中間段的-8-、-260-這類數(shù)字是圖片在原始采集庫(kù)里的編號(hào)_jpg則是數(shù)據(jù)早期從其他格式轉(zhuǎn)換時(shí)遺留的后綴不必特別處理。實(shí)際使用時(shí)我一般會(huì)寫一段腳本統(tǒng)一重命名避免后續(xù)處理時(shí)因?yàn)槲募锏奶厥庾址a(chǎn)生編碼問(wèn)題尤其是Windows環(huán)境直接解壓容易出現(xiàn)路徑解析故障。2.2 讀懂COCO標(biāo)注JSONimages、annotations、categories三個(gè)數(shù)組COCO標(biāo)注格式的核心是JSON文件里面有三個(gè)主要數(shù)組。我拆過(guò)不少數(shù)據(jù)集絕大多數(shù)問(wèn)題都出在這個(gè)JSON的某些字段與圖片實(shí)際內(nèi)容不匹配。先看一個(gè)典型的COCO JSON骨架{ images: [ { id: 1, file_name: COVID19-8-_jpg.rf.d1e42a6f39394fad7a82891eb20d0f82.jpg, width: 512, height: 512 } ], annotations: [ { id: 1, image_id: 1, category_id: 1, bbox: [120, 80, 240, 300], area: 72000, iscrowd: 0 } ], categories: [ {id: 1, name: covid}, {id: 2, name: normal}, {id: 3, name: pneumonia} ] }images數(shù)組里存的是每張圖片的基本信息id是全局唯一編號(hào)file_name對(duì)應(yīng)實(shí)際圖片文件名width和height是圖片原始尺寸。如果訓(xùn)練時(shí)發(fā)現(xiàn)目標(biāo)框位置偏了先查這個(gè)字段和真實(shí)圖片尺寸是否一致。annotations數(shù)組是核心每條記錄對(duì)應(yīng)一個(gè)標(biāo)注框。image_id關(guān)聯(lián)到images里的某張圖category_id關(guān)聯(lián)到categories里的某個(gè)類別bbox是[左上角x, 左上角y, 框?qū)? 框高]四元組area是框面積。iscrowd為0表示這是一個(gè)普通目標(biāo)框。categories數(shù)組定義了類別編號(hào)和名稱的映射。不同數(shù)據(jù)集的編號(hào)起點(diǎn)不一樣有的從0開始有的從1開始訓(xùn)練前必須確認(rèn)清楚。我習(xí)慣用一段Python腳本快速體檢這個(gè)JSONimport json from collections import Counter with open(train/_annotations.coco.json, r, encodingutf-8) as f: coco json.load(f) print(圖片數(shù)量:, len(coco[images])) print(標(biāo)注框數(shù)量:, len(coco[annotations])) print(類別定義:, coco[categories]) # 統(tǒng)計(jì)每張圖的標(biāo)注框數(shù)找出空標(biāo)注圖 img_id_to_anns Counter(a[image_id] for a in coco[annotations]) empty_imgs [img[file_name] for img in coco[images] if img[id] not in img_id_to_anns] print(無(wú)標(biāo)注圖片數(shù)量:, len(empty_imgs)) if empty_imgs: print(示例:, empty_imgs[:5]) # 統(tǒng)計(jì)各類別bbox數(shù)量 cat_counter Counter(a[category_id] for a in coco[annotations]) print(各類別標(biāo)注數(shù)量:, dict(cat_counter))這段腳本做三件事輸出總圖片數(shù)、總標(biāo)注框數(shù)、類別定義找出沒(méi)有任何標(biāo)注的圖片統(tǒng)計(jì)每個(gè)類別的框數(shù)量。如果無(wú)標(biāo)注圖片占比過(guò)高訓(xùn)練時(shí)會(huì)頻繁出現(xiàn)無(wú)目標(biāo)報(bào)錯(cuò)要考慮是否剔除或補(bǔ)充標(biāo)注。實(shí)際拆包時(shí)我遇到過(guò)一種情況圖片有1765張但標(biāo)注框只有1300多個(gè)說(shuō)明有一部分圖是純背景或標(biāo)注遺漏。這類圖對(duì)訓(xùn)練不全是壞事可以當(dāng)作負(fù)樣本但比例失衡會(huì)讓模型偏向誤報(bào)。一般我建議不超過(guò)總量的15%。2.3 三分類的標(biāo)注細(xì)節(jié)胸部X光片的邊界框特點(diǎn)這是一個(gè)三分類目標(biāo)檢測(cè)數(shù)據(jù)集類別為新冠肺炎、正常、肺炎。肺部X光片的目標(biāo)檢測(cè)和自然場(chǎng)景檢測(cè)不太一樣bbox標(biāo)注通常是圍繞肺部區(qū)域或病灶陰影畫的邊界相對(duì)模糊。從標(biāo)注實(shí)踐看X光胸片里的病灶框有兩種畫法一種是框住整個(gè)肺野把左右肺都包進(jìn)去另一種是只框住可見(jiàn)的磨玻璃陰影或?qū)嵶儏^(qū)域。這個(gè)數(shù)據(jù)集更接近后者因?yàn)橐獏^(qū)分新冠肺炎和普通肺炎靠的是病灶形態(tài)和位置差異框住全肺野會(huì)丟失空間判別信息??虻某叽绶植家膊痪鶆?。新冠病灶可能是一個(gè)小斑片也可能是一大片實(shí)變。如果你的訓(xùn)練代碼里用了固定的anchor尺寸小目標(biāo)召回率會(huì)很低。COCO格式里area字段就是為這個(gè)準(zhǔn)備的你可以直接用它來(lái)分析目標(biāo)尺度分布import numpy as np areas [a[area] for a in coco[annotations]] areas np.array(areas) print(f最小面積: {areas.min():.1f}, 最大面積: {areas.max():.1f}) print(f面積中位數(shù): {np.median(areas):.1f}) print(f小于32x32的框占比: {(areas 1024).mean() * 100:.2f}%)尺寸分布統(tǒng)計(jì)決定了你要不要調(diào)整模型的anchor策略。如果在YOLOv8里用默認(rèn)anchor模型會(huì)自己學(xué)習(xí)但前提是你給的訓(xùn)練數(shù)據(jù)框尺寸分布不能過(guò)于極端。用這份數(shù)據(jù)訓(xùn)練之前我建議先跑一遍這個(gè)統(tǒng)計(jì)心里有個(gè)底。3. 把COCO轉(zhuǎn)成YOLO格式并訓(xùn)練檢測(cè)模型轉(zhuǎn)換腳本與訓(xùn)練參數(shù)COCO JSON不能直接喂給YOLO系列訓(xùn)練器YOLO系列使用的是歸一化后的txt格式標(biāo)簽每行一組類別和坐標(biāo)。這一章我把格式轉(zhuǎn)換、數(shù)據(jù)劃分、訓(xùn)練參數(shù)這三步完整串起來(lái)給出可直接運(yùn)行的腳本和YOLOv8訓(xùn)練命令。3.1 轉(zhuǎn)換前的準(zhǔn)備裝好依賴并核對(duì)標(biāo)注完整性環(huán)境需要Python 3.8以上安裝PyTorch和ultralytics。建議創(chuàng)建一個(gè)干凈的虛擬環(huán)境避免依賴沖突。安裝命令如下pip install ultralytics opencv-python pycocotoolsultralytics是YOLOv8的訓(xùn)練和推理庫(kù)pycocotools用來(lái)做COCO格式的數(shù)據(jù)評(píng)估opencv-python負(fù)責(zé)圖片讀取和尺寸校驗(yàn)。裝完后先用上一章體檢腳本確認(rèn)標(biāo)注JSON完好特別是所有標(biāo)注框的坐標(biāo)都在圖片范圍內(nèi)不越界。這一步容易踩坑的地方在于有些導(dǎo)出的COCO JSON里images字段的寬高是縮略圖尺寸但磁盤上的原始圖片分辨率更高訓(xùn)練時(shí)會(huì)直接按實(shí)際圖片尺寸讀取導(dǎo)致坐標(biāo)比例完全錯(cuò)位。校驗(yàn)方法很簡(jiǎn)單隨機(jī)抽幾張圖用OpenCV讀取真實(shí)寬高與JSON里記錄的寬高比對(duì)。不一致的話轉(zhuǎn)換腳本里就要以實(shí)際圖片尺寸為準(zhǔn)。3.2 COCO轉(zhuǎn)YOLO格式一張圖對(duì)應(yīng)一個(gè)txt標(biāo)簽文件YOLO格式的標(biāo)簽規(guī)則是每張圖片的名字去掉后綴后對(duì)應(yīng)一個(gè)同名txt文件放在labels/xxx/目錄下。txt文件每一行表示一個(gè)目標(biāo)框類別id x_center y_center 歸一化寬 歸一化高歸一化指的是除以圖片實(shí)際寬高。轉(zhuǎn)換腳本如下import json import os import cv2 from pathlib import Path def coco_to_yolo(coco_json_path, image_root, label_root): with open(coco_json_path, r, encodingutf-8) as f: coco json.load(f) # 建立image_id到圖片信息的映射 img_info {img[id]: img for img in coco[images]} # 建立category_id到Y(jié)OLO類別索引的映射注意類別id從0開始 # 這里假設(shè)類別id連續(xù)且從1開始 cat_id_to_yolo {cat[id]: idx for idx, cat in enumerate(coco[categories])} print(類別映射:, cat_id_to_yolo) # 按image_id將標(biāo)注框分組 anns_by_img {} for ann in coco[annotations]: img_id ann[image_id] anns_by_img.setdefault(img_id, []).append(ann) label_root Path(label_root) label_root.mkdir(parentsTrue, exist_okTrue) converted_count 0 for img_id, anns in anns_by_img.items(): img img_info[img_id] img_path Path(image_root) / img[file_name] # 讀取圖片真實(shí)寬高防止JSON里的尺寸與實(shí)際不一致 if img_path.exists(): height, width cv2.imread(str(img_path)).shape[:2] else: width, height img[width], img[height] # 寫入對(duì)應(yīng)的txt標(biāo)簽文件 txt_path label_root / (Path(img[file_name]).stem .txt) lines [] for ann in anns: x, y, w, h ann[bbox] # bbox坐標(biāo)歸一化并轉(zhuǎn)為中心點(diǎn)格式 x_center (x w / 2) / width y_center (y h / 2) / height w_norm w / width h_norm h / height # 越界保護(hù)YOLO標(biāo)簽要求坐標(biāo)在0~1之間超出則截?cái)?x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w_norm min(max(w_norm, 0.0), 1.0) h_norm min(max(h_norm, 0.0), 1.0) cat_idx cat_id_to_yolo[ann[category_id]] lines.append(f{cat_idx} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}) if lines: txt_path.write_text(\n.join(lines), encodingutf-8) converted_count 1 else: print(f警告: {img[file_name]} 無(wú)標(biāo)注跳過(guò)) print(f轉(zhuǎn)換完成共生成 {converted_count} 個(gè)標(biāo)簽文件)這段腳本的設(shè)計(jì)邏輯有四個(gè)關(guān)鍵點(diǎn)。第一讀取圖片真實(shí)寬高再歸一化保證坐標(biāo)比例正確這叫“以實(shí)際為準(zhǔn)”。第二類別id做了重映射兼容COCO類別id從1開始、YOLO要求從0開始的問(wèn)題。第三坐標(biāo)做了越界截?cái)啾苊鈽?biāo)注框邊緣超出圖片范圍導(dǎo)致訓(xùn)練報(bào)錯(cuò)。第四無(wú)標(biāo)注圖片不生成標(biāo)簽文件保證數(shù)據(jù)干凈。執(zhí)行時(shí)把對(duì)應(yīng)路徑替換成你解壓后的實(shí)際路徑即可python coco_to_yolo.py3.3 數(shù)據(jù)劃分與YAML配置文件轉(zhuǎn)換完成后把圖片和標(biāo)簽按7:2:1比例劃分成train、val、test三份。劃分時(shí)最忌諱直接random.shuffle整個(gè)列表這樣容易出現(xiàn)同一張圖的數(shù)據(jù)泄漏到多個(gè)集合里。用train_test_split按文件名去重劃分即可import os import random import shutil from pathlib import Path random.seed(42) image_files list(Path(images).glob(*.jpg)) random.shuffle(image_files) train_ratio, val_ratio, test_ratio 0.7, 0.2, 0.1 n len(image_files) train_files image_files[:int(n * train_ratio)] val_files image_files[int(n * train_ratio):int(n * (train_ratio val_ratio))] test_files image_files[int(n * (train_ratio val_ratio)):] def copy_files(file_list, img_dst, label_dst, label_src): img_dst.mkdir(parentsTrue, exist_okTrue) label_dst.mkdir(parentsTrue, exist_okTrue) for img_path in file_list: shutil.copy(img_path, img_dst / img_path.name) label_path label_src / (img_path.stem .txt) if label_path.exists(): shutil.copy(label_path, label_dst / label_path.name) copy_files(train_files, Path(dataset/train/images), Path(dataset/train/labels), Path(labels)) copy_files(val_files, Path(dataset/val/images), Path(dataset/val/labels), Path(labels)) copy_files(test_files, Path(dataset/test/images), Path(dataset/test/labels), Path(labels)) print(ftrain: {len(train_files)}, val: {len(val_files)}, test: {len(test_files)})然后寫YOLOv8的數(shù)據(jù)配置文件。在covid.yaml里定義訓(xùn)練和驗(yàn)證路徑以及三個(gè)類別的名稱注意順序要和轉(zhuǎn)換腳本里的類別索引一致path: /absolute/path/to/dataset train: train/images val: val/images test: test/images names: 0: covid 1: normal 2: pneumonia這里如果類別順序亂了比如把normal放到了0號(hào)位整個(gè)訓(xùn)練就白費(fèi)了。我建議把轉(zhuǎn)換腳本里打印出來(lái)的類別映射和這個(gè)yaml里的names逐行核對(duì)一次。3.4 訓(xùn)練命令與參數(shù)選擇數(shù)據(jù)路徑配好之后直接執(zhí)行YOLOv8訓(xùn)練。第一次訓(xùn)練建議用yolov8n這種小模型跑通全流程確認(rèn)沒(méi)有報(bào)錯(cuò)后再換大模型調(diào)精度yolo detect train \ datacovid.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ workers4 \ patience20 \ saveTrue參數(shù)含義如下epochs是訓(xùn)練輪數(shù)胸片檢測(cè)任務(wù)100輪基本夠收斂imgsz是輸入分辨率X光胸片紋理細(xì)節(jié)多有條件可以用640顯存不夠降到512batch是批大小16GB顯存的顯卡建議設(shè)16以內(nèi)patience是早停輪數(shù)驗(yàn)證集mAP連續(xù)20輪不漲就提前停止節(jié)省時(shí)間。model用yolov8n.pt會(huì)在ImageNet預(yù)訓(xùn)練權(quán)重基礎(chǔ)上做遷移學(xué)習(xí)收斂速度明顯快于隨機(jī)初始化。訓(xùn)練日志里重點(diǎn)看兩個(gè)指標(biāo)box_loss是否持續(xù)下降val mAP50是否穩(wěn)步上升。如果訓(xùn)練了幾輪后box_loss不降反升大概率是標(biāo)簽出錯(cuò)了停下來(lái)檢查數(shù)據(jù)。訓(xùn)練完成后權(quán)重保存在runs/detect/train/weights/best.pt后面做評(píng)估和推理都用這個(gè)文件。4. 訓(xùn)練與標(biāo)注的常見(jiàn)問(wèn)題排查從數(shù)據(jù)翻車到模型欠擬合這個(gè)數(shù)據(jù)集我實(shí)際跑下來(lái)踩了不少坑這里整理出幾條最常見(jiàn)的問(wèn)題每一條都按“現(xiàn)象→原因→解決”來(lái)講避免你在同樣的地方浪費(fèi)時(shí)間。4.1 轉(zhuǎn)換后標(biāo)簽文件為空訓(xùn)練時(shí)提示無(wú)目標(biāo)現(xiàn)象訓(xùn)練日志里出現(xiàn)大量類似WARNING: no labels found in ...的警告某個(gè)類別的目標(biāo)數(shù)始終為0。原因COCO JSON里的images字段寬度高度與磁盤上圖片真實(shí)尺寸不一致。Roboflow導(dǎo)出時(shí)經(jīng)常會(huì)對(duì)圖片做resize而原始COCO JSON里記錄的還是舊尺寸。轉(zhuǎn)換腳本用img[width]做歸一化時(shí)所有坐標(biāo)比例都是錯(cuò)的生成的txt里全是負(fù)數(shù)或大于1的值被過(guò)濾后就成了空標(biāo)簽。解決轉(zhuǎn)換腳本改成cv2.imread讀取真實(shí)寬高。如果確實(shí)不想在轉(zhuǎn)換時(shí)讀圖至少隨機(jī)抽10張圖比對(duì)JSON尺寸和實(shí)際尺寸誤差超過(guò)2%就要換用真實(shí)尺寸。從那以后我每次寫轉(zhuǎn)換腳本都強(qiáng)制檢查這一步。4.2 訓(xùn)練時(shí)圖片加載就報(bào)錯(cuò)提示圖片不存在現(xiàn)象FileNotFoundError: ... does not exist或者提示某張圖片路徑下找不到文件。原因數(shù)據(jù)劃分時(shí)沒(méi)有做統(tǒng)一重命名圖片在train和val里復(fù)用或者文件名里的特殊字符在不同操作系統(tǒng)中表現(xiàn)不同。這個(gè)數(shù)據(jù)集的原始文件名里帶-和_Windows解壓后路徑拼接時(shí)沒(méi)問(wèn)題但如果在Linux或者容器內(nèi)掛載Windows分區(qū)路徑分隔符和大小寫敏感問(wèn)題就會(huì)暴露。解決在劃分?jǐn)?shù)據(jù)之前先把所有圖片統(tǒng)一重命名為純數(shù)字編號(hào)例如0001.jpg、0002.jpg同時(shí)修改JSON里對(duì)應(yīng)的file_name字段。重命名腳本很簡(jiǎn)單但能避免一大半路徑相關(guān)的問(wèn)題。4.3 三種類別數(shù)量懸殊模型偏向正常類現(xiàn)象訓(xùn)練結(jié)束后normal類別的精確率很高但covid類別的召回率只有零點(diǎn)幾約等于沒(méi)檢出。原因數(shù)據(jù)分布不均衡。一份典型的胸片數(shù)據(jù)集中正常樣本數(shù)量往往遠(yuǎn)大于新冠和肺炎樣本。模型在訓(xùn)練時(shí)看到大量正常樣本決策邊界傾向于“寧可漏掉少數(shù)類也不誤報(bào)多數(shù)類”。解決三類手段可以疊加。第一在YOLO的yaml里給少樣本類別增加loss權(quán)重第二做一個(gè)簡(jiǎn)單的過(guò)采樣讓每個(gè)epoch里新冠圖片重復(fù)出現(xiàn)兩次第三數(shù)據(jù)增強(qiáng)時(shí)對(duì)新冠類樣本用更強(qiáng)的隨機(jī)翻轉(zhuǎn)和光照擾動(dòng)。實(shí)測(cè)下來(lái)loss權(quán)重和過(guò)采樣組合效果最穩(wěn)定。4.4 灰度X光圖訓(xùn)練欠擬合紋理特征學(xué)不出來(lái)現(xiàn)象訓(xùn)練loss下降緩慢驗(yàn)證集mAP勉強(qiáng)到0.5就卡住不動(dòng)了。原因X光胸片本質(zhì)是灰度圖而數(shù)據(jù)集導(dǎo)出時(shí)可能被存成了三通道的偽彩色圖或單通道灰度圖。YOLO系列默認(rèn)輸入是RGB三通道如果喂進(jìn)去的是單通道灰度圖imgsz640下信息量少了一個(gè)數(shù)量級(jí)特征提取器學(xué)不到足夠的紋理細(xì)節(jié)。解決在訓(xùn)練前統(tǒng)一把圖片轉(zhuǎn)成RGB三通道并做一次CLAHE自適應(yīng)直方圖均衡增強(qiáng)。這個(gè)增強(qiáng)對(duì)X光片特別有效能讓肺野和病灶的對(duì)比度拉開。從實(shí)踐看加了CLAHE之后新冠病灶的小斑片區(qū)域檢出率會(huì)有明顯提升。4.5 圖像分辨率過(guò)大導(dǎo)致顯存溢出現(xiàn)象CUDA out of memory4090顯卡也撐不住。原因胸片原始圖分辨率通常在2000x2000以上YOLO默認(rèn)的imgsz640會(huì)把大圖縮到640x640顯存不夠是因?yàn)閎atch設(shè)太大或者模型本身選了yolov8x。解決把batch降到4或8imgsz改到512。如果還要用大模型就得換顯存更大的卡。做實(shí)驗(yàn)先用yolov8n跑通調(diào)參數(shù)時(shí)再逐步增大。5. 評(píng)估與進(jìn)階用法用mAP驗(yàn)證結(jié)果再做數(shù)據(jù)增強(qiáng)與模型壓縮訓(xùn)練完成后怎么衡量這份數(shù)據(jù)集的檢出效果以及怎么把模型調(diào)得更好用是這一章要解決的事。評(píng)估階段我會(huì)跳開官方說(shuō)法用一個(gè)吃過(guò)虧的人的角度來(lái)講。5.1 在驗(yàn)證集上評(píng)估m(xù)AP、召回率與混淆矩陣用最優(yōu)權(quán)重跑一遍驗(yàn)證集和測(cè)試集yolo detect val \ datacovid.yaml \ modelruns/detect/train/weights/best.pt \ conf0.25 \ iou0.5 \ save_jsonTrueconf是置信度閾值低于這個(gè)值的框會(huì)被過(guò)濾iou是NMS的IoU閾值用于去重。save_jsonTrue會(huì)輸出預(yù)測(cè)結(jié)果的COCO格式JSON方便用pycocotools計(jì)算更詳細(xì)的指標(biāo)。驗(yàn)證完成后去runs/detect/val/目錄看指標(biāo)文件。胸片檢測(cè)重點(diǎn)關(guān)注mAP50和mAP50-95兩個(gè)指標(biāo)里那個(gè)小的。mAP50只要框大概對(duì)得上就算命中而mAP50-95要求框非常精準(zhǔn)差一點(diǎn)就算錯(cuò)。醫(yī)療影像落地場(chǎng)景里目標(biāo)框位置稍微偏一點(diǎn)都可能影響后續(xù)診斷判斷所以兩個(gè)指標(biāo)都要看。如果mAP50不錯(cuò)但mAP50-95很低說(shuō)明模型的定位精度不行可以考慮增加回歸loss權(quán)重。測(cè)試集上再看一眼confusion_matrix.png。正常情況下normal列的對(duì)角線數(shù)值遠(yuǎn)高于非對(duì)角線。如果covid被大規(guī)模誤分類到normal里說(shuō)明兩類樣本的特征空間重疊度高需要補(bǔ)充更多新冠樣本的特征。5.2 進(jìn)階數(shù)據(jù)增強(qiáng)與遷移學(xué)習(xí)配置YOLO的增強(qiáng)參數(shù)可以在yaml里直接配置。針對(duì)X光胸片我建議這樣配augment: mosaic: 0.5 flipud: 0.5 fliplr: 0.0 hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.2mosaic把四張圖拼成一張能讓模型在小目標(biāo)上見(jiàn)多識(shí)廣flipud上下翻轉(zhuǎn)對(duì)胸片特別有用因?yàn)榉稳~上下形態(tài)有差異但沒(méi)有方向性fliplr水平翻轉(zhuǎn)對(duì)胸片要慎用心臟位置會(huì)左右顛倒有些醫(yī)生標(biāo)注時(shí)會(huì)區(qū)分左右肺葉。hsv_h和hsv_s建議設(shè)為0因?yàn)閄光片是灰度影像色調(diào)和飽和度擾動(dòng)沒(méi)有意義還會(huì)干擾模型。hsv_v可以保留一個(gè)小值模擬不同曝光條件下的亮度差異。如果想進(jìn)一步提升精度而訓(xùn)練時(shí)間有限可以在best.pt基礎(chǔ)上繼續(xù)訓(xùn)練yolo detect train \ datacovid.yaml \ modelruns/detect/train/weights/best.pt \ epochs50 \ lr00.0001這種做法是凍結(jié)特征提取器、只微調(diào)檢測(cè)頭學(xué)習(xí)率調(diào)低一個(gè)數(shù)量級(jí)避免破壞已經(jīng)學(xué)到的特征。5.3 模型壓縮與部署思路實(shí)驗(yàn)階段的模型通常不是最終交付形態(tài)。胸片檢測(cè)如果要做成服務(wù)端接口我一般會(huì)把YOLOv8的權(quán)重導(dǎo)出成TensorRT engine推理速度能提升一到兩倍yolo export \ modelruns/detect/train/weights/best.pt \ formatengine \ imgsz640 \ halfTrue或者先用modelprune做通道剪枝把參數(shù)整體減到原模型的三分之一再量化。壓縮后的模型精度會(huì)掉一點(diǎn)但mAP50一般不會(huì)低于訓(xùn)練時(shí)的90%對(duì)大部分場(chǎng)景是可接受的。我從那以后每次拿到新數(shù)據(jù)集都先寫一個(gè)統(tǒng)計(jì)腳本看三件事各類別的bbox數(shù)量、框尺寸分布、無(wú)標(biāo)注比例。這三項(xiàng)數(shù)據(jù)能預(yù)判訓(xùn)練過(guò)程中八成以上的問(wèn)題。希望這些拆解和分析能幫到你讓你少走一次彎路。本文還有配套的精品資源點(diǎn)擊獲取