From 9db169e404d61311dfdbc546dd1397a17b9d2ce4 Mon Sep 17 00:00:00 2001 From: Kim yeonsu <39877181+dustnehowl@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:45:55 +0900 Subject: [PATCH 1/3] cifar-10 resnet18 --- yeonsu/.gitignore | 229 ++++++++++++++++ yeonsu/.gitkeep | 0 yeonsu/augmentation.py | 81 ++++++ yeonsu/dataset.py | 63 +++++ yeonsu/download_cifar10.py | 69 +++++ yeonsu/losses.py | 67 +++++ yeonsu/models/resnet18.py | 71 +++++ yeonsu/requirements.txt | 8 + yeonsu/scripts/baseline_train.sh | 21 ++ yeonsu/scripts/exp1.sh | 26 ++ yeonsu/scripts/exp2.sh | 28 ++ yeonsu/scripts/exp3.sh | 25 ++ yeonsu/train.py | 457 +++++++++++++++++++++++++++++++ 13 files changed, 1145 insertions(+) create mode 100644 yeonsu/.gitignore delete mode 100644 yeonsu/.gitkeep create mode 100644 yeonsu/augmentation.py create mode 100644 yeonsu/dataset.py create mode 100644 yeonsu/download_cifar10.py create mode 100644 yeonsu/losses.py create mode 100644 yeonsu/models/resnet18.py create mode 100644 yeonsu/requirements.txt create mode 100755 yeonsu/scripts/baseline_train.sh create mode 100755 yeonsu/scripts/exp1.sh create mode 100755 yeonsu/scripts/exp2.sh create mode 100755 yeonsu/scripts/exp3.sh create mode 100644 yeonsu/train.py diff --git a/yeonsu/.gitignore b/yeonsu/.gitignore new file mode 100644 index 0000000..9d9cf0b --- /dev/null +++ b/yeonsu/.gitignore @@ -0,0 +1,229 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + + +# experiments +experiments/ + +# checkpoints +checkpoints/ + +# data +data/ + +# logs +logs/ + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml \ No newline at end of file diff --git a/yeonsu/.gitkeep b/yeonsu/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/yeonsu/augmentation.py b/yeonsu/augmentation.py new file mode 100644 index 0000000..48d1964 --- /dev/null +++ b/yeonsu/augmentation.py @@ -0,0 +1,81 @@ +import torch +import torch.nn as nn +import numpy as np +from torchvision import transforms + + +class Cutout(object): + def __init__(self, length=16): + self.length = length + + def __call__(self, img): + h, w = img.size(1), img.size(2) + mask = np.ones((h, w), np.float32) + + y = np.random.randint(h) + x = np.random.randint(w) + + y1 = np.clip(y - self.length // 2, 0, h) + y2 = np.clip(y + self.length // 2, 0, h) + x1 = np.clip(x - self.length // 2, 0, w) + x2 = np.clip(x + self.length // 2, 0, w) + + mask[y1:y2, x1:x2] = 0. + mask = torch.from_numpy(mask) + mask = mask.expand_as(img) + img = img * mask + + return img + + +def get_advanced_augmentation(use_cutout=True, cutout_length=16): + mean = (0.4914, 0.4822, 0.4465) + std = (0.2023, 0.1994, 0.2010) + + train_transform = transforms.Compose([ + transforms.RandomHorizontalFlip(p=0.5), + transforms.RandomCrop(32, padding=4), + transforms.ColorJitter( + brightness=0.2, + contrast=0.2, + saturation=0.2, + hue=0.1 + ), + transforms.ToTensor(), + transforms.Normalize(mean, std), + ]) + + if use_cutout: + train_transform.transforms.append(Cutout(cutout_length)) + + test_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize(mean, std) + ]) + + return train_transform, test_transform + + +class Mixup(object): + def __init__(self, alpha=1.0): + self.alpha = alpha + + def __call__(self, batch): + images, labels = batch + if self.alpha > 0: + lam = np.random.beta(self.alpha, self.alpha) + else: + lam = 1 + + batch_size = images.size(0) + index = torch.randperm(batch_size).to(images.device) + + mixed_images = lam * images + (1 - lam) * images[index] + labels_a, labels_b = labels, labels[index] + + return mixed_images, labels_a, labels_b, lam + + +def mixup_criterion(criterion, pred, y_a, y_b, lam): + return lam * criterion(pred, y_a) + (1 - lam) * criterion(pred, y_b) + diff --git a/yeonsu/dataset.py b/yeonsu/dataset.py new file mode 100644 index 0000000..5e8413b --- /dev/null +++ b/yeonsu/dataset.py @@ -0,0 +1,63 @@ +import torch +import torchvision +import torchvision.transforms as transforms +from augmentation import get_advanced_augmentation + + +def get_cifar10_dataloaders(data_dir='./data', batch_size=128, num_workers=4, + use_advanced_aug=False, use_cutout=True, cutout_length=16): + if use_advanced_aug: + train_transform, test_transform = get_advanced_augmentation( + use_cutout=use_cutout, + cutout_length=cutout_length + ) + else: + mean = (0.4914, 0.4822, 0.4465) + std = (0.2023, 0.1994, 0.2010) + + train_transform = transforms.Compose([ + transforms.RandomHorizontalFlip(p=0.5), + transforms.RandomCrop(32, padding=4), + transforms.ToTensor(), + transforms.Normalize(mean, std) + ]) + + test_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize(mean, std) + ]) + + train_dataset = torchvision.datasets.CIFAR10( + root=data_dir, + train=True, + download=False, + transform=train_transform + ) + + test_dataset = torchvision.datasets.CIFAR10( + root=data_dir, + train=False, + download=False, + transform=test_transform + ) + + train_loader = torch.utils.data.DataLoader( + train_dataset, + batch_size=batch_size, + shuffle=True, + num_workers=num_workers, + pin_memory=True if torch.cuda.is_available() else False + ) + + test_loader = torch.utils.data.DataLoader( + test_dataset, + batch_size=batch_size, + shuffle=False, + num_workers=num_workers, + pin_memory=True if torch.cuda.is_available() else False + ) + + classes = ('plane', 'car', 'bird', 'cat', 'deer', + 'dog', 'frog', 'horse', 'ship', 'truck') + + return train_loader, test_loader, classes diff --git a/yeonsu/download_cifar10.py b/yeonsu/download_cifar10.py new file mode 100644 index 0000000..838df30 --- /dev/null +++ b/yeonsu/download_cifar10.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +""" +CIFAR-10 데이터셋 다운로드 스크립트 +torchvision을 사용하여 CIFAR-10 데이터를 다운로드합니다. +""" + +import torch +import torchvision +import torchvision.transforms as transforms +import os + +def download_cifar10(data_dir='./data'): + """ + CIFAR-10 데이터셋을 다운로드합니다. + + Args: + data_dir: 데이터를 저장할 디렉토리 경로 + """ + # 데이터 디렉토리 생성 + os.makedirs(data_dir, exist_ok=True) + + print(f"CIFAR-10 데이터를 {data_dir} 디렉토리에 다운로드합니다...") + + # 데이터 변환 (다운로드를 위한 기본 변환) + transform = transforms.ToTensor() + + # CIFAR-10 학습 데이터셋 다운로드 + print("학습 데이터셋 다운로드 중...") + trainset = torchvision.datasets.CIFAR10( + root=data_dir, + train=True, + download=True, + transform=transform + ) + print(f"학습 데이터셋 다운로드 완료: {len(trainset)}개 이미지") + + # CIFAR-10 테스트 데이터셋 다운로드 + print("테스트 데이터셋 다운로드 중...") + testset = torchvision.datasets.CIFAR10( + root=data_dir, + train=False, + download=True, + transform=transform + ) + print(f"테스트 데이터셋 다운로드 완료: {len(testset)}개 이미지") + + # 클래스 이름 출력 + classes = ('plane', 'car', 'bird', 'cat', 'deer', + 'dog', 'frog', 'horse', 'ship', 'truck') + print("\nCIFAR-10 클래스:") + for i, class_name in enumerate(classes): + print(f" {i}: {class_name}") + + print(f"\n다운로드 완료! 데이터는 {data_dir}/cifar-10-batches-py/ 디렉토리에 저장되었습니다.") + return trainset, testset + +if __name__ == "__main__": + # 현재 스크립트가 있는 디렉토리에 data 폴더 생성 + script_dir = os.path.dirname(os.path.abspath(__file__)) + data_dir = os.path.join(script_dir, 'data') + + try: + trainset, testset = download_cifar10(data_dir) + print("\n성공적으로 CIFAR-10 데이터를 다운로드했습니다!") + except Exception as e: + print(f"\n오류 발생: {e}") + import traceback + traceback.print_exc() + diff --git a/yeonsu/losses.py b/yeonsu/losses.py new file mode 100644 index 0000000..75dd1d1 --- /dev/null +++ b/yeonsu/losses.py @@ -0,0 +1,67 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class FocalLoss(nn.Module): + def __init__(self, alpha=1.0, gamma=2.0, reduction='mean'): + super(FocalLoss, self).__init__() + self.alpha = alpha + self.gamma = gamma + self.reduction = reduction + + def forward(self, inputs, targets): + ce_loss = F.cross_entropy(inputs, targets, reduction='none') + pt = torch.exp(-ce_loss) + focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss + + if self.reduction == 'mean': + return focal_loss.mean() + elif self.reduction == 'sum': + return focal_loss.sum() + else: + return focal_loss + + +class LabelSmoothingCrossEntropy(nn.Module): + def __init__(self, smoothing=0.1, num_classes=10): + super(LabelSmoothingCrossEntropy, self).__init__() + self.smoothing = smoothing + self.num_classes = num_classes + + def forward(self, pred, target): + log_probs = F.log_softmax(pred, dim=1) + with torch.no_grad(): + true_dist = torch.zeros_like(log_probs) + true_dist.fill_(self.smoothing / (self.num_classes - 1)) + true_dist.scatter_(1, target.data.unsqueeze(1), 1.0 - self.smoothing) + + return torch.mean(torch.sum(-true_dist * log_probs, dim=1)) + + +class WeightedCrossEntropyLoss(nn.Module): + def __init__(self, class_weights=None, num_classes=10): + super(WeightedCrossEntropyLoss, self).__init__() + if class_weights is None: + self.class_weights = torch.ones(num_classes) + else: + self.class_weights = torch.tensor(class_weights, dtype=torch.float32) + + def forward(self, inputs, targets): + if inputs.is_cuda: + self.class_weights = self.class_weights.cuda() + + weights = self.class_weights[targets] + + ce_loss = F.cross_entropy(inputs, targets, reduction='none') + weighted_loss = weights * ce_loss + + return weighted_loss.mean() + + +def get_cat_dog_focused_weights(num_classes=10, cat_idx=3, dog_idx=5, weight=2.0): + weights = torch.ones(num_classes) + weights[cat_idx] = weight + weights[dog_idx] = weight + return weights.tolist() + diff --git a/yeonsu/models/resnet18.py b/yeonsu/models/resnet18.py new file mode 100644 index 0000000..5e1ba04 --- /dev/null +++ b/yeonsu/models/resnet18.py @@ -0,0 +1,71 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +class BasicBlock(nn.Module): + def __init__(self, in_channels, out_channels, stride=1): + super(BasicBlock, self).__init__() + self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(out_channels) + self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(out_channels) + + self.shortcut = nn.Sequential() + if stride != 1 or in_channels != out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels) + ) + + def forward(self, x): + out = F.relu(self.bn1(self.conv1(x))) + out = self.bn2(self.conv2(out)) + out += self.shortcut(x) + out = F.relu(out) + return out + + +class ResNet18(nn.Module): + def __init__(self, num_classes=10): + super(ResNet18, self).__init__() + # cifar10 데이터셋(32 x 32 x 3)을 위해서 이거 kernel size 3, stride 1, padding 1 로 변경, 원래 논문에서는 kernel size 7, stride 2, padding 3 으로 되어있음 + self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.layer1 = self._make_layer(64, 64, 2, stride=1) + self.layer2 = self._make_layer(64, 128, 2, stride=2) + self.layer3 = self._make_layer(128, 256, 2, stride=2) + self.layer4 = self._make_layer(256, 512, 2, stride=2) + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512, num_classes) + + def _make_layer(self, in_channels, out_channels, num_blocks, stride): + layers = [] + layers.append(BasicBlock(in_channels, out_channels, stride)) + for _ in range(1, num_blocks): + layers.append(BasicBlock(out_channels, out_channels, stride=1)) + return nn.Sequential(*layers) + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.normal_(m.weight, 0, 0.01) + nn.init.constant_(m.bias, 0) + + def forward(self, x): + x = F.relu(self.bn1(self.conv1(x))) + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + x = self.avgpool(x) + x = torch.flatten(x, 1) + x = self.fc(x) + return x + +def resnet18(num_classes=10): + return ResNet18(num_classes=num_classes) \ No newline at end of file diff --git a/yeonsu/requirements.txt b/yeonsu/requirements.txt new file mode 100644 index 0000000..3cbcf74 --- /dev/null +++ b/yeonsu/requirements.txt @@ -0,0 +1,8 @@ +torch>=2.0.0 +torchvision>=0.15.0 +tqdm>=4.65.0 +numpy>=1.24.0 +scikit-learn>=1.3.0 +matplotlib>=3.7.0 +seaborn>=0.12.0 + diff --git a/yeonsu/scripts/baseline_train.sh b/yeonsu/scripts/baseline_train.sh new file mode 100755 index 0000000..f31d545 --- /dev/null +++ b/yeonsu/scripts/baseline_train.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Baseline 실험: 기본 설정 (CrossEntropy Loss, 기본 데이터 증강) +# GPU 1번 사용 + +export CUDA_VISIBLE_DEVICES=1 + +python train.py \ + --epochs 150 \ + --lr 0.1 \ + --momentum 0.9 \ + --weight_decay 5e-4 \ + --scheduler step \ + --step_size 30 \ + --gamma 0.1 \ + --batch_size 128 \ + --num_workers 4 \ + --save_freq 10 \ + --loss_type ce \ + --data_dir ./data + diff --git a/yeonsu/scripts/exp1.sh b/yeonsu/scripts/exp1.sh new file mode 100755 index 0000000..16245cd --- /dev/null +++ b/yeonsu/scripts/exp1.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Exp1: Focal Loss + 고급 데이터 증강 + Cutout +# GPU 2번 사용 + +export CUDA_VISIBLE_DEVICES=2 + +python train.py \ + --epochs 150 \ + --lr 0.1 \ + --momentum 0.9 \ + --weight_decay 5e-4 \ + --scheduler step \ + --step_size 30 \ + --gamma 0.1 \ + --batch_size 128 \ + --num_workers 4 \ + --save_freq 10 \ + --loss_type focal \ + --focal_alpha 1.0 \ + --focal_gamma 2.0 \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --data_dir ./data + diff --git a/yeonsu/scripts/exp2.sh b/yeonsu/scripts/exp2.sh new file mode 100755 index 0000000..18718cd --- /dev/null +++ b/yeonsu/scripts/exp2.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Exp2: Focal Loss + 고급 데이터 증강 + Cutout + Mixup +# GPU 3번 사용 + +export CUDA_VISIBLE_DEVICES=3 + +python train.py \ + --epochs 150 \ + --lr 0.1 \ + --momentum 0.9 \ + --weight_decay 5e-4 \ + --scheduler step \ + --step_size 30 \ + --gamma 0.1 \ + --batch_size 128 \ + --num_workers 4 \ + --save_freq 10 \ + --loss_type focal \ + --focal_alpha 1.0 \ + --focal_gamma 2.0 \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --use_mixup \ + --mixup_alpha 1.0 \ + --data_dir ./data + diff --git a/yeonsu/scripts/exp3.sh b/yeonsu/scripts/exp3.sh new file mode 100755 index 0000000..a5d2c40 --- /dev/null +++ b/yeonsu/scripts/exp3.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Exp3: Weighted Loss (cat/dog 집중) + 고급 데이터 증강 + Cutout +# GPU 4번 사용 + +export CUDA_VISIBLE_DEVICES=4 + +python train.py \ + --epochs 150 \ + --lr 0.1 \ + --momentum 0.9 \ + --weight_decay 5e-4 \ + --scheduler step \ + --step_size 30 \ + --gamma 0.1 \ + --batch_size 128 \ + --num_workers 4 \ + --save_freq 10 \ + --loss_type weighted \ + --class_weight 2.0 \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --data_dir ./data + diff --git a/yeonsu/train.py b/yeonsu/train.py new file mode 100644 index 0000000..67d9200 --- /dev/null +++ b/yeonsu/train.py @@ -0,0 +1,457 @@ +import torch +import torch.nn as nn +import torch.optim as optim +from torch.optim.lr_scheduler import StepLR, CosineAnnealingLR +import os +import time +import json +import csv +import argparse +from datetime import datetime +from tqdm import tqdm +import matplotlib.pyplot as plt + +from models.resnet18 import resnet18 +from dataset import get_cifar10_dataloaders +from losses import FocalLoss, LabelSmoothingCrossEntropy, WeightedCrossEntropyLoss, get_cat_dog_focused_weights +from augmentation import Mixup, mixup_criterion + + +def train_epoch(model, train_loader, criterion, optimizer, device, epoch, use_mixup=False, mixup_alpha=1.0): + model.train() + running_loss = 0.0 + correct = 0 + total = 0 + + mixup_fn = Mixup(alpha=mixup_alpha) if use_mixup else None + + pbar = tqdm(train_loader, desc=f'Epoch {epoch}') + for batch_idx, (inputs, targets) in enumerate(pbar): + inputs, targets = inputs.to(device), targets.to(device) + + if use_mixup and mixup_fn: + inputs, targets_a, targets_b, lam = mixup_fn((inputs, targets)) + + optimizer.zero_grad() + outputs = model(inputs) + + if use_mixup and mixup_fn: + loss = mixup_criterion(criterion, outputs, targets_a, targets_b, lam) + else: + loss = criterion(outputs, targets) + + loss.backward() + optimizer.step() + + running_loss += loss.item() + if use_mixup: + _, predicted = outputs.max(1) + total += targets.size(0) + correct += (lam * predicted.eq(targets_a).sum().item() + + (1 - lam) * predicted.eq(targets_b).sum().item()) + else: + _, predicted = outputs.max(1) + total += targets.size(0) + correct += predicted.eq(targets).sum().item() + + pbar.set_postfix({ + 'loss': f'{running_loss/(batch_idx+1):.4f}', + 'acc': f'{100.*correct/total:.2f}%' + }) + + epoch_loss = running_loss / len(train_loader) + epoch_acc = 100. * correct / total + return epoch_loss, epoch_acc + + +def evaluate(model, test_loader, criterion, device): + model.eval() + test_loss = 0 + correct = 0 + total = 0 + + with torch.no_grad(): + for inputs, targets in tqdm(test_loader, desc='Evaluating'): + inputs, targets = inputs.to(device), targets.to(device) + outputs = model(inputs) + loss = criterion(outputs, targets) + + test_loss += loss.item() + _, predicted = outputs.max(1) + total += targets.size(0) + correct += predicted.eq(targets).sum().item() + + test_loss /= len(test_loader) + test_acc = 100. * correct / total + return test_loss, test_acc + + +def save_checkpoint(model, optimizer, scheduler, epoch, acc, filepath): + checkpoint = { + 'epoch': epoch, + 'model_state_dict': model.state_dict(), + 'optimizer_state_dict': optimizer.state_dict(), + 'scheduler_state_dict': scheduler.state_dict(), + 'accuracy': acc, + } + torch.save(checkpoint, filepath) + print(f'체크포인트 저장: {filepath}') + + +def load_checkpoint(model, optimizer, scheduler, filepath): + checkpoint = torch.load(filepath) + model.load_state_dict(checkpoint['model_state_dict']) + optimizer.load_state_dict(checkpoint['optimizer_state_dict']) + scheduler.load_state_dict(checkpoint['scheduler_state_dict']) + epoch = checkpoint['epoch'] + acc = checkpoint['accuracy'] + print(f'체크포인트 로드: {filepath} (에폭 {epoch}, 정확도 {acc:.2f}%)') + return epoch, acc + + +def create_experiment_folder(config, base_dir='./experiments'): + """실험 폴더 생성 및 하이퍼파라미터 저장""" + # 실험 이름 생성 + exp_name_parts = [] + + # 손실 함수 + if config['loss_type'] == 'focal': + exp_name_parts.append(f"focal_g{config['focal_gamma']}") + elif config['loss_type'] == 'weighted': + exp_name_parts.append(f"weighted_w{config['class_weight']}") + elif config['loss_type'] == 'label_smooth': + exp_name_parts.append(f"labelsmooth_s{config['label_smoothing']}") + else: + exp_name_parts.append("ce") + + # 데이터 증강 + aug_parts = [] + if config['use_advanced_aug']: + aug_parts.append("adv_aug") + if config['use_cutout']: + aug_parts.append(f"cutout{config['cutout_length']}") + if config['use_mixup']: + aug_parts.append(f"mixup{config['mixup_alpha']}") + + if aug_parts: + exp_name_parts.append("_".join(aug_parts)) + + # 타임스탬프 추가 + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + exp_name = "_".join(exp_name_parts) + f"_{timestamp}" + + # 실험 폴더 생성 + exp_dir = os.path.join(base_dir, exp_name) + os.makedirs(exp_dir, exist_ok=True) + + # 하이퍼파라미터 저장 + config_path = os.path.join(exp_dir, 'config.json') + with open(config_path, 'w', encoding='utf-8') as f: + json.dump(config, f, indent=4, ensure_ascii=False) + + print(f'실험 폴더 생성: {exp_dir}') + print(f'하이퍼파라미터 저장: {config_path}') + + return exp_dir + + +def save_results(exp_dir, train_losses, train_accs, test_losses, test_accs): + """학습 결과를 CSV로 저장""" + results_path = os.path.join(exp_dir, 'results.csv') + + with open(results_path, 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['epoch', 'train_loss', 'train_acc', 'test_loss', 'test_acc']) + + for epoch in range(len(train_losses)): + writer.writerow([ + epoch + 1, + f'{train_losses[epoch]:.6f}', + f'{train_accs[epoch]:.2f}', + f'{test_losses[epoch]:.6f}', + f'{test_accs[epoch]:.2f}' + ]) + + print(f'학습 결과 저장: {results_path}') + + +def save_summary(exp_dir, best_acc, final_acc, total_time): + """최종 결과 요약 저장""" + summary = { + 'best_test_accuracy': best_acc, + 'final_test_accuracy': final_acc, + 'total_training_time_seconds': total_time, + 'completed_at': datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + + summary_path = os.path.join(exp_dir, 'summary.json') + with open(summary_path, 'w', encoding='utf-8') as f: + json.dump(summary, f, indent=4, ensure_ascii=False) + + print(f'결과 요약 저장: {summary_path}') + + +def plot_training_curves(exp_dir, train_losses, train_accs, test_losses, test_accs): + """학습 곡선 그래프 저장""" + epochs = range(1, len(train_losses) + 1) + + # Figure 생성 (2x2 subplot) + fig, axes = plt.subplots(2, 2, figsize=(15, 10)) + + # 1. Train/Test Loss + axes[0, 0].plot(epochs, train_losses, 'b-', label='Train Loss', linewidth=2) + axes[0, 0].plot(epochs, test_losses, 'r-', label='Test Loss', linewidth=2) + axes[0, 0].set_xlabel('Epoch', fontsize=12) + axes[0, 0].set_ylabel('Loss', fontsize=12) + axes[0, 0].set_title('Training and Test Loss', fontsize=14, fontweight='bold') + axes[0, 0].legend(fontsize=10) + axes[0, 0].grid(True, alpha=0.3) + + # 2. Train/Test Accuracy + axes[0, 1].plot(epochs, train_accs, 'b-', label='Train Accuracy', linewidth=2) + axes[0, 1].plot(epochs, test_accs, 'r-', label='Test Accuracy', linewidth=2) + axes[0, 1].set_xlabel('Epoch', fontsize=12) + axes[0, 1].set_ylabel('Accuracy (%)', fontsize=12) + axes[0, 1].set_title('Training and Test Accuracy', fontsize=14, fontweight='bold') + axes[0, 1].legend(fontsize=10) + axes[0, 1].grid(True, alpha=0.3) + + # 3. Loss 비교 (확대) + axes[1, 0].plot(epochs, train_losses, 'b-', label='Train Loss', linewidth=2, alpha=0.7) + axes[1, 0].plot(epochs, test_losses, 'r-', label='Test Loss', linewidth=2, alpha=0.7) + axes[1, 0].set_xlabel('Epoch', fontsize=12) + axes[1, 0].set_ylabel('Loss', fontsize=12) + axes[1, 0].set_title('Loss (Zoomed)', fontsize=14, fontweight='bold') + axes[1, 0].legend(fontsize=10) + axes[1, 0].grid(True, alpha=0.3) + # Y축 범위를 최소/최대값 기준으로 설정 + all_losses = train_losses + test_losses + if len(all_losses) > 0: + min_loss = min(all_losses) + max_loss = max(all_losses) + margin = (max_loss - min_loss) * 0.1 + axes[1, 0].set_ylim([max(0, min_loss - margin), max_loss + margin]) + + # 4. Accuracy 비교 (확대) + axes[1, 1].plot(epochs, train_accs, 'b-', label='Train Accuracy', linewidth=2, alpha=0.7) + axes[1, 1].plot(epochs, test_accs, 'r-', label='Test Accuracy', linewidth=2, alpha=0.7) + axes[1, 1].set_xlabel('Epoch', fontsize=12) + axes[1, 1].set_ylabel('Accuracy (%)', fontsize=12) + axes[1, 1].set_title('Accuracy (Zoomed)', fontsize=14, fontweight='bold') + axes[1, 1].legend(fontsize=10) + axes[1, 1].grid(True, alpha=0.3) + # Y축 범위를 최소/최대값 기준으로 설정 + all_accs = train_accs + test_accs + if len(all_accs) > 0: + min_acc = min(all_accs) + max_acc = max(all_accs) + margin = (max_acc - min_acc) * 0.1 + axes[1, 1].set_ylim([max(0, min_acc - margin), min(100, max_acc + margin)]) + + plt.tight_layout() + + # 그래프 저장 + plot_path = os.path.join(exp_dir, 'training_curves.png') + plt.savefig(plot_path, dpi=300, bbox_inches='tight') + plt.close() + + print(f'학습 곡선 그래프 저장: {plot_path}') + + +def parse_args(): + """커맨드라인 인자 파싱""" + parser = argparse.ArgumentParser(description='CIFAR-10 ResNet-18 학습') + + # 데이터 관련 + parser.add_argument('--data_dir', type=str, default='./data', help='데이터 디렉토리') + parser.add_argument('--batch_size', type=int, default=128, help='배치 크기') + parser.add_argument('--num_workers', type=int, default=4, help='데이터 로더 워커 수') + + # 학습 관련 + parser.add_argument('--epochs', type=int, default=150, help='학습 에폭 수') + parser.add_argument('--lr', type=float, default=0.1, help='초기 학습률') + parser.add_argument('--momentum', type=float, default=0.9, help='SGD momentum') + parser.add_argument('--weight_decay', type=float, default=5e-4, help='Weight decay') + + # 스케줄러 + parser.add_argument('--scheduler', type=str, default='step', choices=['step', 'cosine', 'none'], help='학습률 스케줄러') + parser.add_argument('--step_size', type=int, default=30, help='StepLR step_size') + parser.add_argument('--gamma', type=float, default=0.1, help='StepLR gamma') + + # 저장 관련 + parser.add_argument('--save_freq', type=int, default=10, help='체크포인트 저장 주기') + + # 데이터 증강 + parser.add_argument('--use_advanced_aug', action='store_true', help='고급 데이터 증강 사용') + parser.add_argument('--use_cutout', action='store_true', help='Cutout 사용') + parser.add_argument('--cutout_length', type=int, default=16, help='Cutout 길이') + parser.add_argument('--use_mixup', action='store_true', help='Mixup 사용') + parser.add_argument('--mixup_alpha', type=float, default=1.0, help='Mixup alpha') + + # 손실 함수 + parser.add_argument('--loss_type', type=str, default='ce', choices=['ce', 'focal', 'weighted', 'label_smooth'], help='손실 함수 타입') + parser.add_argument('--focal_alpha', type=float, default=1.0, help='Focal Loss alpha') + parser.add_argument('--focal_gamma', type=float, default=2.0, help='Focal Loss gamma') + parser.add_argument('--class_weight', type=float, default=2.0, help='Weighted Loss 클래스 가중치') + parser.add_argument('--label_smoothing', type=float, default=0.1, help='Label Smoothing 값') + + return parser.parse_args() + + +def main(): + args = parse_args() + + config = { + 'data_dir': args.data_dir, + 'batch_size': args.batch_size, + 'num_workers': args.num_workers, + 'epochs': args.epochs, + 'lr': args.lr, + 'momentum': args.momentum, + 'weight_decay': args.weight_decay, + 'scheduler': args.scheduler, + 'step_size': args.step_size, + 'gamma': args.gamma, + 'save_dir': './checkpoints', + 'save_freq': args.save_freq, + + 'use_advanced_aug': args.use_advanced_aug, + 'use_cutout': args.use_cutout, + 'cutout_length': args.cutout_length, + 'use_mixup': args.use_mixup, + 'mixup_alpha': args.mixup_alpha, + + 'loss_type': args.loss_type, + 'focal_alpha': args.focal_alpha, + 'focal_gamma': args.focal_gamma, + 'class_weight': args.class_weight, + 'label_smoothing': args.label_smoothing, + } + + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + # 실험 폴더 생성 + exp_dir = create_experiment_folder(config, base_dir='./experiments') + config['save_dir'] = os.path.join(exp_dir, 'checkpoints') + + train_loader, test_loader, classes = get_cifar10_dataloaders( + data_dir=config['data_dir'], + batch_size=config['batch_size'], + num_workers=config['num_workers'], + use_advanced_aug=config['use_advanced_aug'], + use_cutout=config['use_cutout'], + cutout_length=config['cutout_length'] + ) + + model = resnet18(num_classes=10).to(device) + + if config['loss_type'] == 'focal': + criterion = FocalLoss( + alpha=config['focal_alpha'], + gamma=config['focal_gamma'] + ).to(device) + elif config['loss_type'] == 'weighted': + class_weights = get_cat_dog_focused_weights( + num_classes=10, + weight=config['class_weight'] + ) + criterion = WeightedCrossEntropyLoss( + class_weights=class_weights + ).to(device) + elif config['loss_type'] == 'label_smooth': + criterion = LabelSmoothingCrossEntropy( + smoothing=config['label_smoothing'], + num_classes=10 + ).to(device) + else: + criterion = nn.CrossEntropyLoss() + + if config['use_mixup']: + print(f'Mixup 사용: alpha={config["mixup_alpha"]}') + if config['use_advanced_aug']: + print(f'고급 데이터 증강 사용: Cutout={config["use_cutout"]}') + optimizer = optim.SGD( + model.parameters(), + lr=config['lr'], + momentum=config['momentum'], + weight_decay=config['weight_decay'] + ) + + if config['scheduler'] == 'step': + scheduler = StepLR(optimizer, step_size=config['step_size'], gamma=config['gamma']) + elif config['scheduler'] == 'cosine': + scheduler = CosineAnnealingLR(optimizer, T_max=config['epochs']) + else: + scheduler = None + + os.makedirs(config['save_dir'], exist_ok=True) + + best_acc = 0.0 + total_start_time = time.time() + + print(f'\n학습 시작 (총 {config["epochs"]} 에폭)...') + print('=' * 60) + + train_losses = [] + train_accs = [] + test_losses = [] + test_accs = [] + + for epoch in range(config['epochs']): + start_time = time.time() + + train_loss, train_acc = train_epoch( + model, train_loader, criterion, optimizer, device, epoch, + use_mixup=config['use_mixup'], + mixup_alpha=config['mixup_alpha'] + ) + + test_loss, test_acc = evaluate(model, test_loader, criterion, device) + + if scheduler: + scheduler.step() + current_lr = scheduler.get_last_lr()[0] + else: + current_lr = config['lr'] + + train_losses.append(train_loss) + train_accs.append(train_acc) + test_losses.append(test_loss) + test_accs.append(test_acc) + + epoch_time = time.time() - start_time + print(f'\nEpoch {epoch+1}/{config["epochs"]} ({epoch_time:.1f}초)') + print(f'학습 - Loss: {train_loss:.4f}, Acc: {train_acc:.2f}%') + print(f'테스트 - Loss: {test_loss:.4f}, Acc: {test_acc:.2f}%') + print(f'Learning Rate: {current_lr:.6f}') + print('-' * 60) + + if test_acc > best_acc: + best_acc = test_acc + best_path = os.path.join(config['save_dir'], 'best_model.pth') + save_checkpoint(model, optimizer, scheduler, epoch, test_acc, best_path) + + if (epoch + 1) % config['save_freq'] == 0: + checkpoint_path = os.path.join(config['save_dir'], f'checkpoint_epoch_{epoch+1}.pth') + save_checkpoint(model, optimizer, scheduler, epoch, test_acc, checkpoint_path) + + total_time = time.time() - total_start_time + final_acc = test_accs[-1] if len(test_accs) > 0 else 0.0 + + # 결과 저장 + save_results(exp_dir, train_losses, train_accs, test_losses, test_accs) + save_summary(exp_dir, best_acc, final_acc, total_time) + plot_training_curves(exp_dir, train_losses, train_accs, test_losses, test_accs) + + print('\n' + '=' * 60) + print('학습 완료!') + print(f'실험 폴더: {exp_dir}') + print(f'최고 테스트 정확도: {best_acc:.2f}%') + print(f'최종 테스트 정확도: {final_acc:.2f}%') + print(f'총 학습 시간: {total_time/60:.1f}분') + print('=' * 60) + + +if __name__ == '__main__': + main() + From 8fc5266ef6d357ca79e32dc647d4120726d90fb3 Mon Sep 17 00:00:00 2001 From: Kim yeonsu <39877181+dustnehowl@users.noreply.github.com> Date: Tue, 6 Jan 2026 14:39:04 +0900 Subject: [PATCH 2/3] add readme & add augmentation samples --- yeonsu/README.md | 232 ++++++++++++++++++ .../augmentation_examples/cutout_example.png | Bin 0 -> 88073 bytes .../augmentation_examples/mixup_example.png | Bin 0 -> 100053 bytes 3 files changed, 232 insertions(+) create mode 100644 yeonsu/README.md create mode 100644 yeonsu/augmentation_examples/cutout_example.png create mode 100644 yeonsu/augmentation_examples/mixup_example.png diff --git a/yeonsu/README.md b/yeonsu/README.md new file mode 100644 index 0000000..ba2dac2 --- /dev/null +++ b/yeonsu/README.md @@ -0,0 +1,232 @@ +# CIFAR-10 ResNet-18 학습 프로젝트 + +CIFAR-10 데이터셋을 사용하여 ResNet-18 모델을 학습하고, 특히 Cat과 Dog 클래스 간의 혼동 문제를 해결하기 위한 다양한 기법을 적용한 프로젝트입니다. + +## 📋 목차 + +- [프로젝트 개요](#프로젝트-개요) +- [주요 기능](#주요-기능) +- [설치 방법](#설치-방법) +- [데이터 준비](#데이터-준비) +- [사용 방법](#사용-방법) +- [실험 설정](#실험-설정) +- [프로젝트 구조](#프로젝트-구조) +- [실험 결과](#실험-결과) + +## 🎯 프로젝트 개요 + +이 프로젝트는 CIFAR-10 데이터셋에서 ResNet-18 모델을 학습하며, 특히 유사한 특징을 가진 Cat과 Dog 클래스 간의 혼동 문제를 해결하기 위해 다음과 같은 기법들을 적용합니다: + +- **다양한 손실 함수**: Focal Loss, Weighted Cross-Entropy Loss, Label Smoothing +- **고급 데이터 증강**: Cutout, Mixup, ColorJitter +- **체계적인 실험 관리**: 각 실험의 설정과 결과를 자동으로 저장 + +## ✨ 주요 기능 + +### 1. 다양한 손실 함수 지원 + +- **Cross-Entropy Loss**: 기본 손실 함수 +- **Focal Loss**: 어려운 샘플에 집중하여 학습 (Cat/Dog 혼동 문제 해결에 효과적) +- **Weighted Cross-Entropy Loss**: 특정 클래스(Cat/Dog)에 높은 가중치 부여 +- **Label Smoothing**: 과신뢰 방지 및 일반화 성능 향상 + +### 2. 데이터 증강 기법 + +- **Advanced Augmentation**: RandomHorizontalFlip, RandomCrop, ColorJitter +- **Cutout**: 이미지의 일부 영역을 제거하여 세부 특징에 의존하지 않도록 학습 +- **Mixup**: 두 이미지를 혼합하여 결정 경계를 부드럽게 만듦 + +### 3. 실험 관리 시스템 + +- 각 실험마다 고유한 폴더 자동 생성 +- 하이퍼파라미터 설정 자동 저장 (`config.json`) +- 학습 곡선 그래프 자동 생성 (`training_curves.png`) +- 학습 결과 CSV 저장 (`results.csv`) +- 최종 결과 요약 저장 (`summary.json`) + +## 📦 설치 방법 + +### 패키지 설치 + +```bash +pip install -r requirements.txt +``` + +필요한 패키지: +- torch >= 2.0.0 +- torchvision >= 0.15.0 +- tqdm >= 4.65.0 +- numpy >= 1.24.0 +- scikit-learn >= 1.3.0 +- matplotlib >= 3.7.0 +- seaborn >= 0.12.0 + +## 📁 데이터 준비 + +CIFAR-10 데이터셋을 자동으로 다운로드하고 준비합니다: + +```bash +python download_cifar10.py +``` + +데이터는 `./data/cifar-10-batches-py/` 디렉토리에 저장됩니다. + +## 🚀 사용 방법 + +### 기본 학습 + +가장 간단한 방법으로 학습을 시작합니다: + +```bash +python train.py +``` + +### 고급 설정을 사용한 학습 + +Focal Loss와 고급 데이터 증강을 사용하여 학습: + +```bash +python train.py \ + --epochs 150 \ + --lr 0.1 \ + --batch_size 128 \ + --loss_type focal \ + --focal_gamma 2.0 \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 +``` + +### 제공된 스크립트 사용 + +프로젝트에는 여러 실험 설정이 포함된 스크립트가 제공됩니다: + +```bash +# 기본 실험 (Cross-Entropy Loss) +bash scripts/baseline_train.sh + +# 실험 1: Focal Loss + 고급 증강 + Cutout +bash scripts/exp1.sh + +# 실험 2: Focal Loss + 고급 증강 + Cutout + Mixup +bash scripts/exp2.sh + +# 실험 3: Weighted Loss + 고급 증강 + Cutout +bash scripts/exp3.sh +``` + +## ⚙️ 실험 설정 + +### 주요 하이퍼파라미터 + +#### 학습 관련 +- `--epochs`: 학습 에폭 수 (기본값: 150) +- `--lr`: 초기 학습률 (기본값: 0.1) +- `--batch_size`: 배치 크기 (기본값: 128) +- `--momentum`: SGD momentum (기본값: 0.9) +- `--weight_decay`: Weight decay (기본값: 5e-4) + +#### 학습률 스케줄러 +- `--scheduler`: 스케줄러 타입 (`step`, `cosine`, `none`) +- `--step_size`: StepLR step_size (기본값: 30) +- `--gamma`: StepLR gamma (기본값: 0.1) + +#### 손실 함수 +- `--loss_type`: 손실 함수 타입 (`ce`, `focal`, `weighted`, `label_smooth`) +- `--focal_alpha`: Focal Loss alpha (기본값: 1.0) +- `--focal_gamma`: Focal Loss gamma (기본값: 2.0) +- `--class_weight`: Weighted Loss 클래스 가중치 (기본값: 2.0) +- `--label_smoothing`: Label Smoothing 값 (기본값: 0.1) + +#### 데이터 증강 +- `--use_advanced_aug`: 고급 데이터 증강 사용 +- `--use_cutout`: Cutout 사용 +- `--cutout_length`: Cutout 길이 (기본값: 16) +- `--use_mixup`: Mixup 사용 +- `--mixup_alpha`: Mixup alpha (기본값: 1.0) + +### 추천 설정 조합 + +#### 조합 1: 기본 개선 (추천) +```bash +python train.py \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --loss_type focal \ + --focal_gamma 2.0 +``` + +#### 조합 2: 강력한 개선 +```bash +python train.py \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --loss_type focal \ + --focal_gamma 2.5 \ + --use_mixup \ + --mixup_alpha 0.8 +``` + +#### 조합 3: 극대화 +```bash +python train.py \ + --use_advanced_aug \ + --use_cutout \ + --cutout_length 16 \ + --loss_type weighted \ + --class_weight 2.0 \ + --use_mixup \ + --mixup_alpha 1.0 +``` + +## 📂 프로젝트 구조 + +``` +yeonsu/ +├── README.md # 이 파일 +├── requirements.txt # 의존성 패키지 목록 +├── train.py # 메인 학습 스크립트 +├── dataset.py # 데이터 로더 +├── losses.py # 손실 함수 구현 +├── augmentation.py # 데이터 증강 구현 +├── download_cifar10.py # CIFAR-10 다운로드 스크립트 +├── models/ +│ └── resnet18.py # ResNet-18 모델 정의 +├── scripts/ +│ ├── baseline_train.sh # 기본 학습 스크립트 +│ ├── exp1.sh # 실험 1 스크립트 +│ ├── exp2.sh # 실험 2 스크립트 +│ └── exp3.sh # 실험 3 스크립트 +├── data/ # 데이터 디렉토리 +│ └── cifar-10-batches-py/ +├── experiments/ # 실험 결과 저장 디렉토리 +│ ├── ce_20260106_133608/ +│ │ ├── config.json # 실험 설정 +│ │ ├── summary.json # 결과 요약 +│ │ ├── results.csv # 학습 결과 +│ │ ├── training_curves.png # 학습 곡선 +│ │ └── checkpoints/ # 모델 체크포인트 +│ └── ... +└── augmentation_examples/ # 증강 기법 예제 이미지 + ├── cutout_example.png + └── mixup_example.png +``` + +## 📊 실험 결과 + +각 실험의 결과는 `experiments/` 디렉토리에 저장됩니다. 각 실험 폴더에는 다음 파일들이 포함됩니다: + +- `config.json`: 사용된 하이퍼파라미터 설정 +- `summary.json`: 최고 정확도, 최종 정확도, 학습 시간 등 요약 정보 +- `results.csv`: 에폭별 학습/테스트 손실 및 정확도 +- `training_curves.png`: 학습 곡선 시각화 +- `checkpoints/`: 모델 체크포인트 파일들 + +### 예시 결과 + +실험 예시: +- **기본 (CE)**: 최고 정확도 ~94% +- **Focal Loss + 증강**: 최고 정확도 ~95%+ +- **Focal Loss + 증강 + Mixup**: 최고 정확도 ~94+ diff --git a/yeonsu/augmentation_examples/cutout_example.png b/yeonsu/augmentation_examples/cutout_example.png new file mode 100644 index 0000000000000000000000000000000000000000..ad82f13e2cbde20df61a111f0f068ed7c1c04e84 GIT binary patch literal 88073 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

