Pytorch 기반의 Object Detection 오픈 소스 라이브러리
Backbone/ Neck / DenseHead / RoIHead 등의 모듈을 config 파일을 이용해 각각 커스터마이징
configs/base/ 폴더에 4가지 기본 config 파일이 존재
틀이 갖춰진 copnfig를 상속 받기 때문에 필요한 부분만 수정해 사용

sample_per_gpu
workers_per_gpu
train
val
test

Data pipeline

(초록색/주황색은 해당 step에서 직접적/간접적으로 바뀌는 부분)

type
backbone

@BACKBONES.register_module()로 커스텀 backbone 등록 가능
neck

rpn_head

roi_head

bbox_head
train_cfg
test_cfg


from mmcv import Config
from mmdet.datasets import build_dataset
from mmdet.models import build_detector
from mmdet.apis import train_detector
from mmdet.datasets import (build_dataloader, build_datasets, replace_ImageToTensor)
cfg.data.samples_per_gpu = 4
cfg.seed = 2020
cfg.gpu_ids = [0]
cfg.work_dir = './work_dirs/faster_rcnn_r50_fpn_1x_trash'
cfg.model.roi_head.bbox_head.num_classes = 11
cfg.optimizer_config.grad_clip = dict(max_norm=35, norm_type=2)
model = build_detector(cfg.model)
datasets = [build_datasets(cfg.data.train)]
train_detector(model, datasets[0], cfg, distributed=False, validate=True)
Facebook AI Research의 Pytorch 기반 라이브러리
Segmentation, Pose prediction 등의 알고리즘도 제공하지만 Object Detection으로 많이 사용됨
MMDetection과 유사하게, 기본 config를 상속 받아 필요한 부분만 수정해 파이프라인 build하고 학습
yaml 형식의 config 파일로 채움
데이터셋, 데이터로더와 관련된 config
TRAIN, TEST에 각각 등록한
train 데이터셋과 test
데이터셋의 이름을 입력함
커스텀 데이를 등록해 사용 가능하며 메타 데이터도 등록 가능







FPN

ANCHOR_GENERATOR

RPN


ROI_HEADS

ROI_BOX_HEAD


LR_SCHEDULER

WEIGHT_DECAY

CLIP_GRADIENTS

# Register Dataset
register_coco_instances("coco_trash_train", {}, '/home/data/data/train.json', '/home/data/data/')
register_coco_instances("coco_trash_val", {}, '/home/data/data/val.json', '/home/data/data')
cfg = get_cfg() # get a copy of the default config
cfg.merge_from_file(model_zoo.get_config_file('COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml'))
cfg.DATASETS.TRAIN = ("coco_trash_train",)
cfg.DATASETS.TEST = ("coco_trash_val",)
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = model.zoo.get_checkpoint_url("COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml")
cfg.SOLVER.IMS_PER_BATCH = 4
cfg.SOLVER.BASER_LR = 0.001
cfg.SOLVER.MAX_ITER = 3000 # epoch a = max_iter * batch_size / total_num_images
cfg.SOLVER.STEPS = (1000,1500) # The iteration number to decrease learning rate by GAMMA.
cfg.SOLVER.GAMMA = 0.05
cfg.MODEL_ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128
cfg.MODEL_ROI_HEADS.NUM_CLASSES = 11
cfg.TEST.EVAL_PERIOD = 500
def MyMapper(dataset_dict):
"""Mapper which uses 'detectron2.data.transforms' augmentations"""
dataset_dict = copy.deepcopy(dataset_dict)
image = utils.read_image(dataset_dict['file_name'], format = 'BGR')
transform_list = [
T.randomFlip(prob=0.4, horizontal=False, vertical=True),
T.randomBrightness(0.8, 1.8),
T.randomContrast(0.6, 1.3)
]
image, transforms = T.apply_transfrom_gens(transform_list, image)
dataset_dict['image'] = torch.as_tensor(image.transpose(2, 0, 1).astype("floar32"))
annos = [
uitls.transform_instance_annotations(obj, transforms, image.shape[:2])
for obj in dataset_dict.pop("annotations")
if obj.get("iscrowd", 0) == 0
]
instances = utils.annotations_to_instances(annos, image.shape[:2])
dataset_dict["instances"] = utils.filter_empty_instances(instances)
return dataset_dict
from detectron2.evalutaion import COCOEvaluator
from detectron2.data import build_detection_test_loader, build_detection_train_loader
class MyTrainer(DefaultTrainer):
@classmethod
def build_train_loader(cls, cfg, sampler=None):
return build_detection_train_loader(
cfg, mapper = MyMapper, sampler = sampler
)
@classmethod
def build_evaluator(cls,cfg, dataset_name, output_folder=None):
if output_folder is None:
os.makedirs("./output_eval", exist_ok=True)
output_folder = "./output_eval"
return COCOEvaluator(dataset_name, cfg, False, output_folder)
os.makedirs(cfg.OUTPUT_DIR, exist_ok = True) #'./output'
trainer = MyTrainer(cfg)
trainer.resume_or_load(resume=False)
trainser.train()
Backbone을 통과한 Feature map 중 마지막 계층이 아니라 다른 계층도 사용하기 위한 구조

