AI 개발 공부 공간

AI, 머신러닝, 딥러닝, Python & PyTorch, 실전 프로젝트

딥러닝/딥러닝: 기초 개념

파인튜닝(Fine-Tuning)

qordnswnd123 2025. 6. 11. 17:22

1.전이 학습의 종류 2가지

전이 학습(Transfer Learning)에는 두 가지 주요 방법이 있습니다. 이번에는 미세 조정(Fine-tuning) 에 대해 자세히 알아보겠습니다. 이 두 방법은 사전 학습된 모델의 가중치를 어떻게 활용하고 조정하는지에 대한 접근 방식에서 차이가 있습니다.

 

Fine-tuning 방법은 사전 학습된 모델의 가중치를 초기 상태로 사용하되, 새로운 데이터셋으로 전체 레이어 또는 선택된 레이어의 가중치를 추가로 조정하는 방식입니다. 전체 모델을 미세 조정할 수도 있고, 출력층에 가까운 몇 개의 레이어만 조정할 수도 있습니다.

1) 초록색 네모칸 부분: 전이 학습 초기에는 사전 학습된 특징 추출기(초록색 네모칸)를 그대로 사용하는데, 미세 조정에서는 이 부분의 가중치 도 업데이트합니다.

2) 파란색 네모칸 부분: 완전 연결층(파란색 네모칸)은 새로운 작업에 맞게 더 세밀하게 조정됩니다. 이때, 가중치를 처음부터 다시 학습하거나 기존 가중치를 미세 조정할 수 있습니다.
3) 학습 과정: 미세 조정은 모델의 모든 레이어를 업데이트하는 것이 일반적입니다. 하지만 일부 레이어만 업데이트할 수도 있습니다. 이 방법은 더 많은 데이터가 있을 때 유용하며, 모델이 새로운 작업에 최적화될 수 있도록 합니다.

 

위 두 방법은 각각의 상황에 따라 선택적으로 사용할 수 있으며, 때로는 두 방법을 혼합하여 사용하기도 합니다. 예를 들어, 모델의 일부 레이어는 고정하고 일부 레이어는 미세 조정을 통해 조화롭게 학습을 진행할 수 있습니다. 이러한 접근은 모델의 효율성과 성능을 동시에 극대화 할 수 있도록 도와줍니다.

 

2. Fine-tuning의 특징

2.1 특징 추출과의 차이점

특징 추출과 파인튜닝의 가장 큰 차이점은 가중치 업데이트의 범위입니다. 특징 추출은 사전 학습된 모델의 대부분의 가중치를 고정하고, 출력 레이어만 학습합니다. 즉, 사전 학습된 네트워크의 강력한 특징 추출 능력을 그대로 활용하면서, 새로운 데이터셋에 맞춘 출력을 학습합니 다.
반면 파인튜닝(Fine-tuning) 은 모델 전체 또는 일부 레이어의 가중치를 새 데이터에 맞게 업데이트할 수 있습니다. 따라서 파인튜닝은 더 깊은 레이어까지 새 데이터의 특징을 반영할 수 있어, 특징 추출보다 더 정교한 모델 조정이 가능합니다. 하지만 더 많은 가중치를 업데이트함에 따라 학습 시간이 길어지고, 오버피팅의 위험이 높아질 수 있습니다.

 

2.2 파인튜닝이 필요한 상황

사전학습된 모델과 새로운 데이터셋이 매우 다를 때: 사전 학습된 모델이 매우 다른 데이터셋에서 학습된 경우, 출력 레이어만 학습하는 것 으로는 성능 향상이 제한적일 수 있습니다. 예를 들어, ImageNet 데이터셋으로 학습된 모델을 의료 영상이나 위성 이미지 분류에 사용할 때 는 파인튜닝을 통해 모델 전체를 조정하는 것이 필요할 수 있습니다.


더 높은 성능이 요구될 때: 특징 추출로는 어느 정도 성능을 낼 수 있지만, 특정 프로젝트에서는 매우 높은 성능이 요구될 수 있습니다. 이 경우 파인튜닝을 통해 모든 레이어를 새 데이터셋에 맞게 최적화함으로써 최상의 성능을 얻을 수 있습니다.


데이터셋의 크기가 충분할 때: 파인튜닝은 더 많은 파라미터를 학습하기 때문에 충분한 양의 데이터가 있어야 효과적입니다. 데이터셋이 작을 경우에는 오버피팅의 위험이 높아지므로, 파인튜닝보다 특징 추출이 더 적합할 수 있습니다.

 

2.3 파인튜닝의 장점과 위험 요소

