什么是CNN?理论介绍与简单实践

CNN(Convolutional Neural Network)

1、CNN的过程划分

CNN由卷积层,池化层,激活函数、全连接层构成,
在这里插入图片描述
有时也会搭配激活函数来加入非线性因素,如下图所示在卷积层CONV后增加激活函数RELU。
在这里插入图片描述

通俗来讲,CNN用在图像处理上,就是通过卷积层、池化层来提取和简化图像的特征信息矩阵

之后全连接层将特征信息矩阵转化为神经网络的输入,输出为图像是某种东西的概率。

1.1 卷积层(convolution)

卷积层大大简化了神经网络需要的训练参数

假设输入一个 100*100 的矩阵类型数据,神经网络隐藏层有10个神经元:

对于传统的神经网络模型,输入的是 100*100 个数据,每个数据都与神经元连接,需要训练的参数为 100 * 100 * 10 个参数。

如果加上卷积层,则通过卷积核会过滤一遍数据得到特征矩阵,假设此时过滤后的特征矩阵是10 * 10,此时每个神经元与特征矩阵相连接,只需要训练 10 * 10 * 10 个参数,大大降低了训练量。

卷积层还有一个“权值共享”的特性,由于特征图的每个元素都是由一个同样的卷积核滤波得到,所以与特征图连接的每个神经元的权值都相等,此时实际需要训练的参数为 10 * 10 * 1。

a、卷积核

卷积的过程如图所示,卷积矩阵也称为滤波器
在这里插入图片描述

对于3 * 3的卷积核,最后得到的特征矩阵称为特征图(Feature Map),特征图的每个数据都是输入矩阵的 3* * 3局部连接,即为特征图元素的感受野。
在这里插入图片描述

卷积核有 size、stride、padding 、channels 等参数:

size:卷积核的的尺寸,例如3 * 3

stride:卷积核每次移动的步长,如图所示当 stride = 2 时,特征图的尺寸会发生变化
在这里插入图片描述
padding:即在输入矩阵周围增加填充,可以减少输入边缘的影响,同 stride配合可以实现输入矩阵与输出矩阵维度一致。如图所示 padding = 1,stride = 2 的情况:
在这里插入图片描述

padding常用术语为:

(1)valid:无填充,padding = 0

(2)same:有填充,且需保证输入和输出的矩阵维度一致

输出矩阵的维度 = floor {

(输入矩阵维度-卷积核维度 + 2 * padding)/ stride + 1

}

channels 代表卷积核的通道数,例如一张彩色照片的通道数为3,包含RGB三个通道,所以对应的卷积核的通道数也为3,卷积过程如图所示:

每个卷积核的channel与输入层对应channel进行卷积后,将每个channel的卷积结果按照位相加得到最终的 Feature Map
在这里插入图片描述

当有多个卷积核时,可以得到多种不同的特征,对应产生多个 channel 的feature map,如下图所示:
在这里插入图片描述

1.2 激活函数(activation)

在这里插入图片描述

单纯的卷积层是一个线性处理的过程,激活层主要为了引入非线性因素,一般在卷积或者池化之后引入非线性激活。常用的激活函数有 sigmoid、relu、elu函数等:
在这里插入图片描述

1.3 池化层(Pooling)

在这里插入图片描述

池化层对特征图进行亚采样处理,用于降低矩阵维度以及防止过拟合。

池化层包含三个超参数:

1、pool size 采样窗口的大小

2、stride 移动步长

3、type 采样方式,包含 Max Pooling(取窗口最大值)、Mean Pooling(取窗口的平均值)两种

1.4 全连接层(Full Connection)

在这里插入图片描述

全连接层相当于将特征图数据扁平化,例如特征图的维度为 2*2 的矩阵扁平化为 1 * 4 的列向量,每个元素对应一个输入的神经元,再加上隐藏层,构成传统的神经网络。

1.5 整体概述

卷积层+激化层+池化层可以看作对输入数据的特征简化与提取,得到特征图之后通过全连接层扁平化之后,开始机器学习。