OYP)iDs79l}Q$ijb^X=jM*Env+>*elxGJ`!Y&G= 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 W=Pgsd@BeTd6cnDWelF{r5}E+)3IEOj literal 0 HcmV?d00001 From 9080fa6a15c7abae25714e36bab5bb4a4110ae74 Mon Sep 17 00:00:00 2001 From: Kim yeonsu <39877181+dustnehowl@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:30:48 +0900 Subject: [PATCH 3/3] add test.py --- yeonsu/test.py | 233 ++++++++++++++++++++++++++++++++++++++++++++++++ yeonsu/train.py | 38 ++++---- 2 files changed, 254 insertions(+), 17 deletions(-) create mode 100644 yeonsu/test.py diff --git a/yeonsu/test.py b/yeonsu/test.py new file mode 100644 index 0000000..9470a74 --- /dev/null +++ b/yeonsu/test.py @@ -0,0 +1,233 @@ +""" +ResNet-18 모델 테스트/평가 스크립트 +""" + +import torch +import torch.nn as nn +from tqdm import tqdm +import argparse +import os +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +from sklearn.metrics import confusion_matrix, classification_report + +from models.resnet18 import resnet18 +from dataset import get_cifar10_dataloaders + + +def test_model(model, test_loader, device, classes=None, save_confusion_matrix=False): + """모델 테스트 및 상세 통계 출력""" + model.eval() + criterion = nn.CrossEntropyLoss() + + test_loss = 0 + correct = 0 + total = 0 + class_correct = list(0. for _ in range(10)) + class_total = list(0. for _ in range(10)) + + # Confusion matrix를 위한 예측값과 실제값 저장 + all_preds = [] + all_targets = [] + + with torch.no_grad(): + for inputs, targets in tqdm(test_loader, desc='Testing'): + inputs, targets = inputs.to(device), targets.to(device) + outputs = model(inputs) + loss = criterion(outputs, targets) + + test_loss += loss.item() + _, predicted = outputs.max(1) + total += targets.size(0) + correct += predicted.eq(targets).sum().item() + + # Confusion matrix용 데이터 수집 + all_preds.extend(predicted.cpu().numpy()) + all_targets.extend(targets.cpu().numpy()) + + # 클래스별 정확도 계산 + c = (predicted == targets).squeeze() + for i in range(targets.size(0)): + label = targets[i] + class_correct[label] += c[i].item() + class_total[label] += 1 + + # 전체 통계 + test_loss /= len(test_loader) + test_acc = 100. * correct / total + + print('\n' + '=' * 60) + print('테스트 결과') + print('=' * 60) + print(f'전체 테스트 손실: {test_loss:.4f}') + print(f'전체 테스트 정확도: {test_acc:.2f}% ({correct}/{total})') + print('=' * 60) + + # 클래스별 정확도 + if classes: + print('\n클래스별 정확도:') + print('-' * 60) + for i in range(10): + if class_total[i] > 0: + acc = 100 * class_correct[i] / class_total[i] + print(f'{classes[i]:10s}: {acc:6.2f}% ({int(class_correct[i]):5d}/{int(class_total[i]):5d})') + else: + print(f'{classes[i]:10s}: N/A') + print('-' * 60) + + # Confusion Matrix 계산 및 출력 + all_preds = np.array(all_preds) + all_targets = np.array(all_targets) + cm = confusion_matrix(all_targets, all_preds) + + print('\n' + '=' * 60) + print('Confusion Matrix') + print('=' * 60) + print_confusion_matrix(cm, classes) + + # Classification Report + if classes: + print('\n' + '=' * 60) + print('Classification Report') + print('=' * 60) + report = classification_report( + all_targets, all_preds, + target_names=classes, + digits=4 + ) + print(report) + + return test_loss, test_acc, cm + + +def print_confusion_matrix(cm, classes=None): + """Confusion Matrix를 텍스트로 출력""" + if classes is None: + classes = [f'Class {i}' for i in range(len(cm))] + + # 헤더 출력 + print(f'\n{"실제/예측":>12}', end='') + for cls in classes: + print(f'{cls[:6]:>8}', end='') + print() + print('-' * (12 + 8 * len(classes))) + + # 행 출력 + for i, cls in enumerate(classes): + print(f'{cls:>12}', end='') + for j in range(len(classes)): + print(f'{cm[i, j]:>8}', end='') + print(f' (정확도: {100*cm[i,i]/cm[i].sum():.1f}%)') + print('-' * (12 + 8 * len(classes))) + + +def plot_confusion_matrix(cm, classes=None, save_path='confusion_matrix.png', figsize=(10, 8)): + """Confusion Matrix를 시각화하여 저장""" + if classes is None: + classes = [f'Class {i}' for i in range(len(cm))] + + # 정규화된 confusion matrix 계산 (비율로) + cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] + + # Figure 생성 + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize) + + # 원본 Confusion Matrix (개수) + sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', + xticklabels=classes, yticklabels=classes, + ax=ax1, cbar_kws={'label': 'Count'}) + ax1.set_title('Confusion Matrix (Count)', fontsize=14, fontweight='bold') + ax1.set_xlabel('Predicted Label', fontsize=12) + ax1.set_ylabel('True Label', fontsize=12) + ax1.tick_params(axis='both', labelsize=9) + + # 정규화된 Confusion Matrix (비율) + sns.heatmap(cm_normalized, annot=True, fmt='.2f', cmap='Blues', + xticklabels=classes, yticklabels=classes, + ax=ax2, cbar_kws={'label': 'Proportion'}) + ax2.set_title('Confusion Matrix (Normalized)', fontsize=14, fontweight='bold') + ax2.set_xlabel('Predicted Label', fontsize=12) + ax2.set_ylabel('True Label', fontsize=12) + ax2.tick_params(axis='both', labelsize=9) + + plt.tight_layout() + plt.savefig(save_path, dpi=300, bbox_inches='tight') + plt.close() + print(f'Confusion Matrix 이미지 저장 완료: {save_path}') + + +def load_model(checkpoint_path, device, num_classes=10): + """체크포인트에서 모델 로드""" + print(f'체크포인트 로드: {checkpoint_path}') + + # 모델 생성 + model = resnet18(num_classes=num_classes).to(device) + + # 체크포인트 로드 + checkpoint = torch.load(checkpoint_path, map_location=device) + + if 'model_state_dict' in checkpoint: + model.load_state_dict(checkpoint['model_state_dict']) + if 'epoch' in checkpoint and 'accuracy' in checkpoint: + print(f'체크포인트 정보: 에폭 {checkpoint["epoch"]}, 정확도 {checkpoint["accuracy"]:.2f}%') + else: + # state_dict만 저장된 경우 + model.load_state_dict(checkpoint) + + model.eval() + return model + + +def main(): + parser = argparse.ArgumentParser(description='ResNet-18 CIFAR-10 테스트') + parser.add_argument('--checkpoint', type=str, required=True, + help='체크포인트 파일 경로') + parser.add_argument('--data_dir', type=str, default='./data', + help='데이터 디렉토리 경로') + parser.add_argument('--batch_size', type=int, default=128, + help='배치 크기') + parser.add_argument('--num_workers', type=int, default=4, + help='데이터 로딩 워커 수') + parser.add_argument('--save_cm', action='store_true', + help='Confusion Matrix 이미지 저장') + parser.add_argument('--cm_path', type=str, default='confusion_matrix.png', + help='Confusion Matrix 저장 경로') + + args = parser.parse_args() + + # 체크포인트 파일 확인 + if not os.path.exists(args.checkpoint): + print(f'오류: 체크포인트 파일을 찾을 수 없습니다: {args.checkpoint}') + return + + # 디바이스 설정 + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f'사용 디바이스: {device}') + + # 모델 로드 + model = load_model(args.checkpoint, device) + + # 데이터 로더 + print('\n데이터 로더 준비 중...') + _, test_loader, classes = get_cifar10_dataloaders( + data_dir=args.data_dir, + batch_size=args.batch_size, + num_workers=args.num_workers + ) + + # 테스트 실행 + test_loss, test_acc, cm = test_model( + model, test_loader, device, classes, + save_confusion_matrix=args.save_cm + ) + + if args.save_cm: + plot_confusion_matrix(cm, classes, save_path=args.cm_path) + + print(f'\n최종 테스트 정확도: {test_acc:.2f}%') + + +if __name__ == '__main__': + main() + diff --git a/yeonsu/train.py b/yeonsu/train.py index 67d9200..52da3f0 100644 --- a/yeonsu/train.py +++ b/yeonsu/train.py @@ -216,7 +216,7 @@ def plot_training_curves(exp_dir, train_losses, train_accs, test_losses, test_ac axes[0, 1].legend(fontsize=10) axes[0, 1].grid(True, alpha=0.3) - # 3. Loss 비교 (확대) + # 3. Loss 비교 (확대) - 마지막 절반 에폭의 범위로 확대 axes[1, 0].plot(epochs, train_losses, 'b-', label='Train Loss', linewidth=2, alpha=0.7) axes[1, 0].plot(epochs, test_losses, 'r-', label='Test Loss', linewidth=2, alpha=0.7) axes[1, 0].set_xlabel('Epoch', fontsize=12) @@ -224,15 +224,17 @@ def plot_training_curves(exp_dir, train_losses, train_accs, test_losses, test_ac axes[1, 0].set_title('Loss (Zoomed)', fontsize=14, fontweight='bold') axes[1, 0].legend(fontsize=10) axes[1, 0].grid(True, alpha=0.3) - # Y축 범위를 최소/최대값 기준으로 설정 - all_losses = train_losses + test_losses - if len(all_losses) > 0: - min_loss = min(all_losses) - max_loss = max(all_losses) - margin = (max_loss - min_loss) * 0.1 - axes[1, 0].set_ylim([max(0, min_loss - margin), max_loss + margin]) - - # 4. Accuracy 비교 (확대) + # 마지막 절반 에폭의 범위로 확대하여 세밀한 변화 관찰 + if len(train_losses) > 0: + half_point = len(train_losses) // 2 + zoom_losses = train_losses[half_point:] + test_losses[half_point:] + if len(zoom_losses) > 0: + min_loss = min(zoom_losses) + max_loss = max(zoom_losses) + margin = (max_loss - min_loss) * 0.15 + axes[1, 0].set_ylim([max(0, min_loss - margin), max_loss + margin]) + + # 4. Accuracy 비교 (확대) - 마지막 절반 에폭의 범위로 확대 axes[1, 1].plot(epochs, train_accs, 'b-', label='Train Accuracy', linewidth=2, alpha=0.7) axes[1, 1].plot(epochs, test_accs, 'r-', label='Test Accuracy', linewidth=2, alpha=0.7) axes[1, 1].set_xlabel('Epoch', fontsize=12) @@ -240,13 +242,15 @@ def plot_training_curves(exp_dir, train_losses, train_accs, test_losses, test_ac axes[1, 1].set_title('Accuracy (Zoomed)', fontsize=14, fontweight='bold') axes[1, 1].legend(fontsize=10) axes[1, 1].grid(True, alpha=0.3) - # Y축 범위를 최소/최대값 기준으로 설정 - all_accs = train_accs + test_accs - if len(all_accs) > 0: - min_acc = min(all_accs) - max_acc = max(all_accs) - margin = (max_acc - min_acc) * 0.1 - axes[1, 1].set_ylim([max(0, min_acc - margin), min(100, max_acc + margin)]) + # 마지막 절반 에폭의 범위로 확대하여 세밀한 변화 관찰 + if len(train_accs) > 0: + half_point = len(train_accs) // 2 + zoom_accs = train_accs[half_point:] + test_accs[half_point:] + if len(zoom_accs) > 0: + min_acc = min(zoom_accs) + max_acc = max(zoom_accs) + margin = (max_acc - min_acc) * 0.15 + axes[1, 1].set_ylim([max(0, min_acc - margin), min(100, max_acc + margin)]) plt.tight_layout()