Deep SAD 코드 분석 : MNIST 샘플의 카테고리 (260711)

WonTerry·2026년 7월 11일

Deep Learning

목록 보기
9/26

CLI 입력

python main.py mnist mnist_LeNet ./ ./datasets \
  --ratio_known_outlier 0.01 --ratio_pollution 0.1 \
  --lr 0.0001 --n_epochs 150 --lr_milestone 50 --batch_size 128 --weight_decay 0.5e-6 \
  --pretrain True --ae_lr 0.0001 --ae_n_epochs 150 --ae_batch_size 128 --ae_weight_decay 0.5e-3 \
  --normal_class 0 --known_outlier_class 1 --n_known_outlier_classes 1

입력 파라미터 분석

명령어에서 --ratio_known_normal은 지정하지 않았으므로 기본값 0.0이 사용됩니다. 이를 포함해 실제로 계산해보면 다음과 같습니다 (MNIST 학습셋 기준 0번 숫자는 5,923개, 1번 숫자는 6,742개입니다).

파라미터
normal_class0
known_outlier_class1
n_known_outlier_classes1
ratio_known_normal0.0 (기본값, 미지정)
ratio_known_outlier0.01
ratio_pollution0.1

MNIST 샘플의 카테고리별 분석

카테고리semi-label개수
known normal (라벨 있는 정상, 0번 숫자)+10개
unlabeled normal (라벨 없는 정상, 0번 숫자)05,923개
unlabeled outlier (라벨 없이 섞인 이상치 — 0을 제외한 아무 숫자나)0658개
known outlier (라벨 있는 이상치, 반드시 1번 숫자)-166개
합계 (실제 학습에 쓰이는 총 샘플 수)6,647개
  1. known normal = 0개: ratio_known_normal = 0.0이라 라벨 붙은 정상 샘플은 아예 없습니다. 즉 0번 숫자 5,923개가 전부 "라벨 없는 정상"으로 들어갑니다.
  2. unlabeled normal = 5,923개: 0번 숫자 전체가 known_normal=0이므로 그대로 unlabeled normal이 됩니다.
  3. unlabeled outlier = 658개: ratio_pollution = 0.1은 "라벨 없는 데이터(정상+이상치) 중 이상치 비율"이므로,
    unlabeled_outlier / (unlabeled_normal + unlabeled_outlier) = 0.1
    unlabeled_outlier = 5,923 × (0.1/0.9) ≈ 658.1 → 정수로 잘려서 658개. (이 658개는 known_outlier_class인 1번뿐 아니라 2~9번 숫자 중에서도 무작위로 섞여 뽑힙니다.)
  4. known_outlier = 66개: ratio_known_outlier = 0.01은 "전체 라벨된 데이터(known_normal+unlabeled_normal+unlabeled_outlier+known_outlier) 중 known_outlier 비율"이므로,
    known_outlier / total ≈ 0.01 → 계산하면 약 66.5 → 정수로 잘려서 66개. 이 66개는 반드시 1번 숫자(known_outlier_class=1) 중에서만 무작위로 뽑힙니다 (1번 숫자는 학습셋에 6,742개가 있으므로 66개를 뽑는 데는 문제 없습니다).

참고

  • MNIST 학습셋 전체는 60,000개지만, 이 설정에서 실제 학습에 쓰이는 샘플은 6,647개뿐입니다 (정상 클래스가 0번 하나뿐이라 그 개수(5,923)를 기준으로 나머지 비율이 맞춰지기 때문).
  • 테스트셋은 이 로직과 무관하게 MNIST test set 전체(10,000개, 0~9 전부)를 그대로 사용하며, 0번은 정상/나머지는 전부 이상치로 라벨링되어 평가됩니다.
  • int()로 소수점을 버림 처리하기 때문에 정확한 비율보다 항상 살짝 적게 잡히는 경향이 있습니다 (예: 0.1 목표인데 실제로는 658/6581 ≈ 0.09997).

샘플 선택에 따른 AUC 예측

가장 정답률이 낮은 것은 normal_class = 5입니다.

Deep SVDD 원논문의 실측 데이터

Deep SAD와 같은 저자, 같은 아키텍처, 같은 MNIST one-vs-rest 벤치마크를 사용한 선행 논문(Deep SVDD, ICML 2018)에는 클래스별 실측 AUC 표가 있습니다 (비지도 학습 버전이지만 "어떤 정상 클래스가 압축된 정상 분포를 만들기 쉬운가"라는 근본적인 난이도는 Deep SAD에도 대체로 이어집니다).

Normal ClassOne-Class Deep SVDD AUC
098.0
199.7 (전체 중 최고)
291.7
391.9
494.9
588.5 (전체 중 최저)
698.3
794.6
893.9
996.5

MNIST 클래스 5를 정상 클래스로 했을 때 One-Class Deep SVDD의 평균 AUC는 88.5%(표준편차 0.9)로, 표에 나온 10개 클래스 중 가장 낮은 수치입니다. 반면 클래스 1은 99.7%(표준편차 0.1)로 가장 높은 AUC를 기록했습니다. 이는 지난번 답변에서 말씀드린 추론(숫자 '1'은 형태가 단순해서 탐지가 쉽고, 반대로 형태 변동이 크고 다른 숫자와 헷갈리는 클래스가 어렵다)과 정확히 일치합니다.

왜 5, 2, 3이 어려운가

  • 5: 필기체에서 6, 8, 3, 9와 자주 혼동되는 형태로, 사람마다 쓰는 방식의 변동 폭도 큼
  • 2, 3: 곡선 위주라 다른 곡선형 숫자(3↔8, 2↔7 등)와 겹치는 부분이 많음

known_outlier_class의 영향

known_outlier_class는 학습 시 라벨을 주는 "한 종류"일 뿐이고, 테스트는 항상 나머지 9개 클래스 전체에 대해 이루어지므로, 어떤 known_outlier_class를 고르든 normal_class의 근본적인 난이도(위 표의 순서)를 뒤집을 만큼 크게 영향을 주진 않을 것으로 예상합니다. 다만 부차적으로는:

  • known_outlier_class가 normal_class와 시각적으로 유사하면(예: normal=5, known=8) 모델이 "정상과 가까운 이상치"까지 구분하는 법을 배우게 되어 오히려 일반화에 도움이 될 수도 있고
  • 반대로 그 특정 클래스에만 과적합되어 다른 이상치 클래스 탐지력이 떨어질 수도 있어, 방향은 실험해봐야 확실합니다.

결론

제 예상 1순위 조합은 --normal_class 5 (known_outlier_class는 크게 상관없이, 굳이 고른다면 --known_outlier_class 8처럼 시각적으로 유사한 클래스)이고, 2순위 후보는 --normal_class 2 또는 3입니다. --normal_class 1은 오히려 AUC가 가장 잘 나올 클래스로 예상됩니다.

profile
Hello, I'm Terry! 👋 Enjoy every moment of your life! 🌱 My current interests are Signal processing, Machine learning, Python, Database, LLM & RAG, MCP & ADK, Multi-Agents, Physical AI, ROS2...

0개의 댓글