PyTorch學(xué)習(xí)-總結(jié)篇(3)——最實(shí)用部分
PyTorch學(xué)習(xí)-總結(jié)篇(3)——最實(shí)用部分
一、每個(gè)項(xiàng)目代碼應(yīng)該有五個(gè)部分(大同小異)
二、以一個(gè)項(xiàng)目示例來進(jìn)行講解(MNIST手寫數(shù)據(jù)集)
1.導(dǎo)包及定義超參數(shù)(這步往往是最后才能完成的,因?yàn)橹挥袑懲炅讼旅妫拍苤滥阋x什么及用什么包)
經(jīng)過(1)和(2)的學(xué)習(xí),相信對(duì)基礎(chǔ)知識(shí)有一定的了解,其實(shí)如果想快速進(jìn)行代碼書寫與項(xiàng)目調(diào)試及運(yùn)行,僅看(3)應(yīng)該可以讓你快速掌握項(xiàng)目的編寫規(guī)則。
一、每個(gè)項(xiàng)目代碼應(yīng)該有五個(gè)部分(大同小異)
-
首先,一個(gè)項(xiàng)目的代碼應(yīng)該是導(dǎo)包及定義我們的超參數(shù)
-
然后,將本次項(xiàng)目所需數(shù)據(jù)集讀入,一般包括訓(xùn)練集和測(cè)試集兩個(gè)部分
-
其次,開始搭建我們的網(wǎng)絡(luò)模型主體框架
-
再然后,是進(jìn)行模型的損失函數(shù)、優(yōu)化器及可視化操作
-
最后,是進(jìn)行我們模型的訓(xùn)練及測(cè)試
二、以一個(gè)項(xiàng)目示例來進(jìn)行講解(MNIST手寫數(shù)據(jù)集)
1.導(dǎo)包及定義超參數(shù)(這步往往是最后才能完成的,因?yàn)橹挥袑懲炅讼旅妫拍苤滥阋x什么及用什么包)
# -*- coding: utf-8 -*-
# -代碼界的小菜鳥-
?
import os
import torch
import torch.untils.data as Data
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from tensorboardX import SummaryWriter
from torchvision import datasets,transforms
?
batch_size = 64
epochs = 10
checkpoints_dir = './checkpoints'
event_dir = './event_file'
model_name = None # 如果需要加載模型繼續(xù)訓(xùn)練,則’/10.pth‘
lr = 1e-4
?
#檢測(cè)GPU是否可以使用
print('GPU是否可用:', torch.cuda.is_available()) # 可用為True
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
2.數(shù)據(jù)集讀入
# 實(shí)例化數(shù)據(jù)集Dataset
train_dataset = datasets.MNIST(root='./dataset/', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]))
test_dataset = datasets.MNIST(root='./dataset/', train=False, transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]))
?
# 數(shù)據(jù)加載器
train_loader = Data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # shuffle是否隨機(jī)打亂順序
test_loader = Data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
?
# 保存檢查點(diǎn)的地址
if not os.path.exists(checkpoints_dir):
os.makedirs(checkpoints_dir)
3.模型的搭建
# 模型搭建(pytorch框架定義的的神經(jīng)網(wǎng)絡(luò)模型都需要繼承nn.Module類)
class Net(nn.Module):
?
# 初始化函數(shù),定義了該神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu)
def __init__(self):
super(Net, self).__init__() # 復(fù)制并使用Net的父類的初始化方法,即先運(yùn)行nn.Module的初始化函數(shù)
self.conv1 = nn.Conv2d(in_channels=1, out_channels=20, kernel_size=5, stride=1) # 輸入為圖像(1),即灰度圖,輸出為20張?zhí)卣鲌D,卷積和為5*5的正方形
self.conv2 = nn.Conv2d(in_channels=20, out_channels=20, kernel_size=5, stride=1)
self.fc1 = nn.Linear(in_features=4*4*20, out_features=300) # 定義全連接線性函數(shù):y=Wx+b,并將4*4*20個(gè)節(jié)點(diǎn)連接到300個(gè)節(jié)點(diǎn)上
self.fc2 = nn.Linear(in_features=300, out_features=10)
?
# 定義神經(jīng)網(wǎng)絡(luò)的前向傳播函數(shù)
def forward(self, x):
x = F.relu(self.conv1(x)) # 輸入x經(jīng)過卷積conv1后,再經(jīng)過一個(gè)激活函數(shù)更新x
x = F.max_pool2d(x, kernel_size=2, stride=2) # 經(jīng)過激活函數(shù)后,使用2*2的窗口進(jìn)行最大池化,更新x
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 4 * 4 * 20) # 利用view函數(shù)將張量x變成一維向量的形式,總特征個(gè)數(shù)不變
x = F.relu(self.fc1(x)) # 更新后的x經(jīng)過全連接函數(shù),再經(jīng)過激活函數(shù),更新x
x = self.fc2(x)
return x
# 模型實(shí)例化
model = Net().to(device)
4.損失函數(shù)、優(yōu)化器、可視化及繼續(xù)訓(xùn)練
# 定義損失函數(shù)
criterion = nn.CrossEntropyLoss() # 交叉熵?fù)p失函數(shù)
?
# 定義優(yōu)化器
optimzer = optim.SGD(model.parameters(), lr=lr)
?
# 可視化處理
writer = SummaryWriter(event_dir)
?
# 繼續(xù)訓(xùn)練
start_epoch = 0
if model_name:
print('加載模型:',checkpoints_dir + model_name)
checkpoint = torch.load(checkpoints_dir + model_name)
model.load_state_dict(checkpoint['model_state_dict'])
optimzer.load_state_dict(checkpoint['optimizer_state_dict'])
start_epoch = checkpoint['epoch']
5.模型的訓(xùn)練
# 開始訓(xùn)練
for epoch in range(start_epoch, epochs):
model.train() # 模型訓(xùn)練的標(biāo)志
for batch_idx, (data, target) in enumerate(train_loader):
data = data.to(device) # 訓(xùn)練數(shù)據(jù),放到GPU上
target = target.to(device) # 訓(xùn)練標(biāo)簽,放到GPU上
?
# 前向傳播
output = model(data)
loss = criterion(output, target) # 計(jì)算損失函數(shù)
?
# 反向傳播
optimzer.zero_grad() # 首先進(jìn)行梯度清零
loss.backward() # 反向傳播
optimzer.step() # 更新參數(shù)
?
print('Train Epoch: {} \tLoss:{{:,6f}}'.format(epoch+1, loss.item()))
?
# 可視化
writer.add_scalar(tag='train_loss', scalar_value=loss.item(), global_step=epoch + 1)
writer.flush()
?
?
model.eval() # 模型測(cè)試的標(biāo)志
test_loss = 0
correct = 0
?
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
?
output = model(data)
pred = output.argmax(dim=1, keepdim=True) # 獲取最大的對(duì)數(shù)概率的索引
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss += criterion(output, target).item()
?
test_loss /= len(test_loader.dataset)
print('測(cè)試集:損失:{:.4f},精度:{:.2f}%'.format(test_loss, 100. * correct / len(test_loader.dataset)))
?
# 可視化
writer.add_scalar(tag='val_loss', scalar_value=test_loss, global_step=epoch + 1)
writer.flush()
?
?
# 保存模型
if (epoch + 1) % 10 ==0:
checkpoint = {'model_state_dict':model.state_dict(), 'optimizer_state_dict': optimzer.state_dict(), 'epoch': epoch + 1}
torch.save(checkpoint, '%s/%d.pth' % (checkpoints_dir, epochs))
#結(jié)果顯示
GPU是否可用: True
Train Epoch: 1 Loss:2.264611
測(cè)試集:損失:0.0358