1 環境配置
參考鏈接
2. dir 和 help函數
dir():用于查看某一模塊函數的方法
help(): 用于查看某方法的使用方法
3. dataset類實戰
利用Image對象打開圖片,利用os模塊的地址拼接組成圖片路徑
當我們用方括號訪問元素對象時,實際上是調用了這個對象的__getitem__方法
from torch.utils.data import Dataset
from PIL import Image
import osclass MyData(Dataset):# 初始化,根目錄的相對地址和標簽labeldef __init__(self,root_dir,label_dir):self.root_dir = root_dirself.label_dir = label_dirself.path = os.path.join(self.root_dir,self.label_dir) # 拼接獲得路徑self.img_path = os.listdir(self.path) # 將對應路徑下的元素名轉換為列表# 當我們用方括號訪問元素對象時,實際上是調用了這個對象的__getitem__方法def __getitem__(self, index): # 傳入下標,獲取對應圖片img_name = self.img_path[index] # 從元素名的列表獲取需要的元素名# 拼接所需圖片的路徑img_item_path = os.path.join(self.root_dir,self.label_dir,img_name)img = Image.open(img_item_path) # 根據路徑獲得圖片對象label = self.label_dirreturn img,labeldef __len__(self): # 獲取類中元素的數量return len(self.img_path)root_dir = "E:\\pythonProject\\dataset\\hymenoptera_data\\train"
ants_label_dir = "ants"
bees_label_dir = "bees"
ants_dataset = MyData(root_dir,ants_label_dir)
bees_dataset = MyData(root_dir,bees_label_dir)# 整體數據集可以使用兩個數據集相加
train_dataset = ants_dataset + bees_dataset
然后可以數據集圖片對象進行操作
4.TensorBoard的使用(一)
創建SummaryWriter實例,并生成一個圖像,保存與當前路徑下的 ”logs”文件夾中
SummaryWriter是PyTorch中的一個工具,用于將模型訓練過程中的日志保存到TensorBoard中。可以通過使用SummaryWriter的add_scalar()方法來保存損失函數、準確率等標量信息,使用add_histogram()方法來保存權重、梯度等張量信息,使用add_image()方法來保存圖像信息等。
from torch.utils.tensorboard import SummaryWriter# 傳入某一文件夾的路徑,默認為當前路徑下的文件夾
writer = SummaryWriter("logs")
for i in range(10000):# 參數1:tag(圖表的名稱/label) , 參數2:y軸的數值,參數3:x軸的數值writer.add_scalar("y = x", i ,i)
writer.close()
在對應虛擬環境的終端啟動TensorBoard: logdir = 保存對應圖像的文件夾名;port為打開的端口號
結果:
5. Tensorboard的使用(二)
使用numpy格式,添加文件圖片。
numpy格式有兩種:opencv打開文件和使用numpy直接格式轉換
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image# 傳入某一文件夾的路徑,默認為當前路徑下的文件夾
writer = SummaryWriter("logs")
img_path = "dataset/hymenoptera_data/train/bees/16838648_415acd9e3f.jpg"
img = Image.open(img_path) # img 為PIL的jpeg類型
img_array = np.array(img) # 將img轉換為numpy類型
# numpy的類型的方法二 是用opencv打開# global—step 為步驟順序,dataformats 為 數據格式
writer.add_image("test",img_array,1,dataformats='HWC')for i in range(100):# 參數1:tag(圖表的名稱/label) , 參數2:y軸的數值,參數3:x軸的數值writer.add_scalar("y = x", i ,i)
writer.close()
6. Transfroms的使用(一)
from torchvision import transforms
from PIL import Image# transforms如何使用(python)
img_path = "dataset/hymenoptera_data/train/ants/0013035.jpg"
img = Image.open(img_path) # 打開文件,得到一個圖片類的實例# 獲取一個ToTensor實例
tensor_trans = transforms.ToTensor()
# 由于存在__call__方法,調用該實例,調用該方法
# 由圖片實例轉換為 tensor類型
tensor_img = tensor_trans(img)print(tensor_img)
結果:
注: call 是 Python 中一個魔術方法(magic method),它用于定義對象的函數調用行為。換句話說,當你嘗試調用一個具有 call 方法的對象時,Python 會自動調用該方法。
ToTensor類的__call__方法:
7. Transforms的使用(二)
將圖片轉換為tensor對象,再將該對象利用tensorboard的SummaryWriter打開。
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from PIL import Image# transforms如何使用(python)
img_path = "dataset/hymenoptera_data/train/ants/0013035.jpg"
img = Image.open(img_path) # 打開文件,得到一個圖片類的實例# 獲取一個ToTensor實例
tensor_trans = transforms.ToTensor()
# 由于存在__call__方法,調用該實例,調用該方法
# 由圖片實例轉換為 tensor類型
tensor_img = tensor_trans(img)writer = SummaryWriter("logs")
# 參數 : self, tag, img_tensor, global_step=None, walltime=None, dataformats="CHW"
writer.add_image("Tensor_img",tensor_img) # 保存圖像信息writer.close()
啟動tensorboard:
結果:
8.常見的Transform(一)
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("images/123.jpg")# ToTensor,轉換后張量的范圍均為0-1
trans_totensor = transforms.ToTensor() # 創建ToTensor實例
img_tensor = trans_totensor(img) #調用內置__call__方法
writer.add_image("ToTensor",img_tensor)# normalize 歸一化
# 創建Normalize實例 ,輸入分別為 均值 和 標準差
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
img_norm = trans_norm(img_tensor) # 其父類具有__call__方法,img_norm為tensor類型
writer.add_image("normalize", img_norm)
writer.close()
歸一化會改變tensor的數據的范圍,img_tensor中的值為[0,1] ,而使用標準差與均值均為0.5的歸一化后,其值的范圍變為[-1,1]。若標準差與均值改變,則范圍也會改變
運行結果:
9. 常見的Transform(二)
(1)Resize
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("images/321.jpg")# ToTensor,轉換后張量的范圍均為0-1
trans_totensor = transforms.ToTensor() # 創建ToTensor實例
img_tensor = trans_totensor(img) #調用內置__call__方法
writer.add_image("ToTensor",img_tensor)# normalize 歸一化
# 創建Normalize實例 ,輸入分別為 均值 和 標準差
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
img_norm = trans_norm(img_tensor) # 其父類具有__call__方法,img_norm為tensor類型
writer.add_image("normalize", img_norm)
writer.close()# Resize
trans_resize = transforms.Resize([256,256]) # 傳入要縮放的長和寬的列表
img_resize = trans_resize(img) # 傳入一個PIL數據類型,返回值也為PIL類型
img_resize_tensor = trans_totensor(img_resize) # 轉換為tensor類型
writer.add_image("Resize",img_resize_tensor,0)# Resize 寫法2,使用compose,傳入transform的列表,表示要進行的transform的操作
trans_resize2 = transforms.Resize(256) # 等比縮放
trans_compose = transforms.Compose([trans_resize2,trans_totensor]) # 先改變大小,再轉換為tensor
img_resize_tensor2 = trans_compose(img)
writer.add_image("Resize",img_resize_tensor2,1)
運行結果:
(2) RandomCrop:隨即裁剪
# RandomCrop 隨機裁剪,如果輸入一個值n,則會減為x*x;若輸入兩個值,則裁剪為x*y
trans_randowcrop = transforms.RandomCrop(256)
trans_compose2 = transforms.Compose([trans_randowcrop,trans_totensor])
for i in range(10): # 隨機裁剪十次img_randomcrop = trans_compose2(img)writer.add_image("RandomCrop",img_randomcrop,i)writer.close()
運行結果:
10. torchvision中的數據集使用
數據集常用的參數:
import torchvision
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter# 自定義使用的transform
dataset_transforms = transforms.Compose([transforms.ToTensor() # 轉化為tensor
])# 數據集的路徑,是否為訓練數據集,使用的transform ,是否需要下載
train_set = torchvision.datasets.CIFAR10("./dataset1",train=True,transform=dataset_transforms,download=True)
test_set = torchvision.datasets.CIFAR10("./dataset1",train=False,transform=dataset_transforms,download=True)writer = SummaryWriter("logs")
for i in range(10):img, target = test_set[i] # img為圖片的tensor類型writer.add_image("test_set",img, i)
writer.close()
運行結果:
11. DataLoader的使用
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformstest_set = torchvision.datasets.CIFAR10("./dataset1",train=False,transform=transforms.ToTensor(),download=True)# batch_size: 批大小, shuffle表示是否打亂(一個epoch打亂一次),num_workers表示多進程數(0表示主進程進行)
# drop_last表示當數據總數與批大小不成比例,剩余不夠一批的數據是否舍棄
test_loader = DataLoader(test_set,batch_size=64,shuffle=True,num_workers=0,drop_last=False)writer = SummaryWriter("dataload")for epoch in range(2): # epoch的數量設置為2step = 0for data in test_loader:imgs, targets = data # imgs 是batch(一批)的圖片張量# 注意是add_images 不是 add_imagewriter.add_images(f"Epoch:{epoch}",imgs, step)step += 1writer.close()
運行結果:
12. nn.Module的基本使用
import torch
from torch import nn
class Test(nn.Module):def __init__(self):super().__init__()# 正向傳播def forward(self, x):out = x + 1return outtest = Test()
x = torch.tensor(2.0)
# 使用實例傳參會調用__call__函數,在nn.Module下會自動調用forward方法
print(test(x)) # 輸出3
13. 神經網路-卷積層
卷積層stride默認為1.而后面池化層的stride默認為窗口長/寬。而卷積層的濾波器的初始值是隨機值(在一定初始化方法下的隨機,例如:Kaiming初始化和Xavier初始化)
卷積層作用: 從輸入數據中提取特征,形成特征圖
池化層作用: 對特征圖進行降維處理
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterclass MyConv(nn.Module):def __init__(self):super().__init__()self.conv2 = nn.Conv2d(3,6,3)def forward(self, x):# 使用一個2d卷積,輸入通道數為3,輸出通道數為6,濾波器為3*3x = self.conv2(x)return xtest_data = torchvision.datasets.CIFAR10("./dataset1",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataLoader1 = DataLoader(test_data,batch_size=64)
writer = SummaryWriter("logs")myconv = MyConv()step = 0
for data in dataLoader1:imgs, targets = data # img.shape = 64,3,32,32writer.add_images("imgs",imgs,step)out = myconv(imgs) # out.shape = 64,6,30,30,不能直接被識別為圖像# 因此化為兩個三通道圖片out = torch.reshape(out,(-1,3,30,30))writer.add_images("out",out,step)step += 1writer.close()
結果:
14. 最大池化層的使用
import torchvision.datasets
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterclass MyMaxpool(nn.Module):def __init__(self):super().__init__()# ceil_mode表示是否保存 當池化窗口不滿時,窗口中的最大值self.maxpool = nn.MaxPool2d(3,ceil_mode=True)def forward(self, x):x = self.maxpool(x)return xtest_data = torchvision.datasets.CIFAR10("./dataset1",train=False,transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(test_data, batch_size=64)
writer = SummaryWriter("logs_maxpool")mymaxpool = MyMaxpool()step = 0
for data in dataloader:imgs, targets = datawriter.add_images("imgs",imgs, step)out = mymaxpool(imgs)writer.add_images("out",out,step)step += 1writer.close()
執行結果:
15. 非線性激活
非線性變換的目的: 為網絡引入非線性特征
激活函數作用: 將神經網絡的線性模型變為非線性的
ReLU中,inplace的用法
ReLU與Sigmold的簡單使用
import torchvision.datasets
from torch import nn
from torch.nn import ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterclass MyRelu(nn.Module):def __init__(self):super().__init__()# inplace 表示是否用輸入的變量接收輸出;若為false,則input不變,存在返回值outputself.relu = ReLU(inplace=False)self.sigmoid = Sigmoid()def forward(self, x):x = self.sigmoid(x)return x;writer = SummaryWriter("logs_relu")
test_data = torchvision.datasets.CIFAR10("./dataset1",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataLoader1 = DataLoader(test_data,batch_size=64)myrelu = MyRelu()step = 0
for data in dataLoader1:imgs, targets = datawriter.add_images("imgs",imgs,step)out = myrelu(imgs)writer.add_images("out",out,step)writer.close()
運行結果:
16. 線性層及其他層的介紹
線性層,也就等同于全連接層,將一個多維數據拉伸映射為一維
17. 搭建小實戰Sequential的使用
需要分別計算每個卷積核的padding和stride(卷積后H,W不變,一般padding=(5卷積核寬度-1)的一半),利用公式計算,dilation默認為1。
import torch
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linearclass MySeq(nn.Module):def __init__(self):super().__init__()self.module = Sequential(# 卷積過后尺寸不變, padding = (kernel_size - 1) / 2Conv2d(3,32,5,padding=2),MaxPool2d(2),Conv2d(32,32,5,padding=2),MaxPool2d(2),Conv2d(32,64,5,padding=2),MaxPool2d(2), # 目前為64*4*4,需flatten成線性的Flatten(), # => 1024Linear(1024,64), # 1024=>64Linear(64,10),# 64=> 10)def forward(self, x):x = self.module(x)return xmyseq = MySeq()
x = torch.ones((64,3,32,32)) # 訓練后 batch_size 不變
print(myseq(x).shape)
18. 損失函數和反向傳播
交叉熵:
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoaderdataset = torchvision.datasets.CIFAR10("dataset1",False,torchvision.transforms.ToTensor(),download=True)class MySeq(nn.Module):def __init__(self):super().__init__()self.module = Sequential(# 卷積過后尺寸不變, padding = (kernel_size - 1) / 2Conv2d(3,32,5,padding=2),MaxPool2d(2),Conv2d(32,32,5,padding=2),MaxPool2d(2),Conv2d(32,64,5,padding=2),MaxPool2d(2), # 目前為64*4*4,需flatten成線性的Flatten(), # => 1024Linear(1024,64), # 1024=>64Linear(64,10),# 64=> 10)def forward(self, x):x = self.module(x)return xdataloader = DataLoader(dataset,batch_size=1)loss = nn.CrossEntropyLoss() # 交叉熵損失函數
myseq = MySeq()for data in dataloader:imgs, targets = dataoutputs = myseq(imgs)result_loss = loss(outputs,targets)result_loss.backward() # 反向傳播# loss樣例
x = torch.tensor([0.1,0.2,0.3])
x = torch.reshape(x,(1,3))
target = torch.tensor([1])
print(loss(x,target))
運行結果: 與預想一致
19. 優化器
優化器的作用:
PyTorch的優化器在深度學習模型的訓練過程中起著至關重要的作用。它們的主要功能是根據計算得到的梯度信息來更新模型的參數,以最小化損失函數。以下是PyTorch優化器的主要作用:
- 參數更新:優化器負責根據計算得到的梯度信息更新模型的參數(包括權值)。梯度表示了損失函數關于每個參數的變化率,通過將梯度與學習率相乘,優化器可以決定參數在每個訓練步驟中的更新幅度。
- 學習率調整:優化器還可以控制學習率的調整。學習率決定了參數更新的步長,過大或過小的學習率都可能導致訓練不穩定或收斂速度緩慢。一些優化器提供了自適應調整學習率的功能,根據訓練進程或其他因素自動調整學習率的大小。
- 參數優化算法:優化器實現了不同的參數優化算法,如隨機梯度下降(SGD)、Adam、Adagrad、RMSprop等。這些算法在計算參數更新時使用不同的策略和規則,以提高訓練效果和收斂速度。
- 動量:一些優化器支持動量的概念,通過引入動量項來加速參數更新。動量可以幫助優化器在參數空間中更快地搜索,并有助于克服局部最小值的困境。
總而言之,PyTorch的優化器在深度學習模型的訓練中起著關鍵的作用,負責根據梯度信息更新模型參數、調整學習率,并利用不同的優化算法和技術來提高訓練效果和收斂速度。選擇合適的優化器要根據具體的問題和模型特性進行調整和實驗
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.optim import SGD
from torch.utils.data import DataLoaderdataset = torchvision.datasets.CIFAR10("dataset1",False,torchvision.transforms.ToTensor(),download=True)class MySeq(nn.Module):def __init__(self):super().__init__()self.module = Sequential(# 卷積過后尺寸不變, padding = (kernel_size - 1) / 2Conv2d(3,32,5,padding=2),MaxPool2d(2),Conv2d(32,32,5,padding=2),MaxPool2d(2),Conv2d(32,64,5,padding=2),MaxPool2d(2), # 目前為64*4*4,需flatten成線性的Flatten(), # => 1024Linear(1024,64), # 1024=>64Linear(64,10),# 64=> 10)def forward(self, x):x = self.module(x)return xdataloader = DataLoader(dataset,batch_size=1)loss = nn.CrossEntropyLoss() # 交叉熵損失函數
myseq = MySeq()optim = SGD(myseq.parameters(), lr=0.01)for epoch in range(20):epoch_loss = 0.0for data in dataloader:imgs, targets = dataoutputs = myseq(imgs)result_loss = loss(outputs,targets)optim.zero_grad() # 將梯度清零result_loss.backward() # 反向傳播,獲取梯度optim.step() # 利用優化器優化參數epoch_loss = epoch_loss + result_lossprint(epoch_loss) # 輸出一個epoch總的損失率
20. 現用模型的使用及修改
from torch import nn
from torchvision.models import vgg16vgg16_false = vgg16()
# 遷移學習
# 1. 在最后添加一個線性層,將1024=》10
# vgg16_false.classifier.add_module('add_linear',nn.Linear(1000,10))
print(vgg16_false)
# 2. 修改最后一個線性層
vgg16_false.classifier[6] = nn.Linear(4096,10)
print(vgg16_false)
21. 模型保存和模型加載
模型保存
import torch
import torchvision.modelsvgg16 = torchvision.models.vgg16()# 保存方式1:保存整個模型(不推薦)
torch.save(vgg16,"vgg16_method1.pth")# 保存方式2:僅保存參數(官方推薦)
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
模型加載
import torch
import torchvision# 加載保存方式1,整個模型
model = torch.load("vgg16_method1.pth")
# print(model)# 加載保存方式2,導入參數
# torch.load("vgg16_method2.pth") 導入模型的參數
vgg16_2 = torchvision.models.vgg16()
vgg16_2.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16_2)
運行結果:
22. 完整的模型訓練套路(一)
訓練的代碼:
import torchvision.datasets
from torch.nn import CrossEntropyLoss
from torch.optim import SGD
from torch.utils.data import DataLoader
from torchvision import transformsfrom model import MyModeldataset_train = torchvision.datasets.CIFAR10("dataset1",True,transforms.ToTensor(),download=True)
dataset_test = torchvision.datasets.CIFAR10("dataset1",False,transforms.ToTensor(),download=True)
train_dataloader = DataLoader(dataset_train,batch_size=64)
test_dataloader = DataLoader(dataset_test,batch_size=64)# length長度
train_length = len(dataset_train)
test_length = len(dataset_test)
print(f"訓練集的長度:{train_length}")
print(f"測試集的長度:{test_length}")# 創建網絡模型
myModel = MyModel()# 損失函數
loss_func = CrossEntropyLoss()# 優化器
learning_rate = 1e-2
optimizer = SGD(myModel.parameters(), lr=learning_rate)# 設置訓練網絡的一些參數
# 記錄訓練的總次數(訓練一個batch算一次)
total_train_num = 0
# 記錄測試的總次數
total_test_num = 0
# 訓練的輪次
epoch = 10for i in range(10):print(f"-----第{i+1}輪訓練開始-----")for data in train_dataloader:imgs, targets = dataoutputs = myModel(imgs)loss = loss_func(outputs, targets) # 輸入預測結果和真實結果,得到損失率# 優化器優化模型optimizer.zero_grad() # 將梯度清零loss.backward() # 反向傳播計算梯度optimizer.step() # 利用優化器優化參數total_train_num = total_train_num + 1print(f"訓練次數:{total_train_num}, ;loss:{loss.item()}")
model.py
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linearclass MyModel(nn.Module):def __init__(self):super().__init__()self.module = Sequential(# 卷積過后尺寸不變, padding = (kernel_size - 1) / 2Conv2d(3,32,5,padding=2),MaxPool2d(2),Conv2d(32,32,5,padding=2),MaxPool2d(2),Conv2d(32,64,5,padding=2),MaxPool2d(2), # 目前為64*4*4,需flatten成線性的Flatten(), # => 1024Linear(1024,64), # 1024=>64Linear(64,10),# 64=> 10)def forward(self, x):x = self.module(x)return x
運行結果:
23.完整的模型訓練套路(二)
with: 上下文管理器,with語句可以自動管理上下文資源,不論是什么原因跳出with塊都能確保文件可以正確的關閉 ,以此來達到釋放資源的目的。
with torch.no_grad() : 是一個用于臨時禁用梯度計算的上下文管理器。
add_scalar: add_scalar() 用于展示標量,數
train()和eval() : 只針對某些層有用,例如drop_out層
代碼:
import torch
import torchvision.datasets
from torch.nn import CrossEntropyLoss
from torch.optim import SGD
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformsfrom model import MyModeldataset_train = torchvision.datasets.CIFAR10("dataset1",True,transforms.ToTensor(),download=True)
dataset_test = torchvision.datasets.CIFAR10("dataset1",False,transforms.ToTensor(),download=True)
train_dataloader = DataLoader(dataset_train,batch_size=64)
test_dataloader = DataLoader(dataset_test,batch_size=64)# length長度
train_length = len(dataset_train)
test_length = len(dataset_test)
print(f"訓練集的長度:{train_length}")
print(f"測試集的長度:{test_length}")# 創建網絡模型
myModel = MyModel()# 損失函數
loss_func = CrossEntropyLoss()# 優化器
learning_rate = 1e-2
optimizer = SGD(myModel.parameters(), lr=learning_rate)# 設置tensorboard可視化
writer = SummaryWriter("logs")# 設置訓練網絡的一些參數
# 記錄訓練的總次數(訓練一個batch算一次)
total_train_num = 0
# 記錄測試的總次數
total_test_num = 0
# 訓練的輪次
epoch = 10for i in range(10):print(f"-----第{i+1}輪訓練開始-----")# 訓練步驟開始myModel.train()for data in train_dataloader:imgs, targets = dataoutputs = myModel(imgs)loss = loss_func(outputs, targets) # 輸入預測結果和真實結果,得到損失率# 優化器優化模型optimizer.zero_grad() # 將梯度清零loss.backward() # 反向傳播計算梯度optimizer.step() # 利用優化器優化參數total_train_num = total_train_num + 1if total_train_num % 100 == 0:print(f"訓練次數:{total_train_num}, ;loss:{loss.item()}")# 測試步驟開始myModel.eval()total_test_loss = 0total_accuracy = 0with torch.no_grad():for data in test_dataloader:imgs, targets = dataoutputs = myModel(imgs)loss = loss_func(outputs, targets)total_test_loss = total_test_loss + loss.item() # 計算一epoch中的總損失# argmax中 0 表示列比較 1 表示行比較 => 最后得到一行accuracy = (outputs.argmax(1) == targets).sum() # 準確個數 為 輸出與目標相等數量的總和total_accuracy = total_accuracy + accuracy # 計算本輪總命中數print(f"整體測試集上的loss:{total_test_loss}")print(f"整體測試集上的準確率:{total_accuracy/test_length}")writer.add_scalar("test_loss",total_test_loss,i+1)writer.add_scalar("test_accuracy", total_accuracy/test_length, i+1)# 保存模型torch.save(myModel,f"MyModel_{i+1}.pth")print("模型已保存")writer.close()
運行結果:
24. 利用GPU訓練(一)
使用方法1:
# 創建網絡模型
myModel = MyModel()
if torch.cuda.is_available():myModel = myModel.cuda()# 損失函數
loss_func = CrossEntropyLoss()
if torch.cuda.is_available():loss_func = loss_func.cuda()
imgs, targets = data
if torch.cuda.is_available():imgs = imgs.cuda()targets = targets.cuda()
不使用GUP的時間:
使用GPU的時間:
使用GPU的方法二:
# 單顯卡中cuda:0 == cuda
# device = torch.device("cuda") 寫法1
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 常用寫法
# 創建網絡模型
myModel = MyModel()
myModel = myModel.to(device)# 損失函數
loss_func = CrossEntropyLoss()
loss_func.to(device)
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
運行結果:
25. 完整的模型驗證套路
測試的圖片:
import torch
import torchvision.transforms
from PIL import Image
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linearclass MyModel(nn.Module):def __init__(self):super().__init__()self.module = Sequential(# 卷積過后尺寸不變, padding = (kernel_size - 1) / 2Conv2d(3,32,5,padding=2),MaxPool2d(2),Conv2d(32,32,5,padding=2),MaxPool2d(2),Conv2d(32,64,5,padding=2),MaxPool2d(2), # 目前為64*4*4,需flatten成線性的Flatten(), # => 1024Linear(1024,64), # 1024=>64Linear(64,10),# 64=> 10)def forward(self, x):x = self.module(x)return ximage = Image.open("images/img_1.png")
print(image)
image = image.convert('RGB') # 將圖片轉為三通道
# 裁剪為32*32,再轉換為Tensor類型
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape) # 3,32,32# 加載訓練好的模型
# 當在cpu上運行gpu上訓練的模型時,需添加map_location參數
model = torch.load("MyModel_30_gpu.pth",map_location="cpu")
print(model)# 輸入應為 B C H W 四維
image = torch.reshape(image,(1,3,32,32))
model.eval()
with torch.no_grad():output = model(image)
print(output)
print(output.argmax(1))
運行結果:
索引與分類的對應關系:
可知識別正確