檢測(cè)數(shù)據(jù)集實(shí)戰(zhàn):從清洗到訓(xùn)練與避坑指南)
簡(jiǎn)介建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集面向智慧工地與工程自動(dòng)化場(chǎng)景提供YOLO格式標(biāo)注數(shù)據(jù)適合目標(biāo)檢測(cè)學(xué)習(xí)者、算法工程師及施工安全系統(tǒng)開(kāi)發(fā)者使用。數(shù)據(jù)源自真實(shí)工地現(xiàn)場(chǎng)覆蓋工程機(jī)械、鋼管、塔吊、人員、鋼筋、腳手架、護(hù)欄、模板、汽車(chē)、自行車(chē)等10類核心目標(biāo)包含機(jī)械與人員交互的復(fù)雜場(chǎng)景可支撐安全預(yù)警、施工進(jìn)度管理、機(jī)器人環(huán)境感知等任務(wù)。壓縮包共478個(gè)文件包括238張jpg現(xiàn)場(chǎng)圖片、238個(gè)txt邊界框標(biāo)注、1個(gè)yaml配置及1份docx說(shuō)明文檔其中訓(xùn)練集201張、驗(yàn)證集37張整體19.82MB可直接導(dǎo)入YOLOv5等主流檢測(cè)框架訓(xùn)練驗(yàn)證。已有194人學(xué)習(xí)瀏覽其精細(xì)標(biāo)注和高風(fēng)險(xiǎn)要素專項(xiàng)標(biāo)注塔吊作業(yè)區(qū)、鋼筋裸露區(qū)對(duì)人員闖入預(yù)警、機(jī)械碰撞預(yù)防等安全類算法研發(fā)尤為實(shí)用。1. 建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集-2.zip拆開(kāi)湊不出成品模型先把這份監(jiān)督信號(hào)審清楚收到建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集-2.zip不少人以為解壓后丟進(jìn)訓(xùn)練框架就能直接出模型。我實(shí)際跑過(guò)幾次之后發(fā)現(xiàn)這類壓縮包里最常見(jiàn)的不是模型問(wèn)題而是數(shù)據(jù)本身的問(wèn)題標(biāo)簽格式混排、空標(biāo)簽一大堆、類別編號(hào)和 classes.txt 對(duì)不上甚至同一段監(jiān)控視頻的連續(xù)幀被隨機(jī)分進(jìn)了訓(xùn)練集和驗(yàn)證集。文件名叫“數(shù)據(jù)集-2”多半是指第二個(gè)版本但它仍然只是圖像加標(biāo)注框的監(jiān)督信號(hào)不是能直接部署的成品模型。這篇文章不聊大而全的算法原理就按我處理工地監(jiān)控?cái)?shù)據(jù)的習(xí)慣從解壓、校驗(yàn)、劃分、訓(xùn)練、排坑到最后的模型校準(zhǔn)講一遍能把這份數(shù)據(jù)用起來(lái)的完整路徑。適合正在做安全帽、反光衣、工程機(jī)械目標(biāo)檢測(cè)或者剛拿到一份歷史標(biāo)注數(shù)據(jù)準(zhǔn)備訓(xùn)練基準(zhǔn)模型的開(kāi)發(fā)者參考。如果你期待的是“下載即用”那要先調(diào)整預(yù)期數(shù)據(jù)集整理這件事往往決定了后面所有訓(xùn)練工作的下限。2. 解壓之后的第一步先摸清目錄布局、命名規(guī)則和標(biāo)注格式2.1 目錄布局圖片、標(biāo)簽和劃分清單各在哪個(gè)位置先別急著訓(xùn)練把壓縮包解開(kāi)用find看一下整體目錄結(jié)構(gòu)。大概率會(huì)看到兩種風(fēng)格一種是把 images 和 labels 分開(kāi)放另帶一個(gè) classes.txt另一種是按 train/val/test 分好子目錄里面再各放圖片和標(biāo)注。不同打包風(fēng)格直接決定了你后續(xù)寫(xiě)校驗(yàn)?zāi)_本時(shí)該去哪找文件。unzip -q 建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集-2.zip -d>data-2/ images/ 000001.jpg 000002.jpg labels/ 000001.txt 000002.txt classes.txt也有的版本會(huì)把標(biāo)注放在annotations/下用 XML 或 JSON 格式保存??吹竭@種結(jié)構(gòu)不要慌你先記住一個(gè)原則訓(xùn)練框架要的只是一份“圖片路徑 對(duì)應(yīng)標(biāo)注”的索引原始目錄怎么擺都可以后面通過(guò)腳本轉(zhuǎn)成標(biāo)準(zhǔn)格式就行。真正需要警惕的是 labels 目錄里文件數(shù)明顯少于 images或者某個(gè)子目錄里混著不同后綴的標(biāo)注文件這種數(shù)據(jù)源大多經(jīng)歷過(guò)手工補(bǔ)標(biāo)一致性最差。2.2 判斷標(biāo)注格式先抽三個(gè)樣本再?zèng)Q定要不要寫(xiě)轉(zhuǎn)換腳本建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集的標(biāo)注格式一般逃不出三種YOLO 的 txt、VOC 的 xml、COCO 的 json。YOLO txt 最常見(jiàn)每一行是“類別ID 中心點(diǎn)x 中心點(diǎn)y 寬 高”四個(gè)坐標(biāo)都是相對(duì)圖片寬高的歸一化值VOC xml 則把目標(biāo)框坐標(biāo)寫(xiě)成了絕對(duì)像素值。兩者混在一個(gè)數(shù)據(jù)集里時(shí)訓(xùn)練會(huì)直接報(bào)錯(cuò)或者默默丟掉一部分框。我一般會(huì)寫(xiě)一段極短的探查腳本先隨機(jī)抽幾張圖看看對(duì)應(yīng)標(biāo)簽長(zhǎng)什么樣再?zèng)Q定后續(xù)怎么統(tǒng)一格式import os for img_file in [images/000001.jpg, images/000002.jpg, images/000003.jpg]: base os.path.splitext(img_file)[0].replace(images/, labels/) for ext in [.txt, .xml, .json]: p f{base}{ext} if os.path.exists(p): print(img_file, -, p) with open(p, r, encodingutf-8) as f: lines f.read().strip().splitlines()[:5] print(\n.join(lines)) break這段代碼的核心邏輯是同一個(gè)圖片名依次去 labels 目錄下找 txt、xml、json 三種后綴找到哪個(gè)就打印哪個(gè)的前五行。你不需要把所有文件都解析一遍三個(gè)樣本就能區(qū)分出數(shù)據(jù)集的標(biāo)注體系。如果三張圖分別出現(xiàn)不同格式說(shuō)明這個(gè)包經(jīng)歷過(guò)多次導(dǎo)出后面必須寫(xiě)統(tǒng)一腳本。如果 txt 里的第一列數(shù)字大于 classes.txt 里列出的類目數(shù)減一那就是版本沖突常見(jiàn)于“數(shù)據(jù)集-2”是在舊版基礎(chǔ)上追加了類別卻沒(méi)有重新生成所有標(biāo)簽。3. 清洗數(shù)據(jù)集-2校驗(yàn)、劃分與增強(qiáng)缺一環(huán)都會(huì)白訓(xùn)3.1 清掉空標(biāo)簽、壞圖和越界類別編號(hào)拿到一份建筑工地檢測(cè)數(shù)據(jù)集第一件事不是標(biāo)新立異而是用腳本把所有文件過(guò)一遍。工地監(jiān)控照片有個(gè)特點(diǎn)大量畫(huà)面是空鏡頭、逆光拍糊、或者只有遠(yuǎn)處塔吊但沒(méi)有可標(biāo)注物體。這些圖里如果有標(biāo)簽文件很可能是空文件或者寫(xiě)了一個(gè)不存在的類別 ID。如果直接把這樣一堆數(shù)據(jù)丟給訓(xùn)練框架輕則損失一部分訓(xùn)練樣本重則讓模型學(xué)到“看到空白就輸出一個(gè)奇怪框”。我用這段腳本做第一輪清理import os import cv2 img_dir images label_dir labels problems [] for img_name in sorted(os.listdir(img_dir)): base os.path.splitext(img_name)[0] label_path os.path.join(label_dir, base .txt) if not os.path.exists(label_path): problems.append((img_name, label missing)) continue with open(label_path) as f: lines [line.strip() for line in f if line.strip()] if not lines: problems.append((img_name, empty label)) continue img cv2.imread(os.path.join(img_dir, img_name)) if img is None: problems.append((img_name, broken image)) continue height, width img.shape[:2] for line in lines: parts list(map(float, line.split())) cls, x, y, w, h parts if int(cls) 0 or int(cls) 3: problems.append((img_name, fclass id overflow: {cls})) break if not (0 x 1 and 0 y 1): problems.append((img_name, fcenter out of range: {line})) break if w 0 or h 0 or w 1 or h 1: problems.append((img_name, fbox size out of range: {line})) break print(bad samples:, len(problems)) for p in problems[:20]: print(p)這段腳本把每個(gè)圖片名對(duì)應(yīng)的標(biāo)簽文件讀出來(lái)先看是否存在、是否為空再讀圖片、檢查類別 ID 是否越界、框坐標(biāo)是否在合法區(qū)間。具體執(zhí)行時(shí)把里面的3換成你 classes.txt 的實(shí)際類別數(shù)。這里有個(gè)經(jīng)驗(yàn)值空標(biāo)簽和壞圖一般能清掉 5% 到 15% 的樣本清完之后數(shù)據(jù)集才談得上可用。不要覺(jué)得這是浪費(fèi)把臟數(shù)據(jù)留著訓(xùn)練出來(lái)的模型就會(huì)把誤檢當(dāng)成正常輸出。3.2 按來(lái)源劃分?jǐn)?shù)據(jù)而不是隨機(jī)打散建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集里的圖片很多是從監(jiān)控視頻里抽幀出來(lái)的相鄰幀的內(nèi)容幾乎一樣。如果直接用train_test_split隨機(jī)分同一個(gè)場(chǎng)景的連續(xù)幀會(huì)同時(shí)出現(xiàn)在訓(xùn)練集和驗(yàn)證集里最后指標(biāo)會(huì)異常好看但模型一上真實(shí)場(chǎng)景立刻露餡。正確做法是按“拍攝來(lái)源”分組讓同一個(gè)攝像頭、同一段時(shí)間的畫(huà)面只出現(xiàn)在一個(gè)集合里。如果文件名里帶了攝像頭編號(hào)或時(shí)間前綴可以按前綴分組import os import random from collections import defaultdict images [f for f in os.listdir(images)] groups defaultdict(list) for img in images: group_key img.split(_)[0] if _ in img else scene_ img[:4] groups[group_key].append(img) keys list(groups.keys()) random.shuffle(keys) num len(keys) train_keys keys[: int(num * 0.8)] val_keys keys[int(num * 0.8): int(num * 0.9)] test_keys keys[int(num * 0.9):] def write_list(name, key_list): with open(name, w) as f: for key in key_list: for img in groups[key]: f.write(img \n) write_list(train.txt, train_keys) write_list(val.txt, val_keys) write_list(test.txt, test_keys)這段腳本先按文件名第一個(gè)下劃線前的字段分組然后把組隨機(jī)分到訓(xùn)練、驗(yàn)證、測(cè)試三個(gè)文件里。核心參數(shù)是 8:1:1 的比例如果你的標(biāo)注量很大可以改成 7:1:2。這里容易踩的坑是不要按幀索引切分一定要按場(chǎng)景 key 切分。如果文件名里沒(méi)有明顯分組信息就按時(shí)間排序后整段切前 80% 當(dāng)訓(xùn)練后 20% 當(dāng)驗(yàn)證這樣至少能避免最嚴(yán)重的跨場(chǎng)景泄漏。3.3 數(shù)據(jù)增強(qiáng)小目標(biāo)靠切圖逆光靠光度擾動(dòng)工地場(chǎng)景里最難檢的往往不是機(jī)械大目標(biāo)而是遠(yuǎn)處工人頭上的安全帽十幾像素甚至幾像素的帽子比比皆是。針對(duì)小目標(biāo)增強(qiáng)策略不能只靠隨機(jī)翻轉(zhuǎn)和裁剪我會(huì)顯式開(kāi)啟 Mosaic 和比例縮放用大圖切塊訓(xùn)練讓模型在更小的目標(biāo)尺寸上也見(jiàn)過(guò)足夠多樣本。逆光和傍晚場(chǎng)景則靠亮度對(duì)比度擾動(dòng)來(lái)補(bǔ)不然模型白天好用傍晚就失靈。常見(jiàn)的增強(qiáng)庫(kù)配置可以等價(jià)寫(xiě)成這樣aug dict( mosaic1.0, random_brightness_contrast(0.6, 0.6), hsv_h0.02, hsv_s0.5, hsv_v0.5, fliplr0.5, flip_ud0.0, scale_min0.2, )幾個(gè)參數(shù)要單獨(dú)說(shuō)明flip_ud0.0意味著不做上下翻轉(zhuǎn)因?yàn)榘踩庇肋h(yuǎn)在頭頂上下翻轉(zhuǎn)會(huì)強(qiáng)行讓模型學(xué)習(xí)“帽子長(zhǎng)在腳底”的錯(cuò)誤規(guī)律反而增加誤檢。mosaic1.0表示每張訓(xùn)練圖都來(lái)自四張圖拼接能顯著提升小目標(biāo)附近的上下文多樣性但也會(huì)讓本來(lái)就小的目標(biāo)變得更小所以需要配合scale_min0.2避免把所有目標(biāo)都縮沒(méi)了。亮度對(duì)比度擾動(dòng)控制在 0.6 左右既能模擬傍晚逆光又不會(huì)把白天樣本壓成黑乎乎一團(tuán)。4. 訓(xùn)練參數(shù)怎么設(shè)類別清單、錨框、輸入尺寸一起定4.1 讀取 classes.txt生成訓(xùn)練用的數(shù)據(jù)聲明文件建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集-2 的類別數(shù)不會(huì)太多常見(jiàn)的是安全帽、反光衣、人、挖掘機(jī)、塔吊這幾類。先讀一下 classes.txt把類別列表和數(shù)量輸出再生成訓(xùn)練框架需要的數(shù)據(jù)聲明文件。這樣做看似多了一步實(shí)際上是為了避免在命令行里手寫(xiě)nc4這類參數(shù)一旦類別數(shù)寫(xiě)錯(cuò)訓(xùn)練過(guò)程不報(bào)錯(cuò)但驗(yàn)證時(shí)所有框都會(huì)錯(cuò)位。with open(classes.txt) as f: classes [x.strip() for x in f if x.strip()] print(f類別數(shù): {len(classes)}, 列表: {classes}) data_yaml f path: ./ train: train.txt val: val.txt test: test.txt nc: {len(classes)} names: {classes} with open(data.yaml, w) as f: f.write(data_yaml)這段代碼把classes.txt解析成列表并生成一個(gè) data.yaml 給訓(xùn)練框架用。path指向當(dāng)前數(shù)據(jù)集根目錄train和val指向剛生成的索引文件names里的順序必須和標(biāo)注文件里的類別 ID 嚴(yán)格一致。如果你的標(biāo)注是 VOC 或 COCO這一步要先把標(biāo)注轉(zhuǎn)成 YOLO 格式再生成這個(gè)文件順序不能反不然類別順序會(huì)錯(cuò)位訓(xùn)練出的模型等于每個(gè)目標(biāo)都預(yù)測(cè)錯(cuò)了名字。4.2 錨框不要抄通用預(yù)置值對(duì)小目標(biāo)重新聚類很多訓(xùn)練框架默認(rèn)錨框是從自然圖片數(shù)據(jù)集上統(tǒng)計(jì)出來(lái)的尺寸偏大建筑工地里的安全帽、反光背心這類小目標(biāo)占比高繼續(xù)用默認(rèn)錨框會(huì)讓小目標(biāo)分支的回歸非常吃力。我習(xí)慣在每次訓(xùn)練前用標(biāo)注框重新聚類一組錨框幾行代碼就能跑出來(lái)。import numpy as np from pathlib import Path boxes [] for lp in Path(labels).glob(*.txt): for line in lp.read_text().strip().splitlines(): parts line.split() if len(parts) 5: _, _, _, w, h map(float, parts) boxes.append([w, h]) boxes np.array(boxes, dtypenp.float64) def kmeans_anchor(boxes, k, max_iter100, seed7): rng np.random.default_rng(seed) anchors boxes[rng.choice(len(boxes), k, replaceFalse)].copy() for _ in range(max_iter): w boxes[:, 0] h boxes[:, 1] aw anchors[:, 0] ah anchors[:, 1] inter np.minimum(w[:, None], aw[None, :]) * np.minimum(h[:, None], ah[None, :]) union w[:, None] * h[:, None] aw[None, :] * ah[None, :] - inter iou inter / (union 1e-6) assign np.argmax(iou, axis1) new_anchors [] for j in range(k): group boxes[assign j] if len(group) 0: new_anchors.append(anchors[j]) else: new_anchors.append(group.mean(axis0)) anchors np.array(new_anchors) return anchors anchors kmeans_anchor(boxes, k9) print(anchors:) print(anchors)這段腳本讀取所有 YOLO 格式的標(biāo)簽取出歸一化后的寬和高然后用 IoU 距離做 k-means 聚類最終輸出 9 組錨框。k9 是一般檢測(cè)框架的常見(jiàn)取值如果你用輕量模型可以改成 6 組。這里要提醒一句聚類出來(lái)的錨框尺寸依賴輸入分辨率如果你打算用 1280 訓(xùn)練就按 1280 下的歸一化坐標(biāo)去換算如果訓(xùn)練和推理的輸入尺寸不一致錨框也要同步縮放否則前面的聚類就白做了。配合錨框重聚類我一般把輸入尺寸從默認(rèn) 640 提到 1280尤其安全帽這類小目標(biāo)640 下常常只有 6 到 8 個(gè)像素寬1280 下能翻倍到可辨識(shí)范圍。訓(xùn)練命令可以按這個(gè)思路設(shè)置# 常見(jiàn) YOLO 系框架的參數(shù)示意具體寫(xiě)法以你使用的版本為準(zhǔn) python train.py --data data.yaml --model yolov8n.pt \ --img-size 1280 --batch-size 8 --epochs 100 \ --patience 20 --weights pretrained.ptimg-size 1280是工地小目標(biāo)場(chǎng)景下最值得優(yōu)先加的參數(shù)但顯存不夠時(shí)不要硬上可以把 batch-size 降到 4配合梯度累積來(lái)緩解。patience 20表示驗(yàn)證集指標(biāo)連續(xù) 20 輪不提升就早停省時(shí)間也避免過(guò)擬合到最后開(kāi)始背訓(xùn)練樣本。5. 建筑工地目標(biāo)檢測(cè)避坑指南四個(gè)比模型結(jié)構(gòu)更影響結(jié)果的問(wèn)題5.1 安全帽類別漂移戴帽和不戴帽的邊界不統(tǒng)一現(xiàn)象訓(xùn)練時(shí)安全帽類別指標(biāo)很高但一到新工地視頻模型頻繁把頭頂陰影、安全帽反光、甚至黃色塑料凳識(shí)別成安全帽。原因標(biāo)注者對(duì)“戴帽”的界定不一致。有的標(biāo)注只要帽子出現(xiàn)在頭頂就算正樣本有的要求遮蓋住 60% 以上的頭圍才標(biāo)還有的把帽帶的反光條單獨(dú)標(biāo)成另一個(gè)物體。數(shù)據(jù)源里混了多種標(biāo)準(zhǔn)模型學(xué)到的不是帽子的本質(zhì)而是各種黃色塊和弧形紋理。解決統(tǒng)一標(biāo)注規(guī)則至少按“帽子覆蓋頭部面積過(guò)半”才算正樣本。如果數(shù)據(jù)集里已經(jīng)有大量模棱兩可的框最簡(jiǎn)單的做法是把它們當(dāng)作難例保留但要在訓(xùn)練時(shí)給安全帽類別加一點(diǎn)權(quán)重或者干脆把安全帽拆成“戴帽”“不戴帽”兩個(gè)類別讓模型先分清人再判斷帽子狀態(tài)。5.2 小目標(biāo)密集工人擠在一起被模型“團(tuán)滅”現(xiàn)象畫(huà)面里有十幾個(gè)工人模型只輸出三四個(gè)框另外幾個(gè)被漏掉或者兩個(gè)相近工人被框成一個(gè)巨大矩形。原因工地多人作業(yè)時(shí)標(biāo)注框之間重疊率高模型在 NMS 階段把置信度略低的框壓掉了。另一個(gè)原因是訓(xùn)練時(shí)用的輸入尺寸太小幾像素寬的帽子在特征圖里已經(jīng)退化成一個(gè)點(diǎn)。解決提高輸入分辨率到 1280同時(shí)在增強(qiáng)階段開(kāi) Mosaic 并保證每張訓(xùn)練圖里保留小目標(biāo)樣本。推理階段如果還是漏把 NMS 的 IoU 閾值從默認(rèn)的 0.45 調(diào)高到 0.6能減少高密度場(chǎng)景下的框合并。注意不要調(diào)得太高否則同一個(gè)目標(biāo)會(huì)產(chǎn)生重復(fù)框。5.3 把工地設(shè)備誤檢成人或安全帽現(xiàn)象藍(lán)色鐵皮圍擋、反光錐桶、混凝土攪拌車(chē)滾筒有時(shí)被誤檢成工人或安全帽。原因圍擋和工服的藍(lán)色色塊接近反光衣和錐桶的橙色接近模型學(xué)到的顏色特征沒(méi)有和“人體結(jié)構(gòu)”綁定于是看到大面積近似色就觸發(fā)檢測(cè)。解決不要急著改網(wǎng)絡(luò)結(jié)構(gòu)先看訓(xùn)練數(shù)據(jù)里的負(fù)樣本夠不夠多。我通常會(huì)在訓(xùn)練集里額外放一批沒(méi)有目標(biāo)的背景圖和難負(fù)例圖讓模型明確“這塊區(qū)域即使有顏色也不是目標(biāo)”。另一個(gè)辦法是把類別定義寫(xiě)得更窄不是檢測(cè)“所有反光物體”而是檢測(cè)“穿反光衣的人”標(biāo)注時(shí)只標(biāo)人體范圍內(nèi)的區(qū)域不標(biāo)單獨(dú)的反光布。5.4 驗(yàn)證集虛高同一段視頻漏進(jìn)了兩個(gè)集合現(xiàn)象訓(xùn)練日志里 mAP 到 0.95部署到新攝像頭后準(zhǔn)確率直接掉到 0.6 左右差得離譜。原因圖片來(lái)自監(jiān)控視頻抽幀隨機(jī)劃分時(shí)同一個(gè)攝像頭同一天的連續(xù)幀被分到訓(xùn)練集和驗(yàn)證集模型等于已經(jīng)在考場(chǎng)上見(jiàn)過(guò)驗(yàn)證題。解決按場(chǎng)景劃分?jǐn)?shù)據(jù)而不是按幀隨機(jī)分。具體操作見(jiàn) 3.2 節(jié)文件名里有攝像頭編號(hào)就按編號(hào)分沒(méi)有編號(hào)就按時(shí)間戳整段切。強(qiáng)烈建議在訓(xùn)練完成后再留一個(gè)“完全陌生的攝像頭”的測(cè)試文件夾只有它在 mAP 上也保持住才算真的有效。6. 把數(shù)據(jù)集-2 變成自己的模型遷移、置信度校準(zhǔn)與驗(yàn)收技巧6.1 先小批量跑通端到端再談精度完整地訓(xùn)一個(gè)工地目標(biāo)檢測(cè)模型之前我最先做的事是從清洗后的數(shù)據(jù)里取 100 張圖跑一個(gè) 10 輪的快速實(shí)驗(yàn)。這個(gè)小實(shí)驗(yàn)不是為了出精度而是驗(yàn)證整條鏈路圖片路徑是否正確、類別順序是否對(duì)得上、損失能否正常下降、驗(yàn)證階段能不能輸出預(yù)測(cè)結(jié)果。如果這個(gè)小批量過(guò)程里出現(xiàn)nanloss 或者驗(yàn)證階段一張圖都沒(méi)有輸出基本就是標(biāo)注越界、類別數(shù)不一致或路徑配置錯(cuò)誤趁早停下來(lái)比訓(xùn)到一半再排查省得多。跑通小批量之后再用全量數(shù)據(jù)訓(xùn)練。個(gè)人習(xí)慣是先凍結(jié)骨干網(wǎng)絡(luò)微調(diào) 20 輪等驗(yàn)證集損失不再下降再解凍全部層微調(diào) 50 到 100 輪。這樣能避免新工地?cái)?shù)據(jù)量不足時(shí)把預(yù)訓(xùn)練權(quán)重里的通用特征全部沖掉。6.2 用驗(yàn)證集錯(cuò)誤樣本調(diào)置信度閾值最后一個(gè)值得做的技巧是給推理階段選一個(gè)合適的置信度閾值。默認(rèn) 0.5 不一定適合你的工地場(chǎng)景如果客戶更在意不能漏人就把閾值降到 0.3用誤檢換召回如果誤報(bào)會(huì)導(dǎo)致告警平臺(tái)被刷屏就提到 0.7。別靠肉眼拍腦袋把驗(yàn)證集預(yù)測(cè)結(jié)果導(dǎo)出來(lái)看不同閾值下的精確率和召回率曲線。import json preds json.load(open(val_predictions.json)) labels json.load(open(val_labels.json)) for threshold in [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]: tp fp fn 0 for pred, label in zip(preds, labels): matched set() for p in pred: if p[conf] threshold: continue # 這里省略 IoU 匹配邏輯實(shí)際按框重疊面積計(jì)算 matched.add(p[cls]) for target in label[classes]: if target in matched: tp 1 else: fn 1 fp max(0, len(matched) - len(label[classes])) precision tp / (tp fp) if tp fp 0 else 0 recall tp / (tp fn) if tp fn 0 else 0 print(fthreshold{threshold}, precision{precision:.3f}, recall{recall:.3f})這段代碼按置信度閾值過(guò)濾預(yù)測(cè)框然后粗略統(tǒng)計(jì)精確率和召回率實(shí)際工程里要把 IoU 匹配補(bǔ)上。你真正要觀察的是閾值從 0.5 移動(dòng)到 0.3 時(shí)召回率提升了多少、誤檢增加了多少。如果 0.3 時(shí)誤檢暴增說(shuō)明模型學(xué)到的是顏色特征而不是結(jié)構(gòu)特征該回頭查標(biāo)注質(zhì)量如果 0.7 時(shí)召回率仍然很高說(shuō)明檢測(cè)結(jié)果很可靠可以放心提高閾值減少告警。把這份建筑工地目標(biāo)檢測(cè)數(shù)據(jù)集-2 跑完我最深的感受是真正決定模型能不能用的往往是數(shù)據(jù)組織、場(chǎng)景劃分、標(biāo)注邊界這些最不起眼的地方。我習(xí)慣在最后一輪訓(xùn)練時(shí)留下一個(gè)從沒(méi)參與過(guò)任何訓(xùn)練和驗(yàn)證的攝像頭來(lái)驗(yàn)收如果它在第一幀就丟目標(biāo)那前面所有指標(biāo)都只是數(shù)字。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取