PyTor전이 학습 튜토리얼 (예제 포함)

⚡ 스마트 요약

전이 학습은 이미 대규모 데이터셋으로 학습된 네트워크를 재사용하여, 훨씬 적은 수의 레이블링된 이미지와 훨씬 짧은 학습 시간으로 새로운 관련 작업을 해결할 수 있도록 합니다.

  • 🔘 핵심 아이디어: ImageNet에서 학습된 가중치는 대부분의 컴퓨터 비전 작업에서 재사용되는 가장자리, 질감 및 모양을 이미 인코딩합니다.
  • ☑️ 두 가지 전략: 기능 예시traction은 기본 구조를 고정하는 반면, fine-tuning은 원래 레이어의 일부 또는 전부를 계속 학습시킵니다.
  • 실제 예제: 대략 700장의 에일리언과 프레데터 사진이면 VGG19의 마지막 레이어를 재학습시키기에 충분합니다.
  • 🧪 PyTor조각들: ImageFolder, transforms.Compose 및 DataLoader는 네트워크가 소비하는 배치를 구성합니다.
  • 🛠️ 냉동 보관층: requires_grad를 False로 설정하면 그래디언트 학습이 중지되므로 교체된 분류기만 학습합니다.
  • ⚠️ 보고된 결과: 샘플 데이터셋에서 25개의 에포크가 3분 이내에 완료됩니다.

PyTor전이 학습 튜토리얼 (예제 포함)

전이 학습이란 무엇입니까?

전학 학습 훈련된 모델을 사용하여 다른 관련 작업을 해결하는 기술입니다. 머신 러닝 특정 문제를 해결하는 과정에서 얻은 지식을 저장하고, 동일한 지식을 활용하여 서로 다르지만 관련된 문제를 해결하는 연구 방법입니다. 이는 이전에 학습한 과제에서 얻은 정보를 재사용함으로써 효율성을 향상시킵니다.

신경망을 처음부터 학습시키려면 엄청난 양의 데이터가 필요하기 때문에, 기존 신경망 모델의 가중치를 재사용하는 것이 일반적입니다. 학습 시간을 줄이기 위해 기존 신경망과 그 가중치를 가져와 마지막 레이어를 수정하여 원하는 문제를 해결하도록 합니다. 이렇게 하면 마지막 레이어를 적은 데이터셋으로도 학습시킬 수 있다는 장점이 있습니다.

Py를 작성하기 전에Tor코드 유형이 다르기 때문에, 전이 학습의 어떤 유형에 속하는지 아는 것이 중요합니다. 왜냐하면 유형에 따라 필요한 레이블링된 데이터의 양이 결정되기 때문입니다.

전이 학습의 유형

연구 문헌에서는 이 기법을 세 가지 유형으로 분류합니다. 어떤 유형이 적용되는지는 사용하는 프레임워크가 아니라 문제의 어느 측면에 명칭이 붙어 있는지에 따라 결정됩니다.

타입 소스 도메인 Target 도메인 일반적인 사용
유도 라벨이 붙은 라벨은 붙어 있지만, 다른 작업입니다. ImageNet 백본을 에일리언 대 프레데터라는 두 클래스 문제에 맞게 재조정하기
변환 라벨이 붙은 레이블 없음, 동일한 작업, 데이터 분포가 다름 스튜디오 사진에서 휴대폰 사진으로 모델을 옮기는 것과 같은 도메인 적응.
감독되지 않음 라벨 없음 라벨 없음 Cluster모든 레코드에 레이블을 지정하는 것이 비현실적인 경우 차원 축소 또는 차원 축소

이 튜토리얼에서 다루는 예제는 귀납적 전이 학습입니다. VGG19는 레이블이 지정된 ImageNet 지식을 가지고 있으며, 이제 이전에 접해본 적 없는 레이블이 지정된 이진 클래스 문제에 대한 학습을 ​​수행하게 됩니다.

기능 예시trac조정 vs 미세 조정

사전 학습된 네트워크를 선택한 후에는 두 가지 방법으로 네트워크를 조정할 수 있습니다. 두 방법의 차이점은 학습을 계속할 레이어 수를 얼마나 허용하느냐에 있습니다.

