-
Notifications
You must be signed in to change notification settings - Fork 0
Vineyard Wildlife Multiclass Training
처음에는 단일 종(노루)만 fine-tune해서 RPi에서 돌려보는 것을 목표로 시작했습니다. 그런데 운영 관점에서 노루 한 종만 잡아도 멧돼지·오소리·너구리·조류가 들어오면 의미가 없다는 점이 명확해졌고, 결국 5종 multi-class로 확장했습니다.
이 문서는 단일 종 → 다종 확장 과정에서 어떤 의사결정이 필요했는지, 그리고 imgsz 320/640 병렬 학습 결과를 비교하면서 어떤 점이 보였는지 정리합니다.
- 출처: 한국도로공사 EX 포털 생태통로 모니터링 datasetId 868·870·872·867·873
- 5종: 노루(roe_deer) / 멧돼지(wild_boar) / 오소리(badger) / 너구리(raccoon) / 조류(bird)
- 종별 약 5,000장씩, 합쳐서 24,844장 (조류 156장은 ZIP 손상으로 누락 처리)
- 라벨 포맷: COCO JSON → YOLO txt 자동 변환 스크립트로 통일
종마다 자연 환경·카메라·시기 분포가 달라서 한 번에 합쳐서 split하면 종별 분포가 깨질 위험이 있었습니다. 그래서:
- 종별로 먼저 70/20/10 split (seed=42)
- 각 종의 train/val/test 폴더에 심볼릭 링크 생성
- 종별 split 결과를
processed_multiclass/하나로 합집합
이렇게 하면 종별 분포가 split 단위에서 보존됩니다. 디스크 절약을 위해 모든 데이터는 NAS에 두고 심볼릭 링크로 처리했습니다.
- 모델: YOLO11n (Ultralytics 8.4.32 시작, RPi 쪽은 8.4.36)
- pretrained: COCO
- optimizer: AdamW
- scheduler: cos_lr=True
- imgsz: 320 / 640 두 개 병렬
| 항목 | imgsz=320 | imgsz=640 |
|---|---|---|
| 의도 | RPi 5 FPS 목표용 | 정확도 상한 측정용 |
| 학습 시간 | 짧음 | 길음 |
| 메모리 부담 | 낮음 | 높음 (batch 키울 여지 ↑) |
학습 도중 GPU 메모리 사용량이 절반 이하로 보여서 batch size를 키워 다시 돌리기도 했습니다. 학습 자체는 dev 머신에서 돌리고, RPi에는 .pt → ONNX → ncnn 변환 산출물만 SCP로 보냈습니다.

| imgsz | mAP50 | mAP50-95 | 비고 |
|---|---|---|---|
| 320 | 0.92x | 0.684 | 실시간 데모 권장 |
| 640 | 0.95x | 0.787 | 오프라인 정밀 분석용 |
640이 +9%p 좋지만 RPi에서 FPS가 절반 이하로 떨어져서, 실시간에는 320이 정답이라고 판단했습니다.

5종이라고 다 같은 난이도가 아니었습니다. RPi 4 + ncnn FP16, test split 2,484장 실측 mAP50-95:
| 종 | 320 mAP50-95 | 640 mAP50-95 | 비고 |
|---|---|---|---|
| roe_deer (노루) | 0.768 | 0.849 | 5종 중 최고. 학습 데이터 풍부 + 야간 IR 실루엣 또렷 |
| wild_boar (멧돼지) | 0.679 | 0.749 | 야간 IR 비중 큼. 노루와 자세·실루엣 유사해 헷갈릴 여지 |
| badger (오소리) | 0.704 | 0.784 | 저자세·짧은 다리. 작지만 형태 일관되어 안정적 |
| raccoon (너구리) | 0.653 | 0.735 | 5종 중 320에서 최저. 야간 IR 잡음 + 너구리·오소리 외형 유사 |
| bird (조류) | 0.617 | 0.744 | 작은 객체 비율 높음 — 320에서 가장 큰 폭 하락 (640 대비 -13%p). 실내 인공물(선풍기 등) false positive 위험 |
| all (5종 평균) | 0.684 | 0.787 | 320 → 640: 평균 +10%p. raccoon·bird가 가장 큰 폭으로 향상 |
한눈에 보기: 데이터 풍부도(노루 > 멧돼지 ≈ 오소리 > 너구리 > 조류)와 mAP50-95 순위가 거의 일치. bird만 320 ↔ 640 격차가 가장 큼 (작은 객체일수록 imgsz 영향이 크다는 일반 경향과 부합).
bird가 5종 중 가장 noisy한 점이 카메라 MVP에서 실내 선풍기 false positive로 그대로 드러났습니다 (카메라 실시간 검출 MVP 참고).
학습된 모델로 test 이미지에서 종별 2장씩 추론한 결과입니다. 좌측이 원본, 우측이 bbox + class · confidence 그려진 결과.





