前言
LeNet开启了卷积神经网络的第一枪,这一网络模型由Yann LeCun等人在1998年提出,被视为卷积神经网络的开山之作。
论文地址:
http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf
如果打不开就看csdn:
https://download.csdn.net/download/p731heminyang/89515637
LeNet-5解析
我们通过解析lenet这个最简单的卷积网络来慢慢熟悉神经网络,经典图如下:
通过上面的图可以看到整个网络包含7层
我们如下分析每一层:
卷积计算公式:卷积池化尺寸计算公式_rgb卷积池化计算-CSDN博客
不熟悉的可以先看看卷积的公式,这样可以熟悉下输入和输出如何对应,如何通过输入输出来大体推算卷积核,由于lenet-5没有填充那么就更好分析了,具体如下。
卷积层:是为了获取特征,特征值复杂就需要多层特征提取,增加感受野
池化层:是为了减少计算量简化特征和防止过拟合
全连接层:是为了输出结果
lenet-5 目的主要用于识别数字的算法,所以后面输出层为10,对应10个数字(0~9)。
第一层(卷积层):
输入参数:32x32 ,先针对图片进行处理,变成32x32的数组,再对其进行归一化处理,方便计算,这里通道为1,属于黑白图
输出参数:6x28x28 , 经过卷积核的处理得到了此参数
卷积核:6x5x5 ,通过输出参数深度参数6,可以知道经过了6个卷积核的处理,这里的卷积步长都是为1,而且没有填充,按照公式就是 28=(32-N)/1 +1 推算出N=5
参数个数:156 ,卷积核为y=wx+b ,参数等于权重w格式和b的个数,这里有6个wx+b,w为卷积核为5x5,b就是常数 1,所以参数个数为6x(5x5+1) = 156
第二层(池化层):
输入参数:6x28x28 ,上一层的输出
输出参数:6x14x14, 从这里可以看出维数减半了,那么一般是常用的滤波器2x2,步长为2
滤波器:2x2,步长为:2 通过公式刚好:14 = (28 - N)/2 +1 这里N为2
参数个数:0, 池化层没有权重,一般是最大权重或者最小权重或者平均权重,正常的都是最大权重,选择最大值。
第三层(卷积层):
输入参数:6x14x4,上一层的输出
输出参数:16x10x10, 这里有16个卷积核
卷积核:16x5x5,步长为:1 ,10=(14-N)/1 +1 推算出N=5
参数个数:416, 16x(5x5 + 1)=416
第四层(池化层):
输入参数:16x10x10,上一层的输出
输出参数:16x5x5, 从这里可以看出维数减半了,那么一般是常用的滤波器2x2,步长为2
滤波器:2x2,步长为:2 通过公式刚好:5 = (10 - N)/2 +1 这里N为2
参数个数:0, 池化层没有权重,一般是最大权重或者最小权重或者平均权重,正常的都是最大权重,选择最大值。
第五层(全连接层):
输入参数:16x5x5,上一层的输出
输出参数:120,输出一维数组
参数个数:48,120, 由于是全连接层,所以每个点都得计算,输入点数:16x5x5 =400,由于全连接层转为1维,那么每个点都得配置权重,如y=wx+b 这里的x为(16x5x5),有120组wx+b,那么参数个数为:120x(16x5x5+1) = 48120
第六层(全连接层):
输入参数:120
输出参数:84
参数个数:10,164, 有84组wx+b,x为120,所以为,84x(120+1)=10164
第七层(全连接层输出):
输出为10,代表每个数字的概率,这里是越接近0概率越高,如果1的位置为0,那么这张图片识别为1
输入参数:84
输出参数:10
参数个数:850, 有10组wx+b,x为84,所以为,10x(84+1)=850
总结:
CNN网络的开山之作,很简单的结构,总共就7层,整体的参数个数:59,706 参数接近6万,参数量相对于现在来说是已经很小了,由于之前受计算机性能和数据等影响,也没法发展太大的网络框架。但是此框架给我们开了一个头,而且由于他的简单方便我们学习。
由于这里是识别数字或者字母,特征形状很简单,所以2个卷积层来获取特征就学习到了,学习边缘和形状,一般来说层数越多学习到的特征越多,比如说颜色纹理这些都可以学习到,但是也不是绝对,后续CNN网络发展可以看到当网络层数达到一定得程度效率和精确度、泛化就会到达峰值了,需要更换新的网络结构,比如残差连接、激活参数等。
整个过程分为前向传播、计算损失(误差)、反向传播、更新参数
- 前向传播:把数据输入网络框架,通过网络计算得到结果
- 计算损失:通过损失函数计算真实结果和计算结果的误差值
- 反向传播:和前向传播相反,从输出层开始,通过误差反向计算每个权重的梯度
- 更新参数:根据反向传播得到的梯度调整网络参数,迭代进行以改善模型性能
如果不是训练,只是推理的话,那么只要前向传播就行了。
代码:(基于pytyhon的pytorch)
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
class LeNet5(nn.Module):
#初始化模型结构
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=5)#卷积层1
self.conv2 = nn.Conv2d(6, 16, kernel_size=5)#卷积层3
self.fc1 = nn.Linear(16*5*5, 120)#全连接层5
self.fc2 = nn.Linear(120, 84)#全连接层6
self.fc3 = nn.Linear(84, 10)#全连接层7
#前向传播函数
def forward(self, x):
x = F.relu(self.conv1(x))#卷积+激活,添加了激活函数,线条才会拐弯
x = F.max_pool2d(x, (2, 2))#最大池化
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, (2, 2))#最大池化
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# 初始化网络
model = LeNet5()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() #定义了交叉熵损失函数
optimizer = optim.SGD(model.parameters(), lr=0.001) #随机梯度下降(SGD)优化器 学习率为0.001,每次变化0.001
# 加载数据集,例如MNIST
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
# 训练网络,训练10轮
for epoch in range(10): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()#反向传播修改权重
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / (i + 1)}')
print('Finished Training')