一、確定輸入樣本特征和輸出特征
輸入樣本通道數(shù)4、期待輸出樣本通道數(shù)2、卷積核大小3×3
具體卷積層的構(gòu)建可參考博文:八、卷積層
設(shè)定卷積層torch.nn.Conv2d(in_channels=in_channel,out_channels=out_channel,kernel_size=kernel_size,padding=1,stride=1)
必要參數(shù):輸入樣本通道數(shù)in_channels、輸出樣本通道數(shù)out_channels、卷積核大小kernel_size
padding是否加邊,默認(rèn)不加,這里為了保證輸出圖像的大小不變,加邊數(shù)設(shè)為1
stride步長設(shè)置,默認(rèn)為1
import torch
in_channel, out_channel = 4, 2
width, heigh = 512, 512
batch_size = 1
inputs = torch.randn(batch_size,in_channels,width,heigh)#[B,C,W,H]
kernel_size = 3
conv_layer = torch.nn.Conv2d(in_channels=in_channel,out_channels=out_channel,kernel_size=kernel_size,padding=1,stride=1)
outputs = conv_layer(inputs)
print(inputs.shape)
"""
torch.Size([1, 4, 512, 512])
"""
print(outputs.shape)
"""
torch.Size([1, 2, 512, 512])
"""
print(conv_layer.weight.shape)#看下卷積層核參數(shù)信息
# 卷積層權(quán)重參數(shù)大小,因?yàn)閎atch_size為1,故卷積核參數(shù)的B也為1;
# 因?yàn)檩斎霕颖镜耐ǖ罃?shù)是3,故卷積層傳入?yún)?shù)的channel也為3;
# 因?yàn)檩敵鰳颖镜耐ǖ罃?shù)是1,故卷積層傳入?yún)?shù)的
"""
torch.Size([2, 4, 3, 3])
"""
二、確定卷積核內(nèi)容進(jìn)行卷積
import torch
inputs = [1,1,1,1,1,
2,2,2,2,2,
1,1,2,1,1,
1,1,2,1,1,
1,1,2,1,1]
inputs = torch.Tensor(inputs).view(1,1,5,5)
kernel_size = 3
padding = 0
stride = 1
kernel = torch.Tensor([1,2,1,
2,1,2,
1,2,1]).view(1,1,3,3)
conv_layer = torch.nn.Conv2d(1,1,kernel_size=kernel_size,padding=padding,stride=stride,bias=False)
conv_layer.weight.data = kernel.data
outputs = conv_layer(inputs)
print(outputs)
"""
tensor([[[[19., 20., 19.],
[20., 20., 20.],
[17., 18., 17.]]]], grad_fn=<SlowConv2DBackward0>)
"""
print(inputs)
"""
tensor([[[[1., 1., 1., 1., 1.],
[2., 2., 2., 2., 2.],
[1., 1., 1., 1., 1.],
[2., 2., 2., 2., 2.],
[1., 1., 1., 1., 1.]]]])
"""
print(kernel)
"""
tensor([[[[1., 2., 1.],
[2., 1., 2.],
[1., 2., 1.]]]])
"""
print(inputs.shape)
"""
torch.Size([1, 1, 5, 5])
"""
print(outputs.shape)
"""
torch.Size([1, 1, 3, 3])
"""
print(kernel.shape)
"""
torch.Size([1, 1, 3, 3])
"""
print(conv_layer.weight.shape)
"""
torch.Size([1, 1, 3, 3])
"""
三、根據(jù)需求進(jìn)行網(wǎng)絡(luò)模型搭建
①準(zhǔn)備數(shù)據(jù)集
還是以MNIST手寫數(shù)字?jǐn)?shù)據(jù)集為例,數(shù)據(jù)集細(xì)節(jié)可參考博文:九、多分類問題
設(shè)置batch_size=64,每個(gè)batch中有64張樣本,至于一共有多少個(gè)batch,取決于數(shù)據(jù)集的總數(shù)量
使用transforms.Compose(),組合操作,把數(shù)據(jù)集都轉(zhuǎn)換為Tensor數(shù)據(jù)類型,并且全部都取均值和標(biāo)準(zhǔn)差,方便訓(xùn)練,強(qiáng)化訓(xùn)練效果,這里的值都是經(jīng)過計(jì)算過的,直接用就行
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #為了使用relu激活函數(shù)
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),#把圖片變成張量形式
transforms.Normalize((0.1307,),(0.3081,)) #均值和標(biāo)準(zhǔn)差進(jìn)行數(shù)據(jù)標(biāo)準(zhǔn)化,這倆值都是經(jīng)過整個(gè)樣本集計(jì)算過的
])
②加載數(shù)據(jù)集
pytorch提供MNIST接口,直接調(diào)用相關(guān)函數(shù)即可
datasets中
參數(shù)root
表示數(shù)據(jù)集路徑;
參數(shù)train
表示是否是訓(xùn)練集,True表示下載訓(xùn)練集,False則表示下載測試集;
參數(shù)download
表示是否下載,True表示若指定路徑不存在數(shù)據(jù)集則聯(lián)網(wǎng)下載;
將所有的數(shù)據(jù)集都經(jīng)過上面定義的transforms組合操作,轉(zhuǎn)換成Tensor格式和均值標(biāo)準(zhǔn)差歸一化。
DataLoader中
參數(shù)train_dataset
指定數(shù)據(jù)集datasets;
參數(shù)shuffle
表示是否將數(shù)據(jù)集中的樣本打亂順序,訓(xùn)練集需要,測試集不需要
參數(shù)batch_size
表示一次(batch)取多少個(gè)樣本,至于一共取多少次取決于數(shù)據(jù)集總樣本數(shù)
train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
③模型構(gòu)建
由圖可知,輸入圖像(通道數(shù)為1)首先進(jìn)入一個(gè)卷積層,卷積核大小為5×5,輸出特征通道數(shù)為10,即torch.nn.Conv2d(1,10,kernel_size=5)
之后進(jìn)入一個(gè)ReLU激活函數(shù)層,激活函數(shù)無需參數(shù),即F.relu()
然后再進(jìn)入一個(gè)核為2×2的MaxPool層,即torch.nn.MaxPool2d(2)
之后將通道數(shù)為10的特征參數(shù)再送入一個(gè)卷積層,卷積核大小為5×5,輸出特征通道數(shù)為20,即torch.nn.Conv2d(10,20,kernel_size=5)
之后進(jìn)入一個(gè)ReLU激活函數(shù)層,激活函數(shù)無需參數(shù),即F.relu()
然后再進(jìn)入一個(gè)核為2×2的MaxPool層,即torch.nn.MaxPool2d(2)
有第一張圖可知,最終的特征參數(shù)個(gè)數(shù)為20×4×4=320,將這320個(gè)特征參數(shù)通過線性層(全連接層),轉(zhuǎn)到10個(gè)維度上,即torch.nn.Linear(320,10)
,因?yàn)槭?0分類任務(wù),故需要轉(zhuǎn)到10個(gè)維度上
在模型參數(shù)函數(shù)(def __init__(self):
)中,池化層操作都一樣,故定義一個(gè)即可,最終,卷積操作兩個(gè),一個(gè)池化操作,一個(gè)線性層(全連接)操作
在前向傳播函數(shù)(def forward(self,x):
)中,數(shù)據(jù)集中x為[B,C,W,H]
,故通過x.size(0)
取出batch_size,即B的值
class yNet(torch.nn.Module):
def __init__(self):
super(yNet,self).__init__()
self.conv_1 = torch.nn.Conv2d(1,10,kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.conv_2 = torch.nn.Conv2d(10,20,kernel_size=5)
self.fc = torch.nn.Linear(320,10)
def forward(self,x):
batch_size = x.size(0)
x = self.pooling(F.relu(self.conv_1(x)))
x = self.pooling(F.relu(self.conv_2(x)))
x = x.view(batch_size,-1)
x = self.fc(x)
return x
model = yNet()
GPU加速
只需要通過.to()
方法,將模型、訓(xùn)練函數(shù)中數(shù)據(jù)集、測試函數(shù)中數(shù)據(jù)集調(diào)用該方法即可
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
④損失函數(shù)和優(yōu)化器
lossf = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.0001,momentum=0.5)
⑤訓(xùn)練函數(shù)定義
for i, data in enumerate(train_loader,0):
從train_loader這個(gè)DataLoader中進(jìn)行枚舉,0
表示從DataLoader下標(biāo)為0處開始,train_loader返回兩個(gè)值,索引和數(shù)據(jù),其中數(shù)據(jù)包括兩類,x和yi
接收索引、data
接收數(shù)據(jù)x,y = data
,x和y分別接收data中的28×28=784個(gè)參數(shù),y為所對應(yīng)的某一個(gè)類別
測試
x,y = test_dataset[0]
x.shape
"""
torch.Size([1, 28, 28])
"""
y
"""
7
"""
完整代碼
def ytrain(epoch):
loss_total = 0.0
for batch_index ,data in enumerate(train_loader,0):
x,y = data
#x,y = x.to(device), y.to(device)#GPU加速
optimizer.zero_grad()
y_hat = model(x)
loss = lossf(y_hat,y)
loss.backward()
optimizer.step()
loss_total += loss.item()
if batch_index % 300 == 299:# 每300epoch輸出一次
print("epoch:%d, batch_index:%5d \t loss:%.3f"%(epoch+1, batch_index+1, loss_total/300))
loss_total = 0.0 #每次epoch都將損失清零,方便計(jì)算下一次的損失
⑥測試函數(shù)定義
def ytest():
correct = 0#模型預(yù)測正確的數(shù)量
total = 0#樣本總數(shù)
with torch.no_grad():#測試不需要梯度,減小計(jì)算量
for data in test_loader:#讀取測試樣本數(shù)據(jù)
images, labels = data
#images, labels = images.to(device), labels.to(device) #GPU加速
pred = model(images)#預(yù)測,每一個(gè)樣本占一行,每行有十個(gè)值,后續(xù)需要求每一行中最大值所對應(yīng)的下標(biāo)
pred_maxvalue, pred_maxindex = torch.max(pred.data,dim=1)#沿著第一個(gè)維度,一行一行來,去找每行中的最大值,返回每行的最大值和所對應(yīng)下標(biāo)
total += labels.size(0)#labels是一個(gè)(N,1)的向量,對應(yīng)每個(gè)樣本的正確答案
correct += (pred_maxindex == labels).sum().item()#使用預(yù)測得到的最大值的索引和正確答案labels進(jìn)行比較,一致就是1,不一致就是0
print("Accuracy on testset :%d %%"%(100*correct / total))#correct預(yù)測正確的樣本個(gè)數(shù) / 樣本總數(shù) * 100 = 模型預(yù)測正確率
⑦主函數(shù)調(diào)用
if __name__ == '__main__':
for epoch in range(100):#訓(xùn)練10次
ytrain(epoch)#訓(xùn)練一次
if epoch%10 == 9:
ytest()#訓(xùn)練10次,測試1次
⑧完整代碼
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #為了使用relu激活函數(shù)
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),#把圖片變成張量形式
transforms.Normalize((0.1307,),(0.3081,)) #均值和標(biāo)準(zhǔn)差進(jìn)行數(shù)據(jù)標(biāo)準(zhǔn)化,這倆值都是經(jīng)過整個(gè)樣本集計(jì)算過的
])
train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
class yNet(torch.nn.Module):
def __init__(self):
super(yNet,self).__init__()
self.conv_1 = torch.nn.Conv2d(1,10,kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.conv_2 = torch.nn.Conv2d(10,20,kernel_size=5)
self.fc = torch.nn.Linear(320,10)
def forward(self,x):#傳入單張樣本x
batch_size = x.size(0)
x = self.pooling(F.relu(self.conv_1(x)))
x = self.pooling(F.relu(self.conv_2(x)))
x = x.view(batch_size,-1)
x = self.fc(x)
return x
model = yNet()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
lossf = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.0001,momentum=0.5)
def ytrain(epoch):
loss_total = 0.0
for batch_index ,data in enumerate(train_loader,0):
x,y = data
x,y = x.to(device), y.to(device)#GPU加速
optimizer.zero_grad()
y_hat = model(x)
loss = lossf(y_hat,y)
loss.backward()
optimizer.step()
loss_total += loss.item()
if batch_index % 300 == 299:# 每300epoch輸出一次
print("epoch:%d, batch_index:%5d \t loss:%.3f"%(epoch+1, batch_index+1, loss_total/300))
loss_total = 0.0
def ytest():
correct = 0#模型預(yù)測正確的數(shù)量
total = 0#樣本總數(shù)
with torch.no_grad():#測試不需要梯度,減小計(jì)算量
for data in test_loader:#讀取測試樣本數(shù)據(jù)
images, labels = data
images, labels = images.to(device), labels.to(device) #GPU加速
pred = model(images)#預(yù)測,每一個(gè)樣本占一行,每行有十個(gè)值,后續(xù)需要求每一行中最大值所對應(yīng)的下標(biāo)
pred_maxvalue, pred_maxindex = torch.max(pred.data,dim=1)#沿著第一個(gè)維度,一行一行來,去找每行中的最大值,返回每行的最大值和所對應(yīng)下標(biāo)
total += labels.size(0)#labels是一個(gè)(N,1)的向量,對應(yīng)每個(gè)樣本的正確答案
correct += (pred_maxindex == labels).sum().item()#使用預(yù)測得到的最大值的索引和正確答案labels進(jìn)行比較,一致就是1,不一致就是0
print("Accuracy on testset :%d %%"%(100*correct / total))#correct預(yù)測正確的樣本個(gè)數(shù) / 樣本總數(shù) * 100 = 模型預(yù)測正確率
if __name__ == '__main__':
for epoch in range(10):#訓(xùn)練10次
ytrain(epoch)#訓(xùn)練一次
if epoch%10 == 9:
ytest()#訓(xùn)練10次,測試1次
⑨測試一下
x,y = train_dataset[9]#第9個(gè)數(shù)據(jù)x為圖片,對應(yīng)的結(jié)果為2
y
"""
2
"""
x = x.view(-1,1,28,28)#因?yàn)閠ensor需要格式為(B,C,W,H)轉(zhuǎn)換一下格式
y_hat = model(x)#放入模型中進(jìn)行預(yù)測,因?yàn)闀r(shí)十分類任務(wù),輸出十個(gè)值
y_hat
"""
tensor([[-2.8711, -2.2891, -0.5218, -2.0884, 6.2099, -0.1559, 1.9904, -0.8938,
1.3734, 2.9303]], grad_fn=<AddmmBackward0>)
"""
pred_maxvalue, pred_maxindex = torch.max(y_hat,dim=1)#選出值最大的,和相對于的下標(biāo)索引
pred_maxvalue#最大值
"""
tensor([6.2099], grad_fn=<MaxBackward0>)
"""
pred_maxindex#最大值所對應(yīng)的索引下標(biāo)值
"""
tensor([4])
"""
預(yù)測錯(cuò)了,得多訓(xùn)練幾輪
四、課后作業(yè)
除網(wǎng)絡(luò)模型外,其他的都可以復(fù)用
這里就不再贅述,直接對模型結(jié)構(gòu)進(jìn)行搭建
查看下官網(wǎng)給的卷積層padding的計(jì)算公式
以下是我個(gè)人設(shè)計(jì)的網(wǎng)絡(luò)模型,接下來開始去實(shí)現(xiàn)模型架構(gòu)
①調(diào)試
加載數(shù)據(jù)集
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #為了使用relu激活函數(shù)
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),#把圖片變成張量形式
transforms.Normalize((0.1307,),(0.3081,)) #均值和標(biāo)準(zhǔn)差進(jìn)行數(shù)據(jù)標(biāo)準(zhǔn)化,這倆值都是經(jīng)過整個(gè)樣本集計(jì)算過的
])
train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
#這里取測試集中的一個(gè)樣本
x,y = test_dataset[1]
x.shape
"""
torch.Size([1, 28, 28])
"""
y
"""
2
"""
第一個(gè)卷積層
因?yàn)閿?shù)據(jù)集中樣本shape是torch.Size([1, 28, 28])
,而pytorch提供的接口都得適應(yīng)[B,C,W,H]形式,故需要先通過x = x.view(-1,1,28,28)
轉(zhuǎn)換一下類型
根據(jù)結(jié)構(gòu)需要,定義第一個(gè)卷積層,為了后續(xù)計(jì)算方便,這里加邊padding=1,保證輸入和輸出特征圖大小一致,這里僅為了測試,batch取1conv_1 = torch.nn.Conv2d(1,5,kernel_size=3,padding=1)
x = x.view(-1,1,28,28)
x.shape
"""
torch.Size([1, 1, 28, 28])
"""
conv_1 = torch.nn.Conv2d(1,5,kernel_size=3,padding=1)
x1 = conv_1(x)
x1.shape
"""
torch.Size([1, 5, 28, 28])
"""
由輸出結(jié)果可知,通過第一個(gè)卷積層之后,特征圖x1為[1,5,28,28]
將x1傳入第一個(gè)最大池化層
第一個(gè)最大池化層
x1的形狀為[1,5,28,28]
定義最大池化層:pooling = torch.nn.MaxPool2d(2)
將x1傳入最大池化層,得到特征x2
pooling = torch.nn.MaxPool2d(2)
x2 = pooling(x1)
x2.shape
"""
torch.Size([1, 5, 14, 14])
"""
輸出結(jié)果x2的形狀為[1, 5, 14, 14]
將x2傳入第二個(gè)卷積層中
第二個(gè)卷積層
x2的形狀為[1, 5, 14, 14]
定義第二個(gè)卷積層:conv_2 = torch.nn.Conv2d(5,10,kernel_size=3,padding=1)
將x2傳入第二個(gè)卷積層,得到特征x3
conv_2 = torch.nn.Conv2d(5,10,kernel_size=3,padding=1)
x3 = conv_2(x2)
x3.shape
"""
torch.Size([1, 10, 14, 14])
"""
輸出結(jié)果x3的形狀為[1, 10, 14, 14]
將x3傳入第二個(gè)最大池化層中
第二個(gè)最大池化層
x3的形狀為[1, 10, 14, 14]
使用上述同樣的最大池化層:pooling = torch.nn.MaxPool2d(2)
將x3傳入第二個(gè)最大池化層,得到特征x4
pooling = torch.nn.MaxPool2d(2)
x4 = pooling(x3)
x4.shape
"""
torch.Size([1, 10, 7, 7])
"""
輸出結(jié)果x4的形狀為[1, 10, 7, 7]
將x4傳入第三個(gè)卷積層中
第三個(gè)卷積層
x4的形狀為[1, 10, 7, 7]
定義第三個(gè)卷積層:conv_3 = torch.nn.Conv2d(10,20,kernel_size=3,padding=1)
將x4傳入第三個(gè)卷積層,得到特征x5
conv_3 = torch.nn.Conv2d(10,20,kernel_size=3,padding=1)
x5 = conv_3(x4)
x5.shape
"""
torch.Size([1, 20, 7, 7])
"""
輸出結(jié)果x5的形狀為[1, 20, 7, 7]
將x5傳入第三個(gè)最大池化層中
第三個(gè)最大池化層
x5的形狀為[1, 20, 7, 7]
使用上述同樣的最大池化層:pooling = torch.nn.MaxPool2d(2)
將x5傳入第二個(gè)最大池化層,得到特征x6
pooling = torch.nn.MaxPool2d(2)
x6 = pooling(x5)
x6.shape
"""
torch.Size([1, 20, 3, 3])
"""
輸出結(jié)果x6的形狀為[1, 20, 3, 3]
將x6傳入第一個(gè)線性層中
第一個(gè)全連接層
x6的形狀為[1, 20, 3, 3]
,此時(shí)特征圖x6共有1×20×3×3=180個(gè)參數(shù)
因?yàn)榫€性層傳入的特征是二維矩陣形式,每個(gè)batch占一行,每行存放單個(gè)樣本的所有參數(shù)信息,故需要將x6形狀進(jìn)行轉(zhuǎn)變,x6.size(0)
獲取batch,這里的batch是1,剩下的,系統(tǒng)進(jìn)行自動排列,x_all = x6.view(x6.size(0),-1)
,此時(shí)的x_all的形狀為[1,180]
之后根據(jù)需求,定義第一個(gè)線性層:fc_1 = torch.nn.Linear(180,120)
,這里的輸入180,必須和最終的特征x_all吻合
將x_all傳入第一個(gè)全連接層,得到特征x_x1
x6.shape
"""
torch.Size([1, 20, 3, 3])
"""
x6.size(0)
"""
1
"""
x_all = x6.view(x6.size(0),-1)
x_all.shape
"""
torch.Size([1, 180])
"""
fc_1 = torch.nn.Linear(180,120)
x_x1 = fc_1(x_all)
x_x1.shape
"""
torch.Size([1, 120])
"""
輸出結(jié)果x_x1的形狀為[1, 120]
將x_x1傳入第二個(gè)全連接層中
第二個(gè)全連接層
x_x1的形狀為[1, 120]
根據(jù)需求,定義第二個(gè)全連接層,fc_2 = torch.nn.Linear(120,60)
將x_x1傳入第二個(gè)全連接層,得到特征x_x2
fc_2 = torch.nn.Linear(120,60)
x_x2 = fc_2(x_x1)
x_x2.shape
"""
torch.Size([1, 60])
"""
輸出結(jié)果x_x2的形狀為[1, 60]
將x_x2傳入第三個(gè)全連接層中
第三個(gè)全連接層
x_x2的形狀為[1, 60]
根據(jù)需求,定義第三個(gè)全連接層,fc_3 = torch.nn.Linear(60,10)
將x_x2傳入第三個(gè)全連接層,得到特征x_x3
fc_3 = torch.nn.Linear(60,10)
x_x3 = fc_3(x_x2)
x_x3.shape
"""
torch.Size([1, 10])
"""
最終結(jié)果為x_x3,形狀為[1, 10]
,十分類任務(wù),十個(gè)概率值,取最大的,就是最終預(yù)測的結(jié)果
②模型構(gòu)建
class yNet(torch.nn.Module):
def __init__(self):
super(yNet,self).__init__()
self.conv_1 = torch.nn.Conv2d(1,5,kernel_size=3,padding=1)
self.pooling = torch.nn.MaxPool2d(2)
self.conv_2 = torch.nn.Conv2d(5,10,kernel_size=3,padding=1)
self.conv_3 = torch.nn.Conv2d(10,20,kernel_size=3,padding=1)
self.fc_1 = torch.nn.Linear(180,120)
self.fc_2 = torch.nn.Linear(120,60)
self.fc_3 = torch.nn.Linear(60,10)
def forward(self,x):
batch_size = x.size(0)
x = self.pooling(F.relu(self.conv_1(x)))
x = self.pooling(F.relu(self.conv_2(x)))
x = self.pooling(F.relu(self.conv_3(x)))
x = x.view(batch_size,-1)
x = self.fc_1(x)
x = self.fc_2(x)
x = self.fc_3(x)
return x
model = yNet()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#GPU加速
model.to(device)
③完整代碼
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #為了使用relu激活函數(shù)
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),#把圖片變成張量形式
transforms.Normalize((0.1307,),(0.3081,)) #均值和標(biāo)準(zhǔn)差進(jìn)行數(shù)據(jù)標(biāo)準(zhǔn)化,這倆值都是經(jīng)過整個(gè)樣本集計(jì)算過的
])
train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
class yNet(torch.nn.Module):
def __init__(self):
super(yNet,self).__init__()
self.conv_1 = torch.nn.Conv2d(1,5,kernel_size=3,padding=1)
self.pooling = torch.nn.MaxPool2d(2)
self.conv_2 = torch.nn.Conv2d(5,10,kernel_size=3,padding=1)
self.conv_3 = torch.nn.Conv2d(10,20,kernel_size=3,padding=1)
self.fc_1 = torch.nn.Linear(180,120)
self.fc_2 = torch.nn.Linear(120,60)
self.fc_3 = torch.nn.Linear(60,10)
def forward(self,x):
batch_size = x.size(0)
x = self.pooling(F.relu(self.conv_1(x)))
x = self.pooling(F.relu(self.conv_2(x)))
x = self.pooling(F.relu(self.conv_3(x)))
x = x.view(batch_size,-1)
x = self.fc_1(x)
x = self.fc_2(x)
x = self.fc_3(x)
return x
model = yNet()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
lossf = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.0001,momentum=0.5)
def ytrain(epoch):
loss_total = 0.0
for batch_index ,data in enumerate(train_loader,0):
x,y = data
x,y = x.to(device), y.to(device)#GPU加速
optimizer.zero_grad()
y_hat = model(x)
loss = lossf(y_hat,y)
loss.backward()
optimizer.step()
loss_total += loss.item()
if batch_index % 300 == 299:# 每300epoch輸出一次
print("epoch:%d, batch_index:%5d \t loss:%.3f"%(epoch+1, batch_index+1, loss_total/300))
loss_total = 0.0
def ytest():
correct = 0#模型預(yù)測正確的數(shù)量
total = 0#樣本總數(shù)
with torch.no_grad():#測試不需要梯度,減小計(jì)算量
for data in test_loader:#讀取測試樣本數(shù)據(jù)
images, labels = data
images, labels = images.to(device), labels.to(device) #GPU加速
pred = model(images)#預(yù)測,每一個(gè)樣本占一行,每行有十個(gè)值,后續(xù)需要求每一行中最大值所對應(yīng)的下標(biāo)
pred_maxvalue, pred_maxindex = torch.max(pred.data,dim=1)#沿著第一個(gè)維度,一行一行來,去找每行中的最大值,返回每行的最大值和所對應(yīng)下標(biāo)
total += labels.size(0)#labels是一個(gè)(N,1)的向量,對應(yīng)每個(gè)樣本的正確答案
correct += (pred_maxindex == labels).sum().item()#使用預(yù)測得到的最大值的索引和正確答案labels進(jìn)行比較,一致就是1,不一致就是0
print("Accuracy on testset :%d %%"%(100*correct / total))#correct預(yù)測正確的樣本個(gè)數(shù) / 樣本總數(shù) * 100 = 模型預(yù)測正確率
if __name__ == '__main__':
for epoch in range(10):#訓(xùn)練10次
ytrain(epoch)#訓(xùn)練一次
if epoch%10 == 9:
ytest()#訓(xùn)練10次,測試1次
④測試一下
x,y = train_dataset[12]#第12個(gè)數(shù)據(jù)x為圖片,對應(yīng)的結(jié)果為3
y
"""
3
"""
x = x.view(-1,1,28,28)#因?yàn)閠ensor需要格式為(B,C,W,H)轉(zhuǎn)換一下格式
y_hat = model(x)#放入模型中進(jìn)行預(yù)測,因?yàn)闀r(shí)十分類任務(wù),輸出十個(gè)值
y_hat
"""
tensor([[ 0.0953, 0.0728, 0.0505, 0.0618, -0.0512, -0.1338, -0.0261, -0.0677,
-0.0265, 0.0236]], grad_fn=<AddmmBackward0>)
"""
pred_maxvalue, pred_maxindex = torch.max(y_hat,dim=1)#選出值最大的,和相對于的下標(biāo)索引
pred_maxvalue#最大值
"""
tensor([0.0953], grad_fn=<MaxBackward0>)
"""
pred_maxindex#最大值所對應(yīng)的索引下標(biāo)值
"""
tensor([0])
"""
好家伙,又預(yù)測錯(cuò)了,確實(shí)得多訓(xùn)練幾輪文章來源:http://www.zghlxwxcb.cn/news/detail-406697.html
又是動筆畫,又是單步調(diào)試,若各位客官姥爺有所收獲,還請點(diǎn)個(gè)小小的贊,這將是對我的最大的鼓勵,萬分感謝~
文章來源地址http://www.zghlxwxcb.cn/news/detail-406697.html
到了這里,關(guān)于十、CNN卷積神經(jīng)網(wǎng)絡(luò)實(shí)戰(zhàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!