一、LeNet-5
LeNet-5中主要有2个卷积层、2个下抽样层(池化层)、3个全连接层3种连接方式
1.LeNet-5第一层:卷积层C1
C1层是卷积层,形成6个特征图谱。卷积的输入区域大小是5x5,每个特征图谱内参数共享,即每个特征图谱内只使用一个共同卷积核,卷积核有5x5个连接参数加上1个偏置共26个参数。卷积区域每次滑动一个像素,这样卷积层形成的每个特征图谱大小是(32-5)/1+1=28x28。C1层共有26x6=156个训练参数,有(5x5+1)x28x28x6=122304个连接。
2.LeNet-5第二层:池化层S2
S2层是一个下采样层(为什么是下采样?利用图像局部相关性的原理,对图像进行子抽样,可以减少数据处理量同时保留有用信息)。C1层的6个28x28的特征图谱分别进行以2x2为单位的下抽样得到6个14x14((28-2)/2+1)的图。每个特征图谱使用一个下抽样核。5x14x14x6=5880个连接。
3.LeNet-5第三层:卷积层C3
C3层是一个卷积层,卷积和和C1相同,不同的是C3的每个节点与S2中的多个图相连。C3层有16个10x10(14-5+1)的图,每个图与S2层的连接的方式如下表 所示。C3与S2中前3个图相连的卷积结构见下图.这种不对称的组合连接的方式有利于提取多种组合特征。该层有(5x5x3+1)x6 + (5x5x4 + 1) x 3 + (5x5x4 +1)x6 + (5x5x6+1)x1 = 1516个训练参数,共有1516x10x10=151600个连接。
4.LeNet-5第四层:池化层S4
S4是一个下采样层。C3层的16个10x10的图分别进行以2x2为单位的下抽样得到16个5x5的图。5x5x5x16=2000个连接。连接的方式与S2层类似。
5.LeNet-5第五层:全连接层C5
C5层是一个全连接层。由于S4层的16个图的大小为5x5,与卷积核的大小相同,所以卷积后形成的图的大小为1x1。这里形成120个卷积结果。每个都与上一层的16个图相连。所以共有(5x5x16+1)x120 = 48120个参数,同样有48120个连接。
6.LeNet-5第六层:全连接层F6
F6层是全连接层。F6层有84个节点,对应于一个7x12的比特图,该层的训练参数和连接数都是(120 + 1)x84=10164。
7.LeNet-5第七层:全连接层Output
Output层也是全连接层,共有10个节点,分别代表数字0到9,如果节点i的输出值为0,则网络识别的结果是数字i。采用的是径向基函数(RBF)的网络连接方式。假设x是上一层的输入,y是RBF的输出,则RBF输出的计算方式是:yi的值由i的比特图编码(即参数Wij)确定。yi越接近于0,则标明输入越接近于i的比特图编码,表示当前网络输入的识别结果是字符i。该层有84x10=840个设定的参数和连接。连接的方式如上图。以上是LeNet-5的卷积神经网络的完整结构,共约有60,840个训练参数,340,908个连接。
二、参数改变
# 多层结构:三层卷积 + 两层池化 + 两层全连接
class Net2(nn.Module):
def __init__(self):
super(Net2, self).__init__()
self.conv_unit = nn.Sequential(
# out-> [24,24,40]
nn.Conv2d(1, 40, kernel_size=5, stride=1),
nn.ReLU(),
# out->[12,12,40]
nn.MaxPool2d(kernel_size=2, stride=2),
# out->[10,10,10]
nn.Conv2d(40, 20, kernel_size=3, stride=1),
nn.ReLU(),
# out->[5,5,20]
nn.MaxPool2d(kernel_size=2,stride=2),
# out->[3,3,20]
nn.Conv2d(20,20,kernel_size=3, stride=1),
nn.ReLU()
)
self.fc_unit = nn.Sequential(
nn.Flatten(),
nn.Linear(3*3*20,100),
nn.ReLU(),
nn.Linear(100, 10)
)
def forward(self,x):
x = self.conv_unit(x)
x = self.fc_unit(x)
return x
batch size为128
learning rate为0.001
采用ReLU激活函数
使用交叉熵损失函数
SGD方式优化(momentum为0.9)
1.添加BN
添加batch normalization后,单、多层网络与默认情况相比表现均有所提升,准确率上升1个百分点以上,且模型的收敛速度更快,说明BN对模型训练有加速效果。特别需要注意的是,在多层网络上加速收敛效果尤为明显,通过BN操作,将初始epoch的测试准确率提高至94%,与未加BN的比较好了很多。
2.激活函数为tanh
tanh激活函数的表现一般,两种网络的准确率均有下降,但下降幅度不大。
3.激活函数为LeakyReLU
模型效果并无很大的改善。
4.激活函数为sigmoid
使用sigmoid激活函数时,表现非常差,单层网络准确度下降十几个百分点,而多层网络无法正常工作,test loss值不断跳跃,变化幅度缓慢,说明使用sigmoid激活函数造成了梯度饱和,无法对参数值正常迭代,导致准确率无法上升,仅为11.35%,说明在这个多层网络中,不能使用sigmoid作为激活函数。
5.L2正则化
在网络中添加L2正则化,pytorch很容易可以实现,定义优化器时加入参数weight_decay,即设定L2正则化中的λ \lambdaλ数值,这里设置为1e-4,观察效果,即
optimizer = optim.SGD(model_single.parameters(),
lr=learning_rate,momentum=0.9, weight_decay=1e-4)
训练结果变化不明显,但是可以看到,初始准确率较默认情况还是有上升,有一定的加速作用。
6.DropOut
在网络中加入DropOut层,将丢弃概率设置为0.3
单层网络添加DropOut使最终的准确率下降了,而在多层网络中准确率有所上升,可能原因为单层网络中模型拟合能力较多层网络弱,在丢弃后对数据的拟合能力进一步下降,导致准确率下降,而多层网络丢弃恰好改进了过拟合,使得最终准确率有所上升。
无论是单层还是双层,其test loss最后与train loss 的差距越来越大,考虑是学习率的问题导致在测试集上收敛过快。
7.Adam优化器
将原本的SGD优化器改换为Adam优化器
Adam优化器的表现优于SGD,二者的准确率均有提升,但是在训练后期都出现了过拟合问题,test loss和test acc起伏较大。
8.learning_rate=0.01
提高学习率改善了网络效果,模型收敛速度非常快,但最后出现了过拟合问题,下面使用学习率衰减进行改进。