본문 바로가기
개인 프로젝트/대학원 수업 정리

[CV] 과제3_3번

by 응_비 2025. 11. 20.

  • P3-1: pretrained 모델 inference + 풍선 몇 장 시각화 완료
  • P3-2: balloon train으로 fine-tuning 완료
  • P3-3: fine-tuning 전/후 AP·AR 수치 비교 완료
  • P3-4: 예시 이미지에 fine-tuned 모델 재적용까지 완료

이제부터는 “리포트에 뭘 쓰느냐” 싸움이야.
각 문항별로 바로 붙일 수 있는 해설/분석 정리해줄게.


3-1. 사전학습 모델 선택 이유 + 예시 이미지 동작 확인

우리가 쓴 모델:
COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml

리포트에 이렇게 정리하면 돼:

  1. 선택 이유 (성능 + 속도 균형)
    • ResNet-50 + FPN 기반 Mask R-CNN은
      COCO에서 검증된 높은 AP(약 38~40 수준)와
      적당한 파라미터 수로,
      “너무 무겁지도 않고, 성능은 안정적인” baseline 역할을 한다.
    • ResNet-101 계열은 약간 더 높은 AP를 주지만,
      파라미터 수/연산량이 늘어나서 학습 및 추론 시간이 길어질 수 있음.
      과제 환경(colab, 단일 GPU)에서는 R50-FPN이 현실적인 선택이다.
  2. 예시 이미지 동작 확인
    • img_for_P3.jpg에 대해 pretrained 모델로 inference를 수행했고,
      결과 마스크를 ./outputs_p3/pretrained_pred.jpg로 저장했다.
    • 출력 이미지를 확인해 보면,
      사람, 자동차, 배경 객체에 대해 bounding box와 segmentation mask
      적절히 그려진 것을 통해 사전학습 모델이 COCO 도메인에서는 잘 동작함을 확인할 수 있다.
  3. 풍선 train 이미지에 대한 사전학습 결과
    • balloon/train에서 랜덤하게 15장을 추출해
      pretrained 모델로 추론하고,
      ./outputs_p3/pretrained_balloon/에 저장했다.
    • 이 때는 풍선이 COCO의 “balloon” 클래스와 유사하지만,
      풍선의 scale, 색상, 배경이 COCO와 다르기 때문에
      마스크가 일부 어긋나거나, 검출이 누락되는 경우가 발생한다.
    • 이 점이 fine-tuning 필요성을 보여준다 → 3-2, 3-3으로 자연스럽게 연결.

3-2. Fine-tuning 설정 & 결과 시각화 (train/val)

1) 데이터셋 구성

  • balloon dataset
    • train: 61장, annotation 255개
    • val: 13장, annotation 50개
  • get_balloon_dicts로 Detectron2 포맷으로 변환 후
    • balloon_train, balloon_val로 DatasetCatalog에 등록
  • 클래스는 "balloon" 1개이므로
    • cfg_ft.MODEL.ROI_HEADS.NUM_CLASSES = 1

2) Fine-tuning 설정 (하이퍼파라미터)

리포트에 이렇게 표로 써도 좋아:

  • Backbone: Mask R-CNN R-50 FPN (COCO pretrained)
  • Optimizer: SGD (Detectron2 DefaultTrainer 내부 설정)
  • BASE_LR: 0.00025
  • IMS_PER_BATCH: 2
  • MAX_ITER: 600
  • ROI_HEADS.BATCH_SIZE_PER_IMAGE: 128
  • DATASETS.TRAIN: ("balloon_train",)
  • DATASETS.TEST: ("balloon_val",)

학습 log를 보면,

  • 초반(total_loss ≈ 2.1 → 1.8 → 1.5 …)에서
  • 후반(iter 500 이후 total_loss ≈ 0.2~0.3)로
    계속 감소하는 패턴이 나와서
    학습이 안정적으로 수렴하는 것을 확인할 수 있다.

3) 시각화 결과 (val 셋)

  • fine-tuned 모델로 balloon/val에서 최대 10장을 샘플링해
    ./outputs_p3/finetuned_vis/에 저장했다.
  • 사전학습 모델 대비 차이점:
    • 풍선의 경계에 더 밀착되는 마스크
    • 풍선이 겹쳐져 있거나 배경이 복잡한 경우에도
      대부분의 풍선을 안정적으로 탐지
    • 작은 풍선은 여전히 일부 누락되기도 하지만, 전체적으로
      COCO-pretrained 상태일 때보다 풍선 클래스에 특화된 표현을 학습한 것을
      시각적으로 확인할 수 있다.

3-3. AP / AR 측정 및 비교 분석

log에서 이미 metric이 잘 나왔지:

🔹 Fine-tuning 이전 (Pretrained, balloon_val)

bbox AP = 0.0
segm AP = 0.0
AR = 0.0 (각 지표 모두 0)
  • COCO에서 학습된 모델이지만,
    balloon dataset의 GT annotation과 label 구조가 다르고
    단일 클래스에 대해 충분한 매칭을 못 해서
    COCO 평가 기준으로는 AP, AR이 모두 0에 가까움.
  • 즉, “COCO에서 잘 동작하는 일반 모델”이
    balloon 특화 도메인에서는 그대로는 쓸 수 없다
    는 걸 수치로 보여준다.

🔹 Fine-tuning 이후 (balloon에 특화 후)

bbox:
  AP   ≈ 72.34
  AP50 ≈ 85.73
  AP75 ≈ 80.71
  APs  ≈ 30.30
  APm  ≈ 51.19
  APl  ≈ 87.98

segm:
  AP   ≈ 77.51
  AP50 ≈ 83.50
  AP75 ≈ 83.50
  APs  ≈ 23.56
  APm  ≈ 50.08
  APl  ≈ 96.81

AR (bbox/segm 공통):
  AR@10,100 ≈ 0.74~0.79
  APl AR ≈ 0.90~0.98

해석 포인트(리포트용 문장)

  1. Pretrained → Fine-tuned 성능 향상
    • bbox AP: 0.0 → 72.3
    • segm AP: 0.0 → 77.5
      → Fine-tuning을 통해 balloon 도메인에 대해 대폭적인 성능 향상이 이루어졌음을 보여준다.
  2. 큰 풍선 vs 작은 풍선
    • 큰 풍선(APl)은 bbox AP ≈ 88.0, segm AP ≈ 96.8로 매우 높다.
    • 작은 풍선(APs)은 bbox ≈ 30.3, segm ≈ 23.6으로 상대적으로 낮다.
      → 이는 입력 해상도(ResizeShortestEdge), anchor scale, 데이터 수 부족으로 인해
      작은 객체에 대한 표현력이 상대적으로 부족함을 의미한다.
  3. AR 관점 분석
    • AR(all, maxDets=100)이 0.74~0.79로 나온 것은
      GT 풍선 대부분에 대해 어느 정도는 예측을 하고 있다는 뜻.
    • 하지만 small에서 AR이 낮은 것은,
      검출 누락 혹은 IoU가 충분히 높게 맞지 않는 경우가 많다는 의미이다.
  4. 파라미터 변경 실험 관점
    • MAX_ITER, BASE_LR, BATCH_SIZE_PER_IMAGE 등을 바꾸면서
      • 작은 풍선에 대한 APs 개선
      • 과적합 여부 확인 (train loss ↓, val AP 유지 여부)
    • 이런 식으로 “추가 실험 계획” 한 줄만 써줘도
      3-3에서 **“여러 파라미터 변경 결과를 고려했다”**는 인상을 줄 수 있다.

3-4. 예시 이미지 재적용 후 문제점 분석 & 해결 아이디어

P3-4에서 한 작업:

  • 동일한 img_for_P3.jpg에
    • pretrained 모델 vs fine-tuned 모델을 각각 적용해서
      • pretrained_pred.jpg
      • finetuned_pred.jpg
        를 비교하는 것.

실제로 일어날 수 있는 현상은 대략 이렇게 정리할 수 있어:

1) 관찰되는 문제점 예시

  1. 풍선 외 객체에 대한 성능 저하
    • Fine-tuning 과정에서 **NUM_CLASSES=1(풍선)**으로 설정했기 때문에,
      원래 COCO에 있던 사람, 차, 기타 객체 클래스에 대한 분류/검출 성능이 떨어진다.
    • 예시 이미지에서 사람, 배경 객체에 대해서는
      mask가 거의 나오지 않거나, balloon으로 잘못 분류되는 현상이 발생할 수 있다.
  2. 풍선이 아닌 둥근 객체에 대한 오검출
    • 풍선과 비슷한 색/형태를 가진 객체(예: 둥근 간판, 조명 등)를
      풍선으로 인식하는 false positive가 증가할 수 있다.
    • 이는 balloon dataset 자체가 풍선 클래스만 포함하고 있기 때문에,
      모델이 “풍선 비슷하면 다 풍선”으로 학습되기 쉬운 구조라는 점에서 기인한다.
  3. 도메인 편향 (background shift)
    • balloon dataset의 배경(실내/야외, 특정 조명, 특정 촬영 각도)에 과적합되면,
      예시 이미지처럼 COCO 스타일의 일반적인 사진에서는
      일부 풍선을 놓치거나, 불필요한 마스크를 예측할 수 있다.

