MMDetection - 단일 클래스 Object Detection

dumbbelldore·2025년 1월 17일
0

zero-base 33기

목록 보기
81/97

1. 단일 클래스 Ojbect Detection

  • 모델이 하나의 객체 클래스만 탐지할 수 있도록 설계된 경우를 지칭
    예시) 특정 교통 표지판 탐지: "STOP" 표지판만 탐지
  • 탐지 결과에는 바운딩 박스와 단일 클래스 레이블만 포함됨
  • 특정 객체에 최적화되어 정확도가 높은 편이며, 모델이 단순하고 경량화되어 속도가 빠름 특징을 가짐

2. Faster R-CNN

  • R-CNN을 개선한 Fast R-CNN을 더욱 발전시킨 모델로, 가장 큰 특징은 Region Proposal Network(RPN)의 도입이라고 볼 수 있음
  • RPN에 기반하여 GPU를 사용할 수 있어 실시간 객체 검출이 가능한 수준의 속도와 높은 정확도를 가짐

출처: R. Girshick et al.(2014), Rich feature hierarchies for accurate object detection and semantic segmentation Tech report (v5)


3. Annotation File

  • 객체 탐지(Object Detection), 이미지 분할(Image Segmentation) 등의 컴퓨터 비전 작업에서 이미지 데이터에 대한 라벨 정보를 저장한 파일을 지칭
  • 모델 학습 및 평가 시 사용되며, 이미지와 관련된 객체의 위치, 클래스 등과 같은 중요 정보를 포함함

json 기반 Annotation File 예시


4. COCO 데이터 포맷

  • COCO(Common Objects in Context) 데이터 포맷은 컴퓨터 비전 작업에 널리 사용되는 JSON 기반의 데이터 포맷
  • 객체의 위치, 클래스, 세그멘테이션 마스크 등 다양한 정보를 체계적으로 저장하며, 학습 및 평가를 위해 표준화된 형식을 제공함
  • 주요 구성요소
    • images: 이미지 메타데이터
    • annotations: 객체의 바운딩 박스, 클래스, 세그멘테이션 마스크 등
    • categories: 클래스 정보
    • licensesinfo: 데이터셋 라이선스와 기타 정보
{
  "info": { // 일반 정보
    "year": 2025,
    "version": "1.0",
    "description": "COCO-style dataset",
    "contributor": "Your Name",
    "date_created": "2025-01-16"
  },
  "licenses": [ // 라이센스 정보
    {
      "id": 1,
      "name": "Creative Commons Attribution 4.0",
      "url": "http://creativecommons.org/licenses/by/4.0/"
    }
  ],
  "images": [ // 이미지 파일 메타데이터
    {
      "id": 1,
      "file_name": "image1.jpg",
      "height": 480,
      "width": 640,
      "date_captured": "2025-01-15",
      "license": 1
    }
  ],
  "annotations": [
    {
      "id": 1,
      "image_id": 1,
      "category_id": 1, // 객체의 클래스 ID
       // 바운딩 박스 좌표와 크기 (x_min, y_min, width, height)
      "bbox": [50, 100, 150, 200],
      "area": 30000, // 객체 면적
      // 세그멘테이션 마스크(픽셀 좌표)
      "segmentation": [
        [50, 100, 200, 100, 200, 300, 50, 300]  
      ],
      "iscrowd": 0
    }
  ],
  "categories": [
    {
      "id": 1,
      "name": "cat", // 클래스 이름
      "supercategory": "animal"
    }
  ]
}

5. 예제 코드

5-1. 풍선 데이터셋 다운로드

  • MMDetection 설치 경로에 다음 파일 다운로드 및 압축해제
wget -c https://github.com/matterport/Mask_RCNN/releases/download/v2.1/balloon_dataset.zip

# unzip이 설치되지 않은 경우 apt-get install unzip으로 선설치 필요
unzip balloon_dataset.zip -d ./balloondataset/
  • 데이터셋 크기 확인
import glob
import os

MMDET_PATH = "/workspace/mmdetection"

print(f"train size: {len(glob.glob(os.path.join(MMDET_PATH, 'balloondataset/balloon/train/*.jpg')))}")
print(f"val size: {len(glob.glob(os.path.join(MMDET_PATH, 'balloondataset/balloon/val/*.jpg')))}")
# train size: 61
# val size: 13
  • 샘플 데이터 확인
