全连接神经网络存在很多不足,现在常用的网络是CNN。
一、全连接神经网络的缺点:
在结构方面上:参数居多,容易丢失空间信息(NV结构———(批次,h*w*c))
如果只有两个隐藏层,每层256个节点,则MNIST数据集所需要的参数是:(28*28*256+256*256+256*10)个w,再加上(256+256+10)个b。除了计算过程中需要存储的海量的参数,还有海量的计算。大量的参数过多会导致过拟合。
一个好的拟合应该具有很强的泛化能力,不仅仅是训练时候损失低,测试的时候也需如此。
解决办法:1.训练集增加更多的数据(数据增强)2.降低模型的复杂度
二、卷积神经网络(CNN-Convolutional Neural Networks)
1、为什么用CNN?
在我们最熟悉的图像处理方面,卷积过程是考虑到图像的局部特征,能够更加准确的抽取空间特征。如果使用全连接的话,我们可能会考虑到很多不相关的信息。CNN有平移不变性,因为权值共享,图像平移了,卷积核还是可以识别出来,但是全连接则做不到,其次,目前很多计算采用的是边缘计算,很多使用的是精简指令集,在较小的内存条件下使用全连接神经网络是不现实的。
2、什么是卷积(提炼特征)
什么是卷积?通俗来讲:你在过去不同时刻惹女朋友生气的叠加,对女朋友现在坏心情的贡献就是卷积。卷积运算本质上就是在滤波器和输入数据的局部区域间做点积,将卷积层的前向传播变成一个巨大的矩阵乘法,卷积结构可以减少深层网络占用的内存量。
卷积有三个关键——局部感受野、权值共享、池化层(后面补充讲解),有效的减少了网络的参数个数,缓解了模型的过拟合问题。
在图像处理上:
二维——img.shape(1*6*6),卷积核(1*3*3),输出(1*4*4)
如图中所示,目前卷积核滑动到了图像左上角,我们把图像上的9个值与卷积核的9个数值按照对应位置相乘再相加得到一个和,这个和就是我们得到的卷积值。然后把卷积核向右移动一个像素,再执行对应位置相乘再相加的过程得到第二个卷积值,当把所有像素遍历完成之后我们得到的结果就构成了一幅图像。这就是卷积得到的图像。
上面这些看起来有些抽象,我们来看一看动图:
(1)单输入通道单输出卷积
(2)多输入通道单输出卷积(channel=3)
(3)多输入通道多输出通道卷积(2个卷积,2个输出)
(4)4维度结构可视图N(3张图)C(3通道)H(长10)W(宽10)3*3*10*10
(5)卷积神经网络结构可视化
三、代码实现
#4层卷积-一层全连接神经网络实现,#输入图像shape=1*3*39*31
(1)不加全连接不加池化:
import torch
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.layer=nn.Sequential(
# 由卷积和全连接构成NCHW
# 定义卷积层
# 输出通道3,输出通道(20),卷积核尺寸(2*2)、步长1
nn.Conv2d(3 , 20, 2, 1),
nn.ReLU(),
nn.Conv2d(20, 40, 2, 1),
nn.ReLU(),
nn.Conv2d(40, 60, 2, 1),
nn.ReLU(),
nn.Conv2d(60, 80, 2, 1),
)
def forward(self,x):#前向传播
Conv_out = self.layer(x)
return Conv_out
#测试
if __name__ == '__main__':
net=Net()
x=torch.randn(1,3,39,31)#NCHW
y=net.forward(x)
print(y.shape)
#输出为#(1,80,35,27)
(2)加入全连接未加池化:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#卷积层
self.Conv_layer=nn.Sequential(
# 由卷积和全连接构成NCHW
# 定义卷积层
# 输出通道3,输出通道(20),卷积核尺寸(2*2)、步长1
nn.Conv2d(3 , 20, 2, 1),
nn.ReLU(),
nn.Conv2d(20, 40, 2, 1),
nn.ReLU(),
nn.Conv2d(40, 60, 2, 1),
nn.ReLU(),
nn.Conv2d(60, 80, 2, 1),
)
#全连接层
self.Fnn_layer=nn.Sequential(
##卷积层的最终输出为#(1,80,35,27)
#则全连接的输入为(NV结构-N(1)V(80*35*27)
nn.Linear(80*35*27,160),
nn.Softmax(dim=1)
)
def forward(self,x):#前向传播
Conv_out = self.Conv_layer(x)
#将NCHW转为NV结构
out=Conv_out.reshape(-1,80*35*27)
out=self.Fnn_layer(out)#将NV传入全连接神经网络
return out
#测试
if __name__ == '__main__':
net=Net()
x=torch.randn(1,3,39,31)#NCHW
y=net.forward(x)
print(y.shape)
#输出为#(1,160)NV
总结
以上我们久基本了解了卷积神经网络的基本原理和结构了,后面我们将深入分析卷积神经网络里的各种优化方法(如pooling(池化)等,我将在《卷积神经网络(CNN)基础理解(二)》里面详细解释。