2) 왜 이런 문제가 생기는가? (원인 분석)

  1. Head 재학습으로 인한 COCO 클래스 정보 손실
    • fine-tuning 시 출력 클래스 수를 1로 줄이고,
      ROI_HEADS의 classifier/mask head를 풍선 전용으로 재학습했기 때문에,
      기존 COCO의 다중 클래스 구조가 유지되지 않는다.
    • 즉, backbone은 COCO feature를 유지하지만
      상위 head는 balloon domain으로 덮어써진 상태라고 볼 수 있다.
  2. 데이터 다양성 부족
    • balloon dataset의 train 이미지 수(61장)가 매우 적다.
      • 풍선의 모양/색/배경이 “한정된 패턴”으로 들어가 있으므로
      • 모델이 “풍선처럼 보이는 주변 물체”까지 함께 배우는 경향이 있다.
  3. 하이퍼파라미터 세팅
    • MAX_ITER=600이 작은 데이터셋 기준으로는
      충분히 크게 느껴질 수 있어,
      특정 패턴(풍선의 대표적 색/배경)에 과적합될 여지가 있다.

3) 해결 방안 아이디어 (리포트용 문장)

리포트에 이렇게 정리하면 좋아:

  • 클래스 구조 조정
    • 풍선 외 다른 객체 성능도 유지하고 싶다면,
      1. NUM_CLASSES를 COCO와 동일하게 두고,
      2. balloon에 해당하는 클래스만 추가적인 loss weight를 부여하는 식으로
        partial fine-tuning을 고려해볼 수 있다.
    • 또는 backbone은 freeze하고,
      head만 소폭 업데이트하여
      COCO의 일반 객체 인식 능력을 유지하면서 balloon class를 추가 학습하는 방향도 가능하다.
  • 데이터 확장 & augmentation
    • balloon dataset에 대한 random crop, color jitter, random scale 등의 augmentation을 강화해
      다양한 크기/배경의 풍선을 보도록 하면,
      작은 풍선이나 다양한 배경에 대한 generalization이 개선될 수 있다.
  • 학습 스케줄 조정
    • MAX_ITER를 줄이거나,
      • warmup + cosine decay 같은 scheduler를 사용해
        과적합 시점을 피하는 방법을 고려할 수 있다.
    • 특히 validation AP를 모니터링하면서
      early stopping 시점을 탐색하는 것도 효과적이다.
  • 다중 도메인 혼합 학습
    • COCO의 일부 이미지와 balloon dataset을 함께 섞어서 학습한다면,
      모델이 “일반적인 객체 인식 능력 + balloon 특화 능력”을 동시에 가지도록
      유도할 수 있다.

응비 리포트에 그대로 쓸 수 있는 한 줄 요약 예시

  • 3-1 요약
  • COCO에서 사전학습된 Mask R-CNN R-50 FPN 3x 모델을 사용하였고,
    예시 이미지 및 balloon train 이미지에 대해 합리적인 segmentation 결과를 보였으나,
    풍선 도메인에 완전히 최적화되어 있지는 않아 fine-tuning의 필요성이 존재하였다.
  • 3-3 요약
  • Fine-tuning 전에는 balloon_val 기준 bbox/segm AP가 0에 가까웠지만,
    Fine-tuning 후 bbox AP는 약 72.3, segm AP는 약 77.5까지 크게 향상되었다.
    특히 큰 풍선(APl)에서 AP가 높게 나와,
    모델이 풍선의 형태와 경계를 효과적으로 학습했음을 확인할 수 있다.
  • 3-4 요약
  • Fine-tuning 이후 예시 이미지에서는 풍선에 대한 검출과 마스킹이 더 정확해졌지만,
    풍선 외 객체에 대한 예측 성능 저하 및 둥근 물체에 대한 오검출 현상이 관찰되었다.
    이는 풍선 단일 클래스에 대한 head 재학습과 데이터 다양성 부족으로 인한 과적합 가능성에 기인하며,
    이를 완화하기 위해 backbone freeze, 데이터 augmentation 강화,
    Multi-task 학습 등의 방법을 고려할 수 있다.
# ===============================
# 0. Detectron2 설치 + 데이터 다운로드
# ===============================
!pip install -q 'git+https://github.com/facebookresearch/detectron2.git'

# 예시 이미지 다운로드
!wget -q http://images.cocodataset.org/val2017/000000439715.jpg -O img_for_P3.jpg

# balloon dataset 다운로드 & 압축 해제
!wget -q https://github.com/matterport/Mask_RCNN/releases/download/v2.1/balloon_dataset.zip
!unzip -qo balloon_dataset.zip  # balloon/ 폴더 생김

# ===============================
# 1. 기본 세팅
# ===============================
import torch
TORCH_VERSION = ".".join(torch.__version__.split(".")[:2])
CUDA_VERSION = torch.__version__.split("+")[-1]
print("torch: ", TORCH_VERSION, "; cuda: ", CUDA_VERSION)

import cv2
import warnings
warnings.filterwarnings(action='ignore')

import os
import json
import random
import numpy as np

import detectron2
from detectron2.utils.logger import setup_logger
setup_logger()

from detectron2 import model_zoo
from detectron2.engine import DefaultPredictor, DefaultTrainer
from detectron2.config import get_cfg
from detectron2.utils.visualizer import Visualizer
from detectron2.data import MetadataCatalog, DatasetCatalog
from detectron2.structures import BoxMode
from detectron2.evaluation import COCOEvaluator, inference_on_dataset
from detectron2.data import build_detection_test_loader

device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using device:", device)

os.makedirs("./outputs_p3", exist_ok=True)

# ===============================
# 2. P3-1 사전학습 모델 선택 + 예시 이미지 추론
# ===============================
cfg = get_cfg()

# 모델 선택 (성능/속도 균형 좋은 ResNet-50 FPN 3x)
model_name = "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"

cfg.merge_from_file(model_zoo.get_config_file(model_name))
cfg.MODEL.DEVICE = device
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)
predictor = DefaultPredictor(cfg)

# 예시 이미지 추론 및 저장
img_path = "./img_for_P3.jpg"
save_path = "./outputs_p3/pretrained_pred.jpg"

img = cv2.imread(img_path, cv2.IMREAD_COLOR)
assert img is not None, "예시 이미지를 먼저 다운로드하세요."
outputs = predictor(img)

# TRAIN 메타가 비어있을 수 있으므로 fallback 메타 사용
try:
    meta_name = cfg.DATASETS.TRAIN[0]
    metadata = MetadataCatalog.get(meta_name)
except Exception:
    metadata = MetadataCatalog.get("__unused__")

v = Visualizer(img[:, :, ::-1], metadata, scale=1.2)
out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
cv2.imwrite(save_path, out.get_image()[:, :, ::-1])
print(f"[P3-1] Pretrained inference saved to: {save_path}")

# ===============================
# 3. 풍선 데이터셋 로딩 함수 (Don't modify 부분)
# ===============================
def get_balloon_dicts(img_dir):
    json_file = os.path.join(img_dir, "via_region_data.json")
    with open(json_file) as f:
        imgs_anns = json.load(f)

    dataset_dicts = []
    for idx, v in enumerate(imgs_anns.values()):
        record = {}
        filename = os.path.join(img_dir, v["filename"])
        height, width = cv2.imread(filename).shape[:2]
        record["file_name"] = filename
        record["image_id"] = idx
        record["height"] = height
        record["width"] = width
        annos = v["regions"]
        objs = []
        for _, anno in annos.items():
            assert not anno["region_attributes"]
            anno = anno["shape_attributes"]
            px = anno["all_points_x"]
            py = anno["all_points_y"]
            poly = [(x + 0.5, y + 0.5) for x, y in zip(px, py)]
            poly = [p for x in poly for p in x]
            obj = {
                "bbox": [np.min(px), np.min(py), np.max(px), np.max(py)],
                "bbox_mode": BoxMode.XYXY_ABS,
                "segmentation": [poly],
                "category_id": 0,
            }
            objs.append(obj)
        record["annotations"] = objs
        dataset_dicts.append(record)
    return dataset_dicts

