Pytorch QuickStart

fhyu發表於2024-05-14

1. 配環境

主要需要torchtorchvision這兩個包
官網下載torch-1.13.0+cpu-cp39-cp39-win_amd64.whltorchvision-0.10.0%2Bcpu-cp39-cp39-win_amd64.whl,將其匯入Python直譯器Anaconda的Scripts資料夾下,命令列輸入pip install torch-1.13.0+cpu-cp39-cp39-win_amd64.whlpip install torchvision-0.10.0%2Bcpu-cp39-cp39-win_amd64.whl

2. 導包

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

3. 下載資料

## 下載資料集
training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
)

## 下載測試集
test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor(),
)

4. 建立資料載入器

batch_size = 64

train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)

for X, y in test_dataloader:
    # N = batch_size 即批次大小
    # C = Channels 即通道數 (R, G, B)
    # H, W 為高寬
    print(f"Shape of X [N, C, H, W]: {X.shape}")
    print(f"Shape of y: {y.shape} {y.dtype}")
    break

5. 建立模型

## 使用gpu or cpu 來訓練
device = (
    "cuda"
    if torch.cuda.is_available()
    else "cpu"
)
print(f"Using {device} device")

## 定義模型類
class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        ## self.flatten = nn.Flatten() 是一個將輸入展平的層,用於將
        ## 輸入的影像資料展平為一維向量。對於 MNIST 資料集中的影像,其
        ## 大小為 28x28,經過展平層後,輸入的大小變為 784。
        self.flatten = nn.Flatten()
        ## self.linear_relu_stack 是一個包含多個線性層和啟用函式 ReLU 
        ## 的序列(nn.Sequential)。這個序列由三個線性層組成,分別是輸入
        ## 層到隱藏層的線性層、隱藏層到隱藏層的線性層和隱藏層到輸出層的線
        ## 性層。這些線性層透過 nn.Linear 定義,指定輸入和輸出的維度。激
        ## 活函式 ReLU 在每個線性層之後被應用。
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28 * 28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10)
        )
    ## 在 forward 方法中,首先將輸入資料 x 透過 self.flatten 層展平為一
    ## 維向量。然後將展平後的資料傳入 self.linear_relu_stack 序列,得到
    ## 輸出 logits。
    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork().to(device)
print(model)

6. 訓練模型

## 定義損失函式和最佳化器
## loss_fn = nn.CrossEntropyLoss() 建立了一個交叉熵損失函式的例項。交叉
## 熵損失函式通常用於多分類問題,對於每個樣本,它計算模型的輸出與真實標籤之
## 間的交叉熵損失。在這裡,我們的模型輸出是一個包含對每個類別的預測機率的張
## 量,而真實標籤是類別的索引。損失函式會根據這些預測機率和真實標籤計算損失值。
loss_fn = nn.CrossEntropyLoss()
## optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) 建立了一
## 個隨機梯度下降(SGD)最佳化器的例項。最佳化器用於更新模型的引數,以最小化損
## 失函式。在這裡,我們將模型的引數傳遞給最佳化器,透過 model.parameters() 
## 獲取模型的可學習引數。lr=1e-3 指定了學習率,它控制每次引數更新的步長。
## 學習率越大,引數更新得越快,但可能會導致不穩定的訓練過程;學習率越小,
## 引數更新得越慢,但可能需要更多的訓練時間。
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)

## 定義訓練過程
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    model.train()
    for batch, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device)

        ## 計算預測誤差
        pred = model(X)
        loss = loss_fn(pred, y)

        ## 反向傳播
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

        if batch % 100 == 0:
            loss, current = loss.item(), (batch + 1) * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")

7. 測試模型

## 定義測試過程
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X, y = X.to(device), y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

8. 多次迭代訓練

pochs = 5
for t in range(epochs):
    print(f"Epoch {t + 1}\n-------------------------------")
    train(train_dataloader, model, loss_fn, optimizer)
    test(test_dataloader, model, loss_fn)
print("over")

9. 儲存和載入模型

## 儲存訓練模型
torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")

## 載入模型
model = NeuralNetwork().to(device)
model.load_state_dict(torch.load("model.pth"))

10. 測試效果

classes = [
    "T-shirt/top",
    "Trouser",
    "Pullover",
    "Dress",
    "Coat",
    "Sandal",
    "Shirt",
    "Sneaker",
    "Bag",
    "Ankle boot",
]

model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
    x = x.to(device)
    pred = model(x)
    predicted, actual = classes[pred[0].argmax(0)], classes[y]
    print(f'Predicted: "{predicted}", Actual: "{actual}"')

相關文章