1.Le-Net5神經網絡流程回顧
Le-Net5神經網絡模型如下:(圖片來自Yann LeCun的論文)
本練習流程如下:
32323→conv1(3655)→28286→relu→maxpool(22)→14146→conv2(61655)→101016→relu→maxpool(22)→5516→view(-1,5516)→1400→fc1(400,120)→1120→relu→fc2(120,84)→1*84→relu→fc3(84,10)→softmax(10)
2.神經網絡的搭建
2.1創建神經網絡類對象
①神經網絡類對象繼承torch.nn.Module模型類
②類構造函數中設置神經網絡的conv、pool、fc屬性,其語句分別爲:
self.conv=nn.Conv2d(inchannels,outchannels,kernel_size)通道數、過濾器數量、過濾器大小,其中kernel_size可以是int數也可以是(4,3)這種模式
self.pool=nn.MaxPool2d(2,2)步長stride默認會自適應
self.fc=nn.Linear(infeatures,outfeatures)輸入特徵數,輸出特徵數
③繼承類需要覆寫forward(self,x)前向傳播方法,設置神經網絡的前向傳播流程,如下:
x=self.pool(F.relu(self.conv(x)))一層卷積、激活、池化操作的神經網絡
x=F.relu(self.fc(x))一層全連接神經網絡
代碼示例如下:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#設置卷積矩陣
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
#設置池化層
self.pool1=nn.MaxPool2d(2,2)
self.pool2=nn.MaxPool2d(2,2)
#設置全連接
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool1(F.relu(self.conv1(x)))#第一層神經網絡
x=self.pool2(F.relu(self.conv2(x)))#第二層神經網絡
x=x.view(-1,16*5*5)#矩陣塑形化爲1維網絡
x=F.relu(self.fc1(x))#第三層神經網絡,全連接1
x=F.relu(self.fc2(x))#第四層神經網絡,全連接2
x=self.fc3(x)#第五層神經網絡,全連接3
return x
2.2創建神經網絡對象、定義損失函數、梯度優化器
①神經網絡對象創建完成需要交給GPU運行
net=Net()
net.to(device)
②損失函數criterion=nn.CroseeEntropyLoss()可選用其它計算方法,其作用爲:
loss=certerion(outputs,labels)可以計算實際輸出和理想輸出之間的損失函數
③梯度優化器主要設置學習步長lr
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)此處選擇SGD,可選其它
演示代碼如下:
net=Net()#生成神經網絡對象、
net.to(device)
criterion = nn.CrossEntropyLoss()#定義損失函數
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
2.3利用訓練集訓練神經網絡
①訓練集、訓練加載器設置(此處訓練集選用CIFAR10)
trainset=torchvision.datasets.CIFAR10(root="./data",train=True,download=True,transform=transforn)
root:下載後訓練集的存儲地址,此處下載由外網下載比較慢,可以參考:https://blog.csdn.net/york1996/article/details/81780065解決
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
batch_size:沒批數據的數量
num_workers:線程數量此處設置爲2,但是必須再main線程中運行,否則報錯。參考解決:http://www.manongjc.com/article/60188.html
②訓練過程。訓練過程爲循環遍歷訓練,可以根據需要定義訓練次數,單次訓練如下:
for i, data in enumerate(trainloader,0)#enumerate爲迭代器,參數1爲迭代對象,參數2爲迭代起始值,返回值i爲索引值,data爲迭代返回對象
inputs,labels=data#提取訓練集圖片及對應標籤
inputs,labels=inputs.to(device),labels.to(device)此處必須由原變量接收,否則只會創建新對象,而不會改變原本對象,與Module模型不一樣。參考:https://blog.csdn.net/qq_27261889/article/details/86575033
outputs=net(inputs)
loss=criterion(outputs,labels)#計算損失函數
loss.backword()#反向傳播
optimizer.step#迭代優化
演示代碼如下:
for epoch in range(2):
running_loss=0.0
for i,data in enumerate(trainloader,0):
#獲取輸入
inputs,labels=data
####前面必須用原來的對象接收,不然會包類型不匹配錯誤
####原因是tensor.to()會產生一個新的tensor對象而不是改變原對象
####參考網址:https://blog.csdn.net/qq_27261889/article/details/86575033
inputs=inputs.to(device)
labels=labels.to(device)
#梯度置0
optimizer.zero_grad()
#正向傳播,反向傳播,優化
outputs=net(inputs)
outputs=outputs.to(device)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
2.4 利用測試集測試神經網絡訓練效果
操作與訓練過程相似,只是不需要再計算梯度和方向傳播。此處運用訓練集作爲測試集
代碼示例如下:
correct=0
total=0
with torch.no_grad():
images,labels=data
images=images.to(device)
labels=labels.to(device)
outputs=net(images)
outputs=outputs.to(device)
_,predicted=torch.max(outputs.data,1)
total+=labels.size(0)
correct+=(predicted==labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
3.整體程序及運行結果
整體程序:
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#設置卷積矩陣
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
#設置池化層
self.pool1=nn.MaxPool2d(2,2)
self.pool2=nn.MaxPool2d(2,2)
#設置全連接
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool1(F.relu(self.conv1(x)))#第一層神經網絡
x=self.pool2(F.relu(self.conv2(x)))#第二層神經網絡
x=x.view(-1,16*5*5)#矩陣塑形化爲1維網絡
x=F.relu(self.fc1(x))#第三層神經網絡,全連接1
x=F.relu(self.fc2(x))#第四層神經網絡,全連接2
x=self.fc3(x)#第五層神經網絡,全連接3
return x
#圖片展示
def imshow(img):
img=img/2+0.5 #unnormalize
npimg=img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
#plt.show()必須添加這個才能真正的看見展示的圖片,但是這樣展示窗口庫之後,主程序後續都卡住
#解決方法可以採用多線程
classes=(
"plane","car","bird","cat","deer","dog","frog","horse","ship","truck"
)
#定義GPU設備,如果GPU可用就在GPU上跑,否則在CPU上跑
#然後需要將net對象,input對象,output對象,images對象,lables對象,targets對象全部to到GPU
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
if __name__ == '__main__':
net=Net()#生成神經網絡對象、
net.to(device)
criterion = nn.CrossEntropyLoss()#定義損失函數
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
#設置訓練集
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(
root="./data", train=True, download=True, transform=transform
)
trainloader = torch.utils.data.DataLoader(
trainset, batch_size=4, shuffle=True, num_workers=2
)
#訓練過程
for epoch in range(2):
running_loss=0.0
for i,data in enumerate(trainloader,0):
#獲取輸入
inputs,labels=data
####前面必須用原來的對象接收,不然會包類型不匹配錯誤
####原因是tensor.to()會產生一個新的tensor對象而不是改變原對象
####參考網址:https://blog.csdn.net/qq_27261889/article/details/86575033
inputs=inputs.to(device)
labels=labels.to(device)
#梯度置0
optimizer.zero_grad()
#正向傳播,反向傳播,優化
outputs=net(inputs)
outputs=outputs.to(device)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
#打印狀態信息
running_loss+=loss.item()
if i%2000==1999: #每2000批打印一次
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
runing_loss=0.0
print("Finished Training")
# ######測試集上觀察訓練效果
# #設置測試集
# testset = torchvision.datasets.CIFAR10(
# root="./data", train=False, download=True, transform=transform
# )
#
# testloader = torch.utils.data.DataLoader(
# testset, batch_size=4, shuffle=False, num_workers=2
# )
#
# dataiter=iter(testloader)
# images,labels=dataiter.next()
# images=images.to(device)
# labels=labels.to(device)
# print("GroundTruth","".join('%5s' % classes[labels[j]] for j in range(4)))
# #測試集的輸入
# outputs=net(images)
# outputs=outputs.to(device)
# _,predicted=torch.max(outputs,1)
# print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
# for j in range(4)))
# # 顯示圖片
# imshow(torchvision.utils.make_grid(images))
#####查看神經網絡在整個測試集上的表現
correct=0
total=0
with torch.no_grad():
images,labels=data
images=images.to(device)
labels=labels.to(device)
outputs=net(images)
outputs=outputs.to(device)
_,predicted=torch.max(outputs.data,1)
total+=labels.size(0)
correct+=(predicted==labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
運行結果:
Files already downloaded and verified
[1, 2000] loss: 2.228
[1, 4000] loss: 4.108
[1, 6000] loss: 5.779
[1, 8000] loss: 7.347
[1, 10000] loss: 8.839
[1, 12000] loss: 10.298
[2, 2000] loss: 1.394
[2, 4000] loss: 2.759
[2, 6000] loss: 4.097
[2, 8000] loss: 5.419
[2, 10000] loss: 6.720
[2, 12000] loss: 7.987
Finished Training
Accuracy of the network on the 10000 test images: 50 %
4問題及解決方法
①當程序中需要進行兩次迴歸時,會報錯,解決方法是第一次迴歸時設置retain_graph=True,不釋放資源。參考:https://oldpan.me/archives/pytorch-retain_graph-work
②trainloader在設置num_workers不等於0時會報多線程錯誤,需要將其放在main線程中。參考:
http://www.manongjc.com/article/60188.html
③plt.imshow()所展示的圖片不會顯示,需要在後面加上plt.show()但是如此一來後續的程序不會運行,可以用多線程解決
④inputs、images、labels在傳輸至GPU時如果不用本身接收會報對象不匹配錯誤,因爲tensor.to()只是產生一個新對象不會改變原對象,參考:https://blog.csdn.net/qq_27261889/article/details/86575033