※ 장점

더 높은 성능: 모델 전체를 학습하므로, 기존 가중치를 고정하고 출력 레이어만 학습하는 특징 추출보다 더 높은 성능을 낼 수 있습니다. 특히, 새 데이터셋의 특징이 기존 데이터셋과 다를 때 효과적입니다.
적응력: 파인튜닝은 모델이 새로운 데이터셋에 완전히 적응할 수 있도록 돕습니다. 특히 데이터의 분포가 기존 학습 데이터와 크게 다를 경우, 모델이 더 정교하게 조정됩니다.
세밀한 조정 가능: 모델의 특정 레이어만 선택적으로 파인튜닝하여 고차원적인 특징에만 영향을 줄 수 있어, 효율적인 학습이 가능합니다.


※ 위험 요소

오버피팅 가능성: 작은 데이터셋에서 모델 전체를 학습시키면, 모델이 훈련 데이터에 지나치게 적합하게 되어 일반화 성능이 떨어질 위험이 있습니다. 특히 데이터가 충분하지 않을 때 이 위험이 커집니다.
긴 학습 시간: 파인튜닝은 모델의 전체 가중치를 학습해야 하므로, 학습 시간이 길어지고 컴퓨팅 자원이 더 많이 필요합니다. 특히 깊은 신경망일수록 시간이 더 오래 걸립니다.
하이퍼파라미터 튜닝의 어려움: 파인튜닝 과정에서 학습률(Ir), 조정할 레이어의 범위 등 여러 하이퍼파라미터를 적절히 설정해야 하며, 잘못 설정할 경우 학습이 제대로 이루어지지 않거나 성능이 저하될 수 있습니다.

 

3. 파이토치에서 파인튜닝 구현

사전 학습된 ResNet-18 모델을 불러온 후, 모델의 모든 파라미터에 대해 학습 가능한지 여부를 확인하고 출력하는 코드입니다.
이제 파인튜닝(fine-tuning) 기법에 대해 알아볼 차례입니다. 파인튜닝은 사전 학습된 모델을 새로운 데이터셋에 맞게 미세 조정하는 과정으로, 특정 레이어나 파라미터만 학습하도록 조정하여 효율적으로 성능을 개선할 수 있는 방법입니다.
파인튜닝에는 여러 가지 접근 방식이 있지만, 그 중 4가지 방법을 살펴볼 것입니다. 각 방법은 상황에 따라 다르게 적용되며, 단계별로 모델을 어떻게 조정할 수 있는지 배우게 됩니다.
1) 마지막 레이어들만 학습: 모델의 마지막 레이어들만 학습하고 나머지 레이어들은 고정(freeze)하는 기본적인 방법입니다.
2) 일부 파라미터만 선택적으로 학습: 모델에서 선택된 일부 파라미터만 학습하도록 설정하는 방법을 다룹 니다.
3) 스케줄 기반 파인튜닝: 학습이 진행됨에 따라 점차적으로 더 많은 레이어를 학습하는 방법입니다.
4) 점진적 언프리징(Gradual Unfreezing): 마지막 레이어부터 시작해 순차적으로 더 많은 레이어를 학습 가능하게 조정하는 방식입니다.
이러한 방법들을 통해 모델을 점진적으로 미세 조정하면서 새로운 데이터셋에 맞게 최적화하는 과정을 익혀보겠습니다.

# dataset_utils.py 파일에서 필요한 함수 불러오기
from dataset_utils import setup_folders_and_extract
setup_folders_and_extract()

 

import torch
import torchvision.models as models

model = models.resnet18(pretrained=True)
print(model)
ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=1000, bias=True)
)
for name, param in model.named_parameters():
    print(f'{name}: {param.requires_grad}')