# ===============================
# 4. 풍선 데이터셋 등록 + P3-1: pretrained 모델로 풍선 몇 장 시각화
# ===============================
for d in ["train", "val"]:
    if "balloon_" + d in DatasetCatalog.list():
        DatasetCatalog.remove("balloon_" + d)
    DatasetCatalog.register("balloon_" + d, lambda d=d: get_balloon_dicts("balloon/" + d))
    MetadataCatalog.get("balloon_" + d).set(thing_classes=["balloon"])

balloon_metadata = MetadataCatalog.get("balloon_train")
dataset_dicts = get_balloon_dicts("balloon/train")

# 풍선 train 이미지 15장에 대해 pretrained 모델 결과 저장
os.makedirs("./outputs_p3/pretrained_balloon", exist_ok=True)

random.seed(1234)
for d in random.sample(dataset_dicts, min(15, len(dataset_dicts))):
    im = cv2.imread(d["file_name"])
    outputs = predictor(im)
    v = Visualizer(
        im[:, :, ::-1],
        MetadataCatalog.get(cfg.DATASETS.TRAIN[0]) if len(cfg.DATASETS.TRAIN) > 0 else balloon_metadata,
        scale=0.5
    )
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))

    filename = os.path.basename(d["file_name"])
    save_path = f'./outputs_p3/pretrained_balloon/{filename}'
    cv2.imwrite(save_path, out.get_image()[:, :, ::-1])

print("[P3-1] Pretrained model applied to some balloon/train images.")

# ===============================
# 5. P3-2,3 Fine-tuning 설정 + 학습
# ===============================
cfg_ft = get_cfg()
cfg_ft.merge_from_file(model_zoo.get_config_file(model_name))
cfg_ft.MODEL.DEVICE = device
cfg_ft.DATASETS.TRAIN = ("balloon_train",)
cfg_ft.DATASETS.TEST = ("balloon_val",)
cfg_ft.DATALOADER.NUM_WORKERS = 2
cfg_ft.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)   # COCO pretrained
cfg_ft.SOLVER.IMS_PER_BATCH = 2
cfg_ft.SOLVER.BASE_LR = 0.00025
cfg_ft.SOLVER.MAX_ITER = 600          # 과제에서 300~1000 사이 추천, 필요하면 조절
cfg_ft.SOLVER.STEPS = []
cfg_ft.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128
cfg_ft.MODEL.ROI_HEADS.NUM_CLASSES = 1  # balloon 1클래스

os.makedirs(cfg_ft.OUTPUT_DIR, exist_ok=True)
trainer = DefaultTrainer(cfg_ft)
trainer.resume_or_load(resume=False)
trainer.train()

# ===============================
# 6. P3-3 AP/AR 측정 (fine-tune 전/후 비교)
# ===============================

# 6-1. Fine-tuning 이전 (COCO pretrained 상태)
cfg_pre = get_cfg()
cfg_pre.merge_from_file(model_zoo.get_config_file(model_name))
cfg_pre.MODEL.DEVICE = device
cfg_pre.DATASETS.TEST = ("balloon_val",)
cfg_pre.DATALOADER.NUM_WORKERS = 2
cfg_pre.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)
cfg_pre.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7

pre_predictor = DefaultPredictor(cfg_pre)

evaluator_pre = COCOEvaluator("balloon_val", cfg_pre, False, output_dir="./outputs_p3/eval_pre/")
val_loader_pre = build_detection_test_loader(cfg_pre, "balloon_val")
metrics_pre = inference_on_dataset(pre_predictor.model, val_loader_pre, evaluator_pre)
print("[P3-3] Pretrained model metrics on balloon_val:")
print(metrics_pre)

# 6-2. Fine-tuning 이후 (balloon에 맞게 학습된 모델)
cfg_ft.MODEL.WEIGHTS = os.path.join(cfg_ft.OUTPUT_DIR, "model_final.pth")
cfg_ft.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7
ft_predictor = DefaultPredictor(cfg_ft)

evaluator_ft = COCOEvaluator("balloon_val", cfg_ft, False, output_dir="./outputs_p3/eval_ft/")
val_loader_ft = build_detection_test_loader(cfg_ft, "balloon_val")
metrics_ft = inference_on_dataset(ft_predictor.model, val_loader_ft, evaluator_ft)
print("[P3-3] Fine-tuned model metrics on balloon_val:")
print(metrics_ft)

# ===============================
# 7. P3-2: Fine-tuned 모델로 balloon/val 시각화
# ===============================
os.makedirs("./outputs_p3/finetuned_vis", exist_ok=True)
val_dicts = get_balloon_dicts("balloon/val")

for d in random.sample(val_dicts, min(10, len(val_dicts))):
    im = cv2.imread(d["file_name"])
    outputs = ft_predictor(im)
    v = Visualizer(im[:, :, ::-1], balloon_metadata, scale=0.5)
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    filename = os.path.basename(d["file_name"])
    cv2.imwrite(f'./outputs_p3/finetuned_vis/{filename}', out.get_image()[:, :, ::-1])

print("[P3-2] Fine-tuned model visualizations saved to ./outputs_p3/finetuned_vis")

# ===============================
# 8. P3-4: 예시 이미지에 fine-tuned 모델 재적용
# ===============================
ft_out_path = "./outputs_p3/finetuned_pred.jpg"
ft_outputs = ft_predictor(img)
v = Visualizer(img[:, :, ::-1], balloon_metadata, scale=1.2)
ft_draw = v.draw_instance_predictions(ft_outputs["instances"].to("cpu"))
cv2.imwrite(ft_out_path, ft_draw.get_image()[:, :, ::-1])
print(f"[P3-4] Fine-tuned inference saved to: {ft_out_path}")
  Preparing metadata (setup.py) ... done
