# 環境配置 安裝 pytorch 2.1.2 window 版本 > pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # Quick Start ## 引入函式庫 ```python import torch # 引入 PyTorch 函式庫 from torch import nn # 引入跟神經網路有關的函式庫 from torch.utils.data import DataLoader # 引入跟處理資料集有關的函式庫 from torchvision import datasets # 引入資料集函式庫 from torchvision.transforms import ToTensor # 引入轉換資料格式的函式庫 import matplotlib.pyplot as plt # 引入繪圖函式庫 ``` ## 下載內建的 MINST 資料集 ```python # 引入 MINST 資料集 sample,training_data 是 FashionMNIST 型態的物件 training_data = datasets.FashionMNIST( root="data", train=True, # 決定是訓練資料集 download=True, transform=ToTensor(), ) # 引入 MINST 資料集 label,test_data 是 FashionMNIST 型態的物件 test_data = datasets.FashionMNIST( root="data", train=False, # 決定是測試資料集 download=True, transform=ToTensor(), ) ``` ## 使用 DataLoader 打包資料 * DataLoader 可以幫我們打包 dataset,以更有效的載入和管理 * 功能包含了 batch 處理、打亂資料集等等 * 傳入的 dataset 須為 dataset 型態,同時可以指定 batch size (不指定的話預設為 1) ```python batch_size = 64 #在這邊設定 batch size # 創建 MINST 資料集 sample 的 DataLoader,train_dataloader 是 DataLoader 型態的物件 train_dataloader = DataLoader(training_data, batch_size=batch_size) # 創建 MINST 資料集 label 的 DataLoader,test_dataloader 是 DataLoader 型態的物件 test_dataloader = DataLoader(test_data, batch_size=batch_size) for X, y in test_dataloader: # 每次迭代中,X 是一個 batch 的 sample,y 是一個 batch 的 label print(f"Shape of X [batch size, channel , height, width]: {X.shape}") # 印出 sample 的維度 print(f"Shape of y: {y.shape}") # 印出 label 的維度 break for X, y in test_dataloader: plt.imshow(X[0][0],cmap="gray") # 展示第一個 batch 中的第一張圖片 plt.show() print("label: ",y[0]) # 印出第一個 batch 中的第一張圖片的 label break ``` ## 建立模型 * override basic model 中的 \__init__ 跟 forward 兩個 method 後即可使用 * 再疊加神經網路層的時候,更像是疊上權重及想要的 activation function,而不是像 tensorflow 一樣疊加神經元 ```python # 決定訓練用的硬體裝置 device = ( "cuda" # CUDA 是NVIDIA 研發的平行運算平台及編程模型,可利用繪圖處理單元(GPU) 的能力大幅提升運算效能 if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) print(f"Using {device} device") # 定義神經網路模型 # pytorch 的神經網路模型是繼承自 nn.Module 的,繼承並 override __init__ 和 forward 兩個 method 後即可使用 class NeuralNetwork(nn.Module): def __init__(self): # override __init__ method super().__init__() # 執行 parent class 的 constructor self.flatten = nn.Flatten() # 展平層,將資料展平成一維向量 self.linear_relu_stack = nn.Sequential( # 用 Sequential 的方式依序疊加神經網路層 nn.Linear(28*28, 512), # 定義一個全連接層,連結上一層的 28*28 個 神經元跟下一層的 512 個神經元 nn.ReLU(), # 接上一個 ReLU activation function nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 10) ) def forward(self, x): # override forward method, x 代表模型的輸入資料 x = self.flatten(x) # 讓模型的輸入資料通過剛剛定義的 self.flatten logits = self.linear_relu_stack(x) # 讓模型的輸入資料通過剛剛定義的 self.linear_relu_stack return logits model = NeuralNetwork().to(device) # 創建 NeuralNetwork 的 instance,並將模型移動至指定的裝置上 print(model) ``` ## 定義訓練模型的函式 * 需要實作訓練模型時的各種細節 (計算 loss、反向傳播等) ```python train_loss_history = [] # 儲存每個 epoch 的訓練 loss train_accuracy_history = [] # 儲存每個 epoch 的訓練 accuracy # 定義訓練模型的函式 def train(dataloader, model, loss_fn, optimizer): # 需要的參數有訓練用的資料集, 模型, 採用的損失函數, 採用的 optimizer size = len(dataloader.dataset) # 用於顯示訓練時的資訊 num_batches = len(dataloader) # 用於顯示訓練時的資訊 model.train() # 將模型設為訓練模式,以通知模型接下來的操作會更新權重 train_loss, train_correct = 0, 0 for batch, (X, y) in enumerate(dataloader): # 遍歷訓練資料集。每次迭代中,X 是一個 batch 的 sample,y 是一個 batch 的 label,batch 是當前 batch 的 index X, y = X.to(device), y.to(device) # 將資料移動至指定的裝置上 # 計算預測錯誤 pred = model(X) # 將 sample 傳給模型,得到模型當前的預測結果 loss = loss_fn(pred, y) # 計算當前模型預測結果與正確答案間的 loss train_loss += loss.item() train_correct += (pred.argmax(1) == y).type(torch.float).sum().item() # 反向傳播 loss.backward() # 將 loss 傳給模型,計算出模型中各個參數的梯度,用於更新模型中的參數 optimizer.step() # 使用剛剛計算出的梯度與 learning rate,更新模型中的參數 optimizer.zero_grad() # 將模型中參數的梯度歸零,以避免梯度累加 if batch % 100 == 0: # 每 100 個 batch 印出訓練資訊 loss, current = loss.item(), (batch + 1) * len(X) print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]") train_loss /= num_batches train_correct /= size train_loss_history.append(train_loss) train_accuracy_history.append(train_correct) ``` ## 定義測試模型的函式 * 需要實作測試模型時的各種細節 (計算 loss、計算預測正確的資料數量等) * 用於測試的資料集單純用來衡量模型,並不會影響到模型的權重 ```python test_loss_history = [] # 用於儲存每個 epochs 的測試 loss test_accuracy_history = [] # 用於儲存每個 epochs 的測試正確率 # 定義測試模型的函式 def test(dataloader, model, loss_fn): size = len(dataloader.dataset) # 用於顯示測試時的資訊 num_batches = len(dataloader) model.eval() # 將模型設為測試模式,以通知模型接下來的操作不會更新權重 test_loss, test_correct = 0, 0 # 初始化測試時的 loss 與正確率 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() # 計算當前模型預測結果與正確答案間的 loss test_correct += (pred.argmax(1) == y).type(torch.float).sum().item() # 計算當前模型預測正確的答案數量 test_loss /= num_batches # 計算平均 loss test_correct /= size # 計算正確率 print(f"Test Error: \n Accuracy: {(100*test_correct):>0.1f}%, Avg loss: {test_loss:>8f} \n") test_loss_history.append(test_loss) # 將當前的 tet loss 加入 test_loss_history 中 test_accuracy_history.append(test_correct) # 將當前的 test 正確率加入 test_accuracy_history 中 ``` ## 開始執行訓練及測試 * 呼叫剛剛定義好,用來訓練及測試的函式 ```python epochs = 5 # 決定訓練的 epochs for t in range(epochs): # 遍歷 epochs print(f"Epoch {t+1}\n-------------------------------") train(train_dataloader, model, loss_fn, optimizer) # 使用訓練資料集訓練模型 test(test_dataloader, model, loss_fn) # 使用測試資料集測試模型 print("Done!") ``` ## 分析訓練期間的 loss ```python plt.plot(train_loss_history, label='Train loss') plt.plot(test_loss_history, label='Test loss') plt.xlabel('Epoch') plt.ylabel('loss') plt.legend() plt.show() ``` ## 分析訓練期間的 accuracy ```python plt.plot(train_accuracy_history, label='Train accuracy') plt.plot(test_accuracy_history, label='Test accuracy') plt.xlabel('Epoch') plt.ylabel('accuracy') plt.legend() plt.show() ``` ## 儲存模型 * pytorch 的模型其副檔名為 .pth ```python torch.save(model.state_dict(), "saved_model/course0_model.pth") # 將模型的參數序列化並儲存至指定路徑 print("Saved PyTorch Model Successfully!") ``` ## 載入模型 ```python model = NeuralNetwork().to(device) # 創建空的模型 model.load_state_dict(torch.load("saved_model/course0_model.pth")) # 從指定路徑載入模型的參數 ``` ## 使用模型預測資料 ```python model.eval() # 將模型設為測試模式,以通知模型接下來的操作不會更新權重 with torch.no_grad(): # 在這區域中的程式碼,都不會計算梯度,以加速運算 for X, y in test_dataloader: # 這邊拿測試資料集來讓模型預測 plt.imshow(X[0][0],cmap="gray") # 展示第一個 batch 中的第一張圖片 plt.show() X, y = X.to(device), y.to(device) pred = model(X) print("predict: ",pred.argmax(1)[0]) # 印出第一個 batch 中的第一張圖片的預測結果 print("answer: ",y[0]) # 印出第一個 batch 中的第一張圖片的正確答案 break ``` ## 分析混淆矩陣 ```python from sklearn.metrics import confusion_matrix import seaborn as sn import pandas as pd import numpy as np y_pred = [] y_true = [] # iterate over test data model.eval() # 將模型設為測試模式,以通知模型接下來的操作不會更新權重 with torch.no_grad(): # 在這區域中的程式碼,都不會計算梯度,以加速運算 for X, y in test_dataloader: # 這邊拿測試資料集來讓模型預測 X, y = X.to(device), y.to(device) pred = model(X) X = (torch.max(torch.exp(pred), 1)[1]).data.cpu().numpy() y_pred.extend(X) # Save Prediction y = y.data.cpu().numpy() y_true.extend(y) # Save Truth print("橫軸: 預測結果") print("縱軸: 正確答案") # Build confusion matrix cf_matrix = confusion_matrix(y_true, y_pred) df_cm = pd.DataFrame(cf_matrix / np.sum(cf_matrix, axis=1)[:, None]) plt.figure(figsize = (10,6)) sn.heatmap(df_cm, annot=True) ``` # Tensor * Tensor 的本質跟 numpy 的 mdarray 非常像,但多了一些深度學習特化功能 * 可以在 GPU 上執行 * 微分速度快 # Datasets & DataLoaders * 基本的使用方法在 Quick Start 中有所介紹 # Transforms * 提供了許多方法,可以對資料進行預處理 (翻轉、裁切等等) * 可以提升訓練資料集的數量 # Neural Network * Pytorch 中提供了許多神經網路種類,以下介紹其使用方式