아래 기능 예시trac기 미세 조정
훈련하는 레이어 교체된 분류기만 분류기와 일부 또는 전체 컨볼루션 블록
백본에서 requires_grad를 사용합니다. 거짓 업데이트되는 블록에 대해서는 사실입니다.
필요한 데이터 클래스당 이미지 수가 적고, 대개 수백 개 정도입니다. 더 큰 규모, 보통 수천 개
교육 비용 최저 사양은 CPU에서 실행됩니다. 그보다 높은 해상도에서는 GPU를 사용하는 것이 가치가 있습니다.
일반적인 정확도 원본 이미지와 대상 이미지가 비슷하게 생겼을 때 좋습니다. 두 영역이 서로 다를 때 일반적으로 더 좋습니다.

아래 단계에서는 기능 예시를 사용합니다.trac설정: 모든 VGG19 파라미터가 고정되고 새로운 최종 선형 레이어만 학습됩니다. 미세 조정으로 전환하려면 약간의 변경만 하면 됩니다. 즉, 업데이트하려는 블록에서 requires_grad를 True로 설정하고 학습률을 낮춰 빌려온 가중치가 파괴되지 않도록 하면 됩니다.

데이터 세트 로드 중

Py를 이용한 전이 학습을 시작하기 전에Tor먼저, 사용할 데이터셋을 이해해야 합니다. 이 전이 학습 Py에서는Tor예를 들어, 약 700장의 이미지 중에서 에일리언과 프레데터를 분류하게 됩니다. 이 기법에는 학습에 많은 양의 데이터가 필요하지 않습니다. 데이터셋은 다음에서 다운로드할 수 있습니다. Kaggle: 에일리언 vs. 프레데터.

이 컬렉션은 의도적으로 소규모로 구성되었으며, 포함된 사진의 일부는 아래에 나와 있습니다.

이 파이썬에서는 Kaggle에서 가져온 Alien vs Predator 이미지 데이터셋을 사용했습니다.Torch 전이 학습 예시

출처: 외국인 대 프레데터 카글

다음은 이 Py에서Tor이 전이 학습 튜토리얼에서는 Py를 사용하여 전이 학습을 적용하는 방법을 배우게 됩니다.Tor단계별로.

전이 학습을 사용하는 방법은 무엇입니까?

다음은 Py를 사용하여 딥러닝에 전이 학습을 적용하는 방법에 대한 단계별 설명입니다.Tor채널 :

1단계) 데이터 로드

첫 번째 단계는 데이터를 불러오고 네트워크 요구 사항에 맞도록 이미지에 몇 가지 변환을 적용하는 것입니다.

torchvision.datasets 폴더에서 데이터를 불러옵니다. 이 모듈은 폴더를 순회하며 데이터를 학습 세트와 검증 세트로 분할합니다. 여기에 사용된 변환 파이프라인은 이미지의 중앙 부분을 잘라내고, 텐서로 변환한 후 정규화합니다. 딥러닝.

from __future__ import print_function, division
import os
import time
import torch
import torchvision
from torchvision import datasets, models, transforms
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt

data_dir = "alien_pred"
input_shape = 224
mean = [0.5, 0.5, 0.5]
std = [0.5, 0.5, 0.5]

#data transformation
data_transforms = {
   'train': transforms.Compose([
       transforms.CenterCrop(input_shape),
       transforms.ToTensor(),
       transforms.Normalize(mean, std)
   ]),
   'validation': transforms.Compose([
       transforms.CenterCrop(input_shape),
       transforms.ToTensor(),
       transforms.Normalize(mean, std)
   ]),
}

image_datasets = {
   x: datasets.ImageFolder(
       os.path.join(data_dir, x),
       transform=data_transforms[x]
   )
   for x in ['train', 'validation']
}

dataloaders = {
   x: torch.utils.data.DataLoader(
       image_datasets[x], batch_size=32,
       shuffle=True, num_workers=4
   )
   for x in ['train', 'validation']
}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation']}

print(dataset_sizes)
class_names = image_datasets['train'].classes

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

이제 데이터셋을 시각화해 보겠습니다. 시각화 단계에서는 학습 데이터 로더에서 다음 이미지 배치와 레이블을 가져와 Matplotlib을 사용하여 표시합니다.

images, labels = next(iter(dataloaders['train']))

rows = 4
columns = 4
fig=plt.figure()
for i in range(16):
   fig.add_subplot(rows, columns, i+1)
   plt.title(class_names[labels[i]])
   img = images[i].numpy().transpose((1, 2, 0))
   img = std * img + mean
   plt.imshow(img)