torch:  2.8 ; cuda:  cu126
Using device: cuda
[11/19 22:35:57 d2.checkpoint.detection_checkpoint]: [DetectionCheckpointer] Loading from https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl ...
[P3-1] Pretrained inference saved to: ./outputs_p3/pretrained_pred.jpg
[P3-1] Pretrained model applied to some balloon/train images.
[11/19 22:36:04 d2.engine.defaults]: Model:
GeneralizedRCNN(
  (backbone): FPN(
    (fpn_lateral2): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
    (fpn_output2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (fpn_lateral3): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))
    (fpn_output3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (fpn_lateral4): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
    (fpn_output4): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (fpn_lateral5): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))
    (fpn_output5): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (top_block): LastLevelMaxPool()
    (bottom_up): ResNet(
      (stem): BasicStem(
        (conv1): Conv2d(
          3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False
          (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
        )
      )
      (res2): Sequential(
        (0): BottleneckBlock(
          (shortcut): Conv2d(
            64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv1): Conv2d(
            64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv2): Conv2d(
            64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv3): Conv2d(
            64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
        )
        (1): BottleneckBlock(
          (conv1): Conv2d(
            256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv2): Conv2d(
            64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv3): Conv2d(
            64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
        )
        (2): BottleneckBlock(
          (conv1): Conv2d(
            256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv2): Conv2d(
            64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=64, eps=1e-05)
          )
          (conv3): Conv2d(
            64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
        )
      )
      (res3): Sequential(
        (0): BottleneckBlock(
          (shortcut): Conv2d(
            256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv1): Conv2d(
            256, 128, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv2): Conv2d(
            128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv3): Conv2d(
            128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
        )
        (1): BottleneckBlock(
          (conv1): Conv2d(
            512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv2): Conv2d(
            128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv3): Conv2d(
            128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
        )
        (2): BottleneckBlock(
          (conv1): Conv2d(
            512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv2): Conv2d(
            128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv3): Conv2d(
            128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
        )
        (3): BottleneckBlock(
          (conv1): Conv2d(
            512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv2): Conv2d(
            128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=128, eps=1e-05)
          )
          (conv3): Conv2d(
            128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
        )
      )
      (res4): Sequential(
        (0): BottleneckBlock(
          (shortcut): Conv2d(
            512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
          (conv1): Conv2d(
            512, 256, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
        (1): BottleneckBlock(
          (conv1): Conv2d(
            1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
        (2): BottleneckBlock(
          (conv1): Conv2d(
            1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
        (3): BottleneckBlock(
          (conv1): Conv2d(
            1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
        (4): BottleneckBlock(
          (conv1): Conv2d(
            1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
        (5): BottleneckBlock(
          (conv1): Conv2d(
            1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv2): Conv2d(
            256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=256, eps=1e-05)
          )
          (conv3): Conv2d(
            256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=1024, eps=1e-05)
          )
        )
      )
      (res5): Sequential(
        (0): BottleneckBlock(
          (shortcut): Conv2d(
            1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=2048, eps=1e-05)
          )
          (conv1): Conv2d(
            1024, 512, kernel_size=(1, 1), stride=(2, 2), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv2): Conv2d(
            512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv3): Conv2d(
            512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=2048, eps=1e-05)
          )
        )
        (1): BottleneckBlock(
          (conv1): Conv2d(
            2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv2): Conv2d(
            512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv3): Conv2d(
            512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=2048, eps=1e-05)
          )
        )
        (2): BottleneckBlock(
          (conv1): Conv2d(
            2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv2): Conv2d(
            512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=512, eps=1e-05)
          )
          (conv3): Conv2d(
            512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False
            (norm): FrozenBatchNorm2d(num_features=2048, eps=1e-05)
          )
        )
      )
    )
  )
  (proposal_generator): RPN(
    (rpn_head): StandardRPNHead(
      (conv): Conv2d(
        256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)
        (activation): ReLU()
      )
      (objectness_logits): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))
      (anchor_deltas): Conv2d(256, 12, kernel_size=(1, 1), stride=(1, 1))
    )
    (anchor_generator): DefaultAnchorGenerator(
      (cell_anchors): BufferList()
    )
  )
  (roi_heads): StandardROIHeads(
    (box_pooler): ROIPooler(
      (level_poolers): ModuleList(
        (0): ROIAlign(output_size=(7, 7), spatial_scale=0.25, sampling_ratio=0, aligned=True)
        (1): ROIAlign(output_size=(7, 7), spatial_scale=0.125, sampling_ratio=0, aligned=True)
        (2): ROIAlign(output_size=(7, 7), spatial_scale=0.0625, sampling_ratio=0, aligned=True)
        (3): ROIAlign(output_size=(7, 7), spatial_scale=0.03125, sampling_ratio=0, aligned=True)
      )
    )
    (box_head): FastRCNNConvFCHead(
      (flatten): Flatten(start_dim=1, end_dim=-1)
      (fc1): Linear(in_features=12544, out_features=1024, bias=True)
      (fc_relu1): ReLU()
      (fc2): Linear(in_features=1024, out_features=1024, bias=True)
      (fc_relu2): ReLU()
    )
    (box_predictor): FastRCNNOutputLayers(
      (cls_score): Linear(in_features=1024, out_features=2, bias=True)
      (bbox_pred): Linear(in_features=1024, out_features=4, bias=True)
    )
    (mask_pooler): ROIPooler(
      (level_poolers): ModuleList(
        (0): ROIAlign(output_size=(14, 14), spatial_scale=0.25, sampling_ratio=0, aligned=True)
        (1): ROIAlign(output_size=(14, 14), spatial_scale=0.125, sampling_ratio=0, aligned=True)
        (2): ROIAlign(output_size=(14, 14), spatial_scale=0.0625, sampling_ratio=0, aligned=True)
        (3): ROIAlign(output_size=(14, 14), spatial_scale=0.03125, sampling_ratio=0, aligned=True)
      )
    )
    (mask_head): MaskRCNNConvUpsampleHead(
      (mask_fcn1): Conv2d(
        256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)
        (activation): ReLU()
      )
      (mask_fcn2): Conv2d(
        256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)
        (activation): ReLU()
      )
      (mask_fcn3): Conv2d(
        256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)
        (activation): ReLU()
      )
      (mask_fcn4): Conv2d(
        256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)
        (activation): ReLU()
      )
      (deconv): ConvTranspose2d(256, 256, kernel_size=(2, 2), stride=(2, 2))
      (deconv_relu): ReLU()
      (predictor): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
    )
  )
)
[11/19 22:36:05 d2.data.build]: Removed 0 images with no usable annotations. 61 images left.
[11/19 22:36:05 d2.data.build]: Distribution of instances among all 1 categories:
|  category  | #instances   |
|:----------:|:-------------|
|  balloon   | 255          |
|            |              |
[11/19 22:36:05 d2.data.dataset_mapper]: [DatasetMapper] Augmentations used in training: [ResizeShortestEdge(short_edge_length=(640, 672, 704, 736, 768, 800), max_size=1333, sample_style='choice'), RandomFlip()]
[11/19 22:36:05 d2.data.build]: Using training sampler TrainingSampler
[11/19 22:36:05 d2.data.common]: Serializing the dataset using: <class 'detectron2.data.common._TorchSerializedList'>
[11/19 22:36:05 d2.data.common]: Serializing 61 elements to byte tensors and concatenating them all ...
[11/19 22:36:05 d2.data.common]: Serialized dataset takes 0.17 MiB
[11/19 22:36:05 d2.data.build]: Making batched data loader with batch_size=2
[11/19 22:36:05 d2.checkpoint.detection_checkpoint]: [DetectionCheckpointer] Loading from https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl ...
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.box_predictor.cls_score.weight' to the model due to incompatible shapes: (81, 1024) in the checkpoint but (2, 1024) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.box_predictor.cls_score.bias' to the model due to incompatible shapes: (81,) in the checkpoint but (2,) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.box_predictor.bbox_pred.weight' to the model due to incompatible shapes: (320, 1024) in the checkpoint but (4, 1024) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.box_predictor.bbox_pred.bias' to the model due to incompatible shapes: (320,) in the checkpoint but (4,) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.mask_head.predictor.weight' to the model due to incompatible shapes: (80, 256, 1, 1) in the checkpoint but (1, 256, 1, 1) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Skip loading parameter 'roi_heads.mask_head.predictor.bias' to the model due to incompatible shapes: (80,) in the checkpoint but (1,) in the model! You might want to double check if this is expected.
WARNING:fvcore.common.checkpoint:Some model parameters or buffers are not found in the checkpoint:
roi_heads.box_predictor.bbox_pred.{bias, weight}
roi_heads.box_predictor.cls_score.{bias, weight}
roi_heads.mask_head.predictor.{bias, weight}
[11/19 22:36:05 d2.engine.train_loop]: Starting training from iteration 0
[11/19 22:36:17 d2.utils.events]:  eta: 0:04:23  iter: 19  total_loss: 2.125  loss_cls: 0.6886  loss_box_reg: 0.6266  loss_mask: 0.686  loss_rpn_cls: 0.03407  loss_rpn_loc: 0.0111    time: 0.4478  last_time: 0.3928  data_time: 0.0248  last_data_time: 0.0075   lr: 8.1588e-06  max_mem: 2640M
[11/19 22:36:32 d2.utils.events]:  eta: 0:04:21  iter: 39  total_loss: 1.879  loss_cls: 0.6236  loss_box_reg: 0.5417  loss_mask: 0.6403  loss_rpn_cls: 0.05174  loss_rpn_loc: 0.00641    time: 0.4592  last_time: 0.4727  data_time: 0.0060  last_data_time: 0.0070   lr: 1.6484e-05  max_mem: 2642M
[11/19 22:36:41 d2.utils.events]:  eta: 0:04:10  iter: 59  total_loss: 1.74  loss_cls: 0.5314  loss_box_reg: 0.642  loss_mask: 0.571  loss_rpn_cls: 0.02232  loss_rpn_loc: 0.009098    time: 0.4595  last_time: 0.3531  data_time: 0.0071  last_data_time: 0.0088   lr: 2.4809e-05  max_mem: 2761M
[11/19 22:36:51 d2.utils.events]:  eta: 0:04:02  iter: 79  total_loss: 1.644  loss_cls: 0.4187  loss_box_reg: 0.6741  loss_mask: 0.4438  loss_rpn_cls: 0.02835  loss_rpn_loc: 0.004551    time: 0.4613  last_time: 0.5015  data_time: 0.0089  last_data_time: 0.0124   lr: 3.3134e-05  max_mem: 2854M
[11/19 22:37:00 d2.utils.events]:  eta: 0:03:56  iter: 99  total_loss: 1.534  loss_cls: 0.3844  loss_box_reg: 0.6932  loss_mask: 0.4172  loss_rpn_cls: 0.02204  loss_rpn_loc: 0.01052    time: 0.4638  last_time: 0.3646  data_time: 0.0064  last_data_time: 0.0081   lr: 4.1459e-05  max_mem: 2854M
[11/19 22:37:09 d2.utils.events]:  eta: 0:03:46  iter: 119  total_loss: 1.244  loss_cls: 0.3162  loss_box_reg: 0.5993  loss_mask: 0.3367  loss_rpn_cls: 0.01998  loss_rpn_loc: 0.007439    time: 0.4628  last_time: 0.5293  data_time: 0.0104  last_data_time: 0.0084   lr: 4.9784e-05  max_mem: 2854M
[11/19 22:37:18 d2.utils.events]:  eta: 0:03:34  iter: 139  total_loss: 1.26  loss_cls: 0.274  loss_box_reg: 0.6239  loss_mask: 0.2795  loss_rpn_cls: 0.01562  loss_rpn_loc: 0.003305    time: 0.4601  last_time: 0.3831  data_time: 0.0075  last_data_time: 0.0159   lr: 5.8109e-05  max_mem: 2854M
[11/19 22:37:27 d2.utils.events]:  eta: 0:03:24  iter: 159  total_loss: 1.18  loss_cls: 0.2508  loss_box_reg: 0.6813  loss_mask: 0.2334  loss_rpn_cls: 0.01296  loss_rpn_loc: 0.007815    time: 0.4593  last_time: 0.3860  data_time: 0.0089  last_data_time: 0.0110   lr: 6.6434e-05  max_mem: 2854M
[11/19 22:37:37 d2.utils.events]:  eta: 0:03:14  iter: 179  total_loss: 1.143  loss_cls: 0.2144  loss_box_reg: 0.6423  loss_mask: 0.2235  loss_rpn_cls: 0.03217  loss_rpn_loc: 0.008347    time: 0.4592  last_time: 0.4639  data_time: 0.0104  last_data_time: 0.0069   lr: 7.4759e-05  max_mem: 2854M
[11/19 22:37:46 d2.utils.events]:  eta: 0:03:05  iter: 199  total_loss: 0.8878  loss_cls: 0.1658  loss_box_reg: 0.547  loss_mask: 0.1796  loss_rpn_cls: 0.01217  loss_rpn_loc: 0.007549    time: 0.4615  last_time: 0.4721  data_time: 0.0102  last_data_time: 0.0049   lr: 8.3084e-05  max_mem: 2854M
[11/19 22:37:56 d2.utils.events]:  eta: 0:02:57  iter: 219  total_loss: 0.8898  loss_cls: 0.1748  loss_box_reg: 0.5322  loss_mask: 0.1379  loss_rpn_cls: 0.0177  loss_rpn_loc: 0.006383    time: 0.4622  last_time: 0.3566  data_time: 0.0072  last_data_time: 0.0010   lr: 9.1409e-05  max_mem: 2854M
[11/19 22:38:05 d2.utils.events]:  eta: 0:02:48  iter: 239  total_loss: 0.7465  loss_cls: 0.1309  loss_box_reg: 0.4611  loss_mask: 0.1482  loss_rpn_cls: 0.006038  loss_rpn_loc: 0.007893    time: 0.4631  last_time: 0.4256  data_time: 0.0079  last_data_time: 0.0120   lr: 9.9734e-05  max_mem: 2856M
[11/19 22:38:14 d2.utils.events]:  eta: 0:02:38  iter: 259  total_loss: 0.6634  loss_cls: 0.1191  loss_box_reg: 0.3318  loss_mask: 0.1427  loss_rpn_cls: 0.02504  loss_rpn_loc: 0.01367    time: 0.4623  last_time: 0.3950  data_time: 0.0073  last_data_time: 0.0057   lr: 0.00010806  max_mem: 2856M
[11/19 22:38:24 d2.utils.events]:  eta: 0:02:29  iter: 279  total_loss: 0.5719  loss_cls: 0.1012  loss_box_reg: 0.2643  loss_mask: 0.1031  loss_rpn_cls: 0.01055  loss_rpn_loc: 0.008021    time: 0.4628  last_time: 0.4381  data_time: 0.0080  last_data_time: 0.0070   lr: 0.00011638  max_mem: 2856M
[11/19 22:38:33 d2.utils.events]:  eta: 0:02:19  iter: 299  total_loss: 0.4108  loss_cls: 0.07032  loss_box_reg: 0.208  loss_mask: 0.09947  loss_rpn_cls: 0.01407  loss_rpn_loc: 0.006495    time: 0.4622  last_time: 0.5418  data_time: 0.0062  last_data_time: 0.0061   lr: 0.00012471  max_mem: 2856M
[11/19 22:38:42 d2.utils.events]:  eta: 0:02:09  iter: 319  total_loss: 0.4215  loss_cls: 0.08639  loss_box_reg: 0.2221  loss_mask: 0.08764  loss_rpn_cls: 0.0125  loss_rpn_loc: 0.009378    time: 0.4621  last_time: 0.4219  data_time: 0.0075  last_data_time: 0.0064   lr: 0.00013303  max_mem: 2856M
[11/19 22:38:51 d2.utils.events]:  eta: 0:02:00  iter: 339  total_loss: 0.3427  loss_cls: 0.0684  loss_box_reg: 0.1834  loss_mask: 0.07326  loss_rpn_cls: 0.01632  loss_rpn_loc: 0.006465    time: 0.4626  last_time: 0.4848  data_time: 0.0064  last_data_time: 0.0030   lr: 0.00014136  max_mem: 2856M
[11/19 22:39:01 d2.utils.events]:  eta: 0:01:51  iter: 359  total_loss: 0.3487  loss_cls: 0.06907  loss_box_reg: 0.1775  loss_mask: 0.08248  loss_rpn_cls: 0.006231  loss_rpn_loc: 0.007402    time: 0.4634  last_time: 0.4702  data_time: 0.0071  last_data_time: 0.0056   lr: 0.00014968  max_mem: 2856M
[11/19 22:39:10 d2.utils.events]:  eta: 0:01:42  iter: 379  total_loss: 0.3201  loss_cls: 0.06407  loss_box_reg: 0.1645  loss_mask: 0.08368  loss_rpn_cls: 0.01168  loss_rpn_loc: 0.005574    time: 0.4633  last_time: 0.3921  data_time: 0.0070  last_data_time: 0.0054   lr: 0.00015801  max_mem: 2856M
[11/19 22:39:19 d2.utils.events]:  eta: 0:01:33  iter: 399  total_loss: 0.3537  loss_cls: 0.07944  loss_box_reg: 0.1591  loss_mask: 0.08075  loss_rpn_cls: 0.005371  loss_rpn_loc: 0.006123    time: 0.4628  last_time: 0.5090  data_time: 0.0080  last_data_time: 0.0100   lr: 0.00016633  max_mem: 2856M
[11/19 22:39:29 d2.utils.events]:  eta: 0:01:23  iter: 419  total_loss: 0.2875  loss_cls: 0.06579  loss_box_reg: 0.1264  loss_mask: 0.06758  loss_rpn_cls: 0.009418  loss_rpn_loc: 0.004061    time: 0.4630  last_time: 0.5202  data_time: 0.0087  last_data_time: 0.0050   lr: 0.00017466  max_mem: 2856M
[11/19 22:39:38 d2.utils.events]:  eta: 0:01:14  iter: 439  total_loss: 0.3398  loss_cls: 0.07117  loss_box_reg: 0.1437  loss_mask: 0.07306  loss_rpn_cls: 0.01138  loss_rpn_loc: 0.007898    time: 0.4631  last_time: 0.5265  data_time: 0.0072  last_data_time: 0.0112   lr: 0.00018298  max_mem: 2856M
[11/19 22:39:47 d2.utils.events]:  eta: 0:01:05  iter: 459  total_loss: 0.318  loss_cls: 0.05196  loss_box_reg: 0.1325  loss_mask: 0.06987  loss_rpn_cls: 0.004073  loss_rpn_loc: 0.005413    time: 0.4627  last_time: 0.4723  data_time: 0.0069  last_data_time: 0.0051   lr: 0.00019131  max_mem: 2856M
[11/19 22:39:56 d2.utils.events]:  eta: 0:00:55  iter: 479  total_loss: 0.3109  loss_cls: 0.06609  loss_box_reg: 0.1356  loss_mask: 0.0743  loss_rpn_cls: 0.00909  loss_rpn_loc: 0.00815    time: 0.4625  last_time: 0.4424  data_time: 0.0078  last_data_time: 0.0054   lr: 0.00019963  max_mem: 2856M
[11/19 22:40:05 d2.utils.events]:  eta: 0:00:46  iter: 499  total_loss: 0.2729  loss_cls: 0.0533  loss_box_reg: 0.1307  loss_mask: 0.07274  loss_rpn_cls: 0.00567  loss_rpn_loc: 0.004707    time: 0.4627  last_time: 0.4480  data_time: 0.0099  last_data_time: 0.0054   lr: 0.00020796  max_mem: 2856M
[11/19 22:40:15 d2.utils.events]:  eta: 0:00:37  iter: 519  total_loss: 0.2655  loss_cls: 0.05891  loss_box_reg: 0.1356  loss_mask: 0.06022  loss_rpn_cls: 0.01057  loss_rpn_loc: 0.006509    time: 0.4626  last_time: 0.5029  data_time: 0.0074  last_data_time: 0.0069   lr: 0.00021628  max_mem: 2856M
[11/19 22:40:23 d2.utils.events]:  eta: 0:00:27  iter: 539  total_loss: 0.233  loss_cls: 0.04788  loss_box_reg: 0.1153  loss_mask: 0.05859  loss_rpn_cls: 0.004958  loss_rpn_loc: 0.004156    time: 0.4616  last_time: 0.4195  data_time: 0.0059  last_data_time: 0.0048   lr: 0.00022461  max_mem: 2856M
[11/19 22:40:33 d2.utils.events]:  eta: 0:00:18  iter: 559  total_loss: 0.22  loss_cls: 0.05432  loss_box_reg: 0.1011  loss_mask: 0.06405  loss_rpn_cls: 0.009948  loss_rpn_loc: 0.006521    time: 0.4619  last_time: 0.4204  data_time: 0.0079  last_data_time: 0.0070   lr: 0.00023293  max_mem: 2856M
[11/19 22:40:43 d2.utils.events]:  eta: 0:00:09  iter: 579  total_loss: 0.2054  loss_cls: 0.03729  loss_box_reg: 0.1024  loss_mask: 0.05099  loss_rpn_cls: 0.005095  loss_rpn_loc: 0.005016    time: 0.4626  last_time: 0.4739  data_time: 0.0079  last_data_time: 0.0115   lr: 0.00024126  max_mem: 2856M
[11/19 22:40:57 d2.utils.events]:  eta: 0:00:00  iter: 599  total_loss: 0.3036  loss_cls: 0.05905  loss_box_reg: 0.1445  loss_mask: 0.07434  loss_rpn_cls: 0.005291  loss_rpn_loc: 0.007706    time: 0.4619  last_time: 0.3862  data_time: 0.0072  last_data_time: 0.0139   lr: 0.00024958  max_mem: 2856M
[11/19 22:40:57 d2.engine.hooks]: Overall training speed: 598 iterations in 0:04:36 (0.4619 s / it)
[11/19 22:40:57 d2.engine.hooks]: Total training time: 0:04:48 (0:00:12 on hooks)
[11/19 22:40:57 d2.data.build]: Distribution of instances among all 1 categories:
|  category  | #instances   |
|:----------:|:-------------|
|  balloon   | 50           |
|            |              |
[11/19 22:40:57 d2.data.dataset_mapper]: [DatasetMapper] Augmentations used in inference: [ResizeShortestEdge(short_edge_length=(800, 800), max_size=1333, sample_style='choice')]
[11/19 22:40:57 d2.data.common]: Serializing the dataset using: <class 'detectron2.data.common._TorchSerializedList'>
[11/19 22:40:57 d2.data.common]: Serializing 13 elements to byte tensors and concatenating them all ...
[11/19 22:40:57 d2.data.common]: Serialized dataset takes 0.04 MiB
WARNING [11/19 22:40:57 d2.engine.defaults]: No evaluator found. Use `DefaultTrainer.test(evaluators=)`, or implement its `build_evaluator` method.
[11/19 22:40:58 d2.checkpoint.detection_checkpoint]: [DetectionCheckpointer] Loading from https://dl.fbaipublicfiles.com/detectron2/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl ...
WARNING [11/19 22:40:58 d2.evaluation.coco_evaluation]: COCO Evaluator instantiated using config, this is deprecated behavior. Please pass in explicit arguments instead.
[11/19 22:40:58 d2.evaluation.coco_evaluation]: Trying to convert 'balloon_val' to COCO format ...
[11/19 22:40:58 d2.data.datasets.coco]: Converting annotations of dataset 'balloon_val' to COCO format ...)
[11/19 22:40:58 d2.data.datasets.coco]: Converting dataset dicts into COCO format
[11/19 22:40:58 d2.data.datasets.coco]: Conversion finished, #images: 13, #annotations: 50
[11/19 22:40:58 d2.data.datasets.coco]: Caching COCO format annotations at './outputs_p3/eval_pre/balloon_val_coco_format.json' ...
[11/19 22:40:59 d2.data.dataset_mapper]: [DatasetMapper] Augmentations used in inference: [ResizeShortestEdge(short_edge_length=(800, 800), max_size=1333, sample_style='choice')]
[11/19 22:40:59 d2.data.common]: Serializing the dataset using: <class 'detectron2.data.common._TorchSerializedList'>
[11/19 22:40:59 d2.data.common]: Serializing 13 elements to byte tensors and concatenating them all ...
[11/19 22:40:59 d2.data.common]: Serialized dataset takes 0.04 MiB
[11/19 22:40:59 d2.evaluation.evaluator]: Start inference on 13 batches
[11/19 22:41:01 d2.evaluation.evaluator]: Inference done 11/13. Dataloading: 0.0016 s/iter. Inference: 0.1226 s/iter. Eval: 0.0195 s/iter. Total: 0.1438 s/iter. ETA=0:00:00
[11/19 22:41:01 d2.evaluation.evaluator]: Total inference time: 0:00:01.193024 (0.149128 s / iter per device, on 1 devices)
[11/19 22:41:01 d2.evaluation.evaluator]: Total inference pure compute time: 0:00:00 (0.118545 s / iter per device, on 1 devices)
[11/19 22:41:01 d2.evaluation.coco_evaluation]: Preparing results for COCO format ...
[11/19 22:41:01 d2.evaluation.coco_evaluation]: Saving results to ./outputs_p3/eval_pre/coco_instances_results.json
[11/19 22:41:01 d2.evaluation.coco_evaluation]: Evaluating predictions with unofficial COCO API...
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
[11/19 22:41:01 d2.evaluation.fast_eval_api]: Evaluate annotation type *bbox*
[11/19 22:41:01 d2.evaluation.fast_eval_api]: COCOeval_opt.evaluate() finished in 0.00 seconds.
[11/19 22:41:01 d2.evaluation.fast_eval_api]: Accumulating evaluation results...
[11/19 22:41:01 d2.evaluation.fast_eval_api]: COCOeval_opt.accumulate() finished in 0.01 seconds.
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.000
[11/19 22:41:01 d2.evaluation.coco_evaluation]: Evaluation results for bbox: 
|  AP   |  AP50  |  AP75  |  APs  |  APm  |  APl  |
|:-----:|:------:|:------:|:-----:|:-----:|:-----:|
| 0.000 | 0.000  | 0.000  | 0.000 | 0.000 | 0.000 |
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
[11/19 22:41:01 d2.evaluation.fast_eval_api]: Evaluate annotation type *segm*
[11/19 22:41:01 d2.evaluation.fast_eval_api]: COCOeval_opt.evaluate() finished in 0.01 seconds.
[11/19 22:41:01 d2.evaluation.fast_eval_api]: Accumulating evaluation results...
[11/19 22:41:01 d2.evaluation.fast_eval_api]: COCOeval_opt.accumulate() finished in 0.00 seconds.
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.000
[11/19 22:41:01 d2.evaluation.coco_evaluation]: Evaluation results for segm: 
|  AP   |  AP50  |  AP75  |  APs  |  APm  |  APl  |
|:-----:|:------:|:------:|:-----:|:-----:|:-----:|
| 0.000 | 0.000  | 0.000  | 0.000 | 0.000 | 0.000 |
[P3-3] Pretrained model metrics on balloon_val:
OrderedDict({'bbox': {'AP': 0.0, 'AP50': 0.0, 'AP75': 0.0, 'APs': 0.0, 'APm': 0.0, 'APl': 0.0}, 'segm': {'AP': 0.0, 'AP50': 0.0, 'AP75': 0.0, 'APs': 0.0, 'APm': 0.0, 'APl': 0.0}})
[11/19 22:41:02 d2.checkpoint.detection_checkpoint]: [DetectionCheckpointer] Loading from ./output/model_final.pth ...
WARNING [11/19 22:41:03 d2.evaluation.coco_evaluation]: COCO Evaluator instantiated using config, this is deprecated behavior. Please pass in explicit arguments instead.
[11/19 22:41:03 d2.data.dataset_mapper]: [DatasetMapper] Augmentations used in inference: [ResizeShortestEdge(short_edge_length=(800, 800), max_size=1333, sample_style='choice')]
[11/19 22:41:03 d2.data.common]: Serializing the dataset using: <class 'detectron2.data.common._TorchSerializedList'>
[11/19 22:41:03 d2.data.common]: Serializing 13 elements to byte tensors and concatenating them all ...
[11/19 22:41:03 d2.data.common]: Serialized dataset takes 0.04 MiB
[11/19 22:41:03 d2.evaluation.evaluator]: Start inference on 13 batches
[11/19 22:41:05 d2.evaluation.evaluator]: Total inference time: 0:00:00.982844 (0.122856 s / iter per device, on 1 devices)
[11/19 22:41:05 d2.evaluation.evaluator]: Total inference pure compute time: 0:00:00 (0.109083 s / iter per device, on 1 devices)
[11/19 22:41:05 d2.evaluation.coco_evaluation]: Preparing results for COCO format ...
[11/19 22:41:05 d2.evaluation.coco_evaluation]: Saving results to ./outputs_p3/eval_ft/coco_instances_results.json
[11/19 22:41:05 d2.evaluation.coco_evaluation]: Evaluating predictions with unofficial COCO API...
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
[11/19 22:41:05 d2.evaluation.fast_eval_api]: Evaluate annotation type *bbox*
[11/19 22:41:05 d2.evaluation.fast_eval_api]: COCOeval_opt.evaluate() finished in 0.00 seconds.
[11/19 22:41:05 d2.evaluation.fast_eval_api]: Accumulating evaluation results...
[11/19 22:41:05 d2.evaluation.fast_eval_api]: COCOeval_opt.accumulate() finished in 0.00 seconds.
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.723
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.857
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.807
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.303
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.512
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.880
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.236
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.744
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.744
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.300
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.547
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.900
[11/19 22:41:05 d2.evaluation.coco_evaluation]: Evaluation results for bbox: 
|   AP   |  AP50  |  AP75  |  APs   |  APm   |  APl   |
|:------:|:------:|:------:|:------:|:------:|:------:|
| 72.345 | 85.733 | 80.707 | 30.297 | 51.193 | 87.981 |
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
[11/19 22:41:05 d2.evaluation.fast_eval_api]: Evaluate annotation type *segm*
[11/19 22:41:05 d2.evaluation.fast_eval_api]: COCOeval_opt.evaluate() finished in 0.01 seconds.
[11/19 22:41:05 d2.evaluation.fast_eval_api]: Accumulating evaluation results...
[11/19 22:41:05 d2.evaluation.fast_eval_api]: COCOeval_opt.accumulate() finished in 0.00 seconds.
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.775
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.835
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.835
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.236
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.501
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.968
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.256
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.786
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.786
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.233
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.547
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.977
[11/19 22:41:05 d2.evaluation.coco_evaluation]: Evaluation results for segm: 
|   AP   |  AP50  |  AP75  |  APs   |  APm   |  APl   |
|:------:|:------:|:------:|:------:|:------:|:------:|
| 77.506 | 83.504 | 83.504 | 23.564 | 50.077 | 96.813 |
[P3-3] Fine-tuned model metrics on balloon_val:
OrderedDict({'bbox': {'AP': 72.34481209679068, 'AP50': 85.73285748511225, 'AP75': 80.7072913017707, 'APs': 30.297029702970296, 'APm': 51.19346000534119, 'APl': 87.9805866223441}, 'segm': {'AP': 77.50560590695736, 'AP50': 83.50441884061152, 'AP75': 83.50441884061152, 'APs': 23.564356435643564, 'APm': 50.07715057220008, 'APl': 96.81317875377282}})
[P3-2] Fine-tuned model visualizations saved to ./outputs_p3/finetuned_vis
[P3-4] Fine-tuned inference saved to: ./outputs_p3/finetuned_pred.jpg

0. 전체 흐름 한 줄 요약

  • 3-1: COCO로 학습된 Mask R-CNN 하나 골라서 → 예시 이미지에 적용 → 시각화 + “왜 이 모델 골랐는지” 설명
  • 3-2: balloon train/val dataset 등록 → train으로 fine-tuning → val 이미지에 대한 결과 시각화
  • 3-3:
    • fine-tuning (pretrained COCO 모델) AP/AR
    • fine-tuning (balloon에 맞게 학습된 모델) AP/AR
    • 하이퍼파라미터를 바꾸면서 결과 비교
  • 3-4:
    • 3-1에서 썼던 예시 이미지에 대해 fine-tuning 후 모델로 다시 inference
    • “왜 이런 결과가 나왔는지” + “어떻게 개선할 수 있을지” 분석 글 작성

1. 3-1: 사전학습 모델 선택 + 예시 이미지 시각화 + 선정 이유

1) 모델 선택