2、show me code

CNN识别手写字母,数据来源于Minist 数据集;

Minist 数据集包含训练集和测试集,训练集用于CNN网络各参数的训练,测试集用于测试CNN网络的求解精度。

每个集又包括要识别的图像 + 图像对应的标签。

训练CNN网络时,将images输入进去,得到CNN网络求解出来的labels,再与真实的labels作比较,根据误差不断修正CNN网络的参数之。

在这里插入图片描述

a、模型的建立

下面截取了一段建立与训练CNN模型的代码,完整的代码参考reference的链接。

'''开始建立CNN网络'''
class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        '''
        一般来说,卷积网络包括以下内容:
        1.卷积层
        2.神经网络
        3.池化层
        '''
        self.conv1=nn.Sequential(
            nn.Conv2d(              #--> (1,28,28)
                in_channels=1,      #传入的图片是几层的,灰色为1层,RGB为三层
                out_channels=16,    #输出的图片是几层
                kernel_size=5,      #代表扫描的区域点为5*5
                stride=1,           #就是每隔多少步跳一下
                padding=2,          #边框补全,其计算公式=(kernel_size-1)/2=(5-1)/2=2
            ),    # 2d代表二维卷积           --> (16,28,28)
            nn.ReLU(),              #非线性激活层
            nn.MaxPool2d(kernel_size=2),    #设定这里的扫描区域为2*2,且取出该2*2中的最大值          --> (16,14,14)
        )

        self.conv2=nn.Sequential(
            nn.Conv2d(              #       --> (16,14,14)
                in_channels=16,     #这里的输入是上层的输出为16层
                out_channels=32,    #在这里我们需要将其输出为32层
                kernel_size=5,      #代表扫描的区域点为5*5
                stride=1,           #就是每隔多少步跳一下
                padding=2,          #边框补全,其计算公式=(kernel_size-1)/2=(5-1)/2=
            ),                      #   --> (32,14,14)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),    #设定这里的扫描区域为2*2,且取出该2*2中的最大值     --> (32,7,7),这里是三维数据
        )

        self.out=nn.Linear(32*7*7,10)       #注意一下这里的数据是二维的数据

    def forward(self,x):
        x=self.conv1(x)
        x=self.conv2(x)     #(batch,32,7,7)
        #然后接下来进行一下扩展展平的操作,将三维数据转为二维的数据
        x=x.view(x.size(0),-1)    #(batch ,32 * 7 * 7)
        output=self.out(x)
        return output

b、模型的训练

# 添加优化方法
optimizer=torch.optim.Adam(cnn.parameters(),lr=LR)
# 指定损失函数使用交叉信息熵
loss_fn=nn.CrossEntropyLoss()
step=0
for epoch in range(EPOCH):
    #加载训练数据
    for step,data in enumerate(train_loader):
        x,y=data
        #分别得到训练数据的x和y的取值,x为images图像,y为图像对应的标签
        b_x=Variable(x)
        b_y=Variable(y)

        output=cnn(b_x)         #调用模型预测
        loss=loss_fn(output,b_y)#计算损失值
        optimizer.zero_grad()   #每一次循环之前,将梯度清零
        loss.backward()         #反向传播
        optimizer.step()        #梯度下降

        #每执行50次,输出一下当前epoch、loss、accuracy
        if (step%50==0):
            #利用测试集数据计算一下模型预测正确率
            test_output=cnn(test_x)
            y_pred=torch.max(test_output,1)[1].data.squeeze()
            accuracy=sum(y_pred==test_y).item()/test_y.size(0)

            print('now epoch :  ', epoch, '   |  loss : %.4f ' % loss.item(), '     |   accuracy :   ' , accuracy)

由此得到训练好的可以识别字符的CNN模型。

3、reference

理论部分参考:http://hejunhao.me/archives/1364#more-1364

代码部分参考:https://blog.csdn.net/weixin_38468077/article/details/106592690

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值