经典卷积神经网络——LeNet
2022-09-06 本文已影响0人
小黄不头秃
(一)LeNet神经网络
这个网络是远古时期的网络了,出自美国八十年代。当时为了解决的是支票或者邮件编码的识别问题。也就是MNIST手写数字识别的起源来源。
我们可以看看它具体的网络结构:

- 第一层:卷积核的形状(1,6,5,5),六个(5,5)的卷积核
- 第二层:池化层,窗口的形状是(6,2,2),设置stride = 2.输出大小为:(6,14,14)
- 第三层:卷积层,卷积核的形状为(6,16,5,5).
- 第四层:池化层,窗口大小为(16,2,2),设置stride = 2.输出大小为(16,5,5)
- 第五层:全连接层,120个节点
- 第六层:全连接层,84个节点
- 第七层:输出层,10个分类
(一)LeNet神经网络
这里的输入由于数据集的问题,原本的(32 * 32)被裁减成了(28 * 28)所以在第一个卷积层通过padding给补上了。 网络结构和原本的LeNet还是有小小的差别。
import torch
from torch import nn
from torchvision import transforms
import torchvision
from torch.utils import data
from d2l import torch as d2l
import numpy as np
import matplotlib.pyplot as plt
class Reshape(nn.Module):
def forward(self,x):
return x.view((-1,1,28,28))
net = torch.nn.Sequential(
Reshape(), # (-1,1,28,28)
nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5,padding=2), # (-1,6,28,28)
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2,stride=2), # (-1,6,14,14)
nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5), # (-1,16,10,10)
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2,stride=2), # (-1,16,5,5)
nn.Flatten(),
nn.Linear(in_features=16*5*5,out_features=120), # (-1,120)
nn.Sigmoid(),
nn.Linear(120,84),# (-1,84)
nn.Sigmoid(),
nn.Linear(in_features=84,out_features=10)# (-1,10)
)
print(net)
x = torch.randn(4*28*28,dtype=torch.float32).reshape(4,1,28,28)
for layer in net:
x = layer(x)
print(layer.__class__.__name__,"output shape = ", x.shape)
# 超参数设置
batch_size = 128
learning_rate = 0.3
epochs = 20
# 现在使用mnist数据集测试一下结果
def load_data_fashion_mnist(batch_size, resize=None):
"""下载或者加载Fashion-MNIST数据集"""
trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(
root="../data/",
train=True,
transform=trans,
download=False # 要是没下载过就选择true
)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data/",
train=False,
transform=trans,
download=False # 要是没下载过就选择true
)
return (data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=0),
data.DataLoader(mnist_test,batch_size=batch_size,shuffle=True,num_workers=0))
# 加载数据
train_iter, test_iter = load_data_fashion_mnist(batch_size)
# 简化版评估模型准确率
def evalue_acc(net,data_iter,device=None):
if isinstance(net, nn.Module):
net.eval()
if not device:
device = next(iter(net.parameters())).device
# 正确的预测数量,总预测的数量
acc_list = np.array([])
with torch.no_grad():
for X, y in data_iter:
if isinstance(X, list):
# Bert微调所需
X = [x.to(device) for x in X]
else:
X = X.to(device)
y_hat = net(X)
y = y.to(device)
if len(y_hat.shape) > 1 and y_hat.shape[1] >1:
y_hat = y_hat.argmax(axis=1)
cmp = y_hat.type(y.dtype) == y
acc = torch.tensor(cmp).sum().item()/len(y)
acc_list = np.append(acc_list,acc)
return acc_list.mean()
# print(evalue_acc(net,train_iter,device=None))
%matplotlib inline
# 简化版的训练函数
def train(net,train_iter,test_iter,epochs,lr,device):
"""使用GPU训练模型"""
def init_weights(m):
if type(m) == nn.Linear or type(m) == nn.Conv2d:
nn.init.xavier_uniform_(m.weight)
net.apply(init_weights)
print("Network traning on",device)
net.to(device)
# 优化器和损失函数
optimizer = torch.optim.SGD(net.parameters(),lr)
loss = nn.CrossEntropyLoss()
#画图用的变量
loss_history = np.array([])
train_acc = np.array([])
test_acc = np.array([])
plt.ion()
for epoch in range(epochs):
l_epoch = np.array([])
for x, y in train_iter:
if isinstance(net,torch.nn.Module):
net.train() # 开启训练模式
x = x.to(device)
y = y.to(device)
l = loss(net(x),y)
optimizer.zero_grad()
l.backward()
optimizer.step()
l_epoch = np.append(l_epoch,l.detach().mean().to("cpu"))
print(f"epoch:{epoch}, train_loss:{l_epoch.mean()}")
loss_history = np.append(loss_history,l_epoch.mean())
train_acc = np.append(train_acc,evalue_acc(net,train_iter))
test_acc = np.append(test_acc,evalue_acc(net,test_iter))
# 画图
plt.clf() #清除上一幅图像
plt.plot(np.arange(epoch+1),loss_history,'b',label="train_loss")
plt.plot(np.arange(epoch+1),train_acc,':g',label="train_acc")
plt.plot(np.arange(epoch+1),test_acc,':m',label="test_acc")
plt.xlabel("epoch")
plt.legend()
plt.pause(0.01) # 暂停0.01秒
print(f"train_acc:{train_acc[-1]},test_acc:{test_acc[-1]}")
plt.ioff()
train(net,train_iter,test_iter,epochs,lr=learning_rate,device=d2l.try_gpu())

下面的是书本上的代码写法,比我写的要精炼的多。
# 书本上的版本
def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
"""使用GPU计算模型在数据集上的精度"""
if isinstance(net, nn.Module):
net.eval() # 设置为评估模式
if not device:
device = next(iter(net.parameters())).device
# 正确预测的数量,总预测的数量
metric = d2l.Accumulator(2)
with torch.no_grad():
for X, y in data_iter:
if isinstance(X, list):
# BERT微调所需的(之后将介绍)
X = [x.to(device) for x in X]
else:
X = X.to(device)
y = y.to(device)
metric.add(d2l.accuracy(net(X), y), y.numel())
return metric[0] / metric[1]
#@save 书上的版本
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
"""用GPU训练模型(在第六章定义)"""
def init_weights(m):
if type(m) == nn.Linear or type(m) == nn.Conv2d:
nn.init.xavier_uniform_(m.weight)
net.apply(init_weights)
print('training on', device)
net.to(device)
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=['train loss', 'train acc', 'test acc'])
timer, num_batches = d2l.Timer(), len(train_iter)
for epoch in range(num_epochs):
# 训练损失之和,训练准确率之和,样本数
metric = d2l.Accumulator(3)
net.train()
for i, (X, y) in enumerate(train_iter):
timer.start()
optimizer.zero_grad()
X, y = X.to(device), y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
l.backward()
optimizer.step()
with torch.no_grad():
metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
timer.stop()
train_l = metric[0] / metric[2]
train_acc = metric[1] / metric[2]
if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
animator.add(epoch + (i + 1) / num_batches,
(train_l, train_acc, None))
test_acc = evaluate_accuracy_gpu(net, test_iter)
animator.add(epoch + 1, (None, None, test_acc))
print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
f'test acc {test_acc:.3f}')
print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
f'on {str(device)}')