보통 과제에서 가장 무난한 선택은:

 
model_name = "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"
model_name = "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"

 

선택 이유를 리포트에 이렇게 쓰면 좋아:

  • ResNet-50 + FPN 백본이라 **성능(mAP)**과 **속도(inference time)**의 균형이 좋음
  • Model Zoo에서 자주 baseline으로 쓰이는 구조라, 과제에서 비교/확장에 적합
  • ResNet-101은 성능은 높지만 inference 속도가 느리고, R-50-FPN이 실제 서비스/실험용으로 많이 쓰임

예시 문장:

본 실험에서는 Detectron2 Model Zoo에서 제공하는 mask_rcnn_R_50_FPN_3x 사전학습 모델을 사용하였다. 해당 모델은 ResNet-50 백본과 FPN 구조를 사용하여 COCO val2017 기준으로 비교적 높은 mAP를 유지하면서도, ResNet-101 기반 모델에 비해 파라미터 수와 연산량이 적어 inference time 측면에서 효율적이다. 따라서 성능과 속도의 균형을 고려하여 본 모델을 선정하였다.

2) 예시 이미지 추론 / 시각화

기본 구조는 이미 가지고 있지:

cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file(model_name))
cfg.MODEL.DEVICE = "cpu"  # GPU 없으면 반드시 추가
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)
predictor = DefaultPredictor(cfg)

