PyTorch를 통해 모델 학습

완료됨

PyTorch 는 딥 러닝 모델을 학습하는 데 일반적으로 사용되는 기계 학습 프레임워크입니다. Azure Databricks에서 PyTorch는 ML 클러스터에 미리 설치됩니다.

비고

이 단원의 코드 조각은 핵심 요소를 강조하기 위한 예제로 제공됩니다. 이 모듈의 뒷부분에 있는 연습에서 전체 작업 예제에 대한 코드를 실행할 수 있습니다.

PyTorch 네트워크 정의

PyTorch에서 모델은 사용자가 정의하는 네트워크를 기반으로 합니다. 네트워크는 각각 지정된 입력 및 출력이 있는 여러 계층으로 구성됩니다. 또한 이 작업은 데이터를 네트워크를 통해 전달할 때 각 계층에 함수를 적용하는 정방향 함수를 정의합니다.

다음 예제 코드는 네트워크를 정의합니다.

import torch
import torch.nn as nn
import torch.nn.functional as F

class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.layer1 = nn.Linear(4, 5)
        self.layer2 = nn.Linear(5, 5)
        self.layer3 = nn.Linear(5, 3)

    def forward(self, x):
        layer1_output = torch.relu(self.layer1(x))
        layer2_output = torch.relu(self.layer2(layer1_output))
        y = self.layer3(layer2_output)
        return y

처음에는 코드가 복잡해 보일 수 있지만, 이 클래스는 세 개의 계층으로 비교적 간단한 네트워크를 정의합니다.

  • 4개의 입력 값을 허용하고 다음 계층에 대해 5개의 출력 값을 생성하는 입력 계층입니다.
  • 5개의 입력을 허용하고 5개의 출력을 생성하는 계층입니다.
  • 5개의 입력을 허용하고 3개의 출력을 생성하는 최종 출력 계층입니다.

정방향 함수는 입력 데이터(x)에 계층을 적용하여 각 계층의 출력을 다음 계층으로 전달하고 마지막으로 마지막 계층(레이블 예측 벡터, y 포함)의 출력을 반환합니다. ReLU(정정된 선형 단위) 활성화 함수는 출력 값을 양수로 제한하기 위해 레이어 1과 2의 출력에 적용됩니다.

비고

사용된 손실 기준 유형에 따라 반환 값에 log_softmax 같은 활성화 함수를 적용하여 0에서 1 범위로 강제 적용하도록 선택할 수 있습니다. 그러나 일부 손실 조건(예: 다중 클래스 분류에 일반적으로 사용되는 CrossEntropyLoss)은 자동으로 적합한 함수를 적용합니다.

학습용 모델을 만들려면 다음과 같이 네트워크 클래스의 인스턴스를 만들어야 합니다.

myModel = MyNet()

모델링용 데이터 준비

PyTorch 계층은 행렬과 유사한 구조체인 텐서 형식의 데이터에 대해 작동합니다. 다른 일반적인 데이터 형식을 텐서로 변환하는 다양한 함수가 있으며 PyTorch 데이터 로더 를 정의하여 데이터 텐서를 학습 또는 추론을 위한 모델로 읽을 수 있습니다.

대부분의 감독되는 기계 학습 기술과 마찬가지로 학습 및 유효성 검사를 위해 별도의 데이터 세트를 정의해야 합니다. 이 분리를 사용하면 모델이 학습되지 않은 데이터와 함께 제공될 때 모델이 정확하게 예측하는지 확인할 수 있습니다.

다음 코드는 두 개의 데이터 로더를 정의합니다. 하나는 학습용이고 다른 하나는 테스트용입니다. 이 예제의 각 로더에 대한 원본 데이터는 기능 값의 Numpy 배열 및 해당 레이블 값의 Numpy 배열로 간주됩니다.

# Create a dataset and loader for the training data and labels
train_x = torch.Tensor(x_train).float()
train_y = torch.Tensor(y_train).long()
train_ds = td.TensorDataset(train_x,train_y)
train_loader = td.DataLoader(train_ds, batch_size=20,
    shuffle=False, num_workers=1)

