[TOC] # 安裝環境 > 官網: https://mmdetection.readthedocs.io/zh-cn/v3.2.0/get_started.html > 中文教學: https://blog.csdn.net/qq_16137569/article/details/121316235 > * mmdetection 3.2.0 > * mmengine 0.10.1 > * mmcv 2.1.0 > * pytorch 1.8.0 > * cuda 11.1 # Open-mmlab簡介 主要是目前常見的所有模型集合的工具包,使用者只需要修改幾行參數檔即可開始訓練模型或是測試模型。其中包含許多常見的物件檢測或是其他task的模型,如常見的Yolo系列、RCNN系列等。 ![image](https://hackmd.io/_uploads/B1geQUwrp.png) 目前共有以下的Libraries可使用,每個library下都有包含需多常見的Model可使用。 使用者也可以根據需求去更改模型中特定的module或是其他參數 ![image](https://hackmd.io/_uploads/HyVzNIvB6.png) # mmdetction整體架構 ![image](https://hackmd.io/_uploads/HkhZZIPra.png) # 支持的Backbone、Neck、Loss | Backbones | Necks | Loss | |:-----------------:|:-----------------:|:------------------------:| | CspDarknet | Bfp | VarifocalLoss | | Cspnet | ChannelMapper | AeLoss | | Darknet | CspnetPafpn | BalancedL1Loss | | DetectorsResnet | CtResnetNeck | CrossEntropyLoss | | DetectorsResnext| DilatedEncoder | DdqDeterAuxLoss | | Efficientnet | Dyhead | DiceLoss | | Hourglass | Fpg | Eqlv2Loss | | Hrnet | Fpn | FocalLoss | | MobilenetV2 | FpnCarafe | GaussianFocalLoss | | PVT | FpnDropblock | GfocalLoss | | Regnet | Hrfpn | GhmLoss | | Res2Net | NasFpn | IOULoss | | Resnest | NasfcosFpn | KdLoss | | Resnet | Pafpn | L2Loss | | Resnext | Rfp | MarginLoss | | SAMBackbone | SsdNeck | MseLoss | | SsdVgg | Ssh | MultiposCrossEntropyLoss| | Swin | YoloNeck | PisaLoss | | TridentResnet | YoloxPafpn | SeesawLoss | | | | SmoothL1Loss | | | | TripletLoss | # 支持的Augmentation * Resize * RandomFlip * RandomCrop * PhotoMetricDistortion * MinIoURandomCrop * Mosaic * MixUp * CopyPaste # 可用模型 1. [MMDetection](https://github.com/open-mmlab/mmdetection) 2. [MMSegmentation](https://github.com/open-mmlab/mmsegmentation) 3. [MMYOLO](https://github.com/open-mmlab/mmyolo) # mmdetection的優缺點 :::success 優點: 1. 能夠用非常簡單的方式客制化模型,如更改訓練參數、module更改、資料處理流程、優化器更改、訓練流程、Confusion Matrix生成 2. 支援多GPU同時訓練、分散式訓練 3. 多種分析工具可直接使用,如自動檢驗資料集、各種評估指標分析、模型複雜度、模型參數量等 4. 只需要一行指令即可開始training和testing 5. 支援轉換到onnx或是TensorRT ::: :::danger 缺點: 1. 要添加自訂的model需要follow預定的格式和方法,成本較高 2. 版本間差異大 3. Augmentation支援不多,需要自己手動添加 ::: # 使用教學 ## Config命名規則 ``` {model}_{backbone}_{neck}_{schedule}_{dataset} ``` - {model}: model 種類,例如:faster\_rcnn, mask\_rcnn 等 - {backbone}:Backbone 種類,例如:r50 (ResNet-50), x101 (ResNeXt-101) 等。 - {neck}:Neck 種類,例如:fpn, pafpn, nasfpn, c4 等。 - {schedule}: 訓練方案,選項是 1x、 2x、 20e 等。1x 和 2x 分別代表 12 epoch 和 24 epoch,20e 在級聯 (Cascaded) 模型中使用,表示 20 epoch。 - {dataset}:資料集,例如:coco、 cityscapes、 voc\_0712、 wider\_face 等。 ## 參數檔設置 在mmdetection或是其他的library中,都是使用config檔去training或是testing。 下面以Cascade-Mask-Rcnn的config檔來做介紹: ```python= # 繼承其他的config,可以增加程式的使用率 _base_ = [ '../_base_/models/cascade-mask-rcnn_r50_fpn.py', # model '../_base_/datasets/coco_instance.py', # 用哪一種資料預處理方式 '../_base_/schedules/schedule_2x.py', # 用哪一種訓練流程 '../_base_/default_runtime.py' ] ``` 我們是從**cascade-mask-rcnn_r50_fpn**去進行更改的,所以下面主要是針對想客制化的地方去做更改 (像是class的數量、損失函數等) ```python= model = dict( type='CascadeRCNN', ###### Backbone ###### backbone=dict( type='ResNet', depth=50 ), ###### Neck ###### neck=dict( type='FPN' ), ####### Head ###### roi_head=dict( type='CascadeRoIHead', bbox_head=[ dict( type='Shared2FCBBoxHead', num_classes=16, # 類別數量 loss_bbox=dict(type='L1Loss', loss_weight=1.0) # bbox的損失函數 ), dict( type='Shared2FCBBoxHead', num_classes=16, loss_bbox=dict(type='L1Loss', loss_weight=1.0) ), dict( type='Shared2FCBBoxHead', num_classes=16, loss_bbox=dict(type='L1Loss', loss_weight=1.0) ) ], mask_head=dict( type='FCNMaskHead', num_classes=16 ) ) ) ``` DataLoader也可以利用Config檔去做設定 ```python= ####### 訓練集的dataloader ####### train_dataloader = dict( batch_size=2, # 一個GPU的batchsize num_workers=2, dataset=dict( type=dataset_type, data_root=data_root, metainfo=dict(classes=classes), ) ) ####### 測試集的dataloader ####### test_dataloader = dict( batch_size=1, num_workers=2, dataset=dict( type=dataset_type, data_root=data_root, metainfo=dict(classes=classes), ), ) ``` ## Training ### 單GPU訓練 ```bash python tools/train.py \ ${CONFIG_FILE} \ ``` ### 多GPU訓練 ```bash bash ./tools/dist_train.sh \ ${CONFIG_FILE} \ ${GPU_NUM} \ ``` ## Testing ### 1. 只有評估數據 ```bash python tools/test.py \ ${CONFIG} \ ${WEIGHT} ``` ### 2. 預測結果可視化(不含label) ```bash python demo/image_demo.py \ ${IMAGE or DIR} \ ${CONFIG} \ --weight ${WEIGHT} \ --out-dir ${OUTPUT DIR} \ --show # 是否要顯示結果 ``` 如果遇到 ```unknown argument {'sam_entities'} for `preprocess`, `forward`, `visualize` and `postprocess``` 的錯誤,可以開啟這個```image_demo.py```並註解掉第95行左右的code ```python= # parser.add_argument( # '--sam-entities', # '-c', # action='store_true', # help='Whether to customize entity names? ' # 'If so, the input text should be ' # '"cls_name1 . cls_name2 . cls_name3 ." format') ``` ### 3. 預測結果可視化(含label) ```bash python tools/test.py \ ${CONFIG} \ ${WEIGHT} \ --show-dir ${OUTPUT DIR} \ # 會存在 work_dir/timestamp/show_dir下 --show # 是否要顯示結果 ``` ### 4. 計算fps ```bash python tools/analysis_tools/benchmark.py \ ${CONFIG} \ --checkpoint ${WEIGHT} \ --task inference # 有三個可以選['inference', 'dataloader', 'dataset'] --dataset-type val # 有三個可以選['train', 'val', 'test'] --log-interval 20 # 預設是50,但是這樣執行會有錯誤 ``` ## Inference ```python= from mmdet.apis import DetInferencer # Initialize the DetInferencer inferencer = DetInferencer(model='path/to/config.py', weights='path/to/weight.pth') # Perform inference inferencer('demo/demo.jpg', show=True) ``` ![image](https://hackmd.io/_uploads/BJ4vYhOB6.png) ## 建構自己的模型 在建立自己的模型前,一定要先建構Backbone和Head, ## Backbone 在```mmdet/models/backbones/```創建一個SAMBackbone.py ```python= import torch.nn as nn from mmdet.registry import MODELS from mmcv.cnn import ConvModule @MODELS.register_module() class SAMBackbone(nn.Module): def __init__(self): super().__init__() def forward(self, inputs): pass ``` 建立好了之後要到```mmdet/models/backbones/__init__.py```底下新增 ```python= from .SAMBackbone import SAMBackbone ``` ## Head 在```mmdet/models/seg_heads/```創建一個SAMHead.py ```python= from torch import Tensor from mmdet.registry import MODELS @MODELS.register_module() class SAMHead(BaseSemanticHead): def __init__(self, num_classes: int, in_channel: int, img_size: list) -> None: super().__init__() self.img_size = img_size def forward(self, x: Union[Tensor, Tuple[Tensor]]) -> Dict[str, Tensor]: pass def loss(self, x: Union[Tensor, Tuple[Tensor]], batch_data_samples: SampleList) -> Dict[str, Tensor]: pass ``` 建立好了之後要到```mmdet/models/seg_heads/__init__.py```底下新增 ```python= from .SAMHead import SAMHead ```