img_path = "./img_for_P3.jpg"  # wget으로 다운로드한 이미지
img = cv2.imread(img_path, cv2.IMREAD_COLOR)
assert img is not None, "예시 이미지를 먼저 다운로드하세요."

outputs = predictor(img)

os.makedirs("./outputs_p3", exist_ok=True)
v = Visualizer(img[:, :, ::-1], MetadataCatalog.get("__unused__"), scale=1.2)
out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
cv2.imwrite("./outputs_p3/pretrained_pred.jpg", out.get_image()[:, :, ::-1])
 

리포트에는:

  • “사전학습된 COCO 모델이 사람, 자동차, 기타 물체에 대해 적절히 mask를 생성하는지”
  • “어떤 객체들은 잘 잡고, 어떤 것들은 누락/오탐이 있는지”
    짧게 코멘트 써주면 좋아.

2. 3-2: 풍선 데이터셋 fine-tuning (train/val 확인 + 시각화)

1) Dataset 등록 및 시각화

너 코드에 이미 있는:

for d in ["train", "val"]:
    if "balloon_" + d in DatasetCatalog.list():
        DatasetCatalog.remove("balloon_" + d)
    DatasetCatalog.register("balloon_" + d, lambda d=d: get_balloon_dicts("balloon/" + d))
    MetadataCatalog.get("balloon_" + d).set(thing_classes=["balloon"])

