使用 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

雖然程式碼一開始可能看起來很複雜,但此類別會定義一個相當簡單的網路,其中包含三層:

  • 接受四個輸入值的輸入層,並產生下一層的五個輸出值。
  • 接受五個輸入並產生五個輸出的層。
  • 接受五個輸入並產生三個輸出的最終輸出層。

正向 函式會將圖層套用至輸入資料 (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 中的可用優化器包括 (還有許多其他的):

若要使用這些演算法來定型模型,您需要建立優化器的執行個體,並設定任何必要的參數。 特定參數會根據所選的優化器而有所不同,但大部分都要求您指定一個 學習速率 以控管每個優化所做的調整大小。

下列程式碼會建立 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 上定型模型

若要定型深度學習模型,您通常會多次執行定型函式 (稱為 epochs),目標是減少每個 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))