練全流程與避坑指南)
簡介本資源為面向YOLO系列目標(biāo)檢測算法的深色皮膚病變圖像數(shù)據(jù)集適用于醫(yī)學(xué)圖像識(shí)別、皮膚病輔助診斷等方向的算法訓(xùn)練與驗(yàn)證適合具備一定深度學(xué)習(xí)基礎(chǔ)的目標(biāo)檢測學(xué)習(xí)者與研究人員使用。壓縮包共703個(gè)文件包含234張jpg圖像、234個(gè)txt標(biāo)簽、234個(gè)xml標(biāo)簽及1個(gè)data.yaml配置文件整體約9.16MB已按訓(xùn)練與測試需求劃分完畢可直接投入模型訓(xùn)練。標(biāo)簽覆蓋白糠疹、炎癥后色素沉著過度、特發(fā)性黑色素沉著癥、匯流和網(wǎng)狀、白癜風(fēng)等類別同時(shí)提供YOLO格式與VOC格式兩套標(biāo)注兼容yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流版本。YOLO格式采用歸一化中心點(diǎn)與寬高坐標(biāo)便于直接讀取VOC格式則方便與其他框架對(duì)接。目前已有60人學(xué)習(xí)下載可作為深色皮膚病變檢測的基線數(shù)據(jù)幫助讀者快速搭建訓(xùn)練流程、驗(yàn)證模型效果并開展類別對(duì)比實(shí)驗(yàn)。1. 深色皮膚病變檢測234 張圖像的數(shù)據(jù)集到底能不能撐起一個(gè) YOLO 模型深色皮膚上的色素性病變長期是皮膚影像 AI 里被忽視的一塊。白糠疹、炎癥后色素沉著過度、特發(fā)性黑色素沉著癥、匯流和網(wǎng)狀型色素沉著、白癜風(fēng)這幾類在 Fitzpatrick IV–VI 型皮膚上表現(xiàn)出的顏色對(duì)比度低、邊界模糊、與正常皮膚色差小用常規(guī)皮膚數(shù)據(jù)集訓(xùn)出來的 YOLO 模型往往直接翻車。這個(gè)標(biāo)題指向的就是一個(gè)專門針對(duì)深色皮膚、234 張圖像帶標(biāo)簽、覆蓋上述五類病變的目標(biāo)檢測數(shù)據(jù)集配合 YOLO 算法做檢測與分類。它解決的核心問題是在公開皮膚數(shù)據(jù)集幾乎全是淺色皮膚樣本的現(xiàn)狀下給深色皮膚病變檢測提供一個(gè)可用的起點(diǎn)。適合誰做醫(yī)學(xué)影像目標(biāo)檢測的算法工程師、皮膚科 AI 輔助診斷方向的研究生、以及想用 YOLO 在垂直小數(shù)據(jù)集上跑通全流程的從業(yè)者。234 張不算多但足夠把數(shù)據(jù)管線、標(biāo)注格式、訓(xùn)練策略和評(píng)估方法完整走一遍。2. 從壓縮包到 YOLO 可訓(xùn)練格式數(shù)據(jù)管線的搭建與驗(yàn)證2.1 先搞清楚壓縮包里有什么再?zèng)Q定怎么拆拿到一個(gè)帶標(biāo)簽的圖像數(shù)據(jù)集壓縮包第一件事不是急著解壓跑訓(xùn)練而是把目錄結(jié)構(gòu)和標(biāo)注格式摸清楚。皮膚病變數(shù)據(jù)集常見的標(biāo)注格式有三種PASCAL VOC 的 XML、COCO 的 JSON、以及 YOLO 的 TXT。標(biāo)題里寫的是「帶標(biāo)簽」但沒說是哪種所以需要先做格式探測。解壓后先看目錄樹# 查看壓縮包內(nèi)容不急著全解 unzip -l skin_lesion_234.zip | head -50 # 解壓到工作目錄 mkdir -p ~/datasets/skin_lesion unzip skin_lesion_234.zip -d ~/datasets/skin_lesion # 看目錄結(jié)構(gòu) find ~/datasets/skin_lesion -maxdepth 3 -type d如果看到Annotations/和JPEGImages/兩個(gè)目錄基本可以判定是 VOC 格式如果看到labels/和images/且 labels 里是.txt那就是 YOLO 格式如果只有一個(gè)annotations.json那是 COCO。# 統(tǒng)計(jì)圖像數(shù)量和標(biāo)注文件數(shù)量 find ~/datasets/skin_lesion -name *.jpg -o -name *.png | wc -l find ~/datasets/skin_lesion -name *.xml -o -name *.txt -o -name *.json | wc -l # 看一個(gè)標(biāo)注文件長什么樣 head -30 ~/datasets/skin_lesion/Annotations/$(ls ~/datasets/skin_lesion/Annotations | head -1)這一步的邏輯說明圖像數(shù)量和標(biāo)注文件數(shù)量必須對(duì)得上234 張圖像就應(yīng)該有 234 個(gè)標(biāo)注文件。如果對(duì)不上說明有圖像沒標(biāo)或者標(biāo)注文件命名和圖像不對(duì)應(yīng)這是小數(shù)據(jù)集最常見的坑。參數(shù)上-maxdepth 3是為了避免目錄太深刷屏head -50是先看個(gè)大概。2.2 VOC 轉(zhuǎn) YOLO轉(zhuǎn)換腳本與四個(gè)邊界坑如果標(biāo)注是 VOC XML 格式需要轉(zhuǎn)成 YOLO 的歸一化 TXT。YOLO 格式每行是class_id x_center y_center width height全部歸一化到 0–1。轉(zhuǎn)換腳本如下import os import xml.etree.ElementTree as ET from pathlib import Path # 類別映射按你的數(shù)據(jù)集實(shí)際類別順序改 CLASS_MAP { pityriasis_alba: 0, # 白糠疹 postinflammatory_hyperpigmentation: 1, # 炎癥后色素沉著過度 idiopathic_guttate_hypomelanosis: 2, # 特發(fā)性黑色素沉著癥 confluent_reticulate_papillomatosis: 3, # 匯流和網(wǎng)狀 vitiligo: 4 # 白癜風(fēng) } def voc_to_yolo(xml_path, img_w, img_h, out_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() if cls_name not in CLASS_MAP: continue cls_id CLASS_MAP[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 邊界裁剪防止標(biāo)注越界導(dǎo)致歸一化后為負(fù)或大于1 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue # 跳過無效框 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))邏輯說明這個(gè)腳本做了三件關(guān)鍵事。第一類別映射用字典硬編碼避免順序錯(cuò)亂第二邊界裁剪把標(biāo)注框限制在圖像范圍內(nèi)因?yàn)樾?shù)據(jù)集手工標(biāo)注經(jīng)常出現(xiàn)框超出圖像邊界的情況第三跳過無效框防止寬高為負(fù)或零。參數(shù)上img_w和img_h需要從圖像實(shí)際尺寸讀取不能硬編碼因?yàn)槠つw圖像可能來自不同設(shè)備分辨率不統(tǒng)一。四個(gè)邊界坑一是標(biāo)注框坐標(biāo)是浮點(diǎn)數(shù)但 XML 里可能寫成整數(shù)float()轉(zhuǎn)換不能省二是類別名大小寫和空格strip()必須加三是有些 XML 里object節(jié)點(diǎn)可能沒有bndbox需要 try-except 包住四是歸一化后坐標(biāo)必須保留足夠小數(shù)位.6f是經(jīng)驗(yàn)值太少會(huì)導(dǎo)致小目標(biāo)框精度丟失。2.3 劃分訓(xùn)練集驗(yàn)證集234 張?jiān)趺捶植挪焕速M(fèi)234 張圖像按 8:2 分是 187 訓(xùn)練、47 驗(yàn)證。但皮膚病變類別不平衡如果隨機(jī)分可能出現(xiàn)某個(gè)類別在驗(yàn)證集里一張都沒有。正確做法是按類別分層抽樣import random from collections import defaultdict from pathlib import Path def stratified_split(label_dir, img_dir, val_ratio0.2, seed42): random.seed(seed) # 按主類別分組 cls_to_files defaultdict(list) for lbl in Path(label_dir).glob(*.txt): with open(lbl) as f: lines f.readlines() if not lines: continue # 取第一個(gè)框的類別作為該圖主類別 main_cls lines[0].split()[0] cls_to_files[main_cls].append(lbl.stem) train, val [], [] for cls, files in cls_to_files.items(): random.shuffle(files) n_val max(1, int(len(files) * val_ratio)) # 每類至少1張進(jìn)驗(yàn)證 val.extend(files[:n_val]) train.extend(files[n_val:]) return train, val邏輯說明按主類別分組后每個(gè)類別至少抽 1 張進(jìn)驗(yàn)證集保證驗(yàn)證集覆蓋所有類別。seed42是為了可復(fù)現(xiàn)。參數(shù)上val_ratio0.2是 234 張這種量級(jí)的常用值如果類別特別少可以調(diào)到 0.15。提示劃分完之后一定要打印每個(gè)類別的訓(xùn)練/驗(yàn)證數(shù)量分布確認(rèn)沒有類別在驗(yàn)證集里為零。3. YOLO 訓(xùn)練配置小數(shù)據(jù)集上的參數(shù)怎么調(diào)才不玄學(xué)3.1 選 YOLOv8 還是 YOLOv5小數(shù)據(jù)集的選型理由234 張圖像屬于典型的小數(shù)據(jù)集。YOLOv8 和 YOLOv5 都能跑但選型要看幾個(gè)實(shí)際因素。YOLOv8 的 anchor-free 設(shè)計(jì)在小數(shù)據(jù)集上收斂更快因?yàn)椴恍枰垲?anchor 框YOLOv5 的 anchor-based 設(shè)計(jì)在標(biāo)注框尺寸分布集中時(shí)表現(xiàn)更穩(wěn)。皮膚病變的標(biāo)注框通常比較集中病變區(qū)域占圖像比例中等兩者差距不大。我一般會(huì)選 YOLOv8n 或 YOLOv8s原因是第一n 和 s 的參數(shù)量小234 張圖像用大模型必然過擬合第二YOLOv8 的 CLI 和 Python API 更統(tǒng)一調(diào)試方便第三預(yù)訓(xùn)練權(quán)重在 COCO 上訓(xùn)過遷移到皮膚圖像雖然域差異大但底層紋理特征仍有復(fù)用價(jià)值。# 安裝 ultralytics pip install ultralytics # 驗(yàn)證安裝 yolo checks3.2 data.yaml 的寫法與三個(gè)必調(diào)參數(shù)YOLO 訓(xùn)練需要一個(gè)data.yaml描述數(shù)據(jù)集路徑和類別path: /home/user/datasets/skin_lesion_yolo train: images/train val: images/val nc: 5 names: 0: pityriasis_alba 1: postinflammatory_hyperpigmentation 2: idiopathic_guttate_hypomelanosis 3: confluent_reticulate_papillomatosis 4: vitiligo三個(gè)必調(diào)參數(shù)參數(shù)推薦值理由imgsz640皮膚圖像分辨率通常夠再大顯存吃不消batch8 或 16234 張圖batch 太大一個(gè) epoch 只有十幾步epochs100–150小數(shù)據(jù)集需要多輪但必須配合早停訓(xùn)練命令yolo detect train \ data/home/user/datasets/skin_lesion_yolo/data.yaml \ modelyolov8n.pt \ imgsz640 \ batch8 \ epochs150 \ patience30 \ lr00.001 \ lrf0.01 \ warmup_epochs5 \ augmentTrue \ mosaic0.5 \ mixup0.1 \ projectruns/skin_lesion \ nameexp1邏輯說明patience30是早停驗(yàn)證集 loss 30 輪不降就停防止過擬合。lr00.001比默認(rèn)的 0.01 小因?yàn)樾?shù)據(jù)集梯度噪聲大。mosaic0.5降低默認(rèn)的 1.0因?yàn)槠つw病變圖像拼接后可能產(chǎn)生不真實(shí)的病變組合。mixup0.1輕微混合增加泛化。3.3 數(shù)據(jù)增強(qiáng)在皮膚圖像上的邊界哪些能用哪些會(huì)翻車皮膚病變檢測的數(shù)據(jù)增強(qiáng)有特殊性。顏色抖動(dòng)hsv_h、hsv_s、hsv_v要慎用因?yàn)樯钌つw和淺色皮膚的色差本身就是分類依據(jù)過度抖動(dòng)會(huì)讓模型學(xué)到錯(cuò)誤的顏色關(guān)聯(lián)。翻轉(zhuǎn)flipud、fliplr可以用皮膚病變沒有方向性。旋轉(zhuǎn)degrees可以用小角度大角度旋轉(zhuǎn)會(huì)產(chǎn)生不真實(shí)的病變形態(tài)。# 保守增強(qiáng)配置 hsv_h0.01 hsv_s0.3 hsv_v0.3 \ degrees10.0 translate0.1 scale0.3 \ shear2.0 perspective0.0 \ flipud0.5 fliplr0.5邏輯說明hsv_h0.01幾乎不動(dòng)色調(diào)因?yàn)樯{(diào)變化會(huì)改變病變顏色。hsv_s0.3和hsv_v0.3適度調(diào)整飽和度和亮度模擬不同光照。degrees10.0小角度旋轉(zhuǎn)。perspective0.0關(guān)閉透視變換因?yàn)槠つw是平面拍攝透視變換不真實(shí)。注意如果驗(yàn)證集 mAP 在訓(xùn)練前期就很高但后期下降大概率是增強(qiáng)過強(qiáng)導(dǎo)致模型學(xué)到了增強(qiáng)后的偽特征先把 mosaic 和 mixup 關(guān)掉再試。4. 訓(xùn)練過程排查loss 不降、mAP 不動(dòng)、過擬合怎么定位4.1 loss 曲線讀法box_loss、cls_loss、dfl_loss 分別說明什么YOLOv8 訓(xùn)練輸出三個(gè) lossbox_loss邊界框回歸、cls_loss分類、dfl_loss分布焦點(diǎn)損失。正常情況三者都下降。如果 box_loss 降但 cls_loss 不降說明模型能定位但分不清類別通常是類別不平衡或標(biāo)注類別錯(cuò)誤。如果 cls_loss 降但 box_loss 不降說明分類對(duì)了但框不準(zhǔn)通常是標(biāo)注框質(zhì)量差。# 訓(xùn)練完看結(jié)果 cat runs/skin_lesion/exp1/results.csv | head -5 # 用 tensorboard 看曲線 tensorboard --logdir runs/skin_lesion4.2 驗(yàn)證集 mAP 卡在 0.3 上不去五個(gè)排查方向234 張圖像訓(xùn) YOLOmAP0.5 能到 0.5–0.7 就算不錯(cuò)。如果卡在 0.3 以下按順序排查第一標(biāo)注質(zhì)量。打開幾張驗(yàn)證集圖像把預(yù)測框和標(biāo)注框疊在一起看如果標(biāo)注框本身就不準(zhǔn)模型學(xué)不到正確邊界。第二類別定義。白糠疹和白癜風(fēng)在深色皮膚上視覺相似如果標(biāo)注時(shí)混淆模型必然分不清。第三圖像分辨率。如果原圖是 2000×3000 但訓(xùn)練時(shí)縮到 640小病變可能只剩幾十個(gè)像素。第四預(yù)訓(xùn)練權(quán)重。試試從 COCO 預(yù)訓(xùn)練換成在更大皮膚數(shù)據(jù)集上預(yù)訓(xùn)練的權(quán)重。第五學(xué)習(xí)率。lr0 太大導(dǎo)致震蕩太小導(dǎo)致收斂慢用 lr finder 找一下。# 用 YOLO 自帶的 lr finder yolo detect train datadata.yaml modelyolov8n.pt epochs10 lr00.01 lrf0.01 warmup_epochs0 # 看 runs/.../lr_finder.png4.3 過擬合的早期信號(hào)與三種正則化手段234 張圖像訓(xùn) 150 輪過擬合幾乎必然。早期信號(hào)訓(xùn)練 loss 持續(xù)降但驗(yàn)證 loss 開始升或者驗(yàn)證 mAP 在某個(gè) epoch 后不再漲。三種手段第一早停 patience 設(shè)小一點(diǎn)20–30 輪第二weight_decay 從默認(rèn) 0.0005 加到 0.001第三dropout 在 YOLOv8 里通過dropout參數(shù)控制但 YOLOv8n 本身沒有 dropout 層需要用 YOLOv8s 并手動(dòng)改模型配置。# 加 weight_decay 和 label_smoothing yolo detect train ... weight_decay0.001 label_smoothing0.1邏輯說明label_smoothing0.1讓分類標(biāo)簽不再是硬 0/1而是 0.1/0.9防止模型對(duì)訓(xùn)練樣本過度自信。weight_decay0.001增大 L2 正則化強(qiáng)度。5. 避坑與常見問題小數(shù)據(jù)集訓(xùn) YOLO 的血淚經(jīng)驗(yàn)5.1 現(xiàn)象訓(xùn)練時(shí) mAP 很高推理時(shí)框全錯(cuò)原因驗(yàn)證集和訓(xùn)練集劃分時(shí)沒有按類別分層驗(yàn)證集里某個(gè)類別只有一兩張模型在這兩張上過擬合mAP 虛高。解決用 2.3 節(jié)的分層抽樣重新劃分確保每個(gè)類別在驗(yàn)證集里至少有 3–5 張。5.2 現(xiàn)象模型把白糠疹和白癜風(fēng)混為一談原因這兩類在深色皮膚上都是色素減退視覺特征高度重疊234 張圖像里如果兩類樣本數(shù)量差異大模型會(huì)偏向多數(shù)類。解決檢查兩類樣本數(shù)量如果差異超過 3:1對(duì)少數(shù)類做過采樣或加 class_weight。YOLOv8 不直接支持 class_weight但可以通過復(fù)制少數(shù)類圖像到訓(xùn)練集實(shí)現(xiàn)。5.3 現(xiàn)象訓(xùn)練到 50 輪后驗(yàn)證 loss 突然飆升原因?qū)W習(xí)率在訓(xùn)練后期沒有正確衰減或者 mosaic 增強(qiáng)在后期產(chǎn)生了不真實(shí)的圖像組合。解決確認(rèn)lrf0.01讓學(xué)習(xí)率從 lr0 線性降到 lr0×0.01同時(shí)在最后 20 輪關(guān)閉 mosaicclose_mosaic20。5.4 現(xiàn)象推理時(shí)同一張圖每次框的位置都不一樣原因YOLO 推理時(shí)有 NMS非極大值抑制如果conf閾值設(shè)得太低大量低置信度框參與 NMS結(jié)果不穩(wěn)定。解決推理時(shí)conf0.25起步根據(jù)驗(yàn)證集 PR 曲線調(diào)整。另外確認(rèn)augmentFalse推理時(shí)不要開 TTA。yolo detect predict modelruns/skin_lesion/exp1/weights/best.pt \ sourcetest_images/ conf0.25 iou0.45 augmentFalse5.5 現(xiàn)象換一臺(tái)機(jī)器訓(xùn)練結(jié)果完全不一樣原因隨機(jī)種子沒固定或者 CUDA 版本和 cuDNN 版本不同導(dǎo)致浮點(diǎn)運(yùn)算差異。解決訓(xùn)練時(shí)加seed42 deterministicTrue但注意 deterministic 會(huì)降低訓(xùn)練速度??鐧C(jī)器復(fù)現(xiàn)時(shí)記錄 CUDA、cuDNN、PyTorch 版本盡量保持一致。6. 小數(shù)據(jù)集的進(jìn)階技巧用 234 張圖像榨出可用模型234 張圖像訓(xùn) YOLO如果只跑一遍就結(jié)束大概率得到一個(gè)過擬合的模型。進(jìn)階做法是第一用交叉驗(yàn)證代替單次劃分5 折交叉驗(yàn)證能更可靠地評(píng)估模型真實(shí)性能第二用偽標(biāo)簽pseudo-labeling先用訓(xùn)練好的模型在未標(biāo)注皮膚圖像上推理把高置信度預(yù)測作為偽標(biāo)簽加入訓(xùn)練集第三用 CutMix 和 CopyPaste 增強(qiáng)把病變區(qū)域復(fù)制粘貼到正常皮膚區(qū)域生成更多訓(xùn)練樣本。# 5 折交叉驗(yàn)證的劃分邏輯 from sklearn.model_selection import KFold import numpy as np all_files list(range(234)) kf KFold(n_splits5, shuffleTrue, random_state42) for fold, (train_idx, val_idx) in enumerate(kf.split(all_files)): print(fFold {fold}: train{len(train_idx)}, val{len(val_idx)}) # 按索引生成對(duì)應(yīng)的 data.yaml 并訓(xùn)練邏輯說明5 折交叉驗(yàn)證把 234 張分成 5 份每次用 4 份訓(xùn)練 1 份驗(yàn)證最終報(bào)告 5 次驗(yàn)證 mAP 的均值和標(biāo)準(zhǔn)差。標(biāo)準(zhǔn)差大說明模型對(duì)數(shù)據(jù)劃分敏感需要更多數(shù)據(jù)或更強(qiáng)正則化。驗(yàn)證方法上除了 mAP還要看每個(gè)類別的 AP。如果某個(gè)類別 AP 特別低單獨(dú)把該類別的驗(yàn)證圖像拿出來看預(yù)測結(jié)果判斷是標(biāo)注問題還是模型問題。我一般會(huì)做一個(gè)混淆矩陣看類別之間的誤判方向。# YOLOv8 自帶混淆矩陣輸出 yolo detect val modelbest.pt datadata.yaml plotsTrue # 結(jié)果在 runs/.../confusion_matrix.png一個(gè)具體技巧如果白癜風(fēng)和白糠疹混淆嚴(yán)重可以在推理后加一個(gè)后處理規(guī)則根據(jù)病變區(qū)域的色素脫失程度用圖像灰度直方圖判斷做二次分類。這個(gè)規(guī)則不需要訓(xùn)練純圖像處理就能實(shí)現(xiàn)能顯著降低這兩類的誤判率。我自己做小數(shù)據(jù)集檢測的習(xí)慣是先跑一個(gè) baseline不管效果多差把完整管線跑通然后花 70% 的時(shí)間在數(shù)據(jù)清洗和標(biāo)注校驗(yàn)上而不是調(diào)參最后用交叉驗(yàn)證確認(rèn)模型不是靠運(yùn)氣。234 張圖像不多但足夠驗(yàn)證一個(gè)方向值不值得投入更多數(shù)據(jù)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取