conv1.weight: True
bn1.weight: True
bn1.bias: True
layer1.0.conv1.weight: True
layer1.0.bn1.weight: True
layer1.0.bn1.bias: True
layer1.0.conv2.weight: True
layer1.0.bn2.weight: True
layer1.0.bn2.bias: True
layer1.1.conv1.weight: True
layer1.1.bn1.weight: True
layer1.1.bn1.bias: True
layer1.1.conv2.weight: True
layer1.1.bn2.weight: True
layer1.1.bn2.bias: True
layer2.0.conv1.weight: True
layer2.0.bn1.weight: True
layer2.0.bn1.bias: True
layer2.0.conv2.weight: True
layer2.0.bn2.weight: True
layer2.0.bn2.bias: True
layer2.0.downsample.0.weight: True
layer2.0.downsample.1.weight: True
layer2.0.downsample.1.bias: True
layer2.1.conv1.weight: True
layer2.1.bn1.weight: True
layer2.1.bn1.bias: True
layer2.1.conv2.weight: True
layer2.1.bn2.weight: True
layer2.1.bn2.bias: True
layer3.0.conv1.weight: True
layer3.0.bn1.weight: True
layer3.0.bn1.bias: True
layer3.0.conv2.weight: True
layer3.0.bn2.weight: True
layer3.0.bn2.bias: True
layer3.0.downsample.0.weight: True
layer3.0.downsample.1.weight: True
layer3.0.downsample.1.bias: True
layer3.1.conv1.weight: True
layer3.1.bn1.weight: True
layer3.1.bn1.bias: True
layer3.1.conv2.weight: True
layer3.1.bn2.weight: True
layer3.1.bn2.bias: True
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

 

3.1 마지막 레이어들만 학습 가능하게 설정

사전 학습된 모델에서 특정 레이어(예: layer4와 fc)만 학습 가능하게 설정하는 방법을 보여줍니다. 이 조건은 마지막 블록(layer4)과 출력 레이어(fc)만 학습 가능하도록 지정하고 나머지 레이어는 학습하지 않고 고정시키기 위해 requires_grad 속성을 False로 설정합니다.

for name, param in model.named_parameters():
    if "layer4" in name or "fc" in name:
        param.requires_grad = True
    else:
        param.requires_grad = False

for name, param in model.named_parameters():
    print(f'{name}: {param.requires_grad}')
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: False
layer3.0.bn1.weight: False
layer3.0.bn1.bias: False
layer3.0.conv2.weight: False
layer3.0.bn2.weight: False
layer3.0.bn2.bias: False
layer3.0.downsample.0.weight: False
layer3.0.downsample.1.weight: False
layer3.0.downsample.1.bias: False
layer3.1.conv1.weight: False
layer3.1.bn1.weight: False
layer3.1.bn1.bias: False
layer3.1.conv2.weight: False
layer3.1.bn2.weight: False
layer3.1.bn2.bias: False
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

 

3.2 일부 마지막 파라미터들만 학습 가능하게 설정

사전 학습된 모델에서 마지막 10개의 파라미터만 학습 가능하게 설정하는 방법을 보여줍니다.
나머지 파라미터는 고정되어 업데이트되지 않으며, 특정 파라미터만 학습할 수 있게 설정합니다.

for name, param in model.named_parameters():
    param.requires_grad = False
for name, param in list(model.named_parameters())[-10:]:
    param.requires_grad = True
    
for name, param in model.named_parameters():
    print(f'{name}: {param.requires_grad}')
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: False
layer3.0.bn1.weight: False
layer3.0.bn1.bias: False
layer3.0.conv2.weight: False
layer3.0.bn2.weight: False
layer3.0.bn2.bias: False
layer3.0.downsample.0.weight: False
layer3.0.downsample.1.weight: False
layer3.0.downsample.1.bias: False
layer3.1.conv1.weight: False
layer3.1.bn1.weight: False
layer3.1.bn1.bias: False
layer3.1.conv2.weight: False
layer3.1.bn2.weight: False
layer3.1.bn2.bias: False
layer4.0.conv1.weight: False
layer4.0.bn1.weight: False
layer4.0.bn1.bias: False
layer4.0.conv2.weight: False
layer4.0.bn2.weight: False
layer4.0.bn2.bias: False
layer4.0.downsample.0.weight: False
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

 

3.3 스케줄 기반 파인튜닝

해당 코드는 특정 에포크에서 추가적인 레이어들을 학습 가능하게 설정하는 방식입니다. 초기에는 마지막 레이어만 학습 가능하게 하고, 에포크가 특정 값 이상일 때 추가 레이어를 학습 가능하게 하는 것이 핵심입니다.

# 초기화
for name, param in model.named_parameters():
    param.requires_grad = False

 

에포크가 1인 경우

epoch = 1

# 초기에는 마지막 레이어들만 학습 가능하게 설정
for name, param in model.named_parameters():
    if "layer4" in name or "fc" in name:
        param.requires_grad = True
    else:
        param.requires_grad = False

# 일정 에포크 이후, 추가적인 레이어들을 학습 가능하게 설정
if epoch > 2:
    for name, param in model.named_parameters():
        if "layer3" in name:  
            param.requires_grad = True
            
