[Meat-A-Eye] 성능 개선 프로세스 상세 메모 블로그

2026. 2. 6. 09:27·4. [팀] 프로젝트 및 공모전/4-2 Meat-A-Eye

Meat-A-Eye 성능 개선 프로세스 상세 보고서

4차에 걸친 파인튜닝을 통해 ~70% → 90.0%(소) / 94.2%(돼지)를 달성한 과정의 공학적 분석


목차

  1. 전체 프로세스 요약
  2. 1차 파인튜닝: 기초 검증
  3. 2차 파인튜닝: 현실 데이터 도입
  4. 3차 파인튜닝: 균형 확보
  5. 4차 파인튜닝: 클래스 최적화
  6. 핵심 공학 원리: 왜 기존 지식이 유지되는가
  7. 비교 실험: 다른 아키텍처와의 비교
  8. 정량적 분석 요약

1. 전체 프로세스 요약

graph LR
    A[1차 ~70%] --> B[2차 ~78%]
    B --> C[3차 ~85%]
    C --> D[4차 90%+]

    subgraph "개선 축"
    A1[연구 데이터] -.-> B1[현실 데이터 도입]
    B1 -.-> C1[편향 제거/균등 분할]
    C1 -.-> D1[클래스 최적화]
    end

각 단계에서 하나의 핵심 병목을 식별하고 이를 해결하는 방식으로 순차적 개선을 이루었습니다. 각 단계의 핵심은 다음과 같습니다:

단계 핵심 병목 해결 전략 성과
1차 데이터 부족 연구 데이터로 기저선 확립 ~70%
2차 현실 환경 미반영 유튜브·현장 데이터 수집 ~78% (+8%p)
3차 클래스 불균형 Dataset Balancer + WeightedSampler ~85% (+7%p)
4차 시각적 유사 클래스 혼동 BottomRound→Round 병합 + 정규화 90.0% (+5%p)

2. 1차 파인튜닝: 기초 검증 (~70%)

목표

ImageNet 사전학습 모델을 고기 부위 도메인에 적용할 수 있는지 가능성 검증

데이터

  • 출처: 학술 연구용 데이터베이스
  • 특성: 통제된 환경(균일 조명, 클린 배경)에서 촬영
  • 클래스: 10개 소고기 부위 (Beef_BottomRound 포함)
  • 문제점: 부위별 데이터 양 불균등, 특정 부위 과소 대표

학습 설정

# 1차 기본 구성
model = EfficientNet-B2 (ImageNet pretrained)
classifier = Dropout(0.4) → Linear(1408, 10)
optimizer = AdamW(lr=1e-4)
epochs = 20

결과 분석

  • 정확도: ~70%
  • Grad-CAM 검증: 모델이 고기의 질감/마블링 영역에 주목하는 것을 확인 → 접근 방향 유효
  • 주요 오분류: BottomRound ↔ Round (40%+ 상호 오분류), 연구 환경 데이터만으로는 현실 적용 불가

핵심 인사이트

  • EfficientNet-B2의 SE Block이 고기 질감 채널에 주목하는 것이 Grad-CAM으로 확인됨 → 아키텍처 선택 검증 완료

3. 2차 파인튜닝: 현실 데이터 도입 (~78%)

목표

현실 환경(조명 변화, 그림자, 다양한 배경)에서의 강건성 확보

데이터 수집

유튜브 정육 영상: 다양한 조명 조건, 촬영 각도, 칼/도마 등 도구 배경 프레임 캡처

현장 직접 촬영: 마트 진열대, 정육점 카운터, 포장/비포장 상태 데이터 확보

1차 자동 정제: 유효 확장자 필터링, 크기 기반 필터링 및 중복 제거

점진적 파인튜닝 적용

새 데이터를 추가할 때 전체 데이터를 처음부터 다시 학습하지 않고, 기존 가중치(v1)에서 시작하여 새 데이터 위주로 학습:

# 1차 모델 가중치 로드
model.load_state_dict(torch.load("b2_imagenet_beef_100-v1.pth"))

# 차별적 학습률 적용 시작
optimizer = AdamW([
    {"params": model.features.parameters(), "lr": 1e-4},  # Backbone: 미세 조정
    {"params": model.classifier.parameters(), "lr": 1e-3}, # Head: 빠른 적응
])

결과 분석

  • 정확도: ~78% (+8%p)
  • 개선 요인: 현실 환경 이미지 추가로 모델의 일반화 능력 향상
  • 잔존 문제: 특정 부위(Ribeye, Tenderloin)에 데이터 편중 → 다른 부위 성능 저하

4. 3차 파인튜닝: 균형 확보 (~85%)

목표

모든 부위가 균등하게 학습되도록 데이터 파이프라인 재설계

Dataset Balancer 도입

# dataset_balancer.py 핵심 로직
def split_from_raw(raw_dir, data_dir, samples_per_class=100):
    for class_name in beef_classes:
        images = collect_images(raw_dir, class_name)
        random.shuffle(images)  # seed=42

        selected = images[:samples_per_class]  # 부위별 100장 균등

        # 70:15:15 분할
        train = selected[:70]
        val = selected[70:85]
        test = selected[85:100]

        move_to(train, f"{data_dir}/train/{class_name}/")
        move_to(val, f"{data_dir}/val/{class_name}/")
        move_to(test, f"{data_dir}/test/{class_name}/")

2차 수동 정제

자동 정제 통과 이미지
    ↓
전문가 수동 검수 (Visual Inspection)
    ├── 오분류 이미지 제거 (다른 부위로 잘못 분류된 이미지)
    ├── 품질 불량 제거 (모호한 이미지, 과도한 블러)
    ├── 경계 케이스 판별 (두 부위가 함께 보이는 이미지)
    └── 레이블 수정 (잘못된 폴더에 배치된 이미지)

WeightedRandomSampler 적용

학습 데이터가 균등하더라도 에폭마다 소수 클래스를 더 자주 샘플링:

# 역빈도 가중치 계산
class_counts = [len(class_images[c]) for c in classes]
weights = 1.0 / torch.tensor(class_counts, dtype=torch.float)
sample_weights = weights[all_labels]

sampler = WeightedRandomSampler(sample_weights, len(sample_weights))
train_loader = DataLoader(dataset, sampler=sampler, batch_size=32)

결과 분석

  • 정확도: ~85% (+7%p)
  • 개선 요인: 모든 부위에 대한 균등한 학습 + 소수 클래스 과표집
  • 잔존 문제: Beef_BottomRound ↔ Beef_Round 상호 오분류율 여전히 30%+

5. 4차 파인튜닝: 클래스 최적화 (90.0% / 94.2%)

목표

시각적으로 유사한 클래스의 혼동을 근본적으로 해결

핵심 변경 1: 클래스 병합

Confusion Matrix 분석
    ↓
Beef_BottomRound ←→ Beef_Round: 상호 오분류율 30%+
    ↓
두 부위는 해부학적으로도 인접한 부위 (뒷다리 상부)
    ↓
외관·질감이 매우 유사 → 전문가도 사진만으로 구분 어려움
    ↓
결정: Beef_BottomRound를 Beef_Round로 통합 (10→9 클래스)

이 결정의 공학적 근거:

  • $P(\text{BottomRound}|\mathbf{x}) + P(\text{Round}|\mathbf{x}) \approx P(\text{Round}_{\text{merged}}|\mathbf{x})$
  • 두 클래스의 결정 경계가 중첩되어 모델이 불필요한 분류 경쟁을 하고 있었음
  • 병합 후 해당 클래스의 정확도와 동시에 다른 클래스의 정확도도 상승 (간접 효과)

핵심 변경 2: 정규화 강화

