系列文章目錄
文章目錄
- 系列文章目錄
- 前言
- 一、源碼
- 1. 解決線程沖突
- 2.代碼框架
- 二、代碼詳細介紹
- 1.基礎定義
- 2. epoch 的定義
- 3. 每組圖片的訓練和模型保存
前言
??前面我們已經完成了數據集的制作,VGG 網絡的搭建,現在進行網絡模型的訓練。
一、源碼
import torch.nn as nn
import torchvision
from VggNet import VGGNet
from load_cifa10 import train_data_loader, test_data_loader
import torch.multiprocessing as mp
import torch
import multiprocessing
from torch.utils.data import DataLoaderfrom model.ClassModel import netdef main():# 訓練模型到底放在 CPU 還是GPUdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 如果cuda有效,就在GPU訓練,否則CPU訓練# 我們會對樣本遍歷20次epoch_num = 20# 學習率lr = 0.01# 正確率計算相關batch_num=0correct0 =0# 網絡定義# print("need初始化")net = VGGNet().to(device)# 定義損失函數loss,多分類問題,采用交叉熵loss_func = nn.CrossEntropyLoss()# 定義優化器optimizeroptimizer = torch.optim.Adam(net.parameters(),lr=lr)# 動態調整學習率,第一個參數是優化器,起二個參數每5個epoch后調整學習率,第三個參數調整為原來的0.9倍lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5,gamma=0.9)# 定義循環for epoch in range(epoch_num):# print("epoch is:",epoch+1)# 定義網絡訓練的過程net.train() # BatchNorm 和 dropout 會選擇相應的參數# 對數據進行遍歷for i,data in enumerate(train_data_loader):batch_num = len(train_data_loader)# 獲取輸入和標簽inputs, labels = datainputs, labels = inputs.to(device), labels.to(device) # 放到GPU上去# 拿到輸出# print("need output")outputs = net(inputs) # 這句就會調用前向傳播,在PyTorch中,當執行outputs = net(inputs)時會自動觸發前向傳播,# 這是通過nn.Module的__call__方法實現的特殊機制6。具體原理可分為三個關鍵環節:# 計算損失loss = loss_func(outputs, labels)# 定義優化器,梯度要歸零,loss反向傳播,更新參數optimizer.zero_grad()loss.backward()optimizer.step()_, predicted = torch.max(outputs.data, dim=1) # 得到一個batch的預測類別# 在cpu上面運行,當labels是普通張量時,.data屬性返回?剝離計算圖的純數值張量?(與原始張量共享內存但無梯度追蹤)correct = predicted.eq(labels.data).cpu().sum()correct=100.0*correct/len(inputs)correct0+=correct#自動更新學習率lr_scheduler.step()lr = optimizer.state_dict()['param_groups'][0]['lr']print("loss:{},acc:{}",lr,correct0/batch_num)if __name__ == '__main__':# Windows必須設置spawn,Linux/Mac自動選擇最佳方式mp.set_start_method('spawn' if torch.cuda.is_available() else 'fork')torch.multiprocessing.freeze_support()try:main()except RuntimeError as e:print(f"多進程錯誤: {str(e)}")print("降級到單進程模式...")train_data_loader = DataLoader(..., num_workers=0)main()
1. 解決線程沖突
??windows 跑代碼需要解決線程沖突的問題:需要自行定義main函數,然后把主題加在里面。當我們運行時自動調用main,就會執行下面的 if 語句,然后運行我們的代碼
if __name__ == '__main__':# Windows必須設置spawn,Linux/Mac自動選擇最佳方式mp.set_start_method('spawn' if torch.cuda.is_available() else 'fork')torch.multiprocessing.freeze_support()try:main()except RuntimeError as e:print(f"多進程錯誤: {str(e)}")print("降級到單進程模式...")train_data_loader = DataLoader(..., num_workers=0)main()
2.代碼框架
??代碼分成四個部分,第一個部分是基礎變量定義,第二個部分是循環 epoch ,第三部分是每個 batch 的處理,第四個保存模型,其中最重要的便是第三個。

二、代碼詳細介紹
1.基礎定義
# 訓練模型到底放在 CPU 還是GPUdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 如果cuda有效,就在GPU訓練,否則CPU訓練# 我們會對樣本遍歷200次epoch_num = 200# 學習率lr = 0.01# 正確率計算相關batch_num=0correct0 =0# 網絡定義# print("need初始化")net = VGGNet().to(device)# 定義損失函數loss,多分類問題,采用交叉熵loss_func = nn.CrossEntropyLoss()# 定義優化器optimizeroptimizer = torch.optim.Adam(net.parameters(),lr=lr)# 動態調整學習率,第一個參數是優化器,起二個參數每5個epoch后調整學習率,第三個參數調整為原來的0.9倍lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5,gamma=0.9)
??基礎定義最開始需要定義跑數據的設備,CPU還是GPU.這個是死的。然后定義epoch次數、學習率,至于準確率看自己的使用情況,如果每次跑完一遍數據集打印準確率也不著急定義。我在最終跑完數據才打印準確率,所以需要定義一個全局的變量。接下來便是網絡初始化,初始化的網絡加載到設備上面。在網絡搭建的時候,我們只定義了網絡的層次和前向傳播。后面的損失函數和優化器需要在訓練中進行。那么基礎定義里面需要損失函數的選擇,優化器的選擇和動態調整學習率。epoch 改成200,我的電腦跑了1h還沒出結果,現在還在等,建議別弄大了。

當然順序可以變,最好自己能記住需要的內容。
2. epoch 的定義
??epoch里面開始調用網絡,net.train()
會把網絡的參數進行初始化,BatchNorm 會自動啟用訓練模式,dropout層會全部激活,而這在測試集上不需要dropout的。后面便是每組圖片 batch的訓練行為。最后每一次處理整個數據集需要動態改變學習率,以及打印學習率的方法如下:
#自動更新學習率lr_scheduler.step()# 打印學習率lr = optimizer.state_dict()['param_groups'][0]['lr']print("學習率", lr)
3. 每組圖片的訓練和模型保存
for i,data in enumerate(train_data_loader):batch_num = len(train_data_loader)# 獲取輸入和標簽inputs, labels = datainputs, labels = inputs.to(device), labels.to(device) # 放到GPU上去# 拿到輸出# print("need output")outputs = net(inputs) # 這句就會調用前向傳播,在PyTorch中,當執行outputs = net(inputs)時會自動觸發前向傳播,# 這是通過nn.Module的__call__方法實現的特殊機制6。具體原理可分為三個關鍵環節:# 計算損失loss = loss_func(outputs, labels)# 定義優化器,梯度要歸零,loss反向傳播,更新參數optimizer.zero_grad()loss.backward()optimizer.step()_, predicted = torch.max(outputs.data, dim=1) # 得到一個batch的預測類別
??這里進行數據加載,分批次加載,此處的batch 大小是128,數量是391(用于準確率計算)。加載了數據,獲取數據的輸入和真實標簽。outputs = net(inputs)
這句對網絡傳入數據,自行前向傳播計算獲得輸出。拿到輸出后,進行損失函數計算。損失函數計算,是需要預測值和真實值的,看看偏差多少,因此傳入這兩個參數。優化器優化,開始梯度歸零,然后后向傳播,這個過程是自帶的,我們只定義了前向傳播,后向傳播優化參數后固定參數 optimizer.step()
,最后使用torch.max()
輸出最相似的標簽。過程如圖:

模型的保存就一句話:
torch.save(net.state_dict(),"./model/VGGNet.pth")