CIFAR10 Dataset - 使用 Pytorch 搭建 CNN + 啟用 GPU + 結果展示至 TensorBoard
前言
最近選了一堂AI課程,這是第三個作業,主要參考以下網站:
- 教授如何使用 Pytorch 搭建 CNN:Pytorch Tutorial
- 教授如何使用 TensorBoard:Pytorch TensorBoard Tutorial
- 在 CoLabe 使用 TensorBoard 教學:TensorBoard in CoLabe Tutorial
本篇的主要目的是理解 CNN,並試圖搭建更深層的 Network,並使用GPU加快效率,最後將結果 Loss 與 猜錯的結果 顯示在 TensorBoard 上。
環境設置與作業要求
環境設置:
- Python 3.10.9
- Pytorch 2.0.1
作業要求
Task:
- 先建立一個CNN:Train the same network as in the PyTorch CNN tutorial.
- 建立出CNN滿足以下要求:Change now the network architecture as follows and train the network:
- Conv layer with 3x3 kernel and depth = 8, ReLu activation
- Conv layer with 3x3 kernel and depth = 16, ReLu activation
- Max pooling with 2x2 kernel
- Conv layer with 3x3 kernel and depth = 32, ReLu activation
- Conv layer with 3x3 kernel and depth = 64, ReLu activation
- Max pooling with 2x2 kernel
- Fully connected with 4096 nodes, ReLu activation
- Fully connected with 1000 nodes, ReLu activation
- Fully connected with 10 nodes, no activation
- 使用GPU並比較CPU結果:Run the training on the GPU and compare the training time to CPU.
- 把 Trainning Loss 放到 Tensorboard: Log the training loss in tensorboard.
- 修改表示正確的標準為只要答案在前三者output 的prediction中,就視為正確:Change the test metric as follows: A prediction is considered „correct“ if the true label is within the top three outputs of the network. Print the accuracy on the test data (with respect to this new definition).
- 雖機抽取五個例子是猜錯的,並放到tensorboard中:Randomly take 5 examples on which the network was wrong on the test data (according to the new definition of correct) and plot them to tensorboard together
with the true label. - 在 notebook 上顯示 tensorBoard:Show the tensor board widget at the end of your notebook.
- Bonus: See if you can get better by using a deeper network (or another architecture).
前置準備
- 先載入必要的套件
1 | import torch |
- 下載訓練和測試用的 Dataset 到當前文件中所在的資料夾中建立
/data
資料夾。為了做歸一化,把均值設定為 0.5 標準差設定為 0.5,表示圖像的範圍在 [0, 1] 之間,變成 [-1, 1] 之間。
1 | # 定義圖像轉換,將圖像轉換成張量並進行歸一化 |
Task 1+2 建立出 CNN
- 先建立一個CNN:Train the same network as in the PyTorch CNN tutorial.
- 建立出CNN滿足以下要求:Change now the network architecture as follows and train the network.
建立 CNN
Task 2. 建立出CNN滿足以下要求:Change now the network architecture as follows and train the network:
- Conv layer with 3x3 kernel and depth = 8, ReLu activation
- Conv layer with 3x3 kernel and depth = 16, ReLu activation
- Max pooling with 2x2 kernel
- Conv layer with 3x3 kernel and depth = 32, ReLu activation
- Conv layer with 3x3 kernel and depth = 64, ReLu activation
- Max pooling with 2x2 kernel
- Fully connected with 4096 nodes, ReLu activation
- Fully connected with 1000 nodes, ReLu activation
- Fully connected with 10 nodes, no activation
1 | import torch.nn as nn |
Task 3 + 4 GPU and loss on tensorBoard
- 使用GPU並比較CPU結果:Run the training on the GPU and compare the training time to CPU.
- 把 Trainning Loss 放到 Tensorboard: Log the training loss in tensorboard.
使用 GPU 加速 Network
因為我是使用mac,因此輸入mps
,但如果你是 windows 系統,請輸入 cuda
。
初始化function and optimizer
1 | # device = torch.device("cuda" if torch.backends.mps.is_available() else "cpu") |
建立訓練模型
開始撰寫訓練模型,並且把結果寫到 tensorBoard 上。
1 | start_time = time.time() |
結果如下圖
1 | [1, 3600] loss: 1.977 time elapsed: 1 min |
然後可以再寫一個 cpu 比較一下時間
1 | # Use CPU |
訓練結果儲存
我目前是先把模型儲存在 ./model/cifar_net.pth
,之後再把它讀出來,下次就不用重新訓練了
1 | PATH = './model/cifar_net.pth' |
使用 Test Data 評估模型
Task 5. 修改表示正確的標準為只要答案在前三者output 的prediction中,就視為正確:Change the test metric as follows: A prediction is considered „correct“ if the true label is within the top three outputs of the network. Print the accuracy on the test data (with respect to this new definition).
根據作業要求,要做以下事情:
- TODO 1 調整對準確率的定義,只要答案在前三者output 的prediction中,就視為正確。
- TODO 2 列印出準確率,這邊我列印出 “每個類別” 的準確率 和 "整個準確率“。
- TODO 3 因為他要把錯誤的圖片、輸出和標籤記錄下來,因此我們要先把它們記錄下來,之後隨機選五個錯誤的會使用到。
1 | correct = 0 |
結果長這樣
1 | Predicted: tensor([3, 5, 2]) Actual: 3 Correct: True |
列印出準確率
現在就可以列印出準確率了,我們可以看到準確率是 0.1,因為我們只有 10 個類別,所以隨機猜的準確率就是 0.1。
1 | print(f'Accuracy on test data (top-3): {100 * accuracy:.2f}%') |
結果會如下:
1 | Accuracy on test data (top-3): 91.60% |
Task 6 Random 5 errors img
Task 6. 雖機抽取五個例子是猜錯的,並放到tensorboard中:Randomly take 5 examples on which the network was wrong on the test data (according to the new definition of correct) and plot them to tensorboard together
with the true label.
設定圖片轉換函式
為了後續可以把圖片印出來,我們需要製作一個顯示圖片用的function,而因為 torchvision 資料集的輸出是範圍 [0, 1] 的 PILImage 影像。我們將它們轉換為歸一化範圍 [-1, 1] 的張量。如果我們要把圖片轉換顯示出來,我們必須進行反歸一化,也就是把歸一化後的 [-1, 1] 變回去 [0, 1],所以我們可以透過 達成。
1 | # functions to show an image |
隨機選擇 5 個錯誤
我們剛剛有收集好所有錯誤的 images 還有 predicts 跟 labels,依據題目要求我們需要從中選出 5 個錯誤的 images,並且把它們印出來。
1 | def plot_classes_preds(all_errors): |
會如下圖
把圖片放到 tensorBoard
1 | # 放到 tensorBoard |
Task 7 在 notebook 上顯示 tensorBoard
Task 7. 在 notebook 上顯示 tensorBoard:Show the tensor board widget at the end of your notebook.
1 | # 在 notebook 上顯示 tensorBoard |
補充
歸一化 vs 標準化
歸一化 vs 標準化 差異?
歸一化 (Normalization)
:將數據按比例縮放,使之落入一個小的特定區間,例如 [0, 1] 或 [-1, 1]。- 公式:
標準化 (Standardization)
:將數據按比例縮放,使之落入平均值為 0,方差為 1 的分佈中,因此極端值是可以不在[0, 1]的區間。- 公式:
這兩者的共同標準?
- 都是對某個特徵(column)進行縮放(scaling)而不是對某個樣本的特徵向量(row)進行縮放。
為什麼要做歸一化?
- 提高精準度:在機器學習算法的目標函數,許多學習算法中目標函數的基礎都是假設所有的特徵都是零均值並且具有同一階數上的平方差。如果某個特徵的平方差比其他特徵大幾個數量級,那麼它就會在學習算法中佔據主導位置,導致學習器並不能像我們說期望的那樣,從其他特徵中學習。因此,歸一化是讓不同維度之間的特徵在數值上有一定比較性,可以大大提高分類器的準確性。
- 提升收斂速度:經過歸一化後,最優解的尋優過程明顯會變得平緩,更容易正確的收斂到最優解。
dim ?
dim 參數的不同設置,它決定了在哪個維度上進行排名和獲取最大值。
讓我們透過一個範例來說明它們之間的差異:
- 如果設定 dim=0 就會是看整個 column 的最大值
- 如果設定 dim=1 就會是看整個 row 的最大值。
1 | import torch |
1 | Output tensor: |