iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
AI & Data

AI白話文運動系列之「A!給我那張Image!」系列 第 8

Pytorch實戰(二)--建立與訓練模型--以MLP為例

  • 分享至 

  • xImage
  •  

前言

上次的內容中,我們討論到在Pytorch中訓練一個AI模型的完整流程,並介紹了要如何準備訓練模型所需要的資料集,今天我們將接著往下講如何建立與訓練一個模型,並且在訓練好之後評估模型的表現。

先備知識

  1. Python(至少對Python語法不陌生)
  2. 物件導向(至少需要知道class, function等概念)

看完今天的內容你可能會知道......

  1. 如何利用Pytorch建立出一個AI模型
  2. 如何使用optimizer更新模型

一、建立AI模型(一樣介紹Pytorch提供的預訓練模型與自己建立一個簡單的模型

  • 和資料集一樣,建立模型的方式可以從Pytorch中提供的架構直接拿來用,或是由我們自己定義都可以,以下將分別介紹這兩種方式。

    1. 預訓練模型

    • 一個AI模型的表現主要取決於訓練的資料集以及模型的架構,越複雜的模型通常可以有越好的表現,可是在訓練這樣的模型時也會需要強大的運算資源。因此,如果可以直接使用大公司替我們訓練好的模型,這樣會方便很多。這些已經被訓練好的模型,我們稱之為「預訓練模型(Pre-trained model)」。
    • 在Pytorch中提供了許多預訓練模型(https://pytorch.org/vision/stable/models.html),依照不同的任務類型分別列出來,以影像分類任務為例,我們可以看到許多預訓練在ImageNet-1K大型數據集的模型。https://ithelp.ithome.com.tw/upload/images/20230923/2016329973HpSyoL4U.png
    • 每個模型都可以點進去看更詳細的介紹,從如何使用這個預訓練模型到該模型的表現、模型大小與計算複雜度等等的資訊都有。或是也可以參考這個網站(https://pytorch.org/vision/0.8/models.html),會有比較簡單的操作說明。以VGG16這個模型為例,我們可以使用以下方式取得預訓練模型:
    import torchvision.models as models
    
    # vgg16 = models.vgg16() #僅有模型架構,沒有預訓練權重
    vgg16 = models.vgg16(pretrained=True) #模型架構與預訓練權重
    
    print(vgg16) #直接用print便可查看模型架構
    
    • 註:先前我們在討論模型時,我們一直將裡面可以更新的東西稱為參數,不過在AI這個領域,我們會使用「權重(Weight)」來表示,這是因為這些參數實際上是對輸入訊號進行加權的權重,所以我們就直接把這些參數叫做權重,如果對加權這個動作覺得陌生的話,可以回顧這篇的內容:https://ithelp.ithome.com.tw/articles/10322151

    2. 從頭建立自己的模型

    • 我們在介紹MLP模型的時候有提過,AI模型是由許多「層(Layer)」組成的,就像疊積木一樣一層一層拼起來,Pytorch提供許多常見的「層」的架構,讓我們可以直接使用。如果要建立模型的時候,可以視需要將這些架構直接套進來使用。https://pytorch.org/docs/stable/nn.html 裡面按照不同的功能將這些架構分類列出,感興趣的可以點進去看一看,我們今天介紹兩種常見的架構:全連接層(Full-connected layer)與激勵函數(Activation function),其餘常見架構會待後續內容討論到的時候一併介紹。
    • 全連接層或稱作線性層(https://pytorch.org/docs/stable/generated/torch.nn.Linear.html#torch.nn.Linear),指的是對輸入訊號進行矩陣運算的操作,也就是我們在MLP那篇https://ithelp.ithome.com.tw/articles/10322151 談到的操作。如果把一個訊號(或是向量)中的餒個元素當作一個節點(Node),那麼全連接層的「全連接」這個名稱就是來自於每個節點彼此之間都互相連結,就像下圖的藍色與綠色節點之間的連結一樣:https://ithelp.ithome.com.tw/upload/images/20230923/20163299CQWERv373Q.png
    • 激勵函數(Activation function)同樣在MLP那篇我們有討論到,主要的作用是在模擬神經元累積訓練舊且決定是否要往下傳遞的動作,以數學的角度來看,也可以說是替原先線性運算增加一些非線性,因為如果只有線性運算的話,遇到某些問題時會像是下圖左邊的狀況,對問題的判斷都是一板一眼的,可以如果增加一些非線性的函數的話,運算結果會像是下圖右邊的樣子,比左邊多了一些彈性。https://ithelp.ithome.com.tw/upload/images/20230923/20163299Y2gKfYwG4w.png
    • 回到我們的問題,如果以MLP模型搭配MNIST數據集為例的話,我們可以用下面這種方式建立我們的模型:
    import torch
    import torch.nn as nn
    import torchvision
    
    class MLP(nn.Module):
        def __init__(self, input_size, hidden_size, num_classes):
            super(MLP, self).__init__()
            self.fc1 = nn.Linear(input_size, hidden_size)
            self.relu = nn.ReLU()
            self.fc2 = nn.Linear(hidden_size, num_classes)
    
        def forward(self, x):
            out = self.fc1(x)
            out = self.relu(out)
            out = self.fc2(out)
            return out
    
    # Hyperparameters
    input_size = 28 * 28  # MNIST images are 28x28 pixels
    hidden_size = 128    # Number of neurons in the hidden layer
    num_classes = 10     # Number of output classes (0-9 digits)
    
    # Initialize the model
    model = MLP(input_size, hidden_size, num_classes)
    
    print(model)
    
    • 因為Pytorch會自動幫我們處理好反向傳播的部分,所以在建立自己模型時的關鍵就是需要把正向傳播的過程寫好,也就是上面程式碼中def forward(self, x):的部分,正向傳播需要明確寫出模型中的每一層訊號要如何傳遞到下一層,這樣才能讓Pytorch建立計算圖,替我們處理反向傳播的運算。

二、訓練你的模型(使用梯度下降法)

  • 在建立好模型之後,我們會利用反向傳播(梯度下降法)來訓練模型,以下是範例:
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

# Define the MLP model
class MLP(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

# Hyperparameters
input_size = 28 * 28  # MNIST images are 28x28 pixels
hidden_size = 128    # Number of neurons in the hidden layer
num_classes = 10     # Number of output classes (0-9 digits)
learning_rate = 0.001
batch_size = 64
num_epochs = 10

# Load MNIST dataset and apply transformations
transform = transforms.Compose([transforms.ToTensor(), transforms.Resize((32,32)),transforms.Normalize((0.5,), (0.5,))])

train_dataset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform, download=True)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)

# Initialize the model
model = MLP(input_size, hidden_size, num_classes)

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# Training loop
total_step = len(train_loader)
for epoch in range(num_epochs): # 總共需要跑完幾次全部的訓練資料

    ############## 跑完所有訓練資料一次 ###############
    for i, (images, labels) in enumerate(train_loader):

        # Forward pass
        outputs = model(images)
        loss = criterion(outputs, labels)

        # Backward pass and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

  • 上面有一些專有名次,這邊簡單的定義一下:Epoch,一個Epoch指的是跑完所有訓練資料一次,所以上面的10指的是需要訓練所有資料總共10次;超參數(Hyperparameters),指的是人為控制的參數(相較於模型自動更新的參數:權重),像是每一批資料共有幾筆就是由batch_size這個超參數控制,還有梯度下降時,每一步需要走多遠則是由learning_rate這個參數控制;optimizer是用來協助反向傳播的工具,雖然我們都知道權重的更新是利用梯度下降演算法,但是不同的optimizer會基於梯度下降這個概念,使用不同的更新方式,主要的差別在於學習的速度,以及最後可以更新到的位置,這個部分有許多的研究在探討,礙於篇幅問題我們今天不會深入討論,或許之後有機會可以好好聊聊。
  • 上面的程式碼主要有幾個重點:建立模型、包裝資料集(包裝成一批一批的)、選擇損失函數(衡量輸出結果與預期結果的差異有多少)與optimizer,以及反向傳播的更新。前面幾個在之前的系列中都有討論到,現在,讓我們聚焦在最後一個關鍵:反向傳播的更新。
  • 反向傳播共有如下三個步驟,因為我們是藉由與optimizer這個工具更新的,所以在每次要使用他之前,需要先確保裡面的所有梯度是歸零的,這樣才不會重複計算梯度。接著,我們利用loss.backward()這個指令,使用Pytorch中的動態計算圖計算出loss對所有權重的梯度,最後,使用optimizer.step()這個指令,利用梯度下降法來更新所有參數。
optimizer.zero_grad()
loss.backward()
optimizer.step()

三、總結

  • 今天的內容中,我們主要討論了建立模型的兩種方式(預訓練模型或是從頭搭建),以及如何使用optimizer訓練我們建立出來的模型。這些內容不是絕對的,裡面有很多東西可以替換,例如,我可以建立一個大型的模型,其中的某些部份使用預訓練模型,其他部分從頭搭建,這也是很常見的操作。今天只是介紹很基礎的部分,比較複雜的內容會在之後搭配理論介紹一起討論。

上一篇
Pytorch實戰(一)--準備資料集(Dataset, DataLoader, transforms...)
下一篇
內捲給我捲起來--AI中的捲積運算
系列文
AI白話文運動系列之「A!給我那張Image!」30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言