plt.show()

해당 코드 조각을 실행하면 로더가 반환한 클래스 이름으로 제목이 지정된 4x4 격자 형태의 학습 이미지가 그려집니다.

클래스 제목과 함께 4x4 Matplotlib 그리드에 그려진 16개의 훈련 이미지 배치

2단계) 모델 정의

이 딥러닝 과정에서는 torchvision 모듈의 VGG19를 사용합니다.

torchvision.models를 사용하여 사전 학습된 가중치가 활성화된 vgg19 모델을 로드합니다. 그 후, 레이어를 학습 불가능하도록 고정합니다. 마지막으로, 문제(여기서는 2개 클래스)에 맞는 선형 레이어를 마지막 레이어에 추가합니다. 손실 함수로는 CrossEntropyLoss를 사용하고, 옵티마이저는 SGD를 사용하며, 학습률은 0.001, 모멘텀은 0.9로 설정합니다. 아래 파이썬 코드를 참조하십시오.Tor전이 학습의 예시.

## Load the model based on VGG19
vgg_based = torchvision.models.vgg19(pretrained=True)

## freeze the layers
for param in vgg_based.parameters():
   param.requires_grad = False

# Modify the last layer
number_features = vgg_based.classifier[6].in_features
features = list(vgg_based.classifier.children())[:-1] # Remove last layer
features.extend([torch.nn.Linear(number_features, len(class_names))])
vgg_based.classifier = torch.nn.Sequential(*features)

vgg_based = vgg_based.to(device)

print(vgg_based)

criterion = torch.nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(vgg_based.parameters(), lr=0.001, momentum=0.9)

버전 참고: 전에, 사전 학습됨=True 해당 논리는 여전히 유효하지만, TorchVision 0.13 버전 이후로는 다른 논리로 대체되었습니다. 무게 인수이므로 최신 설치에서는 다음과 같이 예상합니다. torchvision.models.vgg19(weights=VGG19_Weights.DEFAULT) 그렇지 않으면 사용 중단 경고를 출력합니다. 두 형식 모두 동일한 ImageNet 가중치를 로드합니다.

출력 모델 구조

모델을 출력하면 전체 VGG19 그래프가 반환됩니다. 분류기 블록의 마지막 줄을 읽어 스왑이 제대로 되었는지 확인하세요. 이제 1,000개의 ImageNet 클래스 대신 2개의 출력이 생성됩니다.

