모델 튜닝

사전 학습된 YOLO 모델을 철도 도메인에 맞게 최적화하는 과정이다. 하이퍼파라미터 조정, 데이터 증강, 소형 객체 특화 기법, 앙상블을 체계적으로 적용하면 성능을 크게 향상시킬 수 있다.

핵심 요약

튜닝 기법적용 시점예상 성능 향상난이도
학습률 스케줄링학습 초기+2~5% mAP
데이터 증강 강화학습 전+3~8% mAP
SAHI 슬라이싱추론 시+5~15% (소형 객체)
Attention 모듈 추가아키텍처 수정+3~7% mAP
WBF 앙상블추론 후처리+2~5% mAP
Ultralytics 자동 튜닝하이퍼파라미터 탐색+3~10% mAP

문서 탐색


하이퍼파라미터 튜닝

주요 하이퍼파라미터

# 철도 도메인 권장 하이퍼파라미터 (railway_hyp.yaml)
 
# 학습률
lr0: 0.001          # 초기 학습률 (기본 0.01 대비 낮게 설정 — 도메인 특화)
lrf: 0.01           # 최종 학습률 비율 (cosine annealing 종점)
momentum: 0.937     # SGD 모멘텀
weight_decay: 0.0005 # L2 정규화
 
# 배치 및 에포크
batch: 16           # GPU 메모리에 따라 조정 (16GB → 32, 8GB → 16)
epochs: 200         # 조기 종료(patience=50) 적용 권장
imgsz: 640          # 입력 해상도 (소형 객체: 1280 권장)
patience: 50        # 조기 종료 에포크 수
 
# IoU 및 신뢰도
iou: 0.7            # 학습 시 NMS IoU 임계값
conf: 0.001         # 학습 시 신뢰도 임계값 (낮게 → 더 많은 예측 평가)
 
# Warm-up
warmup_epochs: 5.0  # 첫 5 에포크 동안 학습률 선형 증가
warmup_momentum: 0.8
 
# 손실 가중치
box: 7.5            # 바운딩박스 손실 가중치
cls: 0.5            # 분류 손실 가중치 (철도: 클래스 적을 경우 낮춤)
dfl: 1.5            # Distribution Focal Loss 가중치

학습률 스케줄 비교

스케줄특징추천 상황
Cosine Annealing부드러운 감소, 수렴 안정대부분의 경우 (기본값)
Linear Decay단순 선형 감소빠른 실험
OneCycleLR초반 증가 후 감소, 빠른 수렴데이터 많을 때
CyclicLR주기적 반복, 로컬 미니마 탈출데이터 적을 때

Freeze (전이 학습 전략)

from ultralytics import YOLO
 
model = YOLO("yolo11m.pt")
 
# 데이터 적을 때: backbone 고정, head만 학습
model.train(
    data="railway.yaml",
    epochs=100,
    freeze=10,          # 첫 10 레이어 고정 (backbone 대부분)
    lr0=1e-4,           # 낮은 학습률 (head 미세 조정)
    batch=16,
)
 
# 데이터 충분할 때: 전체 학습
model.train(
    data="railway.yaml",
    epochs=200,
    freeze=0,           # 전체 레이어 학습
    lr0=1e-3,
    batch=16,
)

데이터 증강 전략

증강 기법효과철도 적합성사용법
Mosaic4개 이미지 합성, 소형 객체 증가매우 높음mosaic=1.0 (기본값)
Mixup두 이미지 혼합 학습중간mixup=0.15
Copy-Paste객체를 다른 배경에 붙여넣기높음 (지장물)copy_paste=0.3
CLAHE대비 제한 적응 히스토그램 균등화높음 (야간·터널)clahe=True
합성 데이터GAN/디지털 트윈으로 이미지 생성높음 (데이터 부족)별도 파이프라인
Random Flip수평 뒤집기낮음 (레일 방향성 있음)fliplr=0.0 (비권장)
Rotate회전중간 (드론 기울어짐)degrees=15
HSV 변환색조·채도·명도 변환높음 (날씨·조명)hsv_h=0.015, hsv_s=0.7

주의: 철도 레일은 방향성이 있어 수평 뒤집기(fliplr)를 적용하면 비현실적 이미지가 생성될 수 있다. 드론 시점 이미지는 조심스럽게 적용한다.

Albumentations 커스텀 증강

import albumentations as A
 
railway_transforms = A.Compose([
    # 날씨 시뮬레이션
    A.RandomRain(slant_lower=-10, slant_upper=10,
                 drop_length=20, drop_width=1,
                 drop_color=(200, 200, 200), p=0.2),
    A.RandomFog(fog_coef_lower=0.1, fog_coef_upper=0.4, p=0.15),
    A.RandomSunFlare(flare_roi=(0, 0, 1, 0.5),
                     src_radius=200, p=0.1),
 
    # 조명 변화
    A.CLAHE(clip_limit=4.0, tile_grid_size=(8, 8), p=0.3),
    A.RandomBrightnessContrast(
        brightness_limit=0.3, contrast_limit=0.3, p=0.4),
 
    # 블러 (카메라 흔들림 시뮬레이션)
    A.MotionBlur(blur_limit=7, p=0.2),
    A.GaussNoise(var_limit=(10.0, 50.0), p=0.2),
 
    # 기하학적 변환
    A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.1,
                       rotate_limit=15, p=0.3),
], bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels']))