다양한 계층의 Feature을 통해 다양한 크기의 객체를 더 잘 탐지
상위 feature의 semantic을 하위 feature에게 전달

상위 레벨 feature의 시멘틱 정보를 하위 레벨 feature에 전달하기 위한 방법
상위 계층을 upsample하고 기존 계층에 1x1 conv로 채널을 늘려 더함
upsample로는 Nearest Negibor Upsampling 사용



1) ResNet을 Backbone으로 사용해 중간 feature maps 추출
2) Lateral connection으로 최종 feature maps인 m2~m5 추출
3) 3x3 conv를 통해 p2~p5로 변환
3) RPN으로 각 최종 feature map 별로 ROI를 추출한 뒤 TOP N개 선정
4) 선정된 ROI를 아래 공식을 이용해 크기에 맞는 최종 feature maps에 ROI projection(클 수록 상위 feature map에)

ResNet은 수많은 conv, pooling 계층으로 이루어져있음
그러므로, low level의 feature map의 정보가 high level의 feature map에 제대로 전달 X

Top-down Path를 추가한 다음 추가로 Bottom-up Path를 추가함
low level의 feature map의 정보가 high level의 feature map에 더 잘 전달되어 성능 향상

ROI projection 시 공식에 따라 하나의 feature map만 사용하게 되면 ROI의 크기가 경계값 근처인 경우 정확한 projection이 불가능
게다가, 특정 feature map만 사용 시 그 레벨의 feature map의 semantic/detail 정보만 활용하게 됨
ROUAlign을 통해 ROI projection 시 모든 feature map들을 fc layer을 통해 적절히 활용함

Neck에 의해 Backbone model도 학습되는 효과
n번 반복되면 backbone도 n번 실행되므로 cost는 큼
ASPP 사용

여러 rate의 Atrous/dilated convolution로 pooling한 결과를 concat함
receptive field를 키우는 효과


하나의 간선을 가진 노드는 제거
Output 노드에 input 노드 간선 추가
양방향 path 각각을 하나의 feature Layer로 취급하여, repeated
blocks 활용

Lateral connections 시 FPN과 같이 단순 summation을 하는 것이 아니라 각 feature별로 가중치를 부여한 뒤 summation
모델 사이즈의 증가는 거의 없음
feature별 가중치를 통해 중요한 feature를 강조하여 성능 상승



COCO dataset, ResNet기준으로 찾은 architecture이기 때문에 범용적이지 못함
다른 Dataset이나 backbone에서 가장 좋은 성능을 내는 architecture를 찾기 위해 새로운 search cost
Parameter가 많이 필요하여 High search cost
서로 다른 level의 feature간의 semantic차이
Highest feature map의 정보 손실
1개의 feature map에서 RoI 생성

가장 마지막보다 높은 가상의 feature맵을 추가하여 Highest feature map의 정보 손실 막음
Ratio-invariant Adaptive Pooling으로 다양한 scale의 feature map 생성
각각의 feature map을 동일 size로 upsampling한 후 가중치를 두어 summation(like transformer)
가중치 summation 과정에서 concat - conv 1x1 - conv 3x3 - sigmoid를 거침


FPN과 같이 하나의 feature map에서 RoI를 계산하는 경우 sub-optimal
이를 해결하기 위해 PANet에서 모든 feature map을 이용했지만, max pool하여 정보 손실 가능성
PANet과 달리 Channel-wise 가중합 사용