balloon_metadata = MetadataCatalog.get("balloon_train")
dataset_dicts = get_balloon_dicts("balloon/train")
 

그리고 시각화:

os.makedirs("./outputs_p3/pretrained_balloon", exist_ok=True)
random.seed(1234)

for d in random.sample(dataset_dicts, 5):  # 5장만 예시
    im = cv2.imread(d["file_name"])
    outputs = predictor(im)  # 아직은 COCO pretrained 모델
    v = Visualizer(im[:, :, ::-1], MetadataCatalog.get(cfg.DATASETS.TRAIN[0]), scale=0.5)
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    filename = os.path.basename(d["file_name"])
    cv2.imwrite(f'./outputs_p3/pretrained_balloon/{filename}', out.get_image()[:, :, ::-1])
 

리포트 서술 포인트:

  • 풍선 데이터셋은 “작고, 단일 클래스(balloon)”라는 특징
  • train/val 예시 이미지를 통해 annotation이 정상적으로 잘 들어가 있는지 간단히 확인했다는 내용

2) Fine-tuning 코드 핵심

너가 이미 적어둔 구조:

cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file(model_name))
cfg.MODEL.DEVICE = "cpu"  # CPU 환경이면 추가
cfg.DATASETS.TRAIN = ("balloon_train",)
cfg.DATASETS.TEST = ("balloon_val",)
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)  # COCO pretrained
cfg.SOLVER.IMS_PER_BATCH = 2
cfg.SOLVER.BASE_LR = 0.00025
cfg.SOLVER.MAX_ITER = 600       # 과제에서는 300~1000 사이 실험 추천
cfg.SOLVER.STEPS = []
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1  # balloon 클래스 1개

os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)
trainer = DefaultTrainer(cfg)
trainer.resume_or_load(resume=False)
trainer.train()
 

그리고 val 시각화:

cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, "model_final.pth")
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7
predictor = DefaultPredictor(cfg)

os.makedirs("./outputs_p3/finetuned_vis", exist_ok=True)
for d in random.sample(get_balloon_dicts("balloon/val"), 5):
    im = cv2.imread(d["file_name"])
    outputs = predictor(im)
    v = Visualizer(im[:, :, ::-1], balloon_metadata, scale=0.5)
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    filename = os.path.basename(d["file_name"])
    cv2.imwrite(f'./outputs_p3/finetuned_vis/{filename}', out.get_image()[:, :, ::-1])
 