# Create a dataset and loader for the test data and labels
test_x = torch.Tensor(x_test).float()
test_y = torch.Tensor(y_test).long()
test_ds = td.TensorDataset(test_x,test_y)
test_loader = td.DataLoader(test_ds, batch_size=20,
    shuffle=False, num_workers=1)

이 예제의 로더에서는 데이터를 30의 일괄 처리로 분할하여 학습 또는 유추 중에 앞으로 함수에 전달합니다.

손실 기준 및 최적화 프로그램 알고리즘 선택

모델은 학습 데이터를 네트워크에 공급하고, 손실(예측 값과 실제 값 간의 집계된 차이)을 측정하고, 손실을 최소화하기 위해 가중치와 균형을 조정하여 네트워크를 최적화하여 학습됩니다. 손실을 계산하고 최소화하는 방법에 대한 구체적인 세부 정보는 선택한 손실 기준 및 최적화 프로그램 알고리즘에 의해 제어됩니다.

손실 조건

PyTorch는 다음과 같은 여러 손실 조건 함수를 지원합니다.

  • cross_entropy: 여러 변수의 예측 값과 실제 값 간의 집계 차이를 측정하는 함수입니다(일반적으로 다중 클래스 분류에서 클래스 확률의 손실을 측정하는 데 사용됨).
  • binary_cross_entropy: 예측 확률과 실제 확률의 차이를 측정하는 함수입니다(일반적으로 이진 분류에서 클래스 확률의 손실을 측정하는 데 사용됨).
  • mse_loss: 예측 및 실제 숫자 값의 평균 제곱 오차 손실을 측정하는 함수입니다(일반적으로 회귀에 사용됨).

모델을 학습할 때 사용하려는 손실 조건을 지정하려면 적절한 함수의 인스턴스를 만듭니다. 이런 식으로:

import torch.nn as nn

loss_criteria = nn.CrossEntropyLoss

팁 (조언)

PyTorch에서 사용 가능한 손실 조건에 대한 자세한 내용은 PyTorch 설명서의 손실 함수 를 참조하세요.

최적화 프로그램 알고리즘

손실을 계산한 후 최적화 프로그램은 가중치와 균형을 최소화하기 위해 가장 잘 조정하는 방법을 결정하는 데 사용됩니다. 최적화 프로그램은 함수를 최소화하기 위한 그라데이션 하강 방법의 특정 구현입니다. PyTorch에서 사용할 수 있는 최적화 프로그램은 다음과 같습니다(그 중 하나).

  • Adadelta: 적응 학습 속도 알고리즘을 기반으로 하는 최적화 프로그램입니다.
  • Adam: Adam 알고리즘을 기반으로 하는 계산 효율적인 최적화 프로그램입니다.
  • SGD: 확률적 그라데이션 하강 알고리즘을 기반으로 하는 최적화 프로그램입니다.

이러한 알고리즘을 사용하여 모델을 학습하려면 최적화 프로그램의 인스턴스를 만들고 필요한 매개 변수를 설정해야 합니다. 특정 매개 변수는 선택한 최적화 도구에 따라 다르지만, 대부분의 경우 각 최적화에 따른 조정 크기를 제어하는 학습 속도를 지정해야 합니다.

다음 코드는 Adam 최적화 프로그램의 인스턴스를 만듭니다.

import torch.optim as opt

learning_rate = 0.001
optimizer = opt.Adam(model.parameters(), lr=learning_rate)

팁 (조언)

PyTorch에서 사용 가능한 최적화 도구에 대한 자세한 내용은 PyTorch 설명서의 알고리즘 을 참조하세요.

학습 및 테스트 함수 만들기

네트워크를 정의하고 데이터를 준비한 후에는 데이터를 사용하여 네트워크를 통해 학습 데이터를 전달하고, 손실을 계산하고, 네트워크 가중치 및 편향을 최적화하고, 테스트 데이터를 사용하여 네트워크의 성능에 대한 유효성을 검사하여 모델을 학습하고 테스트할 수 있습니다. 일반적으로 네트워크를 통해 데이터를 전달하여 학습 데이터를 사용하여 모델을 학습 시키는 함수와 테스트 데이터로 모델을 테스트 하는 별도의 함수를 정의하는 것이 일반적입니다.

