
1. 項目概述從零上手MMDetection v2.22.0如果你剛拿到一批標注好的圖片想用MMDetection這個強大的目標檢測工具箱來訓練自己的模型但面對官方文檔和繁雜的配置文件感到無從下手那你來對地方了。我最近剛用MMDetection v2.22.0完整跑通了一個自定義數據集的訓練流程從環境搭建、數據準備、配置修改到模型訓練和測試中間踩了不少坑也總結了一套行之有效的“流水線”操作。這篇文章就是我的實戰筆記目標很明確讓你能避開我走過的彎路用最清晰的步驟在MMDetection v2.22.0上成功訓練出第一個屬于你自己的目標檢測模型。無論你是做學術研究、工業質檢還是個人興趣項目這套流程都能直接套用。我們會聚焦于最常用的Faster R-CNN模型和COCO數據格式因為這是最通用、社區支持最好的路徑掌握了它再探索其他模型和格式就會容易得多。2. 環境搭建與MMDetection安裝2.1 基礎環境準備CUDA、PyTorch與MMCVMMDetection的穩定運行嚴重依賴底層環境尤其是PyTorch和MMCVOpenMMLab的計算機視覺基礎庫的版本匹配。v2.22.0版本發布于一段時間其版本依賴相對固定盲目使用最新版PyTorch很可能導致兼容性問題。我的建議是嚴格按照 MMDetection官方安裝文檔 中推薦的版本來。以我使用的環境為例操作系統Ubuntu 20.04 LTS 或 Windows 10/11WSL2環境下。純Windows原生安裝會遇到更多編譯問題強烈推薦WSL2。CUDA Toolkit11.3。這是經過廣泛測試的版本。確保nvidia-smi顯示的CUDA版本不低于此。PyTorch1.11.0。使用以下命令安裝pip install torch1.11.0cu113 torchvision0.12.0cu113 torchaudio0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113MMCV這是關鍵。MMDetection v2.22.0需要mmcv-full而非輕量版的mmcv。我們必須安裝與CUDA、PyTorch版本完全匹配的預編譯包。pip install mmcv-full1.5.3 -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.11.0/index.html請將URL中的cu113和torch1.11.0替換成你的CUDA和PyTorch版本。安裝成功后在Python中運行import mmcv; print(mmcv.__version__)應能正確輸出版本號。注意切勿直接pip install mmcv-full這大概率會觸發從源碼編譯過程漫長且極易失敗。一定要使用-f指定預編譯包的索引地址。2.2 MMDetection安裝與驗證基礎環境就緒后安裝MMDetection本身反而很簡單。推薦從GitHub克隆特定版本以保證代碼一致性。git clone -b v2.22.0 https://github.com/openmmlab/mmdetection.git cd mmdetection pip install -v -e . # “-e”代表可編輯模式安裝方便修改源碼 # 或者使用requirements文件安裝依賴 # pip install -r requirements/build.txt # pip install -r requirements/optional.txt安裝完成后進行一個快速的完整性驗證。創建一個簡單的Python腳本test_install.pyfrom mmdet.apis import init_detector, inference_detector import mmcv config_file configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py checkpoint_file checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth # 下載預訓練模型如果尚未下載 # from mmdet.apis import init_detector # 模型會在首次運行時自動下載也可以手動下載到checkpoints目錄 model init_detector(config_file, checkpoint_file, devicecpu) # 先用CPU測試 print(MMDetection安裝及模型加載測試通過)如果運行沒有報錯說明核心安裝成功。接下來我們需要準備最重要的燃料——你自己的數據集。3. 自定義數據集準備COCO格式詳解與制作MMDetection支持多種數據集格式PASCAL VOC、COCO等但COCO格式是社區生態最完善、文檔示例最全的格式強烈建議將你的數據轉為COCO格式能省去大量適配工作。3.1 COCO數據集格式深度解析COCO格式的核心是一個JSON文件通常命名為annotations.json。它包含以下幾個頂級字段images: 一個列表包含所有圖像的信息。annotations: 一個列表包含所有目標實例的標注信息。categories: 一個列表定義所有物體類別。下面我們拆解每一個部分并說明如何從你的原始標注比如LabelImg生成的XML轉換過來。1.images字段每個圖像是一個字典例如{ id: 1, // 圖像唯一ID從1開始遞增 width: 800, height: 600, file_name: image_001.jpg // 相對于數據集根目錄的路徑 }你需要遍歷你的所有圖片為每一張生成這樣一個記錄。id必須唯一且連續。2.categories字段定義你的檢測類別。id通常從1開始0保留給背景MMDetection內部處理。[ {id: 1, name: cat, supercategory: animal}, {id: 2, name: dog, supercategory: animal}, {id: 3, name: person, supercategory: human} ]supercategory可以用于更粗粒度的分組非必需但建議填寫。3.annotations字段最關鍵每個目標實例一個字典{ id: 1, // 標注實例唯一ID全局遞增 image_id: 1, // 對應 images 中的 id category_id: 1, // 對應 categories 中的 id bbox: [x, y, width, height], // [左上角x, 左上角y, 寬度, 高度] area: width * height, // bbox面積用于評估指標如AP segmentation: [], // 實例分割多邊形坐標目標檢測可留空列表 iscrowd: 0 // 0表示單個物體1表示一群物體如人群 }這里最重要的是bbox的格式。COCO使用的是[x, y, width, height]即左上角坐標和寬高。這與某些標注工具如YOLO使用的中心點坐標和歸一化寬高不同轉換時務必注意。3.2 從常見格式轉換到COCO格式的實操腳本假設你的原始標注是PASCAL VOC格式XML文件下面是一個使用Pythonxml.etree.ElementTree進行轉換的示例腳本核心邏輯import json import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_coco(voc_annotations_dir, images_dir, output_json_path): images [] annotations [] categories [] # 1. 構建 categories # 這里需要你事先知道所有類別并映射到id category_dict {cat: 1, dog: 2, person: 3} for name, cid in category_dict.items(): categories.append({id: cid, name: name, supercategory: none}) ann_id 1 for img_id, xml_file in enumerate(os.listdir(voc_annotations_dir), 1): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_annotations_dir, xml_file)) root tree.getroot() # 2. 構建 image 信息 filename root.find(filename).text img_path os.path.join(images_dir, filename) with Image.open(img_path) as img: width, height img.size images.append({ id: img_id, width: width, height: height, file_name: filename, }) # 3. 構建 annotation 信息 for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in category_dict: continue # 或者跳過未知類別 xml_box obj.find(bndbox) xmin int(float(xml_box.find(xmin).text)) ymin int(float(xml_box.find(ymin).text)) xmax int(float(xml_box.find(xmax).text)) ymax int(float(xml_box.find(ymax).text)) # VOC是[xmin, ymin, xmax, ymax]需轉為COCO的[x, y, width, height] coco_bbox [xmin, ymin, xmax - xmin, ymax - ymin] area coco_bbox[2] * coco_bbox[3] annotations.append({ id: ann_id, image_id: img_id, category_id: category_dict[cls_name], bbox: coco_bbox, area: area, segmentation: [], iscrowd: 0 }) ann_id 1 # 4. 組裝成COCO JSON coco_format_json { images: images, annotations: annotations, categories: categories } with open(output_json_path, w) as f: json.dump(coco_format_json, f, indent2) print(f轉換完成共 {len(images)} 張圖片{len(annotations)} 個標注。) # 使用示例 voc_to_coco(./voc_annotations, ./images, ./annotations/train.json)運行這個腳本你就能得到標準的COCO格式標注文件。記得將圖片文件放在images_dir指定的目錄下。3.3 數據集目錄結構規劃一個清晰的數據集目錄結構能讓后續配置變得簡單。我推薦如下結構mmdetection/ ├── data/ │ └── my_dataset/ # 你的數據集根目錄 │ ├── annotations/ # 存放COCO格式的JSON文件 │ │ ├── train.json │ │ └── val.json │ └── images/ # 存放所有圖片或按train/val放子目錄 │ ├── train/ │ │ ├── img1.jpg │ │ └── ... │ └── val/ │ ├── img2.jpg │ └── ...實操心得在制作train.json和val.json時images列表和annotations列表只包含對應劃分的數據。categories列表在兩個文件中必須完全一致。你可以先用一個腳本生成完整的all.json再根據劃分列表拆分成train.json和val.json。4. 配置文件解析與關鍵修改MMDetection采用模塊化、可繼承的配置文件系統這是其強大之處也是新手最容易困惑的地方。我們不需要從頭寫配置而是基于一個基準配置文件進行修改。4.1 配置文件繼承機制解讀以訓練Faster R-CNN為例我們查看configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py會發現它的第一行是_base_ [ ../_base_/models/faster_rcnn_r50_fpn.py, ../_base_/datasets/coco_detection.py, ../_base_/schedules/schedule_1x.py, ../_base_/default_runtime.py ]這表示它繼承了四個基礎配置文件分別定義了模型結構、數據流水線、訓練策略和運行時設置如日志、鉤子。我們的修改策略是創建一個新的配置文件繼承我們選中的基準配置然后只覆蓋需要修改的部分。這樣做既保證了配置的完整性又使修改清晰可追溯。4.2 創建自定義配置文件在mmdetection/configs目錄下或任何你喜歡的位置建議在項目根目錄新建一個configs文件夾創建我們的配置文件例如my_faster_rcnn_r50_fpn_1x_mydataset.py。# my_faster_rcnn_r50_fpn_1x_mydataset.py _base_ ./faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py # 相對于當前文件的路徑 # 1. 修改數據集相關配置 dataset_type CocoDataset classes (cat, dog, person) # 務必與你的 categories 中 name 的順序和內容一致 data_root data/my_dataset/ # 指向你的數據集根目錄 # 覆蓋 _base_ 中關于數據集的配置 data dict( samples_per_gpu2, # 批大小。根據你的GPU內存調整。如果遇到CUDA out of memory就調小這個值。 workers_per_gpu2, # 數據加載線程數。通常設為CPU核心數但不宜過大。 traindict( typedataset_type, ann_filedata_root annotations/train.json, img_prefixdata_root images/train/, classesclasses # 指定類別 ), valdict( typedataset_type, ann_filedata_root annotations/val.json, img_prefixdata_root images/val/, classesclasses ), testdict( typedataset_type, ann_filedata_root annotations/val.json, # 測試集可以用驗證集代替 img_prefixdata_root images/val/, classesclasses ) ) # 2. 修改模型頭部類別數 # 找到 _base_ 中模型定義的路徑然后修改 roi_head 的 bbox_head model dict( roi_headdict( bbox_headdict( num_classeslen(classes) # 關鍵必須修改為你的類別數這里是3 ) ) ) # 3. 修改訓練策略可選但建議調整 # 學習率根據 batch size 線性縮放是一個經驗法則。原配置 base_lr0.02 對應 8 GPUs * 2 imgs/gpu 16 的總batch size。 # 如果你用單卡samples_per_gpu2總batch size2那么學習率應縮放為 0.02 * (2 / 16) 0.0025 optimizer dict(typeSGD, lr0.0025, momentum0.9, weight_decay0.0001) lr_config dict( policystep, warmuplinear, warmup_iters500, warmup_ratio0.001, step[8, 11]) # 學習率在第8和第11個epoch下降 runner dict(typeEpochBasedRunner, max_epochs12) # 總訓練輪數 # 4. 修改運行時配置如日志、檢查點頻率 checkpoint_config dict(interval1) # 每個epoch保存一次檢查點 log_config dict(interval50, hooks[dict(typeTextLoggerHook)]) # 每50個iteration打印一次日志 # 指定工作目錄訓練日志和模型權重將保存在這里 work_dir ./work_dirs/my_faster_rcnn_exp1這個配置文件是核心中的核心。請逐行理解特別是num_classes和lr的修改這是新手最常出錯的兩個地方。num_classes不修改會導致維度不匹配錯誤lr設置不當會導致訓練不收斂。4.3 配置文件的調試與驗證在開始漫長訓練之前先用一個極小的設置驗證整個數據流和配置是否正確。我們可以創建一個“玩具”配置文件只加載幾張圖片跑通前向傳播。# debug_config.py _base_ ./my_faster_rcnn_r50_fpn_1x_mydataset.py # 覆蓋數據加載部分僅用于調試 data dict( samples_per_gpu1, workers_per_gpu1, traindict( type_base_.dataset_type, ann_file_base_.data_root annotations/train.json, img_prefix_base_.data_root images/train/, classes_base_.classes, # 使用更小的流水線加速調試 pipeline[ dict(typeLoadImageFromFile), dict(typeLoadAnnotations, with_bboxTrue), dict(typeResize, img_scale(1333, 800), keep_ratioTrue), dict(typeRandomFlip, flip_ratio0.5), dict(typeNormalize, **img_norm_cfg), dict(typePad, size_divisor32), dict(typeDefaultFormatBundle), dict(typeCollect, keys[img, gt_bboxes, gt_labels]), ] ) )然后運行一個簡單的測試腳本python tools/misc/browse_dataset.py debug_config.py --show這個命令會可視化你的數據加載和增強效果確保圖片和標注能正確配對、顯示。這是排查數據問題最直觀的方法。5. 模型訓練、監控與測試5.1 啟動訓練與分布式訓練單GPU訓練命令很簡單python tools/train.py my_faster_rcnn_r50_fpn_1x_mydataset.py如果你有多張GPU可以使用分布式訓練以大幅加速。MMDetection基于PyTorch的DistributedDataParallel(DDP) 封裝了分布式訓練命令./tools/dist_train.sh my_faster_rcnn_r50_fpn_1x_mydataset.py 8 --work-dir ./work_dirs/my_exp這里的8代表使用8個GPU。dist_train.sh腳本會自動處理進程啟動、端口分配等繁瑣細節。訓練日志和模型權重會保存在--work-dir指定的目錄如果配置文件中已指定work_dir則以配置文件為準。5.2 訓練過程監控與日志解讀訓練開始后控制臺會打印日志。你需要關注以下幾個關鍵信息Loss曲線loss_rpn_cls、loss_rpn_bbox、loss_cls、loss_bbox是Faster R-CNN的主要損失。在訓練初期這些loss應該呈現明顯的下降趨勢。如果loss劇烈震蕩或居高不下可能是學習率過高、數據有問題或標注錯誤。學習率日志會顯示當前的學習率。根據lr_config的設置你應該能看到在指定epoch學習率按比例下降。內存使用關注GPU內存占用。如果接近上限可以嘗試減小samples_per_gpu或輸入圖片尺寸。更強大的監控工具是TensorBoard。MMDetection默認集成了TensorBoard日志。在訓練命令后加上--tensorboard參數或者在配置文件中添加log_config dict( interval50, hooks[ dict(typeTextLoggerHook), dict(typeTensorboardLoggerHook) # 添加這行 ])訓練后在work_dir下會生成tf_logs目錄使用tensorboard --logdir ./work_dirs/my_exp/tf_logs即可在瀏覽器中查看豐富的可視化圖表包括Loss曲線、學習率、驗證集mAP等這對于分析訓練狀態至關重要。5.3 模型測試與性能評估訓練完成后我們使用驗證集評估模型性能。使用以下命令# 單GPU測試 python tools/test.py my_faster_rcnn_r50_fpn_1x_mydataset.py ./work_dirs/my_exp/latest.pth --eval bbox # 多GPU測試 ./tools/dist_test.sh my_faster_rcnn_r50_fpn_1x_mydataset.py ./work_dirs/my_exp/latest.pth 8 --eval bbox--eval bbox指定評估邊界框檢測的指標。MMDetection會計算COCO風格的一系列指標其中最重要的是AP (Average Precision): IoU閾值從0.5到0.95步長0.05的平均精度。這是COCO的主要評價指標記為AP或AP[.5:.95]。AP50: IoU閾值為0.5時的AP即PASCAL VOC的評價標準。AP75: IoU閾值為0.75時的AP。AP_s, AP_m, AP_l: 分別對應小、中、大尺寸目標的AP。一份合格的訓練結果AP和AP50應該達到一個合理的值取決于你的數據集難度和規模。如果AP_s遠低于AP_l說明模型對小目標檢測不好可能需要調整FPN結構、使用更小的anchor或增加小目標的訓練數據。5.4 模型推理與可視化訓練出模型后我們當然想看看它的實際檢測效果。MMDetection提供了簡單的推理APIfrom mmdet.apis import init_detector, inference_detector, show_result_pyplot import mmcv # 指定配置文件和訓練好的模型 config_file my_faster_rcnn_r50_fpn_1x_mydataset.py checkpoint_file ./work_dirs/my_exp/latest.pth # 初始化模型 model init_detector(config_file, checkpoint_file, devicecuda:0) # 對單張圖片進行推理 img test.jpg # 或者 img mmcv.imread(test.jpg) result inference_detector(model, img) # 可視化結果 # show_result_pyplot函數會直接顯示圖片適合在Jupyter Notebook中使用 # show_result_pyplot(model, img, result, score_thr0.3) # score_thr是顯示分數閾值 # 更常用的方式將結果繪制到圖片上并保存 vis_img model.show_result(img, result, score_thr0.3, showFalse) mmcv.imwrite(vis_img, result.jpg) print(檢測結果已保存至 result.jpg)你可以調整score_thr來過濾低置信度的檢測框這個值需要根據你的具體應用場景來權衡召回率和精度。6. 實戰避坑指南與高級技巧6.1 常見錯誤與解決方案KeyError: ‘xxx’ is not in the fields或AssertionError: Thenum_classes(xx) shared by all branches must be the same問題這是最經典的錯誤。根本原因是模型的num_classes沒有修改或者修改得不徹底。Faster R-CNN的num_classes需要同時在roi_head.bbox_head和rpn_head如果RPN也有分類頭的話新版通常不需要中修改。最穩妥的方法是像我們之前那樣在配置文件中通過model.dict()覆蓋。解決仔細檢查配置文件確保model.roi_head.bbox_head.num_classes已正確設置為你的類別數。使用print(model)打印模型結構來確認。CUDA out of memory (OOM)問題GPU內存不足。解決減小配置中的samples_per_gpu批大小。減小輸入圖片尺寸。在train_pipeline和test_pipeline中找到Resize操作將img_scale改小例如從(1333, 800)改為(800, 600)。使用梯度累積Gradient Accumulation。這需要在優化器配置和train_cfg中設置對新手稍復雜但可以有效模擬大batch size訓練。嘗試更輕量的模型如RetinaNet或FCOS。Loss為NaN或訓練不收斂問題學習率設置不當、數據存在極端值如坐標超出圖像范圍、標注錯誤。解決首要檢查數據使用browse_dataset.py腳本仔細檢查標注框是否合理。確保bbox坐標非負且不超過圖像寬高。調整學習率根據你的batch size按線性縮放規則調整lr。如果loss爆炸變成NaN大幅降低學習率如除以10再試。使用預訓練權重確保你的配置中load_from指向了在COCO上預訓練的模型權重MMDetection會自動下載或你需要手動指定路徑。從隨機初始化開始訓練檢測器非常困難。驗證集mAP為0或極低但訓練loss正常下降問題過擬合或者訓練集和驗證集分布差異極大。解決增加數據增強的多樣性如更多的隨機裁剪、顏色抖動。檢查是否不小心在驗證集上使用了訓練時的數據增強如RandomFlip。驗證集流水線應該只有Resize,Normalize,Pad,DefaultFormatBundle等確定性操作。使用更小的模型或添加正則化如Dropout但檢測模型中不常用。確保訓練輪數max_epochs沒有過多。6.2 性能調優與進階技巧數據增強策略調優MMDetection的數據增強流水線pipeline非常靈活。對于小數據集增強是防止過擬合的關鍵。你可以在配置文件的train_pipeline中添加或調整增強操作例如train_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations, with_bboxTrue), dict(typeResize, img_scale[(1333, 800), (1600, 960)], multiscale_moderange, keep_ratioTrue), # 多尺度訓練 dict(typeRandomFlip, flip_ratio0.5), dict(typeRandomCrop, crop_size(0.8, 0.8), crop_typerelative_range), # 隨機裁剪 dict(typePhotoMetricDistortion, # 光度失真 brightness_delta32, contrast_range(0.5, 1.5), saturation_range(0.5, 1.5), hue_delta18), dict(typeNormalize, **img_norm_cfg), dict(typePad, size_divisor32), dict(typeDefaultFormatBundle), dict(typeCollect, keys[img, gt_bboxes, gt_labels]), ]注意增強不是越多越好需要根據你的任務特性調整。工業質檢可能不需要RandomFlip而自然場景目標檢測則需要。學習率策略與優化器選擇除了StepLR還可以嘗試CosineAnnealingLR余弦退火它通常能帶來更好的收斂效果和最終精度。將lr_config修改為lr_config dict( policyCosineAnnealing, warmuplinear, warmup_iters500, warmup_ratio0.001, min_lr_ratio1e-5 # 最小學習率 )對于優化器SGD with momentum是檢測任務的主流但也可以嘗試AdamW尤其在小數據集或訓練不穩定時。模型微調與凍結骨干網絡如果你的數據集與預訓練數據集如COCO差異很大或者數據量很小可以考慮凍結骨干網絡Backbone的前幾層只訓練后面的網絡層以防止過擬合和加速訓練。# 在配置文件中修改 model dict( backbonedict( frozen_stages2, # 凍結前2個stageResNet有4個stage norm_cfgdict(typeBN, requires_gradFalse), # 凍結BN層的統計量 norm_evalTrue), ... )訓練初期驗證集指標提升很快但后續可能遇到瓶頸此時可以解凍部分層繼續訓練。6.3 部署與落地考量訓練出一個指標不錯的模型只是第一步要真正用起來還需要考慮部署。模型轉換MMDetection模型通常需要轉換為其他格式以便部署。常用的有ONNX: 使用tools/deployment/pytorch2onnx.py腳本轉換可以獲得一個跨平臺的中間表示。TorchScript: 使用PyTorch自帶的torch.jit.trace或torch.jit.script進行轉換適合在PyTorch生態內部署。TensorRT (for NVIDIA GPUs): 通過ONNX中轉或直接使用MMDeploy等工具鏈可以極大提升推理速度。速度與精度權衡在配置文件中選擇不同的Backbone如將r50換成r18或mobilenetv2和Neck如修改FPN的通道數可以顯著影響模型速度和精度。MMDetection的Model Zoo提供了大量預訓練模型及其性能指標可以作為選型參考。構建簡易推理服務對于原型驗證可以快速搭建一個基于Flask或FastAPI的Web服務將上面提到的推理代碼封裝成API方便其他系統調用。走到這一步你已經完成了從數據準備到模型訓練、評估和初步部署的完整閉環。MMDetection的功能遠不止于此它支持數十種檢測算法、實例分割、全景分割等高級任務。但掌握這套基于Faster R-CNN和COCO格式的標準流程就像掌握了打開寶庫的鑰匙你可以自信地去探索更復雜的模型和任務了。記住遇到問題多查官方文檔和GitHub Issues社區里很可能已經有現成的解決方案。