# 4차에서 추가/강화된 정규화
CONFIG = {
    "label_smoothing": 0.1,       # 과도한 확신 방지
    "mixup_alpha": 0.2,           # 결정 경계 부드럽게
    "grad_clip_max_norm": 1.0,    # 그래디언트 안정화
    "use_weighted_sampler": True,  # 클래스 균형
}

# WarmupCosineScheduler 정교화
scheduler = WarmupCosineScheduler(
    optimizer,
    warmup_epochs=3,        # 1e-6 → target LR
    warmup_start_lr=1e-6,
    max_epochs=30,          # 소고기는 30에폭으로 확장
    eta_min=1e-6,
)

핵심 변경 3: 데이터 증강 최적화

고기 분류에 특화된 증강 조합:

증강 고기 분류에서의 역할
Affine(rotate=±30°) 진열대에서 다양한 각도로 놓인 고기 대응
RandomBrightnessContrast 마트 형광등 vs 자연광 vs 어두운 환경
HueSaturationValue 고기 색상의 개체 차이 (신선도, 숙성 정도)
CLAHE 저조도에서 질감 디테일 강화
CoarseDropout 포장 스티커/손가락 등에 의한 부분 가림 대응
GaussNoise + GaussianBlur 저해상도 카메라, 손 떨림 대응

돼지고기 모델 병행 학습

소고기와 동일한 아키텍처와 학습 전략을 돼지고기에 적용:

항목 소고기 돼지고기
클래스 수 9부위 7부위
부위당 데이터 100장 50장
에폭 30 20
최종 정확도 90.0% 94.2%

돼지고기 높은 정확도의 원인:

  • 부위 간 시각적 차이가 소고기보다 뚜렷 (삼겹살의 지방층, 갈비의 뼈 등)
  • 7개 클래스로 분류 경계가 더 명확

최종 결과

소고기 (Beef v4):
  Overall Accuracy: 90.0% (9 classes, 100장/부위)

  Per-class Performance (추정):
  ┌──────────────────┬──────────┬──────────┬──────────┐
  │ 부위             │ Precision│ Recall   │ F1       │
  ├──────────────────┼──────────┼──────────┼──────────┤
  │ Beef_Tenderloin  │  ~95%    │  ~93%    │  ~94%    │
  │ Beef_Rib         │  ~93%    │  ~95%    │  ~94%    │
  │ Beef_Brisket     │  ~92%    │  ~90%    │  ~91%    │
  │ Beef_Shank       │  ~91%    │  ~92%    │  ~91%    │
  │ Beef_Ribeye      │  ~90%    │  ~88%    │  ~89%    │
  │ Beef_Sirloin     │  ~89%    │  ~90%    │  ~89%    │
  │ Beef_Chuck       │  ~88%    │  ~87%    │  ~87%    │
  │ Beef_Shoulder    │  ~86%    │  ~88%    │  ~87%    │
  │ Beef_Round       │  ~85%    │  ~87%    │  ~86%    │
  └──────────────────┴──────────┴──────────┴──────────┘

돼지고기 (Pork v4):
  Overall Accuracy: 94.2% (7 classes, 50장/부위)

6. 핵심 공학 원리: 왜 기존 지식이 유지되는가

문제: Catastrophic Forgetting

딥러닝에서 새로운 데이터로 모델을 재학습하면, 이전에 학습한 지식이 소실되는 현상을 Catastrophic Forgetting (파국적 망각)이라 합니다.

일반적인 학습:
  전체 데이터 A로 학습 → 모델₁
  전체 데이터 B로 재학습 → 모델₂ (A의 지식 대부분 소실!)

해결: 3중 보호 메커니즘

Meat-A-Eye 프로젝트에서는 다음 3가지 메커니즘을 조합하여 기존 지식을 보존합니다:

보호 1: 차별적 학습률 (Differential Learning Rate)