VGG(
  (features): Sequential(
	(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(1): ReLU(inplace)
	(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(3): ReLU(inplace)
	(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(6): ReLU(inplace)
	(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(8): ReLU(inplace)
	(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(11): ReLU(inplace)
	(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(13): ReLU(inplace)
	(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(15): ReLU(inplace)
	(16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(17): ReLU(inplace)
	(18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(20): ReLU(inplace)
	(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(22): ReLU(inplace)
	(23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(24): ReLU(inplace)
	(25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(26): ReLU(inplace)
	(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
	(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(29): ReLU(inplace)
	(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(31): ReLU(inplace)
	(32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(33): ReLU(inplace)
	(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
	(35): ReLU(inplace)
	(36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (classifier): Sequential(
	(0): Linear(in_features=25088, out_features=4096, bias=True)
	(1): ReLU(inplace)
	(2): Dropout(p=0.5)
	(3): Linear(in_features=4096, out_features=4096, bias=True)
	(4): ReLU(inplace)
	(5): Dropout(p=0.5)
	(6): Linear(in_features=4096, out_features=2, bias=True)
  )
)

3단계) ​​모델 훈련 및 테스트

우리는 이것의 몇 가지 기능을 사용할 것입니다. PyTorch 튜토리얼 모델을 훈련하고 평가하는 데 도움이 됩니다.

def train_model(model, criterion, optimizer, num_epochs=25):
   since = time.time()

   for epoch in range(num_epochs):
       print('Epoch {}/{}'.format(epoch, num_epochs - 1))
       print('-' * 10)

       #set model to trainable
       # model.train()

       train_loss = 0

       # Iterate over data.
       for i, data in enumerate(dataloaders['train']):
           inputs , labels = data
           inputs = inputs.to(device)
           labels = labels.to(device)

           optimizer.zero_grad()
          
           with torch.set_grad_enabled(True):
               outputs  = model(inputs)
               loss = criterion(outputs, labels)

           loss.backward()
           optimizer.step()

           train_loss += loss.item() * inputs.size(0)

           print('{} Loss: {:.4f}'.format(
               'train', train_loss / dataset_sizes['train']))
          
   time_elapsed = time.time() - since
   print('Training complete in {:.0f}m {:.0f}s'.format(
       time_elapsed // 60, time_elapsed % 60))

   return model

def visualize_model(model, num_images=6):
   was_training = model.training
   model.eval()
   images_so_far = 0
   fig = plt.figure()

   with torch.no_grad():
       for i, (inputs, labels) in enumerate(dataloaders['validation']):
           inputs = inputs.to(device)
           labels = labels.to(device)

           outputs = model(inputs)
           _, preds = torch.max(outputs, 1)

           for j in range(inputs.size()[0]):
               images_so_far += 1
               ax = plt.subplot(num_images//2, 2, images_so_far)
               ax.axis('off')
               ax.set_title('predicted: {} truth: {}'.format(class_names[preds[j]], class_names[labels[j]]))
               img = inputs.cpu().data[j].numpy().transpose((1, 2, 0))
               img = std * img + mean
               ax.imshow(img)

               if images_so_far == num_images:
                   model.train(mode=was_training)
                   return
       model.train(mode=was_training)

마지막으로, Py를 이용한 전이 학습에 대해 알아보겠습니다.Tor예를 들어, 에포크 수를 25로 설정하여 학습 과정을 시작하고 이후 네트워크를 평가합니다. 각 학습 단계에서 모델은 입력을 받아 출력을 예측합니다. 예측값은 손실을 계산하는 기준 함수로 전달되고, 역전파는 기울기를 계산하며, 최적화기는 자동 미분(autograd)을 통해 가중치를 업데이트합니다.

시각화 기능에서는 학습된 네트워크를 이미지 배치로 테스트하여 레이블을 예측하고, 그 결과를 Matplotlib을 사용하여 시각화합니다.

vgg_based = train_model(vgg_based, criterion, optimizer_ft, num_epochs=25)

visualize_model(vgg_based)

plt.show()

4단계) 결과

이번 실행의 정확도는 92%입니다. 학습이 끝날 때 출력되는 로그에는 마지막 두 에포크 동안의 손실과 총 학습 시간이 표시됩니다.

Epoch 23/24
----------
train Loss: 0.0044
train Loss: 0.0078
train Loss: 0.0141
train Loss: 0.0221
train Loss: 0.0306
train Loss: 0.0336
train Loss: 0.0442
train Loss: 0.0482
train Loss: 0.0557
train Loss: 0.0643
train Loss: 0.0763
train Loss: 0.0779
train Loss: 0.0843
train Loss: 0.0910
train Loss: 0.0990
train Loss: 0.1063
train Loss: 0.1133
train Loss: 0.1220
train Loss: 0.1344
train Loss: 0.1382
train Loss: 0.1429
train Loss: 0.1500
Epoch 24/24
----------
train Loss: 0.0076
train Loss: 0.0115
train Loss: 0.0185
train Loss: 0.0277
train Loss: 0.0345
train Loss: 0.0420
train Loss: 0.0450
train Loss: 0.0490
train Loss: 0.0644
train Loss: 0.0755
train Loss: 0.0813
train Loss: 0.0868
train Loss: 0.0916
train Loss: 0.0980
train Loss: 0.1008
train Loss: 0.1101
train Loss: 0.1176
train Loss: 0.1282
train Loss: 0.1323
train Loss: 0.1397
train Loss: 0.1436
train Loss: 0.1467
Training complete in 2m 47s

모델의 예측 결과는 아래와 같이 Matplotlib을 사용하여 시각화됩니다.

학습 후 예측 클래스와 실제 클래스로 레이블링된 검증 이미지

전이 학습에서 흔히 발생하는 오류와 해결 방법

전이 학습 스크립트에서 발생하는 대부분의 오류는 수학적 오류보다는 기계적 오류입니다. 다음은 위 코드가 실행되지 못하게 하는 오류들과 각각의 의미입니다.

  • 마지막 레이어의 크기 불일치: 교체된 선형 레이어는 원래 분류기가 보고한 in_features를 받아들이고 정확히 len(class_names)개의 출력을 내보내야 합니다. 2단계에서처럼 모델을 출력하는 것이 두 수치를 확인하는 가장 빠른 방법입니다.
  • 핵심 부품은 절대 얼지 않았습니다. requires_grad가 True로 설정된 상태로 두면 모든 VGG19 매개변수가 업데이트되어 CPU에서 실행 속도가 매우 느려집니다. 분류기를 교체하기 전에 requires_grad를 False로 설정하십시오.
  • 정규화 불일치: transforms.Normalize에 사용되는 평균과 표준 편차는 학습 시와 추론 시에 동일한 값이어야 합니다. 그렇지 않으면 예측값이 뚜렷한 이유 없이 변동될 수 있습니다.
  • 더 이상 사용되지 않는 가중치 인수: TorchVision 0.13 이상 버전에서는 pretrained=True를 사용하면 사용 중단 경고가 표시되며, weights 열거형을 사용하는 것이 좋습니다.
  • num_workers에 Windows 그리고 노트북: num_workers=4로 설정된 DataLoader는 진입점을 보호해야 하므로, 필요한 경우 num_workers=0으로 설정하십시오. Python 생성 또는 피클링 오류가 발생합니다.
  • 훈련 모드에서 평가 중: Dropout과 BatchNorm이 결정론적으로 동작하도록 스코어링 전에 model.eval()을 호출하고, 그 후에 model.train()을 호출하여 원래대로 되돌리세요.

자주 묻는 질문

최종 레이어만 학습하는 경우에는 클래스당 수백 장의 이미지면 충분합니다. 이 예제에서는 총 약 700장의 이미지를 사용했습니다. 더 깊은 블록을 미세 조정하려면 훨씬 더 많은 매개변수를 업데이트해야 하므로 더 많은 이미지(종종 수천 장)가 필요합니다.

ResNet, VGG, EfficientNet 및 Vision Transformer 백본은 모두 TorchVision 가중치를 포함하고 있습니다. ResNet50은 정확도와 용량의 균형을 잘 맞춰주기 때문에 일반적으로 기본값으로 사용됩니다. 여기에서 사용된 VGG19는 더 무거운 가중치를 가진 백본입니다. 합성 신경망 하지만 층별로 분석하기는 간단합니다.

아니요. 백본을 고정하고 단일 레이어를 학습시키는 것은 CPU에서도 충분히 실행 가능하며, 위의 실행 결과가 3분 이내에 완료되는 이유도 바로 그 때문입니다. 하지만 전체 네트워크를 미세 조정하거나 수천 장의 이미지로 학습시킬 때는 GPU가 필수적입니다.

자동화된 모델 검색 벤치마킹은 사용자의 데이터 샘플에서 여러 사전 학습된 네트워크를 평가하고 정확도, 지연 시간 및 크기를 기준으로 순위를 매깁니다. 이를 통해 백본 선택 시 추측에 의존하는 부분을 제거하고 하이퍼파라미터 검색과 함께 사용하면 효과적입니다. 사이 킷 학습.

변환, DataLoader 설정 및 학습 루프가 익숙한 패턴을 따르기 때문에 기본 템플릿을 잘 작성합니다. 추론할 수 없는 부분, 즉 출력 클래스 수, 정규화 통계 및 requires_grad가 실제로 비활성화되었는지 여부를 확인하십시오.

소스 도메인과 타겟 도메인이 너무 다를 때 부정적인 전이가 발생하여, 빌려온 가중치가 도움이 되기보다는 오히려 해를 끼칩니다. 검증 손실이 초기에 정체되거나, 처음부터 학습시킨 작은 네트워크보다 높은 값을 보이는지 주의 깊게 살펴보세요.

네. 언어 모델은 대규모 텍스트 코퍼스를 사용하여 사전 학습된 후 분류 또는 질의응답에 적용되며, 동일한 개념이 다른 분야에도 적용됩니다. 시퀀스 모델오디오 및 표 형식 임베딩을 포함합니다. 기본 구조만 변경됩니다.

처음부터 학습시킨 네트워크보다 훨씬 적은 에포크가 필요합니다. 여기서는 25 에포크를 사용했지만, 특징 추출에는 10~20 에포크면 충분한 경우가 많습니다.trac고정된 횟수를 실행하는 대신, 검증 손실이 더 이상 개선되지 않을 때 중지합니다.

이 게시물을 요약하면 다음과 같습니다.