import mmcv
import matplotlib.pyplot as plt

fname = os.listdir(os.path.join(MMDET_PATH, "balloondataset/balloon/train/"))[0]
img = mmcv.imread(os.path.join(MMDET_PATH, "balloondataset/balloon/train", fname))
plt.figure(figsize=(8,4))
plt.imshow(mmcv.bgr2rgb(img))
plt.axis(False)
plt.show()

5-2. 풍선 데이터셋 변환 (COCO 포맷)

  • 샘플 데이터의 Annotation 확인
import mmengine

annotation = mmengine.load(os.path.join(MMDET_PATH, "balloondataset/balloon/train/via_region_data.json"))
ann_sample = annotation[fname+"1115004"] # Annotation File 참조
print(ann_sample)

# {'fileref': '',
#  'size': 1115004,
#  'filename': '34020010494_e5cb88e1c4_k.jpg',
#  'base64_img_data': '',
#  'file_attributes': {},
#  'regions': {'0': {'shape_attributes': {'name': 'polygon',
#     'all_points_x': [1020,
#      1000,
#      994,
# (후략)
  • COCO 포맷 변환용 함수 정의
def COCOConverter(ann_file, out_file, img_prefix):
    # Annotation File 읽어오기
    data_infos = mmengine.load(ann_file)

    annots, images = list(), list()
    obj_cnt = 0

    # Annotation File 값을 하나씩 불러오기
    for idx, v in enumerate(mmengine.track_iter_progress(list(data_infos.values()))):
        file_name = v["filename"]
        img_path = os.path.join(img_prefix, file_name)
        height, width = mmcv.imread(img_path).shape[:2] # (높이, 너비, 채널) 중 채널 제외

        images.append(
            dict(
                id = idx,
                file_name = file_name,
                height = height,
                width = width,
            )
        )

        bboxes, labels, masks = list(), list(), list()

        for _, obj in v["regions"].items():
            assert not obj["region_attributes"]
            obj = obj["shape_attributes"]
            px = obj["all_points_x"]
            py = obj["all_points_y"]
            
            # COCO와 Balloon 데이터셋의 좌표 보정
            poly = [(x+0.5, y+0.5) for x, y in zip(px, py)] # [(1.5, 2.5), (2.5, 7.5) ...]
            poly = [p for x in poly for p in x] # [1.5, 2.5, 2.5, 7.5, ...]

            x_min, y_min, x_max, y_max = (min(px), min(py), max(px), max(py))

            annot = dict(
                image_id = idx,
                id = obj_cnt,
                category_id = 0,
                bbox = [x_min, y_min, x_max-x_min, y_max-y_min],
                area = (x_max - x_min) * (y_max - y_min),
                segmentation = [poly],
                iscrowd=0,
            )
            annots.append(annot)
            obj_cnt += 1

    coco = dict(
        images=images,
        annotations=annots,
        categories=[{"id": 0, "name": "balloon"}], # 단일 Class
    )
    mmengine.dump(coco, out_file) # COCO 포맷 파일 저장  
  • COCO 포맷 변환
TRAIN_PATH = "balloondataset/balloon/train"
VAL_PATH = "balloondataset/balloon/val"

# Train 데이터 변환
COCOConverter(
    os.path.join(MMDET_PATH, TRAIN_PATH, "via_region_data.json"),
    os.path.join(MMDET_PATH, TRAIN_PATH, "annotation_coco.json"),
    os.path.join(MMDET_PATH, TRAIN_PATH, ""),
)

# Val 데이터 변환
COCOConverter(
    os.path.join(MMDET_PATH, VAL_PATH, "via_region_data.json"),
    os.path.join(MMDET_PATH, VAL_PATH, "annotation_coco.json"),
    os.path.join(MMDET_PATH, VAL_PATH, ""),
)

5-3. Faster R-CNN 다운로드

  • MMDetection 설치 경로에 다음 명령어 입력하여 config 파일과 모델 다운로드
mim download mmdet --config faster-rcnn_r50_fpn_1x_coco --dest ./checkpoints
  • config 파일 수정
from mmengine import Config

# config 파일 로드
cfg = Config.fromfile(os.path.join(MMDET_PATH, "checkpoints/faster-rcnn_r50_fpn_1x_coco.py"))

from mmengine.runner import set_random_seed