위 4종은 IR 카메라트랩 야간 이미지가 다수, bird만 주간 일반 카메라 이미지 비중이 큽니다. 이 분포 차이가 카메라 MVP에서 bird 클래스의 실내 false positive로 그대로 드러납니다 (카메라 실시간 검출 MVP 참고).
multi_scale=True 옵션으로 학습 도중 imgsz를 랜덤하게 바꿔서 일반화를 높이려고 시도했습니다. 그러나:
- 첫 epoch에서
ZeroDivisionError - 원인:
nn.functional.interpolatedecomposition이 torch+ultralytics 특정 버전에서 multi_scale 경로에 버그가 있음 - 우회: torch 다운그레이드 또는 ultralytics 패치 필요
지금은 일정 압박이 있어 보류했고, 다음 분기에 다시 시도할 예정입니다.
640으로 학습한 모델을 imgsz=320으로 추론하면 정확도가 더 좋을지 궁금해서 측정했습니다.
- 결과: 320 학습 모델 320 추론과 거의 동일
- 결론: 별 이득 없음, 학습 imgsz와 추론 imgsz를 맞추는 게 자연스럽다.
종별 데이터 분포·라벨 ID·split 전략을 처음부터 다종을 가정하고 짜야 했습니다. 단일 종 코드를 그대로 두고 다종으로 확장하면 split 분포가 깨지고 라벨 ID가 꼬입니다.
imgsz 640이 mAP는 좋지만 RPi에서 못 돌면 의미가 없습니다. deploy 컨텍스트의 제약을 학습 단계부터 의식해야 합니다.
bird mAP 0.617은 학습 단계에서 그냥 "아 5종 중 제일 낮네" 였지만, 카메라 MVP에서 100% false positive로 그대로 드러났습니다. 종별 약점은 데이터 단계의 신호이자 운영 단계의 트리거입니다.
- RPi 4 추론 백엔드 비교 — 학습된 모델을 어떤 백엔드로 deploy할지
- INT8 양자화 진단 — 양자화 시 종별로 다른 영향
- 카메라 실시간 검출 MVP — 학습 mAP가 현장에서 어떻게 드러나는지
Deepvisions | AI Engineer 2026.03 ~ 재직중
2026.05 ~ | @ Deepvisions 캠퍼스 CCTV 4대 · 자전거 OCR + 차량 공회전 다중 신호
2026.04 ~ | @ Deepvisions 포도밭 침입 탐지 (5종 multi-class · 라즈베리파이 4 실시간)
2026.03 ~ | @ Deepvisions 드론 이미지 기반 객체 탐지 + GSD calibration + 수확량 예측
- 프로젝트 메인
- 관련 연구 종합 + 한계 (2026-05) ← 최신
- 수확량 close-up 4장 + 3-Model (2026-05-19)
- 드론 포도 수확량 예측 — 파이프라인 (2026-05)
- 드론 포도송이 탐지 — 학습 변천사 (2026-04)
- SAM3 vs Fine-tuned YOLO
- Grounding DINO vs YOLO Top3 비교 요약
- YOLO Baseline Top3 비교 요약
- YOLO Model Comparison Summary
- 포도 탐지를 위한 데이터 수집
- 포도 수확량 측정을 위한 Object Detection
2025.03 ~ 2025.08 | 카카오테크부트캠프 | ✅ 종료 AI 기반 데스크테리어 추천 서비스
- Name: Woody (이동재)
- Focus: Vision AI, LLM Integration, Backend Engineering
- GitHub: @ehdwo0427
- Email: ehdwo0427@naver.com
- 포트폴리오 : 포트폴리오