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