品檢測(cè)數(shù)據(jù)集:9551張12類YOLO訓(xùn)練實(shí)戰(zhàn))
簡介這份安檢X光危險(xiǎn)物品識(shí)別數(shù)據(jù)集面向安檢圖像算法開發(fā)者、目標(biāo)檢測(cè)學(xué)習(xí)者與安防科研人員用于訓(xùn)練和驗(yàn)證X光場(chǎng)景下的違禁品檢測(cè)模型解決危險(xiǎn)物品自動(dòng)識(shí)別中樣本不足、類別覆蓋有限的問題。資源采用Pascal VOC與YOLO雙格式標(biāo)注包含9551張jpg圖片及一一對(duì)應(yīng)的xml與txt標(biāo)注文件共12個(gè)類別涵蓋罐頭、玻璃瓶、塑料瓶、噴霧罐、瑞士軍刀、刀片、匕首、刀、剪刀等常見安檢目標(biāo)可直接接入YOLO系列或VOC流程訓(xùn)練。壓縮包約350.67MB內(nèi)含2000個(gè)文件以1999個(gè)xml標(biāo)注文件和1個(gè)使用說明txt為主標(biāo)注信息完整便于快速構(gòu)建訓(xùn)練與評(píng)估流程。目前已有852人學(xué)習(xí)下載適合需要擴(kuò)充安檢違禁品數(shù)據(jù)、驗(yàn)證檢測(cè)算法效果或開展課程實(shí)踐的用戶參考使用。1. 安檢場(chǎng)景下的 9551 張 X 光危險(xiǎn)品數(shù)據(jù)集12 類目標(biāo)檢測(cè)到底能落地到什么程度安檢機(jī)每天吐出的 X 光圖像里刀具、噴霧罐、玻璃瓶混在行李重疊區(qū)域靠人眼盯屏幕漏檢率一直下不來。這份「安檢 X 光危險(xiǎn)物品識(shí)別檢測(cè)數(shù)據(jù)集」給的就是 9551 張真實(shí)安檢視角的 jpg 圖片每張都配了 Pascal VOC 的 xml 和 YOLO 的 txt 雙格式標(biāo)注覆蓋 12 個(gè)類別Cans、CartonDrinks、GlassBottle、PlasticBottle、SprayCans、SwissArmyKnife、Tin、VacuumCup、blade、dagger、knife、scissors。它解決的不是「有沒有數(shù)據(jù)」的問題而是「能不能直接喂給 YOLO 系列訓(xùn)練、省掉自己標(biāo)注幾千張 X 光圖」的問題。適合做安檢智能判圖、危險(xiǎn)品檢測(cè)課題、YOLOv5/v8 遷移學(xué)習(xí)驗(yàn)證的從業(yè)者和學(xué)生。下面按「這份資源是什么 → 怎么跑起來 → 坑在哪 → 怎么用得更狠」的順序拆開講。2. 雙格式標(biāo)注怎么選VOC 與 YOLO 的目錄結(jié)構(gòu)和轉(zhuǎn)換邏輯拿到壓縮包先別急著解壓訓(xùn)練得先搞清楚 VOC 和 YOLO 兩套標(biāo)注在同一批圖片上是怎么共存的。這份數(shù)據(jù)集的特點(diǎn)是「一圖三文件」一張 jpg對(duì)應(yīng)一個(gè)同名 xmlVOC和一個(gè)同名 txtYOLO沒有分割路徑的 txt也沒有 ImageSets 目錄。這意味著它省掉了 VOC 標(biāo)準(zhǔn)里那套 Main/train.txt 的劃分文件你得自己切分訓(xùn)練集和驗(yàn)證集。2.1 VOC xml 的字段含義與坐標(biāo)讀取VOC 格式的坐標(biāo)是絕對(duì)像素值原點(diǎn)在左上角xmin/ymin/xmax/ymax直接對(duì)應(yīng)圖片像素。用 Python 讀一個(gè) xml 看結(jié)構(gòu)import xml.etree.ElementTree as ET tree ET.parse(firc_xray_3342.xml) root tree.getroot() # 圖片尺寸歸一化時(shí)要用 size root.find(size) w int(size.find(width).text) h int(size.find(height).text) print(size:, w, h) for obj in root.findall(object): name obj.find(name).text # 類別名如 knife bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) print(name, xmin, ymin, xmax, ymax)邏輯說明size節(jié)點(diǎn)給出寬高是后面歸一化的分母object節(jié)點(diǎn)每個(gè)代表一個(gè)標(biāo)注框name就是 12 類里的字符串。參數(shù)上要注意有些 VOC 文件里xmax可能等于圖片寬度歸一化后是 1.0YOLO 訓(xùn)練時(shí)一般要求坐標(biāo)嚴(yán)格小于 1遇到等于 1 的框要么裁剪要么減一個(gè)像素否則部分框架會(huì)報(bào)越界。2.2 YOLO txt 的歸一化坐標(biāo)與類別索引YOLO 格式每行是class_id x_center y_center width height全部是 0~1 的相對(duì)值。類別索引取決于你訓(xùn)練時(shí) data.yaml 里 names 的順序這份數(shù)據(jù)集給的 txt 已經(jīng)按固定順序編好了號(hào)常見順序就是摘要里那 12 個(gè)類名的排列。讀一個(gè) txtwith open(firc_xray_3342.txt) as f: for line in f: c, x, y, w, h line.split() # 反歸一化回像素方便和 xml 對(duì)照校驗(yàn) print(int(c), float(x), float(y), float(w), float(h))邏輯說明c是類別索引x/y/w/h是歸一化值。參數(shù)上x_center和y_center是框中心點(diǎn)不是左上角這點(diǎn)和 VOC 的xmin/ymin完全不同做格式互轉(zhuǎn)時(shí)最容易在這里翻車。校驗(yàn)方法很簡單把 txt 反歸一化后和 xml 的像素框?qū)Ρ戎行狞c(diǎn)應(yīng)該一致寬高應(yīng)該一致。2.3 兩套格式的取舍與目錄組織實(shí)際訓(xùn)練時(shí)我一般只保留 YOLO 的 txt因?yàn)?YOLOv5/v8 原生吃 txtVOC 的 xml 留作備份和交叉校驗(yàn)。目錄按下面這樣組織最省事dataset/ ├── images/ │ ├── train/ # 約 7640 張 │ └── val/ # 約 1911 張 ├── labels/ │ ├── train/ │ └── val/ └── data.yaml劃分比例常見做法是 8:2用腳本按文件名隨機(jī)切保證同名 jpg 和 txt 進(jìn)同一個(gè)子集。注意別用shutil.move直接搬原文件先復(fù)制一份原始 9551 張留著當(dāng)后悔藥標(biāo)注清洗時(shí)還要回頭查。3. 從零跑通 YOLOv8 訓(xùn)練data.yaml、類別映射與首輪驗(yàn)證數(shù)據(jù)組織好之后真正決定能不能跑起來的是 data.yaml 和類別順序。這份數(shù)據(jù)集 12 類里有幾個(gè)容易混淆的knife、dagger、blade、SwissArmyKnife都是刀類Cans和Tin都是罐類類別順序一旦和 txt 里的索引對(duì)不上訓(xùn)練 loss 會(huì)正常下降但 mAP 一塌糊涂屬于典型的「玄學(xué)」故障。3.1 寫對(duì) data.yaml 的類別順序path: /data/xray_dataset train: images/train val: images/val nc: 12 names: 0: Cans 1: CartonDrinks 2: GlassBottle 3: PlasticBottle 4: SprayCans 5: SwissArmyKnife 6: Tin 7: VacuumCup 8: blade 9: dagger 10: knife 11: scissors邏輯說明nc必須等于 12names的鍵必須從 0 連續(xù)到 11順序要和 txt 里的 class_id 嚴(yán)格一致。參數(shù)上path寫數(shù)據(jù)集根目錄train/val寫相對(duì)路徑。驗(yàn)證順序?qū)Σ粚?duì)有個(gè)笨辦法隨便挑一張圖用labelimg或labelme打開對(duì)應(yīng) txt看框上的類別名和圖片內(nèi)容是否吻合比如玻璃瓶的框不該標(biāo)成 PlasticBottle。3.2 啟動(dòng)訓(xùn)練與關(guān)鍵超參yolo detect train \ data/data/xray_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/xray \ nameexp1邏輯說明model用預(yù)訓(xùn)練權(quán)重做遷移X 光圖像和自然圖像分布差異大但底層邊緣紋理特征仍可復(fù)用比從頭訓(xùn)收斂快。imgsz640是 YOLOv8 默認(rèn)安檢圖里小目標(biāo)blade、scissors多如果顯存夠可以上 960 或 1280小目標(biāo)召回會(huì)明顯改善。batch16按顯存調(diào)V100 上 640 分辨率跑 yolov8s 可以到 32。patience20是早停X 光數(shù)據(jù)容易過擬合別設(shè)太大。3.3 首輪驗(yàn)證看什么指標(biāo)訓(xùn)練完先別急著導(dǎo)出模型看runs/xray/exp1/下的混淆矩陣和 PR 曲線。重點(diǎn)看三件事一是knife/dagger/blade三類之間有沒有大量互相誤判這是類別定義重疊導(dǎo)致的二是GlassBottle和PlasticBottle在 X 光下顏色接近看混淆矩陣?yán)镞@兩類的對(duì)角線是否干凈三是小目標(biāo)類別的 recall如果scissors召回低于 0.5說明分辨率不夠或 anchor 不匹配下一輪調(diào)imgsz。提示首次訓(xùn)練建議先用 500 張子集跑 10 個(gè) epoch確認(rèn) data.yaml 和標(biāo)注沒問題再上全量全量跑一輪幾小時(shí)方向錯(cuò)了重來成本高。4. 標(biāo)注清洗與類別不平衡12 類里哪些坑必須先填9551 張、12 類平均每類不到 800 個(gè)框但實(shí)際分布肯定不均。刀類可能幾千個(gè)VacuumCup、CartonDrinks這種可能只有幾百個(gè)。直接開訓(xùn)少數(shù)類基本學(xué)不動(dòng)。這一章講怎么在訓(xùn)練前把標(biāo)注和分布問題處理掉。4.1 統(tǒng)計(jì)類別分布與框尺寸import os, glob from collections import Counter cnt Counter() sizes [] for txt in glob.glob(labels/train/*.txt): with open(txt) as f: for line in f: c, x, y, w, h line.split() cnt[int(c)] 1 sizes.append((float(w), float(h))) for k in sorted(cnt): print(k, cnt[k])邏輯說明這段腳本統(tǒng)計(jì)每個(gè)類別的框數(shù)量sizes收集歸一化寬高用于分析小目標(biāo)占比。參數(shù)上如果某類框數(shù)低于 300基本要單獨(dú)做增強(qiáng)或過采樣。框?qū)捀咝∮?0.05 的屬于小目標(biāo)X 光里的 blade、scissors 經(jīng)常落在這個(gè)區(qū)間訓(xùn)練時(shí)imgsz要相應(yīng)放大。4.2 針對(duì)少數(shù)類的增強(qiáng)策略YOLOv8 內(nèi)置的mosaic、mixup、copy_paste對(duì)小目標(biāo)有幫助但 X 光圖像有特殊性顏色是偽彩翻轉(zhuǎn)和旋轉(zhuǎn)物理上合理但色調(diào)抖動(dòng)hsv_h要謹(jǐn)慎因?yàn)轭伾旧頂y帶材質(zhì)信息。我一般這樣配# 在 train 參數(shù)里追加 hsv_h: 0.0 # X 光偽彩不做色調(diào)抖動(dòng) hsv_s: 0.3 hsv_v: 0.3 degrees: 10.0 # 小角度旋轉(zhuǎn)模擬行李擺放 translate: 0.1 scale: 0.5 mosaic: 1.0 copy_paste: 0.3 # 對(duì)少數(shù)類做粘貼增強(qiáng)邏輯說明hsv_h0是關(guān)鍵X 光顏色對(duì)應(yīng)材質(zhì)密度抖動(dòng)會(huì)破壞語義。copy_paste把少數(shù)類目標(biāo)摳出來貼到其他圖上對(duì)VacuumCup這類稀缺類別提升明顯。參數(shù)上degrees別超過 15安檢視角基本水平大角度旋轉(zhuǎn)不符合真實(shí)分布。4.3 標(biāo)注錯(cuò)誤的三種典型形態(tài)清洗時(shí)重點(diǎn)查三類問題一是框超出圖片邊界VOC 里xmax大于 width轉(zhuǎn) YOLO 后歸一化值大于 1二是空 txt圖片有目標(biāo)但標(biāo)注文件是空的三是類別名拼寫不一致比如SwissArmyKnife寫成SwissArmyKnif。用下面腳本批量掃import glob, os from PIL import Image for txt in glob.glob(labels/**/*.txt, recursiveTrue): img_path txt.replace(labels, images).replace(.txt, .jpg) if not os.path.exists(img_path): print(缺圖:, txt); continue w, h Image.open(img_path).size with open(txt) as f: lines f.readlines() if not lines: print(空標(biāo)注:, txt) for line in lines: c, x, y, bw, bh map(float, line.split()) if not (0 x 1 and 0 y 1 and 0 bw 1 and 0 bh 1): print(越界:, txt, line.strip())邏輯說明先檢查圖片是否存在再檢查空標(biāo)注最后檢查歸一化值范圍。參數(shù)上bw/bh等于 0 也要報(bào)出來那是無效框。跑完把問題文件列出來人工過一遍別直接刪有些是標(biāo)注規(guī)范差異不是錯(cuò)誤。5. 訓(xùn)練排查清單loss 不降、mAP 卡住、顯存爆的五個(gè)真實(shí)翻車現(xiàn)場(chǎng)這一章是血淚經(jīng)驗(yàn)合集都是我在 X 光數(shù)據(jù)集上實(shí)際踩過的。每條按「現(xiàn)象 → 原因 → 解決」寫照著排查能省不少時(shí)間。5.1 現(xiàn)象loss 正常下降但 mAP 始終在 0.01 附近原因類別索引和 data.yaml 的 names 順序錯(cuò)位模型學(xué)的是「第 0 類」但你的第 0 類實(shí)際是別的目標(biāo)評(píng)估時(shí)全判錯(cuò)。X 光數(shù)據(jù)集類別多txt 里的編號(hào)如果和 yaml 不一致表現(xiàn)就是 loss 降但指標(biāo)不動(dòng)。解決抽 10 張圖用腳本把 txt 的 class_id 映射回類名和圖片內(nèi)容人工核對(duì)。確認(rèn)順序后重訓(xùn)。別信「再跑幾個(gè) epoch 就好了」順序錯(cuò)永遠(yuǎn)好不了。5.2 現(xiàn)象訓(xùn)練到一半 loss 突然變 NaN原因?qū)W習(xí)率過大或某個(gè) batch 里有異???qū)捀邽?0 或坐標(biāo)越界梯度爆炸。X 光數(shù)據(jù)里偶爾有標(biāo)注框退化成一條線歸一化后寬為 0算 loss 時(shí)除零。解決先跑 4.3 的清洗腳本把異??蚯宓粲?xùn)練時(shí)加lr00.01起步配合cos_lr余弦退火如果還炸開ampFalse排除混合精度問題。V100 上 AMP 一般沒問題但異常數(shù)據(jù)會(huì)放大數(shù)值不穩(wěn)定。5.3 現(xiàn)象顯存爆batch 降到 4 還 OOM原因imgsz設(shè)太大或者 dataloader 的workers開太多導(dǎo)致內(nèi)存泄漏。X 光圖分辨率如果原始是 2000resize 到 1280 后單張顯存占用翻倍。解決先imgsz640跑通再逐步往上加workers設(shè)成 CPU 核數(shù)的 1/4別拉滿開cacheFalseX 光數(shù)據(jù)集 9551 張全緩存進(jìn)內(nèi)存要幾十 G。顯存實(shí)在緊就上梯度累積nbs64模擬大 batch。5.4 現(xiàn)象驗(yàn)證集 mAP 比訓(xùn)練集低一大截原因訓(xùn)練集和驗(yàn)證集分布不一致隨機(jī)切分時(shí)某些類別只在訓(xùn)練集出現(xiàn)。12 類里少數(shù)類樣本少隨機(jī)切容易切偏。解決改用分層切分按類別分層抽樣保證每個(gè)子集里 12 類都有?;蛘哂胹klearn.model_selection.train_test_split的stratify參數(shù)以每張圖的主類別為分層依據(jù)。5.5 現(xiàn)象推理時(shí)同一張圖多次預(yù)測(cè)結(jié)果不一致原因模型沒切到 eval 模式BN 層還在用 batch 統(tǒng)計(jì)量或者推理時(shí)做了隨機(jī)增強(qiáng)。X 光圖如果推理管線里帶了 mosaic結(jié)果每次都不一樣。解決導(dǎo)出模型時(shí)用model.eval()推理走yolo detect predict默認(rèn)就是 eval檢查推理配置里augmentFalse。這個(gè)坑在部署階段特別隱蔽離線測(cè)試好好的上線就飄。6. 進(jìn)階玩法用這份數(shù)據(jù)做小目標(biāo)切片推理與類別合并實(shí)驗(yàn)基礎(chǔ)訓(xùn)練跑通之后這份數(shù)據(jù)集還能壓榨出更多價(jià)值。X 光安檢的核心難點(diǎn)是小目標(biāo)blade、scissors和類別邊界模糊knife/dagger/blade下面兩個(gè)方向是我實(shí)測(cè)有效的。6.1 小目標(biāo)切片推理SAHI 思路640 分辨率下blade 這種目標(biāo)可能只占 20×20 像素特征太弱。常見做法是把原圖切成重疊子圖分別推理再合并類似 SAHI 的思路。不依賴額外庫手寫一個(gè)簡化版import cv2 from ultralytics import YOLO model YOLO(runs/xray/exp1/weights/best.pt) img cv2.imread(test.jpg) H, W img.shape[:2] tile, overlap 640, 128 step tile - overlap boxes [] for y in range(0, H, step): for x in range(0, W, step): patch img[y:ytile, x:xtile] if patch.shape[0] 32 or patch.shape[1] 32: continue res model.predict(patch, conf0.25, verboseFalse)[0] for b in res.boxes: x1, y1, x2, y2 b.xyxy[0].tolist() boxes.append([x1x, y1y, x2x, y2y, float(b.conf), int(b.cls)]) # 用 NMS 合并跨切片的重復(fù)框 import torch from torchvision.ops import nms if boxes: t torch.tensor(boxes) keep nms(t[:, :4], t[:, 4], 0.5) print(t[keep])邏輯說明tile640是切片大小overlap128保證目標(biāo)不被切斷。每個(gè)切片單獨(dú)推理后把坐標(biāo)加回原圖偏移最后用 NMS 去重。參數(shù)上conf0.25可以調(diào)低到 0.15 提高小目標(biāo)召回代價(jià)是誤檢增多靠 NMS 的 IoU 閾值平衡。這套在 blade 類上召回能提升 10 個(gè)點(diǎn)以上。6.2 類別合并實(shí)驗(yàn)把 12 類壓成 4 類knife、dagger、blade、SwissArmyKnife在安檢業(yè)務(wù)里往往統(tǒng)一按「刀具」處置Cans、Tin統(tǒng)一按「金屬罐」。如果業(yè)務(wù)只關(guān)心「有沒有危險(xiǎn)品」可以把 12 類合并成 4 大類刀具類、瓶罐類、噴霧類、剪刀類。合并后每類樣本量翻幾倍mAP 通常能漲 5~8 個(gè)點(diǎn)。# 類別合并映射12 - 4 merge_map { 0: 1, 6: 1, # Cans, Tin - 罐類 1: 1, # CartonDrinks - 罐類 2: 0, 3: 0, # GlassBottle, PlasticBottle - 瓶類 4: 2, # SprayCans - 噴霧類 5: 3, 8: 3, 9: 3, 10: 3, # 刀類 7: 1, # VacuumCup - 罐類 11: 3 # scissors - 刀類按業(yè)務(wù)可調(diào) } import glob for txt in glob.glob(labels/**/*.txt, recursiveTrue): out [] with open(txt) as f: for line in f: c, x, y, w, h line.split() out.append(f{merge_map[int(c)]} {x} {y} {w} {h}\n) with open(txt, w) as f: f.writelines(out)邏輯說明merge_map把 12 個(gè)索引映射到 4 個(gè)新索引重寫 txt。參數(shù)上映射關(guān)系按業(yè)務(wù)定比如scissors歸刀類還是單獨(dú)一類看安檢處置流程。合并后 data.yaml 的nc改成 4names 對(duì)應(yīng)改。注意這個(gè)操作會(huì)覆蓋原 txt先備份。6.3 驗(yàn)證合并效果與部署取舍合并后重訓(xùn)一輪對(duì)比混淆矩陣原來 knife/dagger 之間的誤判會(huì)消失因?yàn)樽兂赏活惖款惡凸揞愔g可能新增混淆因?yàn)楹喜⒎糯罅祟悆?nèi)差異。部署時(shí)如果業(yè)務(wù)需要細(xì)分刀具類型就不能合并得靠 6.1 的切片推理提召回。兩條路各有取舍我一般先跑合并版看整體 mAP 上限再?zèng)Q定要不要為細(xì)分類型單獨(dú)優(yōu)化。從那以后我每次拿到新數(shù)據(jù)集都強(qiáng)制先跑一遍類別分布統(tǒng)計(jì)和標(biāo)注越界掃描再動(dòng)訓(xùn)練腳本。這份 9551 張的 X 光數(shù)據(jù)底子不錯(cuò)雙格式標(biāo)注省了大量清洗時(shí)間12 類的劃分也貼合安檢實(shí)際場(chǎng)景值得拿來當(dāng)危險(xiǎn)品檢測(cè)的基線。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取