실습 개요
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 주의 (잘못된 어노테이션 존재)
'勉強 > A.I.' 카테고리의 다른 글
| PP-YOLOE+ 실습 및 YOLOv11과 비교 - PaddleDetection, COCO JSON 변환, 모델 구조 차이점 정리 (1) | 2026.06.02 |
|---|