mmdet train
DataSet
Data 수집
기존 데이터셋 : 다운로드
- coco : https://cocodataset.org/#home
- pascal voc
신규 데이터셋 : 구성
1. Image 수집
- 직접수집
- 동영상에서 이미지 추출 (ffmpeg 사용)
ffmpeg -i example.mp4 -vf fps=Afolder/ex_detect_%4d.jpg - google에서 수집
- Unity를 통해 가상데이터 생성
2. Annotation (CVAT 사용)
- Bbox
- Polygon : segmentation
- Key-point (top-down, down-top)
3. 데이터셋 만들기 (Image와 Annotation을 연결)
- CoCo 데이터셋 포멧으로 CVAT에서 Export
(keypoint에 경우, coco형식으로 export가 되지 않아, CVAT(xml)포멧으로 내보내기 한후, datumaru를 통해 coco 데이터셋으로 변환 - Custom 데이터셋
mmdetection에서 custom dataset 등록후 사용
DataSet 구성 (train / valid & test)
train / valid & test 데이터셋 준비 : 이미지는 그대로 두고, 각 DataSet별로 Annotation파일 분리하여 준비
(coco데이터셋은 새로 annotation후 채번을 다시 해야함)
Config에서, 소스의 trn, val, tst 의 디렉토리 구조 결정
커스텀 데이터셋의 경우
MyCustomDataset을 등록 (load_annotations 잘 수정해서)
dataset 생성
- datasets = [build_dataset(cfg.data.train)] # /tools/train.py에서
cocoset으로 변환
웬만하면 Coco로 변환
Model
모델 선정
open-mmlab/mmdetection 의 model-zoo
Model-zoo 에서
ex) faster_rcrnn
https://comlini8-8.tistory.com/86
MMDet 모델을 5가지 요소로 구분
Backbone | 피처맵을 추출하기 위한 FCN 네트워크 | (ex. ResNet, MobileNet) |
neck | backbone과 head 사이를 연결하는 요소 | (ex. FPN, PAFPN) |
head | 구체적인 태스크를 위한 요소 | (ex. bbox prediction, mask prediction) |
roi extractor | 피처맵으로부터 RoI 특징을 추출하는 부분 | (ex. RoI Align) |
loss | loss를 계산하기 위한 head의 구성 요소 | (ex. FocalLoss, L1Loss, GHMLoss) |
checkpoints 파일 준비
mmdet 에서 ConvNeXt (CVPR’2022).
Model Zoo에서 pretrained Model의 네트웍을 받아옴.
w g e t -O checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
configuration – Config
기존 Config 가져오기
sixxconfigs/makeConfig.py 를 통해 초기 Config 생성
import os from mmcv import Config os.chdir('/home/oschung_skcc/my/git/mmdetection') config_file = 'configs/convnext/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco.py' out_config = 'sixxconfigs/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco_sixx.py' cfg = Config.fromfile(config_file) #print(cfg.pretty_text) try: with open(out_config, 'w') as f: f.write(cfg.pretty_text) except FileNotFoundError: print("The 'docs' directory does not exist")
import argparse import logging import os from mmcv import Config parser = argparse.ArgumentParser(description="") parser.add_argument("-i", "--fromconfig", default='', type=str, metavar="PATH", help="path from getting config") parser.add_argument("-o", "--toconfig", default='', type=str, metavar="PATH", help="path to getting config") def print_info(message: str): logging.info(message) def main(): print_info("Starting...") args = parser.parse_args() if not args.fromconfig : print("Warning!", "Nothing to set.\ Please specify a path!") print_info("Exiting...") return else: config_file = args.fromconfig if not args.toconfig: out_config = 'sixxconfigs/'+ os.path.basename(args.fromconfig) print(args.toconfig) else: out_config = args.toconfig os.chdir('/home/oschung_skcc/my/git/mmdetection') # config_file = 'configs/convnext/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco.py' # out_config = 'sixxconfigs/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco_sixx.py' cfg = Config.fromfile(config_file) #print(cfg.pretty_text) try: with open(out_config, 'w') as f: f.write(cfg.pretty_text) except FileNotFoundError: print("The 'docs' directory does not exist") print_info("... End") if __name__ == "__main__": main()
쉬운 수정을 위해 풀어진 config 만들기
$ python sixxtools/makeConfig_sixx.py \\ --fromconfig configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py \\ --toconfig sixxconfigs/faster_rcnn_r50_fpn_1x_coco_001.py
$ python sixxtools/misc/print_config.py \\ configs/convnext/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco.py
config 대분류 및 주요설정내역
config 대분류 | 설명 |
dataset | dataset의 type(customdataset, cocodataset 등), train/val/test dataset 유형, data_root, train/val/test dataset의 주요 파라미터 설정(type, ann_file, img_prefix, pipeline 등) |
model | object detection model의 backbone, neck, dense head, roi extractor, roi head(num_classes=4) 주요 영역별로 세부 설정 |
scheduler | optimizer 유형 설정 (sgd, adam, rmsprop 등), 최초 learning 설정 학습중 동적 learning rate 적용 정책 설정(step, cyclic, cosine annealing 등) train 시 epochs 횟수 : learning rate scheduler |
runtime | 주로 hook(callback)관련 설정 학습 중 checkpoint 파일, log 파일 생성을 위한 interval epochs 수 |
config 수정
기존 config가져와서, training에 사용할 config 파일생성
sixxconfigs/faster_rcnn_r50_fpn_1x_coco_sixx.py 그리고 수정
- num_classes=4, 수정(model아래)
- dataset_type = ‘CocoDataset’ 확인
- data_root = ‘data/msc_pilot2/’ 수정
- classes = [‘TRAY_A_1’, ‘TRAY_A_2’, ‘TRAY_A_3’, ‘TRAY_B_1’] 추가
- …
gpu
- samples_per_gpu
- workers_per_gpu
data
- train / val / test
– ann_file 수정
– classes 추가
config 수정 예
model = dict( roi_head=dict( bbox_head=dict( num_classes=4, dataset_type = 'CocoDataset' #data_root = 'data/coco/' data_root = 'data/msc_pilot2/' classes=('Car', 'Truck', 'Pedestrian', 'Cyclist') data = dict( train=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc.json', #img_prefix='data/kitti_tiny/training/image_2', classes=classes, val=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc_val.json', #img_prefix='data/kitti_tiny/training/image_2', classes=classes, test=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc_val.json', #img_prefix='data/kitti_tiny/training/image_2', classes=classes, )
W&B설정 예
#log_config = dict(interval=1, hooks=[dict(type='TextLoggerHook')]) log_config = dict( interval=10, #500 hooks=[ dict(type='TextLoggerHook', interval=500), dict(type='WandbLoggerHook', interval=1000, init_kwargs=dict( project='faster_rcnn_r50_fpn_1x', #entity = 'ENTITY 이름', name='sixx_tray') ) ] ) # workflow = [('train', 1)] # 1 epoch에 train과 validation을 모두 하고 싶으면 workflow = [('train', 1), ('val', 1)]
transfer learning
load_from = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
# 200epoch 학습하는 동안 50번 마다 pth파일 만들고, 100번마다 로그 찍음 # 평가는 200번 돌고 함. evaluation = dict(interval=200, metric='mIoU') #'mAP') runner = dict(type='EpochBasedRunner', max_epochs=400) checkpoint_config = dict(interval=50) log_config = dict(interval=100, hooks=[dict(type='TextLoggerHook')]) # 학습율 변경 환경 파라미터 설정. optimizer = dict(type='SGD', lr=0.02/8, momentum=0.9, weight_decay=0.0001) lr_config = dict( policy='step', warmup=None, warmup_iters=500, warmup_ratio=0.001, step=[8, 11]) # 가장 최근꺼 부터 이어서 학습 resume_from = 'work_dirs/sixx_faster_rcnn_r50_fpn_1x_coco/latest.pth'
예시2>
model = dict( roi_head=dict( bbox_head=dict( num_classes=4, \t\t\t\t dict( num_classes=4, \t\t\t dict( num_classes=4, ... mask_head=dict( num_classes=4, dataset_type = 'CocoDataset' data_root = 'data/kitti_tiny/' classes=('Car', 'Truck', 'Pedestrian', 'Cyclist'), data = dict( samples_per_gpu=4, workers_per_gpu=4, train=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc.json', img_prefix='data/kitti_tiny/training/image_2', classes=classes, val=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc_val.json', img_prefix='data/kitti_tiny/training/image_2', classes=classes, test=dict( type='CocoDataset', ann_file='data/kitti_tiny/anno_cc_val.json', img_prefix='data/kitti_tiny/training/image_2', classes=classes, ) evaluation = dict(metric=['bbox', 'segm'], save_best='auto', interval=50) runner = dict(type='EpochBasedRunner', max_epochs=10000) checkpoint_config = dict(interval=500) # workflow = [('train', 1)] # 1 epoch에 train과 validation을 모두 하고 싶으면 workflow = [('train', 1), ('val', 1)] #load_from = 'checkpoints/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco_20220510_201004-3d24f5a4.pth' load_from = 'https://download.openmmlab.com/mmclassification/v0/convnext/downstream/convnext-small_3rdparty_32xb128-noema_in1k_20220301-303e75e3.pth'
runner 의 max_epochs 가 원하는 epoch 46
Batch_size
step 1473/ 46 약 32 …= iteration..
평가 (evaluation, 50번에 한번)
checkpoint 1번에 한번
log_config 1번
CUDA_VISIBLE_DEVICES=2,3 port=29506 sixxtools/dist_train.sh "sixxconfigs/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco_sixx.py" 2
work_dir = './work_dirs/cascade_mask_rcnn_convnext-s_p4_w7_fpn_giou_4conv1f_fp16_ms-crop_3x_coco_sixx' auto_resume = False gpu_ids = range(0, 2)
model
- num_class
dataset_type
data_root
classes
data
- samples_per_gpu
- workers_per_gpu
- train / val / test
– ann_file
– classes
load_from
evaluation
- save_best=’auto’, interval=50
checkpoint_config
optimizer의 lr 줄임
lr_config = dict( policy='step', # 어떤 scheduler 를 쓸건지 warmup='linear', # warmup을 할건지 warmup_iters=500, # warmup iteration 얼마나 줄건지 warmup_ratio=0.001, step=[8, 11]) # step은 얼마마다 밟은 건지
runner (_1x는 epoch 12번, _2x는 epoch 24번, _20e는 epoch 20번을 의미)
- max_epochs=10000
auto_resume
gpu_ids
https://onesixx.com/mmdet-log/
# 평가는 200번 돌고 함. evaluation = dict(interval=200, metric='mIoU') #'mAP') # 200 epoch 학습하는 동안 50번 마다 pth파일 만들고, 100번마다 로그 찍음 runner = dict(type='EpochBasedRunner', max_epochs=400) checkpoint_config = dict(interval=50) log_config = dict(interval=100, hooks=[dict(type='TextLoggerHook')]) # 학습율 변경 환경 파라미터 설정. optimizer = dict(type='SGD', lr=0.02/8, momentum=0.9, weight_decay=0.0001) lr_config = dict( policy='step', warmup=None, warmup_iters=500, warmup_ratio=0.001, step=[8, 11]) # 가장 최근꺼 부터 이어서 학습 resume_from = 'work_dirs/sixx_faster_rcnn_r50_fpn_1x_coco/latest.pth'
GPU사용량 모니터링 (nvidia-smi, nvitop, gpustat)
watch -d -n 0.5 nvidia-smi
$ conda update -n base -c defaults conda # https://anaconda.org/conda-forge/nvitop # https://github.com/XuehaiPan/nvitop $ conda install -c conda-forge nvitop $ nvitop # https://anaconda.org/conda-forge/gpustat $ conda install -c conda-forge gpustat $ gpustat
Training 실행
$ python sixxtools/train.py "sixxconfigs/faster_rcnn_r50_fpn_1x_coco_sixx.py"
~/my/git/mmdetection/tools ==> sixxtools
$ python sixxtools/train.py \\ "sixxconfigs/cascade_rcnn_r50_fpn_1x_coco.py" \\ --work-dir "work_dirs/ttt"
work_dirs에 작업할 폴더를 만들어짐
수정된 cfg 확인
epoch_69.pth (PyTorch Model)이 생성된다.
모델 실험을 위한 config 수정
https://pebpung.github.io/wandb/2021/10/06/WandB-1.html
직관적으로 수정하는 방법은 비효율적이다..
여러 GPU 사용
$ CUDA_VISIBLE_DEVICES=2,3 port=29506 sixxtools/dist_train.sh work_dirs/sixx_faster_rcnn_r50_fpn_1x_coco.py 2
$ CUDA_VISIBLE_DEVICES=2,3,4,5,6,7 port=29506 sixxtools/dist_train.sh sixxconfigs/faster_rcnn_r50_fpn_1x_coco_sixx.py 6
CUDA_VISIBLE_DEVICES로 사용할 GPU를 한정해주고,
Port를 분리한 후,
실행
CUDA_VISIBLE_DEVICES=2,3 python train.py
CUDA_VISIBLE_DEVICES=2,3 python train.py
CUDA_VISIBLE_DEVICES=2,3 python train.py
참고
#!/usr/bin/env bash CONFIG=$1 GPUS=$2 NNODES=${NNODES:-1} NODE_RANK=${NODE_RANK:-0} PORT=${PORT:-29501} MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \\ python -m torch.distributed.launch \\ --nnodes=$NNODES \\ --node_rank=$NODE_RANK \\ --master_addr=$MASTER_ADDR \\ --nproc_per_node=$GPUS \\ --master_port=$PORT \\ $(dirname "$0")/train.py \\ $CONFIG \\ --seed 0 \\ --launcher pytorch ${@:3}
gpu_ids = range(1,3)
$ watch -d -n0.5 nvidia-smi ~/my/git/mmdetection$ bash sixx/dist_train.sh work_dirs/sixx_faster_rcnn_r50_fpn_1x_coco/sixx_faster_rcnn_r50_fpn_1x_coco.py 3
다시 Training work_dirs
sixx/dist_train.sh: line 2: $’\r’: command not found
이런 에러가 날 경우, 전체 줄바꿈(Carriage return과 New Line \r )을 newline( )으로 바꿔준다.
sed -i -e ‘s/\r$//’ ./sixx/dist_train.sh
https://github.com/open-mmlab/mmdetection/issues/334
$ bash tools/dist_train.sh configs/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoints.py 1 --work-dir work_dirs/slowonly_r50_u48_240e_ntu120_xsub_keypoints --validate --test-best --seed 0 --deterministic
https://github.com/facebookresearch/maskrcnn-benchmark
export NGPUS=2 CUDA_VISIBLE_DEVICES=2,3 python -m torch.distributed.launch --nproc_per_node=$NGPUS tools/train.py configs/faster_rcnn_r101_fpn_1x.py --gpus 2
https://artiiicy.tistory.com/61
“CUDA_VISIBLE_DEVICES”를 통해 cuda가 볼 수 있는 GPU 제한하기
항상 cuda는 GPU 0번(torch.cuda.current_device())부터 사용을 하게 되고, CUDA_VISBLE_DEVICES= 2,3 이라면, cuda는 2,3번째만 볼수 있기때문에 GPU 0을 할당하는다는 것이 2를 사용하는것과 같다.
단, multi인 경우, nn.DataParallel()을 작성해주어야 한다.
1-2) Jupyter notebook 등의 python script “~.ipynb” file 내에서 돌리는 경우
“~.ipynb” 와 같이 python script 내에서 돌리는 경우에는 다음과 같이 os.environ[ ] code를 활용하여 environment를 설정하여 실행할 수 있다.
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID" # Arrange GPU devices starting from 0 os.environ["CUDA_VISIBLE_DEVICES"]= "2,3" # Set the GPUs 2 and 3 to use
$ python sixx/train.py work_dirs/sixx_faster_rcnn_r50_fpn_1x_coco.py
$ python sixxtools/train.py sixxconfigs/cascade_rcnn_r50_fpn_1x_coco.py