for name, param in model.named_parameters():
    print(f'{name}: {param.requires_grad}')
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: False
layer3.0.bn1.weight: False
layer3.0.bn1.bias: False
layer3.0.conv2.weight: False
layer3.0.bn2.weight: False
layer3.0.bn2.bias: False
layer3.0.downsample.0.weight: False
layer3.0.downsample.1.weight: False
layer3.0.downsample.1.bias: False
layer3.1.conv1.weight: False
layer3.1.bn1.weight: False
layer3.1.bn1.bias: False
layer3.1.conv2.weight: False
layer3.1.bn2.weight: False
layer3.1.bn2.bias: False
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

 

에포크가 3인 경우

학습이 진행되면서 특정 레이어의 파라미터를 점진적으로 학습 가능하게 설정하는 예시입니다. 처음에는 layer4와 fc만 학습 가능하게 설정하고, 학습이 특정 에포크 이상이 되면 layer3도 학습 가능하게 설정합니다.

epoch = 3

for name, param in model.named_parameters():
    if "layer4" in name or "fc" in name:
        param.requires_grad = True
    else:
        param.requires_grad = False

if epoch > 2:
    for name, param in model.named_parameters():
        if "layer3" in name:  
            param.requires_grad = True
            
for name, param in model.named_parameters():
    print(f'{name}: {param.requires_grad}')
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: True
layer3.0.bn1.weight: True
layer3.0.bn1.bias: True
layer3.0.conv2.weight: True
layer3.0.bn2.weight: True
layer3.0.bn2.bias: True
layer3.0.downsample.0.weight: True
layer3.0.downsample.1.weight: True
layer3.0.downsample.1.bias: True
layer3.1.conv1.weight: True
layer3.1.bn1.weight: True
layer3.1.bn1.bias: True
layer3.1.conv2.weight: True
layer3.1.bn2.weight: True
layer3.1.bn2.bias: True
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

 

3.4 점진적 언프리징 (Gradual Unfreezing)

점진적으로 레이어를 '언프리징(unfreezing)'하여 특정 레이어의 파라미터만 학습 가능하게 설정하는 방법을 보여줍니다. 각 레이어를 순차적으로 학습 가능하게 설정한 후, 모델의 파라미터 상태를 출력합니다.

for param in model.parameters():
    param.requires_grad = False
layer_names = ["fc", "layer4", "layer3", "layer2"]
trainable_layers = [model.fc, model.layer4, model.layer3, model.layer2]

for i, layer in enumerate(trainable_layers):
    print(f"\n단계 {i+1}: {layer_names[i]} 레이어 해제")

    for param in layer.parameters():
        param.requires_grad = True
    for name, param in model.named_parameters():
        print(f'{name}: {param.requires_grad}')

print("\n점진적 언프리징 완료")
단계 1: fc 레이어 해제
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: False
layer3.0.bn1.weight: False
layer3.0.bn1.bias: False
layer3.0.conv2.weight: False
layer3.0.bn2.weight: False
layer3.0.bn2.bias: False
layer3.0.downsample.0.weight: False
layer3.0.downsample.1.weight: False
layer3.0.downsample.1.bias: False
layer3.1.conv1.weight: False
layer3.1.bn1.weight: False
layer3.1.bn1.bias: False
layer3.1.conv2.weight: False
layer3.1.bn2.weight: False
layer3.1.bn2.bias: False
layer4.0.conv1.weight: False
layer4.0.bn1.weight: False
layer4.0.bn1.bias: False
layer4.0.conv2.weight: False
layer4.0.bn2.weight: False
layer4.0.bn2.bias: False
layer4.0.downsample.0.weight: False
layer4.0.downsample.1.weight: False
layer4.0.downsample.1.bias: False
layer4.1.conv1.weight: False
layer4.1.bn1.weight: False
layer4.1.bn1.bias: False
layer4.1.conv2.weight: False
layer4.1.bn2.weight: False
layer4.1.bn2.bias: False
fc.weight: True
fc.bias: True

단계 2: layer4 레이어 해제
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: False
layer3.0.bn1.weight: False
layer3.0.bn1.bias: False
layer3.0.conv2.weight: False
layer3.0.bn2.weight: False
layer3.0.bn2.bias: False
layer3.0.downsample.0.weight: False
layer3.0.downsample.1.weight: False
layer3.0.downsample.1.bias: False
layer3.1.conv1.weight: False
layer3.1.bn1.weight: False
layer3.1.bn1.bias: False
layer3.1.conv2.weight: False
layer3.1.bn2.weight: False
layer3.1.bn2.bias: False
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

