카테고리 없음

Fine-Tuning

wonone11 2025. 3. 24. 20:54

Fine-Tuning이란 무엇일까?

Fine-Tuning을 한국어로 직역하면 "미세 조정"이다.

 

Fine-Tuning은 "미세 조정"이라는 뜻과 같게 이미 학습된 모델을 주어진 요구사항에 맞춰 추가 학습을 시키는 것이다.

 

왜 Fine-Tuning을 사용하는가?

나와 같은 학생들은 거대한 모델을 만들 수 있는 컴퓨팅 파워(GPU 서버)가 없다.

 

하지만 Fine-Tuning을 사용한다면 이미 만들어진 거대 모델(YOLO, ResNet 등)들을 자신의 필요에 맞춰 사용할 수 있는 것이다.

 

이 외의 Fine-Tuning의 장점을 설명하자면

  1. 데이터 부족 문제 해결
    데이터가 적어도 기존 모델의 지식을 활용할 수 있음 
  2. 학습 시간과 비용 절감
    처음부터 학습하는 것보다 훨씬 적은 시간과 비용이 듦
  3. 더 나은 성능
    기존의 지식을 활용해서 더 나은 성능을 보여줌

이렇게나 좋은 Fine-Tuning은 딥러닝 산업에서 빠질 수 없는 기술이 되었다.

 

 

Fine-Tuning 사용 코드

ResNet-18을 Fine-Tuning하여 개와 고양이를 분류하는 모델을 만들었다.

dataloader.py

import kagglehub
from torch.utils.data import DataLoader
import torch
import pandas as pd
import os
from torchvision import datasets, transforms

def get_transform():
    transform = transforms.Compose([
        transforms.Resize((224, 224)),  # ResNet은 224x224 입력 사용
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # ImageNet 정규화
    ])

    return transform

def get_dataset(transform):
    base_path = r"C:\Users\user\.cache\kagglehub\datasets\tongpython\cat-and-dog\versions\1"

    train_dir = os.path.join(base_path, "training_set", "training_set")
    test_dir = os.path.join(base_path, "test_set", "test_set")

    train_dataset = datasets.ImageFolder(root=train_dir, transform=transform)
    test_dataset = datasets.ImageFolder(root=test_dir, transform=transform)

    return train_dataset, test_dataset

def get_dataloader(train_dataset, test_dataset):
    train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)
    test_dataloader = DataLoader(test_dataset, batch_size=64, shuffle=False)

    return train_dataloader, test_dataloader

main.py

import torch.optim as optim
import torch.nn as nn
import torchvision.models as models
from dataloader import get_dataloader, get_dataset, get_transform
import torch

transform = get_transform()

train_dataset, test_dataset = get_dataset(transform)

train_loader, test_loader = get_dataloader(train_dataset, test_dataset)

model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)

model.fc = nn.Linear(model.fc.in_features, 2)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

best_accuracy = 0.0  # best accuracy 초기화
best_model_weights = None  # best model weights 초기화
model.train()  # batch_norm, drop_out 활성화

epochs = 3

for epoch in range(epochs):
    running_loss = 0.0  # loss 초기화

    for images, labels in train_loader:
        outputs = model(images)  # images feedforward
        loss = criterion(outputs, labels)  # loss 계산

        optimizer.zero_grad()  # gradient 초기화
        loss.backward()  # backpropagation
        optimizer.step()  # step

        running_loss += loss.item()  # sum of loss

    avg_train_loss = running_loss / len(train_loader)  # loss avg

    model.eval()  # batch_norm, drop_out 비활성화
    correct, total = 0, 0  # correct, total 초기화
    with torch.no_grad():  # 역전파와 gradient 계산 비활성화
        for images, labels in test_loader:
            outputs = model(images)  # images feedforward
            _, predicted = torch.max(outputs, 1)  # 확률 값이 가장 큰 index 값 저장
            total += labels.size(0)  # 데이터의 개수 저장
            correct += (predicted == labels).sum().item()  # 맞은 데이터 개수 저장

    accuracy = 100 * correct / total  # 정확도 계산

    if accuracy > best_accuracy:  # best accuracy 보다 현 epoch의 accuracy가 높다면
        best_accuracy = accuracy  # best accuracy로 저장
        best_model_weights = model.state_dict().copy()  # best accuracy의 model weights 저장

    print(f"Epoch [{epoch+1}/{epochs}], Loss: {avg_train_loss:.4f}, Validation Accuracy: {accuracy:.2f}%")

    model.train()

if best_model_weights:
    model.load_state_dict(best_model_weights)  # model에 best accuracy의 weight를 가져옴
    torch.save(best_model_weights, 'best_model.pth')  # model 저장
    print(f"Best model weights saved with accuracy: {best_accuracy:.2f}")

 

결과는 아쉽게도 Fine-Tuning한 것보다 그냥 학습시킨 모델이 더 잘나왔다...

내 생각에는 너무 간단한 테스크를 수행하는 것이여서 거대한 모델의 기존 지식이 노이즈화 되어 오히려 학습에 악영향을 끼친거 같다.

그냥 학습 모델
Fine-Tuning 모델

하지만 3% 정도 차이면 개와 고양이만 구별할 수 있는 그냥 학습 모델보다 1000개의 클래스를 분류할 수 있는 Fine-Tuning 모델이 더 좋지 않을까 생각한다.

 

전이 학습과 Fine-Tuning의 차이

과정)

  1. 사전 학습되어 있는 모델을 가져오고 최종 출력층 레이어를 보유 중인 데이터에 맞춰 설정한 뒤 결합한다.
  2. 결합한 최종 출력층을 보유 중인 데이터로 학습시킨다.

전이 학습

이 과정에서 기존 모델의 파라미터는 바뀌지 않고 최종 출력층 파라미터만 바뀌게 된다.

Fine-Tuning

이 과정에서 기존 모델의 파라미터까지 바뀐다.

 

마무리

나와 같이 컴퓨팅 파워가 약한 사람들에게는 정말 희망적인 기술이다. 그리고 적은 비용으로 엄청난 모델을 만들 수 있는 기술이기 떄문에 딥러닝 산업에 필수적인 기술이 되었다. 그렇기 때문에 모두 한 번은 Fine-Tuning으로 모델을 만들고 프로젝트 경험이 있었으면 좋겠다.