소형 객체 탐지 개선

SAHI 슬라이싱 추론

from sahi import AutoDetectionModel
from sahi.predict import get_sliced_prediction
from sahi.utils.cv import read_image_as_pil
 
# 모델 로드
detection_model = AutoDetectionModel.from_pretrained(
    model_type="ultralytics",
    model_path="best.pt",
    confidence_threshold=0.25,
    device="cuda:0",
)
 
# 단일 이미지 슬라이싱 추론
image = read_image_as_pil("railway_scene.jpg")
result = get_sliced_prediction(
    image=image,
    detection_model=detection_model,
    slice_height=640,
    slice_width=640,
    overlap_height_ratio=0.2,
    overlap_width_ratio=0.2,
    postprocess_type="NMS",   # 슬라이스 병합 방식: NMS 또는 NMW
    postprocess_match_threshold=0.5,
)
 
# 결과 저장
result.export_visuals(export_dir="./output/")
object_list = result.object_prediction_list
print(f"탐지된 객체 수: {len(object_list)}")
 
# 배치 처리 (디렉토리 전체)
from sahi.predict import predict
predict(
    model_type="ultralytics",
    model_path="best.pt",
    source="./railway_images/",
    slice_height=640, slice_width=640,
    overlap_height_ratio=0.2, overlap_width_ratio=0.2,
    export_dir="./output/",
)

Multi-scale Fusion 비교

기법원리성능 향상속도 영향구현 난이도
SAHI 슬라이싱타일 분할 추론 후 병합+5~15% (소형)슬라이스 수만큼 느림하 (라이브러리)
FPN (Feature Pyramid)다중 스케일 피처맵+3~7%경미한 영향중 (기본 내장)
P2 레이어 추가고해상도 탐지 헤드+4~9%약간 느림
TTA (테스트 증강)여러 변환 후 결과 평균+2~4%2~8배 느림
Super-resolutionSR로 해상도 향상 후 탐지+3~8%매우 느림

앙상블 기법

WBF (Weighted Boxes Fusion)

WBF는 여러 모델의 탐지 결과를 가중 평균으로 병합하는 기법이다. NMS보다 박스 위치가 더 정확하고 신뢰도가 잘 보정된다.

from ensemble_boxes import weighted_boxes_fusion
 
# 세 모델의 탐지 결과
boxes_list = [
    [[0.1, 0.1, 0.5, 0.5], [0.6, 0.6, 0.9, 0.9]],  # 모델 1
    [[0.11, 0.09, 0.51, 0.51], [0.61, 0.59, 0.91, 0.91]],  # 모델 2
    [[0.09, 0.11, 0.49, 0.49]],  # 모델 3
]
scores_list = [
    [0.9, 0.85],   # 모델 1 신뢰도
    [0.85, 0.88],  # 모델 2 신뢰도
    [0.78],        # 모델 3 신뢰도
]
labels_list = [
    [0, 1],  # 모델 1 클래스
    [0, 1],  # 모델 2 클래스
    [0],     # 모델 3 클래스
]
weights = [2, 1, 1]  # 모델별 가중치 (성능 좋은 모델에 높은 가중치)
 
# WBF 실행
boxes, scores, labels = weighted_boxes_fusion(
    boxes_list,
    scores_list,
    labels_list,
    weights=weights,
    iou_thr=0.5,     # 같은 객체로 판단하는 IoU 임계값
    skip_box_thr=0.0001,  # 이 신뢰도 미만 박스 제외
)
 
print(f"병합된 박스 수: {len(boxes)}")

TTA (Test Time Augmentation)

from ultralytics import YOLO
 
model = YOLO("best.pt")
 
# TTA 적용 추론 (원본 + 수평뒤집기 + 스케일 변환 평균)
results = model.predict(
    source="railway_image.jpg",
    augment=True,    # TTA 활성화
    conf=0.30,
    iou=0.5,
)

Ultralytics 자동 튜닝

Ultralytics는 Ray Tune 기반의 하이퍼파라미터 자동 탐색 기능을 내장하고 있다.

from ultralytics import YOLO
 
model = YOLO("yolo11m.pt")
 
# 자동 하이퍼파라미터 튜닝
result_grid = model.tune(
    data="railway.yaml",
    epochs=50,          # 각 시도당 학습 에포크
    iterations=100,     # 탐색 반복 횟수
    optimizer="AdamW",  # 최적화 알고리즘
    plots=True,         # 결과 시각화
    save=True,          # 최적 모델 저장
    val=True,           # 각 시도 후 검증
 
    # 탐색 공간 정의 (선택적)
    # lr0=(1e-5, 1e-1),
    # momentum=(0.6, 0.98),
    # weight_decay=(0.0, 0.001),
)
 
# 최적 하이퍼파라미터 확인
print("최적 하이퍼파라미터:", result_grid.best_config)
print("최적 mAP@50:", result_grid.best_result["metrics/mAP50(B)"])

자동 튜닝 결과 활용

# 탐색된 최적 하이퍼파라미터로 전체 학습
best_hyp = result_grid.best_config
 
model_final = YOLO("yolo11m.pt")
model_final.train(
    data="railway.yaml",
    epochs=200,
    **best_hyp,         # 최적 하이퍼파라미터 적용
)

문서 탐색


참고 자료