단계 3: layer3 레이어 해제
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: False
layer2.0.bn1.weight: False
layer2.0.bn1.bias: False
layer2.0.conv2.weight: False
layer2.0.bn2.weight: False
layer2.0.bn2.bias: False
layer2.0.downsample.0.weight: False
layer2.0.downsample.1.weight: False
layer2.0.downsample.1.bias: False
layer2.1.conv1.weight: False
layer2.1.bn1.weight: False
layer2.1.bn1.bias: False
layer2.1.conv2.weight: False
layer2.1.bn2.weight: False
layer2.1.bn2.bias: False
layer3.0.conv1.weight: True
layer3.0.bn1.weight: True
layer3.0.bn1.bias: True
layer3.0.conv2.weight: True
layer3.0.bn2.weight: True
layer3.0.bn2.bias: True
layer3.0.downsample.0.weight: True
layer3.0.downsample.1.weight: True
layer3.0.downsample.1.bias: True
layer3.1.conv1.weight: True
layer3.1.bn1.weight: True
layer3.1.bn1.bias: True
layer3.1.conv2.weight: True
layer3.1.bn2.weight: True
layer3.1.bn2.bias: True
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

단계 4: layer2 레이어 해제
conv1.weight: False
bn1.weight: False
bn1.bias: False
layer1.0.conv1.weight: False
layer1.0.bn1.weight: False
layer1.0.bn1.bias: False
layer1.0.conv2.weight: False
layer1.0.bn2.weight: False
layer1.0.bn2.bias: False
layer1.1.conv1.weight: False
layer1.1.bn1.weight: False
layer1.1.bn1.bias: False
layer1.1.conv2.weight: False
layer1.1.bn2.weight: False
layer1.1.bn2.bias: False
layer2.0.conv1.weight: True
layer2.0.bn1.weight: True
layer2.0.bn1.bias: True
layer2.0.conv2.weight: True
layer2.0.bn2.weight: True
layer2.0.bn2.bias: True
layer2.0.downsample.0.weight: True
layer2.0.downsample.1.weight: True
layer2.0.downsample.1.bias: True
layer2.1.conv1.weight: True
layer2.1.bn1.weight: True
layer2.1.bn1.bias: True
layer2.1.conv2.weight: True
layer2.1.bn2.weight: True
layer2.1.bn2.bias: True
layer3.0.conv1.weight: True
layer3.0.bn1.weight: True
layer3.0.bn1.bias: True
layer3.0.conv2.weight: True
layer3.0.bn2.weight: True
layer3.0.bn2.bias: True
layer3.0.downsample.0.weight: True
layer3.0.downsample.1.weight: True
layer3.0.downsample.1.bias: True
layer3.1.conv1.weight: True
layer3.1.bn1.weight: True
layer3.1.bn1.bias: True
layer3.1.conv2.weight: True
layer3.1.bn2.weight: True
layer3.1.bn2.bias: True
layer4.0.conv1.weight: True
layer4.0.bn1.weight: True
layer4.0.bn1.bias: True
layer4.0.conv2.weight: True
layer4.0.bn2.weight: True
layer4.0.bn2.bias: True
layer4.0.downsample.0.weight: True
layer4.0.downsample.1.weight: True
layer4.0.downsample.1.bias: True
layer4.1.conv1.weight: True
layer4.1.bn1.weight: True
layer4.1.bn1.bias: True
layer4.1.conv2.weight: True
layer4.1.bn2.weight: True
layer4.1.bn2.bias: True
fc.weight: True
fc.bias: True

점진적 언프리징 완료

 

※ 요약
점진적 언프리징은 전이 학습에서 모델의 레이어들을 한 번에 모두 학습하지 않고, 단계적으로 학습 가능하게 설정하는 전략입니다.
이 코드에서는 가장 상위 레이어인 fc 부터 시 작해, layer4, layer3, layer2 순으로 학습 가능하게 설정하고 있습니다. 각 단계에서는 더 많은 레이어를 학습 가능 상태로 확장하여, 초기에는 상위 레이어만 미세 조정하고, 이후에 하위 레이어들까지 학습을 진행할 수 있습니다.
이렇게 하면 모델이 점진적으로 학습할 수 있도록 하여, 처음부터 전체 모델을 학습하는 것 보다 더 안정적이고 효율적인 학습이 가능합니다.


※ 기대 효과
초기 안정성: 상위 레이어만 학습하면서 새로운 데이터에 맞게 모델을 조정하는 동안, 하위 레이어는 기존의 사전 학습된 특성을 유지할 수 있습니다.
점진적 최적화: 이후 하위 레이어까지 확장되면서, 점차적으로 모델의 모든 레이어가 새로운 데이터에 적응할 수 있습니다.