본문 바로가기

勉強/A.I.

YOLOv11 객체 탐지 실습 - Open Images V7 데이터 수집부터 학습/평가까지 (FiftyOne, Ultralytics)

실습 개요

Open Images V7 데이터셋에서 Camera 클래스 이미지를 수집하고, YOLOv11 모델을 학습시켜 객체 탐지를 구현하는 전체 파이프라인을 실습했습니다.

전체 파이프라인

Open Images Dataset
    ↓
클래스 선택 (Label ID 확인)
    ↓
데이터 다운로드 (FiftyOne)
    ↓
Annotation 변환 (COCO → YOLO)
    ↓
Dataset Split (train / val)
    ↓
YOLOv11 학습
    ↓
평가 / 추론

1. 환경 설치

# Python 3.11.14
pip install fiftyone openimages pandas tqdm ultralytics split-folders

2. 클래스(Label) 검색 - Open Images V7

Open Images V7에는 600개 이상의 클래스가 있습니다. CSV 파일을 다운로드해서 원하는 클래스의 Label ID를 찾습니다.

import urllib.request, csv, os

url = 'https://storage.googleapis.com/openimages/v7/oidv7-class-descriptions.csv'
urllib.request.urlretrieve(url, 'oidv7-class-descriptions.csv')

keyword = 'camera'
matches = []
with open('oidv7-class-descriptions.csv', encoding='utf-8') as f:
    for row in csv.reader(f):
        if len(row) >= 2 and keyword in row[1].lower():
            matches.append(row)

print(matches)

실행 결과:

['/m/0dv5r', 'Camera'], ['/m/01bjxx', 'Camera lens'],
['/m/0h8mhv3', 'Surveillance camera'], ['/m/025t6n0', 'Video camera'], ...

'Camera' 클래스의 Label ID = /m/0dv5r

3. FiftyOne으로 데이터 다운로드

FiftyOne은 Voxel51에서 만든 컴퓨터 비전 데이터 관리 라이브러리입니다. Open Images, COCO 등 대규모 데이터셋을 클래스 필터링 후 간편하게 다운로드할 수 있습니다.

import fiftyone.zoo as foz

# 학습용 1000장 다운로드
train_dataset = foz.load_zoo_dataset(
    "open-images-v7",
    split="train",
    label_types=["detections"],
    classes=['Camera'],
    max_samples=1000,
    only_matching=True,   # Camera가 있는 이미지만
    num_workers=4
)
train_dataset.save()

# 검증용 다운로드 (요청 200장 → 실제 142장만 존재)
val_dataset = foz.load_zoo_dataset(
    "open-images-v7",
    split="validation",
    label_types=["detections"],
    classes=['Camera'],
    max_samples=200,
    only_matching=True
)
val_dataset.save()

실행 결과:

Downloading 1000 images: 100% 1000/1000 [2.4m, 5.8 files/s]
Dataset 'open-images-v7-train-1000' created

Only found 142 (<200) samples matching requirements
Dataset 'open-images-v7-validation-200' created

데이터는 C:\Users\[user]\fiftyone\open-images-v7\에 저장됩니다.

4. YOLO 형식으로 변환 (Export)

FiftyOne의 fo.types.YOLOv5Dataset으로 COCO 어노테이션을 YOLO 형식의 .txt 파일로 자동 변환합니다.

import fiftyone as fo
from fiftyone import ViewField as F

dataset_root = './camera_yolo_v7'
train_dataset = fo.load_dataset('open-images-v7-train-1000')

# Camera 레이블만 포함된 뷰 생성
train_view = train_dataset.filter_labels('ground_truth', F('label') == 'Camera')

train_view.export(
    export_dir=dataset_root,
    dataset_type=fo.types.YOLOv5Dataset,
    label_field='ground_truth',
    classes=['Camera'],
    split='train',
    overwrite=True
)

# 검증셋도 동일하게 export (split='val')

출력 폴더 구조

camera_yolo_v7/
  images/
    train/  ← 1000장 .jpg
    val/    ← 142장 .jpg
  labels/
    train/  ← 각 이미지마다 .txt (YOLO 형식)
    val/
  camera.yaml

YOLO 어노테이션 형식

# labels/train/000091f4a275d0fb.txt
# 형식: class_id cx cy width height (0~1 정규화)
0 0.535286 0.329608 0.12571 0.22581

