손 X-Ray 이미지에서 뼈를 29개 클래스로 세그멘테이션하는 딥러닝 프로젝트입니다. 자세한 프로젝트 진행 내용은 WrapUpReport를 참고해주세요!
- 프로젝트 구조
- 환경 설정
- 빠른 시작
- 실험 진행 방법
- 설정 파일 가이드
- WandB 사용법
- TTA (Test Time Augmentation)
- 앙상블 (Ensemble)
- 협업 규칙
- 대회 제출용 CSV 생성
- 트러블슈팅
- 실험 체크리스트
- 29개 클래스 목록
Xray-Segmentation/
├── .gitignore # Git 무시 파일 목록
├── README.md # 이 파일
├── requirements.txt # 필요 라이브러리 목록
├── main.py # 학습/추론 메인 코드
├── configs/ # 실험 설정 파일 (YAML)
│ ├── base_config.yaml # 기본 설정 템플릿
│ ├── exp01_fcn_resnet50.yaml # 실험 1: FCN 베이스라인
│ ├── exp02_loss_experiment.yaml # 실험 2: Loss 실험
│ └── exp03_augmentation.yaml # 실험 3: Augmentation 실험
├── src/ # 핵심 코드 모듈
│ ├── __init__.py
│ ├── dataset.py # 데이터셋 클래스
│ ├── models.py # 모델 정의
│ ├── losses.py # Loss 함수
│ └── utils.py # 유틸리티 함수
├── notebooks/ # (생성 필요) EDA, 개인 실험용 노트북
├── data/ # (Git 무시) 데이터셋 심볼릭 링크 또는 복사
└── saved_models/ # (Git 무시) 학습된 모델 저장
git clone [repository-url]
cd Xray-Segmentation# conda 사용시
conda create -n xray python=3.10
conda activate xray
# 또는 venv 사용시
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windowspip install -r requirements.txt
# PyTorch GPU 버전 설치 (CUDA 11.8 기준)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118데이터는 Git에 올리지 않으므로 심볼릭 링크 또는 config 파일 수정으로 연결합니다.
# 방법 1: 심볼릭 링크 생성
ln -s /path/to/Xray-Segmentation/data/train
ln -s /path/to/Xray-Segmentation/data/test
# 방법 2: config 파일에서 직접 경로 수정
# configs/base_config.yaml의 data 섹션 수정# 기본 실험 (FCN ResNet50)
python main.py --config configs/exp01_fcn_resnet50.yaml --mode train
# Loss 실험 (BCE + Dice)
python main.py --config configs/exp02_loss_experiment.yaml --mode train
# Augmentation 실험
python main.py --config configs/exp03_augmentation.yaml --mode train# 방법 1: main.py 사용 (config 파일 필요)
python main.py --config configs/exp01_fcn_resnet50.yaml --mode inference
# 방법 2: inference.py 사용 (더 간단!)
python inference.py --config configs/exp01_fcn_resnet50.yaml
# 방법 3: 모델 경로 직접 지정
python inference.py --model saved_models/exp01/best_model.pt --output output.csv
# 방법 4: 상세 옵션 지정
python inference.py --model saved_models/exp01/best_model.pt \
--model_name fcn_resnet50 \
--test_root data/test/DCM \
--output my_submission.csv \
--threshold 0.5
# 방법 5: TTA 사용 (성능 향상!)
python inference.py --config configs/exp01_fcn_resnet50.yaml --tta
python inference.py --model saved_models/exp01/best_model.pt --tta --output output_tta.csvpython main.py --config configs/exp01_fcn_resnet50.yaml --mode all# base_config.yaml을 복사하여 새 실험 파일 생성
cp configs/base_config.yaml configs/exp04_your_experiment.yaml# configs/exp04_your_experiment.yaml
experiment:
name: "exp04_deeplabv3" # ✏️ 실험 이름 수정
description: "DeepLabV3 실험" # ✏️ 설명 추가
author: "your_name" # ✏️ 본인 이름
model:
name: "deeplabv3_resnet101" # ✏️ 모델 변경
pretrained: true
loss:
name: "bce_dice" # ✏️ Loss 변경
bce_weight: 0.5
dice_weight: 0.5
save:
dir: "saved_models/exp04_deeplabv3" # ✏️ 저장 폴더 수정python main.py --config configs/exp04_your_experiment.yaml --mode train실험 결과를 팀 노션이나 스프레드시트에 기록합니다.
| 모델명 | 설명 | 메모리 사용량 |
|---|---|---|
fcn_resnet50 |
FCN with ResNet50 | 낮음 |
fcn_resnet101 |
FCN with ResNet101 | 중간 |
deeplabv3_resnet50 |
DeepLabV3 with ResNet50 | 중간 |
deeplabv3_resnet101 |
DeepLabV3 with ResNet101 | 높음 |
deeplabv3_mobilenet |
DeepLabV3 with MobileNet | 낮음 |
model:
name: "deeplabv3_resnet101" # 원하는 모델 선택
pretrained: true| Loss명 | 설명 | 사용 상황 |
|---|---|---|
bce |
Binary Cross Entropy | 기본 베이스라인 |
dice |
Dice Loss | 클래스 불균형 |
bce_dice |
BCE + Dice 조합 | 안정적인 학습 |
focal |
Focal Loss | 심한 클래스 불균형 |
tversky |
Tversky Loss | FP/FN 가중치 조절 |
# BCE만 사용
loss:
name: "bce"
# BCE + Dice 조합
loss:
name: "bce_dice"
bce_weight: 0.5 # BCE 가중치
dice_weight: 0.5 # Dice 가중치
# Focal Loss
loss:
name: "focal"
alpha: 0.25 # 양성 클래스 가중치
gamma: 2.0 # focusing parameter
# Tversky Loss
loss:
name: "tversky"
alpha: 0.3 # FP 가중치
beta: 0.7 # FN 가중치augmentation:
train:
resize: 512 # 이미지 크기
horizontal_flip: false # 좌우 반전 (X-ray는 주의)
vertical_flip: false # 상하 반전
rotate: true # 회전
rotate_limit: 15 # 회전 각도 범위 (±15도)
brightness_contrast: true # 밝기/대비 조절
elastic_transform: true # Elastic 변형
grid_distortion: true # Grid 왜곡
valid:
resize: 512training:
epochs: 50 # 총 에폭 수
batch_size: 8 # 배치 크기 (GPU 메모리에 따라 조절)
learning_rate: 0.0001 # 학습률
weight_decay: 0.000001 # 가중치 감쇠
optimizer: "adam" # adam, adamw, sgd
scheduler: "cosine" # null, cosine, step
val_every: 5 # 검증 주기
num_workers: 4 # DataLoader 워커 수
n_splits: 5 # K-Fold 수
fold: 0 # 사용할 fold (0~4)# wandb 로그인 (처음 한 번만)
wandb login
# API 키 입력 (https://wandb.ai/authorize 에서 확인)# 📊 WandB 설정
wandb:
enabled: true # false로 끄면 로깅 안함
entity: "let_cv_03" # 팀 entity 이름 (변경 금지!)
project: "segmentation" # 프로젝트 이름 (변경 금지!)
name: "gh_fcn_resnet50_epoch50" # ⚠️ 실험 이름 (필수 수정!)
tags: ["baseline", "fcn"] # 태그 (선택)
notes: "FCN 베이스라인 실험" # 메모 (선택)형식: 이니셜_모델_추가정보
| 예시 | 설명 |
|---|---|
gh_fcn_resnet50_baseline |
가현, FCN ResNet50 베이스라인 |
jh_deeplabv3_bce_dice |
지훈, DeepLabV3 BCE+Dice Loss |
sm_unet_augmentation |
수민, UNet Augmentation 실험 |
yj_fcn_cosine_lr |
영준, FCN Cosine LR 스케줄러 |
실험 실행 후 아래 주소에서 결과 확인:
- 프로젝트 URL: https://wandb.ai/let_cv_03/segmentation
| 항목 | 설명 |
|---|---|
train/step_loss |
매 step loss |
train/epoch_loss |
에폭 평균 loss |
train/learning_rate |
현재 learning rate |
val/loss |
검증 loss |
val/dice |
검증 평균 Dice |
val_dice/{class} |
클래스별 Dice |
val/predictions |
🖼️ 시각화 이미지 (Input, GT, Prediction) |
best_dice |
최고 Dice (summary) |
best_epoch |
최고 성능 에폭 (summary) |
validation마다 자동으로 예측 결과가 WandB에 이미지로 로깅됩니다!
시각화되는 내용:
- Input: 원본 X-Ray 이미지
- Ground Truth: 실제 정답 마스크 (색상별 클래스)
- Prediction: 모델 예측 마스크
확인 방법:
- WandB 대시보드 접속
- 해당 run 클릭
- Media 탭 또는 Charts →
val/predictions확인
시각화 샘플 수 조절:
wandb:
num_vis_samples: 4 # 0으로 설정하면 시각화 안함로컬 테스트시 wandb를 끄려면:
wandb:
enabled: false # false로 변경# 오프라인 모드로 실행 (인터넷 없을 때)
WANDB_MODE=offline python main.py --config configs/exp01.yaml --mode train
# 실행 후 나중에 sync
wandb sync ./wandb/offline-run-*TTA는 테스트/추론 시 여러 augmentation을 적용하여 예측을 앙상블하는 기법입니다. 일반적으로 0.5~2% Dice score 향상을 기대할 수 있습니다.
# CLI에서 --tta 플래그 사용
python inference.py --config configs/exp01.yaml --tta
# 모델 직접 지정 + TTA
python inference.py --model saved_models/best_model.pt --tta --output output_tta.csvinference:
threshold: 0.5
batch_size: 2 # TTA 사용 시 메모리 고려하여 작게
output_csv: "output_tta.csv"
# 🔄 TTA 설정
tta:
enabled: true # TTA 활성화
horizontal_flip: true # 수평 뒤집기 (권장)
vertical_flip: false # 수직 뒤집기
rotate90: false # 90도 단위 회전
merge_mode: "mean" # "mean" 또는 "max"| 옵션 | 설명 | 효과 | 시간 증가 |
|---|---|---|---|
horizontal_flip |
좌우 반전 | ⭐⭐⭐ 가장 효과적 | x2 |
vertical_flip |
상하 반전 | ⭐⭐ | x2 |
rotate90 |
90/180/270도 회전 | ⭐ X-ray에는 비추천 | x4 |
| 조합 | Transform 수 | 추론 시간 | 권장도 |
|---|---|---|---|
| HFlip만 | 2 (원본 + HFlip) | x2 | ⭐⭐⭐ 기본 권장 |
| HFlip + VFlip | 4 (원본 + HFlip + VFlip + HVFlip) | x4 | ⭐⭐ |
| 모든 옵션 | 8 | x8 | ⭐ 과도할 수 있음 |
X-ray 손 이미지 특성을 고려한 권장 설정:
tta:
enabled: true
horizontal_flip: true # ✅ 좌/우 손 대칭, 매우 효과적
vertical_flip: false # ❌ 손은 특정 방향이라 효과 제한적
rotate90: false # ❌ X-ray 특성상 비추천
merge_mode: "mean" # mean이 max보다 안정적| 방법 | 설명 | 특징 |
|---|---|---|
mean |
모든 예측의 평균 | 안정적, 노이즈 감소 |
max |
모든 예측 중 최대값 | 민감도 높음, FP 증가 가능 |
batch_size를 줄이세요.
# 메모리 부족 시
inference:
batch_size: 1 # 배치 크기 줄이기
tta:
enabled: true
horizontal_flip: true # 필요한 것만 사용여러 모델의 예측 결과를 결합하여 성능을 향상시키는 방법입니다. 일반적으로 1~3% Dice score 향상을 기대할 수 있습니다.
# CSV 파일 앙상블 (가장 간단)
python ensemble.py --csvs output1.csv output2.csv output3.csv \
--output ensemble.csv
# 가중치 기반 앙상블 (성능 좋은 모델에 높은 가중치)
python ensemble.py --csvs output1.csv output2.csv output3.csv \
--weights 0.5 0.3 0.2 \
--method weighted_average \
--output ensemble_weighted.csv
# Config 파일 사용 (권장)
python ensemble.py --config configs/ensemble/ensemble_csv_simple.yaml| 방법 | 설명 |
|---|---|
simple_average |
모든 모델의 확률값 평균 |
weighted_average |
성능 기반 가중치 평균 |
max_voting |
각 픽셀에서 최대 확률값 선택 |
hard_voting |
이진화 후 다수결 |
rank_average |
순위 기반 평균 |
geometric_mean |
기하평균 |
# Step 1: 여러 모델 학습
python main.py --config configs/exp01_unetpp_efficientb4.yaml
python main.py --config configs/exp02_unetpp_mobilenet.yaml
python main.py --config configs/exp03_deeplabv3_resnet50.yaml
# Step 2: 각 모델로 추론
python inference.py --config configs/exp01_unetpp_efficientb4.yaml
python inference.py --config configs/exp02_unetpp_mobilenet.yaml
python inference.py --config configs/exp03_deeplabv3_resnet50.yaml
# Step 3: 앙상블
python ensemble.py --csvs exp01_output.csv exp02_output.csv exp03_output.csv \
--method simple_average \
--output final_ensemble.csv# configs/ensemble/my_ensemble.yaml
ensemble:
method: "weighted_average"
csv_files:
- "exp01_output.csv" # dice: 0.95
- "exp02_output.csv" # dice: 0.93
- "exp03_output.csv" # dice: 0.91
# Validation Dice Score 기반 가중치
weights: [0.5, 0.3, 0.2]
output_csv: "ensemble_output.csv"
threshold: 0.5✅ 다양성 확보: 서로 다른 아키텍처, 백본, 이미지 크기 사용
✅ 가중치 설정: Validation Dice Score 기반으로 가중치 부여
✅ 적절한 개수: 3~5개 모델이 일반적으로 충분
✅ 방법 선택: Simple Average로 시작, 성능 차이 크면 Weighted Average
더 자세한 내용은 앙상블 가이드를 참고하세요.
# 새로운 실험은 본인 브랜치에서 진행
git checkout -b exp/홍길동/loss_experiment
# 작업 완료 후 main에 merge
git checkout main
git merge exp/홍길동/loss_experiment# 형식: [타입] 내용
# 예시
git commit -m "[exp] exp04 Loss 실험 추가"
git commit -m "[fix] dataset 경로 버그 수정"
git commit -m "[feat] Cosine scheduler 추가"
git commit -m "[docs] README 사용법 업데이트"exp[번호]_[실험내용].yaml
# 예시
exp01_fcn_resnet50.yaml # 모델 실험
exp02_loss_bce_dice.yaml # Loss 실험
exp03_augmentation.yaml # Augmentation 실험
exp04_scheduler_cosine.yaml # 스케줄러 실험
실험 후 아래 정보를 팀과 공유합니다:
| 항목 | 내용 |
|---|---|
| 실험 번호 | exp04 |
| 실험자 | 홍길동 |
| 변경 사항 | DeepLabV3 + Dice Loss |
| Best Dice | 0.9523 |
| 학습 시간 | 2시간 |
| 특이사항 | epoch 30에서 수렴 |
# Config 파일 사용 (권장)
python inference.py --config configs/exp01_fcn_resnet50.yaml
# 또는 직접 모델 경로 지정
python inference.py --model saved_models/exp01/best_model.pt \
--output submission.csv| 옵션 | 설명 | 기본값 |
|---|---|---|
--config |
Config yaml 파일 경로 | - |
--model |
학습된 모델 파일 (.pt) | - |
--model_name |
모델 이름 | fcn_resnet50 |
--test_root |
테스트 이미지 경로 | data/test/DCM |
--output |
출력 CSV 파일명 | output.csv |
--image_size |
입력 이미지 크기 | 512 |
--threshold |
이진화 임계값 | 0.5 |
--batch_size |
배치 크기 | 2 |
--tta |
🔄 TTA 사용 (성능 향상) | false |
image_name,class,rle
image001.png,finger-1,1 5 10 3 ...
image001.png,finger-2,20 8 35 12 ...
...- 테스트 데이터 경로가 올바른가? (
data/test/DCM) - 학습된 모델 파일(.pt)이 존재하는가?
- 모델 이름(
--model_name)이 학습 때와 동일한가? - CSV 파일이 정상적으로 생성되었는가?
- CSV 파일 크기가 적절한가? (빈 파일 아닌지)
- 🔄 TTA 사용 여부를 고려했는가? (
--tta플래그)
# 배치 사이즈 줄이기
training:
batch_size: 4 # 8 → 4
# 또는 이미지 크기 줄이기
image:
size: 256 # 512 → 256# num_workers 늘리기
training:
num_workers: 8 # 4 → 8
# 또는 가벼운 모델 사용
model:
name: "deeplabv3_mobilenet"# 1. Loss 변경
loss:
name: "bce_dice"
# 2. Learning rate 조절
training:
learning_rate: 0.00001 # 줄이기
# 3. Augmentation 추가
augmentation:
train:
rotate: true
brightness_contrast: true# config 파일의 경로 확인
data:
train_image_root: "../Segmentation/train/DCM"
# 실제 경로가 맞는지 확인!
# 상대 경로 대신 절대 경로 사용
data:
train_image_root: "/home/user/data/Segmentation/train/DCM"새로운 실험 전 확인사항:
- 새 config 파일 생성했는가?
- 실험 이름(
experiment.name)을 고유하게 설정했는가? - 저장 폴더(
save.dir)를 실험별로 다르게 설정했는가? - 출력 CSV(
inference.output_csv)를 실험별로 다르게 설정했는가? - 실험자 이름(
experiment.author)을 입력했는가? - 데이터 경로가 올바른가?
- WandB 설정:
wandb.name을 본인 이니셜 + 실험 정보로 설정했는가? - WandB 설정:
wandb.tags에 실험 키워드를 추가했는가?
| 번호 | 클래스명 | 설명 |
|---|---|---|
| 0-18 | finger-1 ~ finger-19 | 손가락 뼈 |
| 19 | Trapezium | 대능형골 |
| 20 | Trapezoid | 소능형골 |
| 21 | Capitate | 유두골 |
| 22 | Hamate | 유구골 |
| 23 | Scaphoid | 주상골 |
| 24 | Lunate | 월상골 |
| 25 | Triquetrum | 삼각골 |
| 26 | Pisiform | 두상골 |
| 27 | Radius | 요골 |
| 28 | Ulna | 척골 |
| 이름 | 역할 | 담당 실험 |
|---|---|---|
| 박상범 | 멋쟁이 | EDA, data preprocessing, loss, augmentation |
| 안진경 | 멋쟁이 | model, augmentation, feature research |
| 이가현 | 멋쟁이 | setting, model, fine-tuning |
| 이혜준 | 멋쟁이 | EDA, data preprocessing, loss, feature research |
| 황은배 | 멋쟁이 | model, augmentation, feature research |
Happy Experimenting! 🚀