Neural Network의 계층적 특징 표현:

  ┌─────────────────────────────────────────────────┐
  │  Backbone (features)                             │
  │  ┌─────────────┐  ┌─────────────┐               │
  │  │ 저수준 특징   │  │ 고수준 특징   │   LR = 1e-4  │
  │  │ 에지, 텍스처  │→│ 질감, 패턴   │   (느리게)    │
  │  │ (범용)       │  │ (도메인)     │               │
  │  └─────────────┘  └─────────────┘               │
  │                                                   │
  │  기존 가중치를 "거의 보존"하면서 미세 적응           │
  └─────────────────────────────────────────────────┘
                         ↓
  ┌─────────────────────────────────────────────────┐
  │  Classifier (head)                               │
  │  ┌─────────────────────────────────────┐         │
  │  │ Dropout(0.4) → Linear(1408, 9)      │ LR=1e-3 │
  │  │ 새로운 부위 분류 경계 학습             │ (빠르게) │
  │  └─────────────────────────────────────┘         │
  └─────────────────────────────────────────────────┘

수학적 근거:

가중치 업데이트 공식: $\theta_{t+1} = \theta_t - \eta \cdot \nabla_\theta \mathcal{L}$

여기서 $\eta$ (학습률)이 작을수록 가중치 변화량 $|\Delta\theta|$가 작아집니다:

  • Backbone: $\eta = 10^{-4}$ → $|\Delta\theta_{\text{backbone}}| \approx 0.001 \cdot |\nabla\mathcal{L}|$
    • 기존 ImageNet 특징(에지, 텍스처, 색상 감지)이 거의 그대로 유지
    • 고기 도메인에 필요한 만큼만 미세 조정 (질감 채널 가중치 증가)
  • Head: $\eta = 10^{-3}$ → $|\Delta\theta_{\text{head}}| \approx 0.01 \cdot |\nabla\mathcal{L}|$
    • 10배 큰 업데이트로 새로운 부위별 결정 경계를 빠르게 학습

핵심 논리: Backbone의 낮은 LR은 기존 가중치에 대한 일종의 정규화(regularization) 역할을 합니다. 기존 가중치에서 크게 벗어나는 것을 물리적으로 제한하여, 이전 데이터에서 학습한 범용 시각 특징이 보존됩니다.

보호 2: Warmup 스케줄러

학습 초기 3 에폭:

  LR: 1e-6 ──→ 1e-5 ──→ 1e-4 (점진적 증가)

  이 구간에서 일어나는 일:
  ① 기존 가중치의 loss landscape에서 현재 위치 탐색
  ② 새 데이터의 그래디언트 방향 파악
  ③ 급격한 가중치 변화 없이 안정적으로 학습 시작

매우 낮은 LR(1e-6)로 시작하면, 학습 초기에 기존 가중치가 거의 변하지 않습니다. 이는 새 데이터의 그래디언트 방향이 기존 지식과 양립 가능한지 모델이 탐색할 시간을 주는 것입니다.

보호 3: 정규화 앙상블

기법 기존 지식 보호 메커니즘
Label Smoothing 새 데이터에 대한 과신(overconfidence) 방지 → 기존 분류 경계 깨뜨리지 않음
Mixup 두 샘플을 혼합하여 부드러운 결정 경계 학습 → 급격한 결정면 변화 억제
Weight Decay L2 정규화로 가중치 크기 제한 → 기존 가중치에서의 이탈 억제
Early Stopping 새 데이터에 과적합되기 전에 학습 중단 → 기존 지식 보존

종합: 왜 이 조합이 작동하는가

기존 모델 (v3)의 가중치 공간:

     Loss
      │
      │    ╲  ╱
      │     ╲╱  ← v3 최적점 (기존 지식)
      │      │
      │      │  ← 낮은 LR이 이 범위 내에서만 이동 가능하게 함
      │      │
      │   ╲  │  ╱
      │    ╲ │ ╱
      │     ╲│╱  ← v4 최적점 (기존 지식 + 새 지식)
      │
      └──────────→ 파라미터 공간

  차별적 LR: 작은 반경 내 탐색
  Warmup: 반경 내 방향 결정
  정규화: 반경 밖 이탈 방지
  Early Stopping: 과도한 이동 차단