# Class 정보 수정
cfg.metainfo = {
    "classes": ("balloon",), # 단일 Class
    "palette": [(220, 20, 60),], # Class 수와 일치
}
cfg.model.roi_head.bbox_head.num_classes = 1

# 데이터셋 정보 수정
cfg.data_root = os.path.join(MMDET_PATH, "balloondataset/balloon")
cfg.train_dataloader.dataset.ann_file = "train/annotation_coco.json" # data_root 이하
cfg.train_dataloader.dataset.data_root = cfg.data_root
cfg.train_dataloader.dataset.data_prefix.img = "train/"
cfg.train_dataloader.dataset.metainfo = cfg.metainfo

cfg.val_dataloader.dataset.ann_file = "val/annotation_coco.json"
cfg.val_dataloader.dataset.data_root = cfg.data_root
cfg.val_dataloader.dataset.data_prefix.img = "val/"
cfg.val_dataloader.dataset.metainfo = cfg.metainfo

cfg.test_dataloader = cfg.val_dataloader

# Evaluator 수정
cfg.val_evaluator.ann_file = cfg.data_root + "/" + "val/annotation_coco.json"
cfg.test_evaluator = cfg.val_evaluator

# 모델 경로 수정
cfg.load_from = "checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth"

# 학습결과 저장 경로 수정
cfg.work_dir = os.path.join(MMDET_PATH, "work_dir/balloon/objD")

# Val 인터벌 설정 (3 epoch 마다 validation 실시)
cfg.train_cfg.val_interval = 3
cfg.default_hooks.checkpoint.interval = 3

# Logging 인터벌 설정
cfg.default_hooks.logger.interval = 10

# Learning Rate 설정 
cfg.optim_wrapper.optimizer.lr = 0.02 / 8

# Seed 설정
cfg.seed = 0

# Visualizer 설정
cfg.visualizer.vis_backends.append({"type": "TensorboardVisBackend"})

# 수정 config 저장
with open(os.path.join(MMDET_PATH, "checkpoints/balloon_objD.py"), "w") as f:
    f.write(cfg.pretty_text)

5-4. 학습 진행

  • bash에서 저장한 config 파일을 불러와 학습 진행
python tools/train.py ./checkpoints/balloon_objD.py
# (앞부분 생략)
#  Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=1000 ] = 0.808
#  Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=1000 ] = 0.000
#  Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=1000 ] = 0.775
#  Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=1000 ] = 0.864
# 01/16 14:44:57 - mmengine - INFO - bbox_mAP_copypaste: 0.760 0.881 0.865 0.000 0.639 0.830
# 01/16 14:44:57 - mmengine - INFO - Epoch(val) [12][13/13]    coco/bbox_mAP: 0.7600  coco/bbox_mAP_50: 0.8810  coco/bbox_mAP_75: 0.8650  coco/bbox_mAP_s: 0.0000  coco/bbox_mAP_m: 0.6390  coco/bbox_mAP_l: 0.8300  data_time: 0.0067  time: 0.0685

5-5. 결과 확인

  • Tensorboard 기반 시각화
import tensorboard
%reload_ext tensorboard
%tensorboard --logdir "/workspace/mmdetection/work_dir/balloon/objD/20250116_144309"

5-6. 샘플 데이터 추론

  • 학습된 모델로 Object Detection 실시
import mmcv
from mmdet.apis import init_detector, inference_detector
import random

# Val 데이터셋 중 샘플 이미지 1개 추출
img_list = [img for img in os.listdir(os.path.join(MMDET_PATH, VAL_PATH)) if img.endswith("jpg")]
samp = random.sample(img_list, k=1)[0]
print(samp) # 3825919971_93fb1ec581_b.jpg

img = mmcv.imread(os.path.join(MMDET_PATH, VAL_PATH, samp), channel_order="rgb")
checkpoint_file = os.path.join(MMDET_PATH, "./work_dir/balloon/objD/epoch_12.pth")

# 모델 생성
model = init_detector(cfg, checkpoint_file, device="cuda:0")

# 추론 실시
pred = inference_detector(model, img)
  • 추론 결과 시각화
from mmdet.visualization import DetLocalVisualizer

visualizer = DetLocalVisualizer()
visualizer.add_datasample(
    'result',
    img,
    pred,
    show=False
)
visualizer.show()

*이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.

profile
데이터 분석, 데이터 사이언스 학습 저장소

0개의 댓글