CNN-LeNet
总述
CNN基本概念
- 卷积层:卷积层可通过重复使用卷积核有效地表征局部空间
-
池化层:池化层是为了缓解卷积层对位置的过度敏感性
-
卷积尺寸计算公式:
定义以下参数:
输入图片大小 W×W
卷积核大小 F×F
步长 S
填充的像素数 P
则卷积输出尺寸$N$为
$$
N = \frac{W-F+2P}{S}+1
$$ -
池化尺寸计算公式:
定义以下参数:
输入图片大小 W×W
池化核大小 F×F
步长 S
则卷积输出尺寸$N$为
$$
N = \frac{W-F}{S}+1
$$
LeNet(卷积神经网络)
基本介绍
为了解决DNN中全连接的参数过多,CNN提出来利用卷积核来表示有效特征空间,其最开始的也是最简单的就是LeNet网络其,LeNet交替使用卷积层和最大池化层后接全连接层来进行图像分类,具体采用了两层卷积,两层池化和三层全连接层来进行搭建模型
Pytorch
pytorch是Facebook的机器学习库,可以方便的进行梯度下降等过程,因为我觉得tensorflow有点紊乱,所以用pytorch来1进行接下来的NN学习
Pytorch实现代码(对自己有用的写了注释)
import torchvision #基于pytorch的处理图像视频工具库-torchvision
import torchvision.transforms as transforms #transforms包括很多处理图像的方法,比如归一化,剪切..
import torch
import torch.nn as nn #最常用的torch块,封装了很多有用的东西
from torch.utils.data import Dataset, DataLoader #方便训练中数据处理,一个是数据转化类,一个是数据加载类
import sys
import numpy as np
import matplotlib.pyplot as plt
import time
def watchimg(dataset, batch_size):
imglist = []
for i in range(batch_size):
imglist.append(dataset[i][0])
grid = torchvision.utils.make_grid(imglist, padding=2, nrow=int(batch_size ** 0.5)) #把四维输出图像合成一张图像输出,其中padding是间距,nrow是每行数量
npgrid = grid.cpu().numpy()
plt.imshow(np.transpose(npgrid, (1, 2, 0)), interpolation='nearest')
plt.show()
# torchvision.datasets有现成的数据集和训练集,download参数代表下载,已经是DataSet类,可以用transforms.ToTensor()进行归一处理
mnist_train = torchvision.datasets.FashionMNIST(root='./Datasets/FashionMNIST', train=True, download=True,transform=transforms.ToTensor())
mnist_test = torchvision.datasets.FashionMNIST(root='./Datasets/FashionMNIST', train=False, download=True,transform=transforms.ToTensor())
batch_size = 256
if sys.platform.startswith('win'):
num_workers = 0
else:
num_workers = 4
# DataLoader负责数据加载,num_workers代表多线程加载,batch_size代表一次取出样本数,shuffle代表打乱次序
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)
# 所有模型都是nn.Module的子类,要定义__init__和forward函数
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv = nn.Sequential( ## nn.Sequential提供了一个训练步骤容器,可以按次序进行每一步
nn.Conv2d(1, 6, 5), # 输入通道, 输出通道, 核大小
nn.Sigmoid(),
nn.MaxPool2d(2, 2), # 核大小, 步长
nn.Conv2d(6, 16, 5),
nn.Sigmoid(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Sequential( #全连接层
nn.Linear(16 * 4 * 4, 120),
nn.Sigmoid(),
nn.Linear(120, 84),
nn.Sigmoid(),
nn.Linear(84, 10)
)
def forward(self, img): #向前传播
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
def evaluate_accuracy(data_iter, net):
acc_sum, n = 0.0, 0
with torch.no_grad():
for i, data in enumerate(data_iter):# DataLoader后可以进行enumerate输出,类似list
x, y = data
net.eval() # 评估模式, 这会关闭dropout
acc_sum += (net(x.to('cuda')).argmax(dim=1) == y.to('cuda')).float().sum().cpu().item()
n += y.shape[0]
return acc_sum / n
def train_ch5(net, train_iter, test_iter, optimizer, num_epochs):
net = net.to('cuda') # 在gpu上训练模型,如果模型在gpu训练,则所有的都需要定义在gpu训练
print("training on ", 'cuda')
loss = torch.nn.CrossEntropyLoss() # nn中的交叉熵损失函数
for epoch in range(num_epochs):
train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()
for i, data in enumerate(train_iter):
x, y = data
x = x.to('cuda')
y = y.to('cuda')
y_hat = net(x)
l = loss(y_hat, y)
optimizer.zero_grad() #梯度清零,为了下一步梯度下降准备
l.backward() #反向传播,计算梯度
optimizer.step() #梯度下降
train_l_sum += l.cpu().item()
train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
n += y.shape[0]
batch_count += 1
test_acc = evaluate_accuracy(test_iter, net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
% (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))
net = LeNet() #模型实例化
lr, num_epochs = 0.001, 5 #步长和训练次数
optimizer = torch.optim.Adam(net.parameters(), lr=lr) # torch.optim是一个实现了多种优化算法的包,Adam是其中一个可以调整学习率的算法
train_ch5(net, train_iter, test_iter, optimizer, num_epochs) #开始训练
总结
像我这样的懒狗一般不爱写注释,这是因为第一个pytorch就是认真的记录了一下,至于安装啥的,用conda创建环境就好了,没有啥坑,所以就不写了,下一篇应该是更细致的一些CNN模型和一些tips 🐛🐛🐛
Comments | NOTHING