학습 함수 만들기

다음 예제에서는 모델을 학습시키는 함수를 보여줍니다.

def train(model, data_loader, optimizer):

    # Use GPU if available, otherwise CPU
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)
    
    # Set the model to training mode (to enable backpropagation)
    model.train()
    train_loss = 0
    
    # Feed the batches of data forward through the network
    for batch, tensor in enumerate(data_loader):
        data, target = tensor # Specify features and labels in a tensor
        optimizer.zero_grad() # Reset optimizer state
        out = model(data) # Pass the data through the network
        loss = loss_criteria(out, target) # Calculate the loss
        train_loss += loss.item() # Keep a running total of loss for each batch

        # backpropagate adjustments to weights/bias
        loss.backward()
        optimizer.step()

    #Return average loss for all batches
    avg_loss = train_loss / (batch+1)
    print('Training set: Average loss: {:.6f}'.format(avg_loss))
    return avg_loss

다음 예제에서는 모델을 테스트하는 함수를 보여줍니다.

def test(model, data_loader):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)
    # Switch the model to evaluation mode (so we don't backpropagate)
    model.eval()
    test_loss = 0
    correct = 0

    # Pass the data through with no gradient computation
    with torch.no_grad():
        batch_count = 0
        for batch, tensor in enumerate(data_loader):
            batch_count += 1
            data, target = tensor
            # Get the predictions
            out = model(data)

            # calculate the loss
            test_loss += loss_criteria(out, target).item()

            # Calculate the accuracy
            _, predicted = torch.max(out.data, 1)
            correct += torch.sum(target==predicted).item()
            
    # Calculate the average loss and total accuracy for all batches
    avg_loss = test_loss/batch_count
    print('Validation set: Average loss: {:.6f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        avg_loss, correct, len(data_loader.dataset),
        100. * correct / len(data_loader.dataset)))
    return avg_loss

여러 Epoch를 통해 모델 학습

딥 러닝 모델을 학습하기 위해 일반적으로 각 Epoch 학습 데이터에서 계산된 손실을 줄이기 위해 학습 함수를 여러 번 실행합니다( epoch라고 함). 테스트 함수를 사용하여 테스트 데이터(모델이 학습되지 않은)의 손실도 학습 손실에 따라 감소하고 있는지 확인할 수 있습니다. 즉, 모델 학습이 학습 데이터에 과잉 맞춤된 모델을 생성하지 않는다는 것입니다.

팁 (조언)

모든 Epoch에 대해 테스트 함수를 실행할 필요가 없습니다. 매 두 번째 에포크마다 또는 마지막에 한 번 실행하도록 선택할 수 있습니다. 그러나 모델을 학습할 때 테스트하는 것은 모델이 몇 번째 Epoch부터 과적합되기 시작하는지 결정하는 데 도움이 될 수 있습니다.

다음 코드는 50개 이상의 Epoch 모델을 학습시킵니다.

epochs = 50
for epoch in range(1, epochs + 1):

    # print the epoch number
    print('Epoch: {}'.format(epoch))
    
    # Feed training data into the model to optimize the weights
    train_loss = train(model, train_loader, optimizer)
    print(train_loss)
    
    # Feed the test data into the model to check its performance
    test_loss = test(model, test_loader)
    print(test_loss)

학습된 모델 상태 저장

모델을 성공적으로 학습한 후에는 다음과 같이 가중치와 바이어스를 저장할 수 있습니다.

model_file = '/dbfs/my_model.pkl'
torch.save(model.state_dict(), model_file)

나중에 모델을 로드하고 사용하려면 모델이 기반이 되는 네트워크 클래스의 인스턴스를 만들고 저장된 가중치 및 바이어스를 로드합니다.

model = myNet()
model.load_state_dict(torch.load(model_file))