리포트에는:

  • fine-tuning 후, COCO 사전학습 모델보다 풍선 경계가 얼마나 더 정확해졌는지
  • 작은 풍선/겹쳐진 풍선에 대한 성능이 향상되었는지 여부
    이런 걸 이미지 예시와 함께 짧게 설명해주면 좋아.

3. 3-3: 파인 튜닝 전후 AP/AR 계산 + 파라미터 실험

여기가 채점 포인트가 큰 부분이라 구조 + 서술이 중요해.

1) Pretrained vs Fine-tuned 평가 코드 패턴

(1) 파인튜닝 “이전” (COCO pretrained)

from detectron2.evaluation import COCOEvaluator, inference_on_dataset
from detectron2.data import build_detection_test_loader

cfg_pre = get_cfg()
cfg_pre.merge_from_file(model_zoo.get_config_file(model_name))
cfg_pre.MODEL.DEVICE = "cpu"
cfg_pre.DATASETS.TEST = ("balloon_val",)
cfg_pre.DATALOADER.NUM_WORKERS = 2
cfg_pre.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)
cfg_pre.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7

pre_predictor = DefaultPredictor(cfg_pre)

evaluator_pre = COCOEvaluator("balloon_val", cfg_pre, False, output_dir="./outputs_p3/eval_pre/")
val_loader_pre = build_detection_test_loader(cfg_pre, "balloon_val")
metrics_pre = inference_on_dataset(pre_predictor.model, val_loader_pre, evaluator_pre)
print("Pretrained model metrics:", metrics_pre)
 

(2) 파인튜닝 “이후” (balloon에 맞게 학습된 모델)

cfg_ft = cfg.clone()             # 앞에서 fine-tuning에 사용한 cfg
cfg_ft.MODEL.DEVICE = "cpu"
cfg_ft.DATASETS.TEST = ("balloon_val",)

evaluator_ft = COCOEvaluator("balloon_val", cfg_ft, False, output_dir="./outputs_p3/eval_ft/")
val_loader_ft = build_detection_test_loader(cfg_ft, "balloon_val")

metrics_ft = inference_on_dataset(predictor.model, val_loader_ft, evaluator_ft)
print("Fine-tuned model metrics:", metrics_ft)
  • bbox, segm 기준의 AP, AP50, AP75, AP_small, AP_medium, AP_large
  • 그리고 AR(Average Recall)들도 들어있을 거야.

리포트에서는 중요한 것만 골라서 표로 정리:

ModelAP(segm)AP50(segm)AR(segm)설정 (lr, max_iter 등)
Pretrained (no FT) 0.xx 0.xx 0.xx COCO pretrained, no FT
Fine-tuned (iter=300) 0.yy 0.yy 0.yy lr=0.00025, iter=300
Fine-tuned (iter=600) 0.zz 0.zz 0.zz lr=0.00025, iter=600

2) “여러 파라미터 변경”은 어떻게 할까?

추천 실험 축:

  1. MAX_ITER
    • 300, 600, 900 정도
    • iter가 늘어날수록 AP가 증가하다가, 어느 시점부터 과적합으로 떨어지거나 plateau
  2. BASE_LR
    • 0.0001 vs 0.00025 vs 0.001
    • 너무 크면 발산, 너무 작으면 수렴이 느리고 AP 낮음
  3. ROI_HEADS.BATCH_SIZE_PER_IMAGE
    • 64 vs 128
    • RoI 샘플 수 바꾸면서 성능/시간 비교

리포트에서는:

MAX_ITER를 300, 600, 900으로 변경하여 실험한 결과, 300에서 AP는 X.XXX, 600에서 Y.YYY로 증가하였으나, 900에서는 성능 향상이 크지 않거나 소폭 감소하였다. 이는 풍선 데이터셋의 크기가 작기 때문에, 반복 수를 과도하게 늘릴 경우 풍선 영역에 과적합(overfitting)이 발생한 것으로 해석할 수 있다.

이런 식으로 AP/AR 변화 + 이유를 써주면 된다.


4. 3-4: 예시 이미지에서 나타나는 문제 분석 + 개선 방향

마지막 파트는 코드보다 글이 더 중요해.

1) 할 일

  • 3-1에서 사용한 img_for_P3.jpg를
  • fine-tuned 모델(predictor)으로 다시 inference
ft_out_path = "./outputs_p3/finetuned_pred.jpg"
ft_outputs = predictor(img)  # 위에서 이미 img = cv2.imread(img_for_P3.jpg)

v = Visualizer(img[:, :, ::-1], balloon_metadata, scale=1.2)
ft_draw = v.draw_instance_predictions(ft_outputs["instances"].to("cpu"))
cv2.imwrite(ft_out_path, ft_draw.get_image()[:, :, ::-1))

2) 분석에서 자주 나오는 “문제 상황”

대부분 이런 현상이 나타날 수 있어:

  • COCO 전체 객체를 인식하던 모델이 → 이제 풍선에만 과하게 반응
  • 풍선이 아닌 둥근/빨간 객체도 balloon으로 잘못 segmentation (false positive)
  • 원래 잘 잡던 사람/차량/배경 객체는 더 이상 검출하지 않음
    • 이유: NUM_CLASSES = 1로 설정해서 COCO 멀티클래스 정보가 덮여씀

3) 리포트에 쓸 수 있는 예시 분석 문장

Fine-tuning 이후 3-1에서 사용한 COCO val 이미지에 대해 재추론을 수행한 결과, 풍선과 유사한 색상 또는 형태를 가진 영역에 대해서는 과도하게 balloon mask가 예측되는 반면, 원래 사전학습 모델이 잘 검출하던 사람, 차량 등의 일반 객체는 거의 검출되지 않았다. 이는 풍선 데이터셋이 단일 클래스에 대한 소규모 데이터로 구성되어 있고, fine-tuning 과정에서 ROI_HEADS.NUM_CLASSES를 1로 설정함으로써 COCO의 멀티 클래스 표현력이 상당 부분 상실되었기 때문으로 해석할 수 있다.

또한 MAX_ITER를 크게 설정한 경우, balloon 데이터셋에 대한 과적합이 발생하여 풍선과 유사한 둥근 객체(예: 표지판, 특정 장식물)에 대해 false positive가 증가하는 현상이 관찰되었다.

4) “어떻게 해결할 수 있을지” 제안

  • 해결 아이디어 예시:
    1. 풍선뿐 아니라 다양한 객체가 포함된 추가 데이터로 multi-class fine-tuning 수행
    2. backbone을 동결(freeze)하고 ROI head만 미세 조정하여 과적합을 완화
    3. learning rate를 줄이거나, MAX_ITER를 조정해 과도한 업데이트 방지
    4. 강한 augmentation (scale jittering, color jitter, random crop)으로 데이터 다양성 증가
    5. SCORE_THRESH_TEST를 올려서 confidence가 낮은 false positive를 줄이기

리포트용 문장 예시:

이러한 문제를 완화하기 위한 방안으로는 (1) 풍선 외의 다양한 객체를 포함한 데이터로 multi-class fine-tuning을 수행하거나, (2) backbone을 동결하고 ROI head만 미세 조정하여 COCO 사전학습 표현을 최대한 보존하는 방법이 있다. 또한 (3) MAX_ITER와 BASE_LR을 조정하여 과도한 파라미터 업데이트를 방지하고, (4) 풍선 데이터셋에 대한 강한 데이터 증강을 적용함으로써 모델의 일반화 성능을 향상시킬 수 있을 것으로 판단된다.


마무리

지금까지 한 걸 정리하면:

  • 코드 측면:
    • 모델 선택 → 예시 이미지 inference
    • balloon dataset 등록 → fine-tuning → val 시각화
    • COCOEvaluator로 pretrained / fine-tuned 둘 다 AP/AR 측정
    • 예시 이미지 재추론
  • 리포트 측면:
    • 왜 R50-FPN 3x를 선택했는지
    • balloon dataset 특성 (소규모, single-class)
    • 파라미터 변화에 따른 AP/AR 표 + 해석
    • fine-tuning 이후 COCO 이미지에서 나타나는 문제와 개선 아이디어

이 네 축만 잘 채우면 P3 문제는 충분히 높은 점수 나올 구조야.

'개인 프로젝트 > 대학원 수업 정리' 카테고리의 다른 글

[CV] 기말고사 정리  (0) 2025.12.03
[CV] Classification, Segmentation  (0) 2025.12.02
[CV] 과제3_문제2  (0) 2025.11.20
[논문리뷰] CharGrid OCR 중요 원리  (0) 2025.11.19
[CV] 과제 3 최종코드  (0) 2025.11.16

댓글