数据集
大名鼎鼎的MNIST数据集,包含60000张手写数字的图片,其中50000张被划分为训练集,剩下10000张被划分为测试集。数据集中图片尺寸为28281的黑白图片。
torchvision中集成了MNIST数据集,用起来很方便。
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
train_dataset = datasets.MNIST(root='./data/', train=True, transform=transforms.ToTensor(),
download=True)
test_dataset = datasets.MNIST(root='./data/', train=False, transform=transforms.ToTensor(),
download = True)
随便搭一个网络
需要注意的是,BN紧跟于卷积或全连接层之后,且BN的通道数需要与权重层的输出通道相等。另外全连接层之间也需要加非线性激活!
def __init__(self):
super(Net, self).__init__()
self.stage1 = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, padding=1),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.Conv2d(16, 16, kernel_size=3, padding=1),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(2),
)
self.stage2 = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size=3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2),
)
self.classify = nn.Sequential(
nn.Linear(1568, 256),
nn.BatchNorm1d(256),
nn.ReLU(),
nn.Linear(256, 10),
)
训练/测试过程
第 1 行:根据上面搭出的网络进行实例化,用GPU跑时model、data、target必须加“.cuda()”
第 2 行:定义一个优化器,这里使用带动量的SGD,选择优化对象为model.parameters(),学习率0.1
第 5 行:dataloader可以根据要求每次给出一个batch的(数据,标签)元组
第 6 行:前向推理
第 7 行:清空当前优化器梯度以便第9行的梯度反传
第 8 行:计算交叉熵loss
第 9 行:根据loss进行梯度反传
第10行:根据反传的梯度更新模型参数
第17行:with torch.no_grad()下的所有代码段对parameter的操作都将不进行自动求导,test下可加速
第18行:前向推理
第19行:计算交叉熵,reduction有none、mean、sum三种模式,分别表示不降维、取batch的平均loss、取 batch中loss的总和
第20行:取出模型前向推理结果中预测概率最大的分类作为预测分类
第21行:比对预测分类与target(lable),记录预测正确的样例数
第23行:将loss总和除以样例数(len(test_dataset)为10000,len(test_loader)为10000/batch_size);
如果再第19行中取reduction=’mean’,并将loss总和除以len(teset_loader)是错的,因为每个epoch
的最后一个batch可能样例数不足batch_size,导致算出来的平均loss略微偏小。
第15、22行:model.eval()与model.train()两个函数用于控制flag,决定dropout是否启用,以及BN使用批 统计还是running_mean、running_var。所以需要在test时候调用model.eval(),并在test结束的 时候调用model.train()。
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
def train(epoch):
for batch_idx, (data, target) in enumerate(train_loader):
output = model(data.cuda())
optimizer.zero_grad()
loss = F.cross_entropy(output, target.cuda())
loss.backward()
optimizer.step()
def test():
test_loss = 0
correct = 0
model.eval()
for data, target in test_loader:
with torch.no_grad():
output = model(data.cuda())
test_loss += F.cross_entropy(output, target.cuda(), reduction='sum').item()
pred = output.data.cpu().max(1, keepdim=True)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum()
model.train()
test_loss /= len(test_loader.dataset)