본문 바로가기
C.W.K.
Stream
Lesson 01 of 06 · published

전이 학습은 실제로 무엇을 할까?

~12 min · transfer, feature-extraction, fine-tuning

Level 0텐서 탐구자
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

처음부터 시작할 필요는 없어. 대부분은 그러지 않는 게 좋아

비전의 ImageNet이나 텍스트의 Common Crawl 같은 거대 데이터셋으로 사전 학습한 모델은 다른 작업에도 통하는 표현을 이미 배웠어. 작업이 서로 무관해 보여도, 작은 데이터셋으로 새 모델을 처음부터 학습하는 것보다 사전 학습 모델을 해당 작업에 적응시키는 편이 거의 항상 나아.

두 극단과 그 사이

  • 특징 추출: 사전 학습 모델 전체를 동결하고 새 헤드만 학습해. 비용이 적고 빠르며 데이터가 적어도 가능해. 새 작업이 사전 학습 작업과 충분히 비슷할 때 잘 작동해.
  • 전체 미세 조정: 모든 계층의 동결을 풀고 작은 학습률로 모델 전체를 학습해. 보통 가장 좋은 결과를 내지만 더 많은 데이터와 세심한 조정이 필요해. 중요한 작업에서는 이 방식이 표준이야.
  • 부분 미세 조정: 일반적인 특징을 배우는 앞쪽 계층은 동결하고, 작업별 특징을 배우는 뒤쪽 계층만 풀어. 두 극단 사이의 실용적인 절충안이야.

현대적인 확장: 매개변수 효율 미세 조정

BERT-Large, Llama, ViT-Huge 같은 거대 모델은 전체 미세 조정도 비싸. 수십억 개의 매개변수를 갱신해야 하거든. LoRA(저랭크 적응) 같은 방법은 동결한 가중치 옆에 작은 학습 가능 행렬을 넣어 전체 매개변수의 0.1~1%만 학습하면서도 전체 미세 조정에 가까운 품질을 내. 뒤에서 LoRA를 자세히 다룰 거야. 지금은 이 방법들이 미세 조정의 비용 구조를 바꾼다는 점만 알아 둬.

현대적인 torchvision 가중치 API

기존의 models.resnet50(pretrained=True)는 사용 중단됐어. 이제는 models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)처럼 호출해. 새 API는 버전을 지정한 가중치와 함께 weights.transforms()를 제공해. 이 함수는 모델 학습에 사용한 정확한 전처리를 반환해 전처리 불일치를 막아 주므로 항상 사용해.

Code

특징 추출: 백본 동결, 헤드 학습·python
import torch
import torch.nn as nn
from torchvision.models import resnet50, ResNet50_Weights

model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)

# Freeze the entire pretrained model
for p in model.parameters():
    p.requires_grad = False

# Replace the final classifier — new layer is trainable by default
num_classes = 5
model.fc = nn.Linear(model.fc.in_features, num_classes)

trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f"trainable: {trainable:,} / {total:,} ({trainable/total*100:.2f}%)")
# trainable: 10,245 / 25,567,037 (0.04%)
부분 미세 조정: 뒤쪽 계층 동결을 해제·python
import torch.nn as nn
from torchvision.models import resnet50, ResNet50_Weights

model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)

# Freeze everything
for p in model.parameters():
    p.requires_grad = False

# Replace head + unfreeze layer4 (the deepest backbone block)
model.fc = nn.Linear(model.fc.in_features, 5)
for p in model.layer4.parameters():
    p.requires_grad = True

# Per-group learning rate — backbone gets smaller LR
import torch.optim as optim
optimizer = optim.AdamW([
    {'params': model.layer4.parameters(), 'lr': 1e-5},
    {'params': model.fc.parameters(),     'lr': 1e-3},
], weight_decay=0.01)
모델별 변환이 가중치에서 옴·python
from torchvision.models import resnet50, ResNet50_Weights

weights = ResNet50_Weights.IMAGENET1K_V2

# This is the EXACT preprocessing the model was pretrained with
preprocess = weights.transforms()
print(preprocess)
# ImageClassification(
#     crop_size=[224]
#     resize_size=[232]
#     mean=[0.485, 0.456, 0.406]
#     std=[0.229, 0.224, 0.225]
#     interpolation=InterpolationMode.BILINEAR
# )

# Pass it to your DataLoader transform pipeline. No more hard-coded means.

External links

Exercise

torchvision 모델 하나를 골라 봐. 빠르게 시험하려면 resnet18이 좋아. 모델을 동결하고 마지막 계층을 5클래스용으로 바꾼 뒤, 학습 가능한 매개변수 수와 전체 매개변수 수를 출력해. 그다음 layer4의 동결도 풀어 다시 출력해. 두 숫자를 비교하면 특징 추출과 부분 미세 조정의 차이가 한눈에 보여.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.