# COCO Bounding Box: [x_min, y_min, w, h] (픽셀)
# YOLO: cx = (x_min + w/2) / img_w,  cy = (y_min + h/2) / img_h

camera.yaml 설정 파일

path: C:/Users/mello/Desktop/yolo/camera_yolo_v7
train: images/train
val:   images/val

nc: 1
names: ['Camera']

5. YOLOv11 학습

Ultralytics의 YOLOv11은 YOLOv8의 후속 모델입니다. 동일한 API로 사용 가능합니다.

모델 크기 비교

모델 파라미터 mAP50 속도
yolo11n 2.6M 39.5% 가장 빠름
yolo11s 9.4M 47.0% 빠름
yolo11m 20.1M 51.5% 중간
yolo11l 25.3M 53.4% 느림
yolo11x 56.9M 54.7% 가장 느림
from ultralytics import YOLO

model = YOLO('yolo11n.pt')  # 사전학습 모델 로드

results = model.train(
    data='./camera_yolo_v7/camera.yaml',
    epochs=20,
    imgsz=640,
    batch=16,
    name='camera_detection',
    device='cpu',         # GPU: 0, M1: 'mps'
    workers=4,
    project='./runs/detect',
    save=True,
    plots=True,
    val=True
)

6. 학습 로그 지표 해설

지표 설명
box_loss Bounding Box 위치 오차 (낮을수록 좋음)
cls_loss 클래스 분류 오차
dfl_loss Distribution Focal Loss - 박스 경계 정밀도
mAP50 IoU 0.5 기준 평균 정밀도 (대표 지표)
mAP50-95 IoU 0.5~0.95 평균 (전반적 정밀도)
Precision (P) 예측 중 실제 정답 비율
Recall (R) 전체 정답 중 찾아낸 비율

7. 평가 결과

model = YOLO('runs/detect/camera_detection/weights/best.pt')
metrics = model.val()
           Class  Images  Instances  Box(P)     R   mAP50  mAP50-95
             all     142        153   0.816  0.752   0.790     0.555

mAP50:    0.790
mAP50-95: 0.555
Speed: 0.5ms preprocess, 52.0ms inference per image (CPU)

Camera 클래스 1000장으로 20 epoch 학습 → mAP50 0.790 달성.

8. 추론 코드 (Inference)

import cv2, matplotlib.pyplot as plt, matplotlib.patches as mpatches
from ultralytics import YOLO
import os, random

model = YOLO('runs/detect/camera_detection/weights/best.pt')
val_dir = './camera_yolo_v7/images/val'

for img_path in random.sample(os.listdir(val_dir), 4):
    results = model.predict(img_path, conf=0.25, verbose=False)[0]
    for box in results.boxes:
        x1,y1,x2,y2 = map(int, box.xyxy[0])
        conf = box.conf[0]
        cv2.rectangle(img, (x1,y1),(x2,y2), (255,0,0), 2)
        cv2.putText(img, f'{conf:.2f}', (x1,y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,0,0), 2)

9. 자동 적용 데이터 증강 기법

기법 설명 효과
Mosaic 4장 이미지를 조각 합성 YOLO 성능 향상의 핵심 기여
HSV 변형 색조/채도/명도 무작위 변경 조명 변화에 강건함
Fliplr 좌우 반전 방향 무관한 특징 학습
회전/이동 이미지 기하학적 변환 위치 무관한 학습
MixUp 두 이미지 투명하게 혼합 일반화 성능 향상

10. 핵심 개념 정리

Negative Sample(배경 이미지)의 중요성

Camera가 없는 이미지를 학습에 포함하면 오탐(False Positive)을 줄일 수 있습니다. 방법: 빈 .txt 파일을 labels 폴더에 생성. 권장 비율: 전체의 0~10%.

라벨링 미기재 객체

YOLO는 라벨이 없는 모든 영역을 배경으로 학습합니다. 타겟 외 물체는 따로 라벨링하지 않아도 됩니다.

다중 클래스 필요 시

Camera와 비슷한 물체(핸드폰 렌즈 등)를 구분해야 한다면, 해당 클래스도 함께 학습시켜야 합니다.

성능 향상 팁

  • imgsz 값이 클수록 소형 객체 탐지 정확도 향상 (속도 저하)
  • 데이터 품질(Bbox 정확도)이 모델 성능에 직결
  • Open Images는 Noisy label 주의 (잘못된 어노테이션 존재)

undefined