결론적으로, 새 데이터만으로 학습해도 기존 지식이 유지되는 이유는:

  1. 낮은 학습률(1e-4)이 Backbone 가중치의 변화를 물리적으로 제한
  2. Warmup이 학습 초기 기존 가중치의 급격한 파괴를 방지
  3. 정규화 기법들이 기존 loss surface에서의 이탈을 다중으로 억제
  4. ImageNet 특징의 범용성: 에지·텍스처·색상 감지는 고기 분류에도 유용하므로, 새 데이터의 그래디언트가 기존 특징과 대체로 같은 방향을 가리킴

7. 비교 실험: 다른 아키텍처와의 비교

프로젝트에서 EfficientNet-B2 외에 3개 아키텍처를 비교 실험하였습니다:

ai-server/
├── convnext_l/          # ConvNeXt-L (2022, Meta)
├── efficientnetv2_l/    # EfficientNetV2-L (2021, Google)
└── swin_transformer/    # Swin Transformer (2021, Microsoft)

선택 근거

기준 EfficientNet-B2 ConvNeXt-L EfficientNetV2-L Swin Transformer
파라미터 수 ~9M ✅ ~198M ~120M ~88M
추론 속도 빠름 ✅ 보통 보통 느림
데이터 효율성 높음 ✅ 보통 보통 낮음 (대규모 필요)
SE Block 있음 ✅ 없음 있음 Attention
실시간 서비스 적합 ✅ 무거움 무거움 무거움

B2를 선택한 결정적 이유:

  1. 데이터 규모 제한 (부위당 100장) → 소형 모델이 과적합 위험 낮음
  2. 실시간 서비스 요구 → 경량 모델 필수
  3. SE Block의 채널 attention → 고기 질감/마블링 학습에 핵심적

8. 정량적 분석 요약

하이퍼파라미터 최종 설정

파라미터 값 역할
image_size 260 EfficientNet-B2 표준 해상도
batch_size 32 GPU 메모리 효율 + 배치 정규화 안정성
backbone_lr 1e-4 기존 특징 보존
head_lr 1e-3 새 분류기 빠른 학습
weight_decay 1e-2 L2 정규화
warmup_epochs 3 학습 초기 안정성
warmup_start_lr 1e-6 극도로 낮은 시작점
label_smoothing 0.1 과신 방지
mixup_alpha 0.2 결정 경계 부드럽게
dropout 0.4 분류기 과적합 억제
grad_clip 1.0 그래디언트 안정화
patience 10 Early Stopping
tta_transforms 5 추론 시 앙상블

데이터 통계

항목 소고기 돼지고기
클래스 수 9 7
부위당 데이터 100장 50장
Train 70장/부위 (630장) 35장/부위 (245장)
Val 15장/부위 (135장) 8장/부위 (56장)
Test 15장/부위 (135장) 7장/부위 (49장)
총 데이터 900장 350장

성능 변화 비교

차수 주요 변경 소고기 돼지고기 향상
v1 기초 학습 ~70% - 기저선
v2 현실 데이터 ~78% - +8%p
v3 균등 분할 + Sampler ~85% ~88% +7%p
v4 클래스 병합 + 정규화 90.0% 94.2% +5%p / +6.2%p

핵심 교훈

  1. 데이터 정제 > 데이터 양: 수동 정제를 통한 100장의 고품질 데이터가 1000장의 노이즈 데이터보다 효과적
  2. 클래스 최적화: 시각적으로 구분 불가능한 클래스를 병합하는 것이 전체 성능 향상에 기여
  3. 학습률 설계: LR 한 가지만 잘 설정해도 Catastrophic Forgetting 문제의 대부분 해결
  4. 정규화 앙상블: 단일 기법보다 여러 기법의 조합이 시너지 효과 발생
  5. 소형 모델의 강점: 제한된 데이터(100장/부위)에서는 소형 모델(9M params)이 대형 모델보다 우수

'4. [팀] 프로젝트 및 공모전 > 4-2 Meat-A-Eye' 카테고리의 다른 글

[프로젝트 회고] Meat-A-Eye: AI 기반 축산물 부위 인식 및 관리 플랫폼 개발기  (0) 2026.02.24
[Meat_A_Eye] 소고기 부위 분류 모델 성능 개량  (0) 2026.02.03
[개발 기록] 대시보드 가격 API 응답 시간 줄이기 - 병렬 호출과 캐시 사용  (0) 2026.02.02
[개발 기록] KAMIS API 연동 개선 및 대시보드 필터링 로직 최적화  (0) 2026.02.01
[Meat-A-Eye] 데이터 수집 과정 정리  (0) 2026.01.24
'4. [팀] 프로젝트 및 공모전/4-2 Meat-A-Eye' 카테고리의 다른 글
  • [프로젝트 회고] Meat-A-Eye: AI 기반 축산물 부위 인식 및 관리 플랫폼 개발기
  • [Meat_A_Eye] 소고기 부위 분류 모델 성능 개량
  • [개발 기록] 대시보드 가격 API 응답 시간 줄이기 - 병렬 호출과 캐시 사용
  • [개발 기록] KAMIS API 연동 개선 및 대시보드 필터링 로직 최적화
고니3000원
고니3000원
공부 내용 정리, 자기발전 블로그 입니다. 기존 네이버 블로그에서 티스토리로 이전했습니다. https://blog.naver.com/pak1010pak
  • 고니3000원
    곤이의 공부 블로그
    고니3000원
  • 전체
    오늘
    어제
    • 분류 전체보기 (176)
      • 1. AI 논문 + 모델 분석 (19)
        • AI 논문 분석 (13)
        • AI 모델 분석 (6)
      • 2. 자료구조와 알고리즘 (16)
        • 2-1 자료구조와 알고리즘 (13)
        • 2-2 강화학습 알고리즘 (3)
      • 3. 자습 & 메모(실전, 실습, 프로젝트) (25)
        • 3-1 문제 해석 (4)
        • 3-2 메모(실전, 프로젝트) (14)
        • 3-3 배포 실전 공부 (7)
      • 4. [팀] 프로젝트 및 공모전 (14)
        • 4-1 팀 프로젝트(메모, 공부) (1)
        • 4-2 Meat-A-Eye (6)
        • 4-3 RL-Tycoon-Agent (3)
        • 4-4 구조물 안정성 물리 추론 AI 경진대회(D.. (4)
      • 5. [개인] 프로젝트 및 공모전 (0)
        • 4-1 귀멸의칼날디펜스(자바스크립트 활용) (5)
        • 4-2 바탕화면 AI 펫 프로그램 (4)
        • 4-3 개인 프로젝트(기타) (3)
      • 개념 정리 step1 (32)
        • Python 기초 (7)
        • DBMS (1)
        • HTML | CSS (3)
        • Git | GitHub (1)
        • JavaScript (5)
        • Node.js (5)
        • React (1)
        • 데이터 분석 (6)
        • Python Engineering (3)
      • 개념 정리 step2 (56)
        • Machine | Deep Learning (15)
        • 멀티모달(Multi-modal) (23)
        • 강화 학습 (10)
        • AI Agent (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 네이버 곤이의 블로그(Naver->Tistory)
    • Github
  • 공지사항

  • 인기 글

  • 태그

    OCR학습
    bottleneck
    알고리즘
    Grad-CAM
    javascript
    Attention Is All You Need
    데이터분석
    EfficientNet
    Python
    학습
    논문 리뷰
    파인튜닝
    pandas
    transformer
    Ai
    ViT
    Vision
    공모전
    github
    자료구조
    파이썬
    OCR
    강화 학습
    html
    paddleocr
    강화학습
    자바스크립트
    구현
    프로젝트
    귀칼
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고니3000원
[Meat-A-Eye] 성능 개선 프로세스 상세 메모 블로그
상단으로

티스토리툴바