深度学习七日打卡营-Day02(1)卷积神经网络

今天是深度学习七日打卡营的第二天,学到了第二课,也是时候了解图像识别领域的常规算法,卷积神经网络啦

深度学习七日打卡营第二天

  • 1.图像分类简介
    • 1.1常见图像分类场景
    • 1.3 为什么要用卷积神经网络
  • 2.浅话卷积神经网络
    • 2.1 神经网络结构
    • 2.2浅话卷积神经网络要点
      • 2.2.1卷积操作
      • 2.2.2 池化操作
      • 2.2.3 卷积操作后图像大小计算
    • 2.2.4 Padding
      • 2.2.5 常用激活函数
      • 2.2.6 Dropout
  • 3 LeNet卷积神经网络手写数字识别案例
    • 3.1 回顾深度学习万能公式
      • 3.1.1 数据准备及导入相关库
      • 3.1.2模型选择和开发
        • 3.1.2.1 复现论文
        • 3.1.2.2另一种模型
        • 3.1.2.3 类方法实现
        • 3.1.2.4 直接调用高层API封装模型
      • 3.1.3 模型训练调优
      • 3.1.4 部署上线
      • 3.1.5 保存模型
  • 总结

1.图像分类简介

人工智能有三大主要板块:图像识别、语音处理和推荐系统,而在图像识别领域,分类问题是一个不可避免的问题

深度学习七日打卡营-Day02(1)卷积神经网络_第1张图片
其主要框架如下:

深度学习七日打卡营-Day02(1)卷积神经网络_第2张图片
经过数据处理,用卷积神经网络搭建相关模型,来达到图像分类的目的

1.1常见图像分类场景

深度学习七日打卡营-Day02(1)卷积神经网络_第3张图片
生活中到处可见图像分类用途场景,适用范围广泛,比如二分类任务,分类猫狗图片,多分类任务给多种图片贴上标签,多标签任务给同一图片的不同物种贴上标签等。

深度学习七日打卡营-Day02(1)卷积神经网络_第4张图片

1.3 为什么要用卷积神经网络

深度学习七日打卡营-Day02(1)卷积神经网络_第5张图片
如图,计算机看到的图像是一堆矩阵,图像在计算机中是[0,255]区间的象素点,在图像分类任务中,该图像属于‘0’类的概率最大,故将其归为0类。

深度学习七日打卡营-Day02(1)卷积神经网络_第6张图片

通常,在图像识别时,因为计算机只能识别像素点的关系,我们会出现语义鸿沟现象,图像的特征提取成为图像识别的一个难点(以往的机器学习为人工提取特征)

深度学习七日打卡营-Day02(1)卷积神经网络_第7张图片

与人眼识别图像相类似,卷积神经网络通过不断抽象的方式提取图像特征,通过图像送入,发现边缘和方向,再不断抽象,提取相关特征,最后达到分类目的。
深度学习七日打卡营-Day02(1)卷积神经网络_第8张图片
在1998年。LeNet网络架构被提出,从此卷积神经网络被引入科学领域,特别是AlexNet赢得imageNet冠军之后,卷积神经网络越来越被人们所重视,经过若干发展呢,现在在图像识别领域取得了较大成功, 其中GoogleNet又被叫做Inception V3/V4

深度学习七日打卡营-Day02(1)卷积神经网络_第9张图片

2.浅话卷积神经网络

深度学习七日打卡营-Day02(1)卷积神经网络_第10张图片

2.1 神经网络结构

神经元
深度学习七日打卡营-Day02(1)卷积神经网络_第11张图片
其一般公式为:y=w*x+b,其中b为偏置项,通过计算,得出数值,向前传播

神经网络:

深度学习七日打卡营-Day02(1)卷积神经网络_第12张图片

许多神经元的运算集合就是神经网络啦

2.2浅话卷积神经网络要点

2.2.1卷积操作

单通道卷积
深度学习七日打卡营-Day02(1)卷积神经网络_第13张图片
通过卷积的内积操作,如左上角为 10+21+42+53=25,得到卷积后的第一个元素,而后向右移动步长1,继续卷积操作

多通道卷积:
深度学习七日打卡营-Day02(1)卷积神经网络_第14张图片
与单通道卷积不同的是,比如输入的是一个彩色图像,其高度为3维的,故卷积核对应的高度也应该是三维的,分别做内积再相加,得到输出为一维的矩阵

深度学习七日打卡营-Day02(1)卷积神经网络_第15张图片
当想要输出几个通道的图像,卷积核就用几个通道的,比如我们是两个通道的卷积核,故结果也输出两个通道的特征图像

2.2.2 池化操作

目前池化有两种操作,平均池化和最大池化
(使用某一位置的相邻输出的总体统计特征代替网络在该位置的输出,其好处是当输入数据做出少量平移时,经过池化函数后的大多数输出还能保持不变。)
比如:当识别一张图像是否是人脸时,我们需要知道人脸左边有一只眼睛,右边也有一只眼睛,而不需要知道眼睛的精确位置,这时候通过池化某一片区域的像素点来得到总体统计特征会显得很有用。由于池化之后特征图会变得更小,如果后面连接的是全连接层,能有效的减小神经元的个数,节省存储空间并提高计算效率。

即特征选择和信息过滤,减少参数运算量(卷积神经网络的三大特性:局部连接,位置共享和下采样)

Avg Pooling 平均池化与最大池化

深度学习七日打卡营-Day02(1)卷积神经网络_第16张图片

平均池化是一个区域像素点的平均值代替整体特征,其好处是提取到了局部的所有特征

对邻域内特征点求平均

优缺点:能很好的保留背景,但容易使得图片变模糊
正向传播:邻域内取平均
反向传播:特征值根据领域大小被平均,然后传给每个索引位置
平均池化是一个区域像素点的平均值代替整体特征,其好处是提取到了局部的所有特征

而最大池化是选取局部区域的最大像素值作为整体特征点,其特点是选取最有效的特征

优缺点:能很好的保留一些关键的纹理特征,现在更多的再使用Max Pooling而很少用Avg Pooling
正向传播:取邻域内最大,并记住最大值的索引位置,以方便反向传播
反向传播:将特征值填充到正向传播中,值最大的索引位置,其他位置补0

2.2.3 卷积操作后图像大小计算

在这里插入图片描述
在这里插入图片描述

其中W是输入图片宽度,p是padding值,k是卷积核宽度,S是Stride步长
高度计算同理

2.2.4 Padding

深度学习七日打卡营-Day02(1)卷积神经网络_第17张图片
其主要作用为:

1):当进行卷积操作时,左角边缘或右角边缘总是只计算一次(少量计算),而中间区域进行多次叠加操作,故角落边缘特征提取少,为提取角落边缘特征,我们需用padding进行填充操作

2):为达到与原始图像一样的大小,我们也可以用padding’操作

2.2.5 常用激活函数

深度学习七日打卡营-Day02(1)卷积神经网络_第18张图片

                                  Sigmoid函数

深度学习七日打卡营-Day02(1)卷积神经网络_第19张图片

                              Tanh函数

Sigmoid和Tanh激活函数有共同的缺点:即在值很大或很小时,梯度几乎为零,因此使用梯度下降优化算法更新网络很慢。

深度学习七日打卡营-Day02(1)卷积神经网络_第20张图片

                                  ReLU函数

Relu目前是选用比较多的激活函数,但是也存在一些缺点,在z小于0时,斜率即导数为0。 为了解决这个问题,后来也提出来了Leaky Relu激活函数,不过目前使用的不是特别多。

2.2.6 Dropout

深度学习七日打卡营-Day02(1)卷积神经网络_第21张图片

当一个复杂的前馈神经网络被训练在小的数据集时,容易造成过拟合。为了防止过拟合,可以通过随机丢弃部分特征节点的方式来减少这个问题发生。

3 LeNet卷积神经网络手写数字识别案例

学会了基础知识,那现在就来实践一下吧

3.1 回顾深度学习万能公式

在这里插入图片描述

3.1.1 数据准备及导入相关库

import paddle
import numpy as np
import matplotlib.pyplot as plt

paddle.__version__

在这里插入图片描述
还是采用现有数据集

# 数据预处理
import paddle.vision.transforms as T

# 数据预处理,TODO:找一下提出的原论文看一下
transform = T.Normalize(mean=[127.5], std=[127.5])#归一化数据

# 训练数据集
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)

# 验证数据集
eval_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)

print('训练样本量:{},测试样本量:{}'.format(len(train_dataset), len(eval_dataset)))

在这里插入图片描述
数据查看:

print('图片:')
print(type(train_dataset[0][0]))
print(train_dataset[0][0])
print('标签:')
print(type(train_dataset[0][1]))
print(train_dataset[0][1])

# 可视化展示
plt.figure()
plt.imshow(train_dataset[0][0].reshape([28,28]), cmap=plt.cm.binary)
plt.show()

深度学习七日打卡营-Day02(1)卷积神经网络_第22张图片
归一化后的像素数组

3.1.2模型选择和开发

深度学习七日打卡营-Day02(1)卷积神经网络_第23张图片

在这里插入图片描述

3.1.2.1 复现论文

import paddle.nn as nn#导入相关接口

network = nn.Sequential(
    nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=0),  # C1 卷积层
    nn.Tanh(),#激活函数,非线性变化,方便梯度计算
    nn.AvgPool2D(kernel_size=2, stride=2),  # S2 平局池化层
    nn.Sigmoid(),   # Sigmoid激活函数
    nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=0),  # C3 卷积层
    nn.Tanh(),
    nn.AvgPool2D(kernel_size=2, stride=2),  # S4 平均池化层
    nn.Sigmoid(),  # Sigmoid激活函数
    nn.Conv2D(in_channels=16, out_channels=120, kernel_size=5, stride=1, padding=0), # C5 卷积层
    nn.Tanh(),#激活函数,非线性变化,方便梯度计算
    nn.Flatten(),#展平
    nn.Linear(in_features=120, out_features=84), # F6 全连接层
    nn.Tanh(),#激活函数,非线性变化,方便梯度计算
    nn.Linear(in_features=84, out_features=10) # OUTPUT 全连接层
)

按照LeNet模型搭建就可

模型可视化:

model = paddle.Model(network)#封装已经设置好的网络结构

#模型可视化
model.summary((1, 28, 28))

对比:

paddle.summary(network, (1, 1, 32, 32))

深度学习七日打卡营-Day02(1)卷积神经网络_第24张图片

3.1.2.2另一种模型

import paddle.nn as nn

network_2 = nn.Sequential(
    nn.Conv2D(in_channels=1, out_channels=6, kernel_size=3, stride=1, padding=1),#kernerl为3*3
    nn.ReLU(),
    nn.MaxPool2D(kernel_size=2, stride=2),
    nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=0),
    nn.ReLU(),
    nn.MaxPool2D(kernel_size=2, stride=2),
    nn.Flatten(),
    nn.Linear(in_features=400, out_features=120),  # 400 = 5x5x16,输入形状为32x32, 输入形状为28x28时调整为256
    nn.Linear(in_features=120, out_features=84),
    nn.Linear(in_features=84, out_features=10)
)
paddle.summary(network_2, (1, 1, 28, 28))#输入的是28*28,上面的网络模型也做出了一些调整

深度学习七日打卡营-Day02(1)卷积神经网络_第25张图片

3.1.2.3 类方法实现

class LeNet(nn.Layer):
    """
    继承paddle.nn.Layer定义网络结构
    """

    def __init__(self, num_classes=10):
        """
        初始化函数
        """
        super(LeNet, self).__init__()

        self.features = nn.Sequential(
            nn.Conv2D(in_channels=1, out_channels=6, kernel_size=3, stride=1, padding=1),  # 第一层卷积
            nn.ReLU(), # 激活函数
            nn.MaxPool2D(kernel_size=2, stride=2),  # 最大池化,下采样
            nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=0), # 第二层卷积
            nn.ReLU(), # 激活函数
            nn.MaxPool2D(kernel_size=2, stride=2) # 最大池化,下采样
        )

        self.fc = nn.Sequential(
            nn.Linear(400, 120),  # 全连接
            nn.Linear(120, 84),   # 全连接
            nn.Linear(84, num_classes) # 输出层
        )

    def forward(self, inputs):
        """
        前向计算
        """
        y = self.features(inputs)
        y = paddle.flatten(y, 1)
        out = self.fc(y)

        return out

network_3 = LeNet()

3.1.2.4 直接调用高层API封装模型

network_4 = paddle.vision.models.LeNet(num_classes=10)

3.1.3 模型训练调优

搭好模型后就是模型的训练了,与第一天的步骤一样

# 模型封装
model = paddle.Model(network_4)

# 模型配置
model.prepare(paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()), # 优化器
              paddle.nn.CrossEntropyLoss(), # 损失函数
              paddle.metric.Accuracy()) # 评估指标

# 启动全流程训练
model.fit(train_dataset,  # 训练数据集
          eval_dataset,   # 评估数据集
          epochs=5,       # 训练轮次
          batch_size=64,  # 单次计算数据样本量
          verbose=1)      # 日志展示形式

模型评估:

result = model.evaluate(eval_dataset, verbose=1)

print(result)

深度学习七日打卡营-Day02(1)卷积神经网络_第26张图片
准确率达到0.9861

模型预测:

# 进行预测操作
result = model.predict(eval_dataset)
# 定义画图方法
import random
def show_img(img, predict):
    plt.figure()
    plt.title('predict: {}'.format(predict))
    plt.imshow(img.reshape([28, 28]), cmap=plt.cm.binary)
    plt.show()

# 抽样展示
indexs=[]
i=10
while  i>0:
    a=random.randint(0,10000)
    indexs.append(a)
    i=i-1
print(indexs)
for idx in indexs:
    show_img(eval_dataset[idx][0], np.argmax(result[0][idx]))


深度学习七日打卡营-Day02(1)卷积神经网络_第27张图片

3.1.4 部署上线

model.save('finetuning/mnist')

#继续调优训练
from paddle.static import InputSpec

network = paddle.vision.models.LeNet(num_classes=10)
# 模型封装,为了后面保存预测模型,这里传入了inputs参数
model_2 = paddle.Model(network, inputs=[InputSpec(shape=[-1, 1, 28, 28], dtype='float32', name='image')])

# 加载之前保存的阶段训练模型
model_2.load('finetuning/mnist')

# 模型配置
model_2.prepare(paddle.optimizer.Adam(learning_rate=0.0001, parameters=network.parameters()),  # 优化器
                paddle.nn.CrossEntropyLoss(), # 损失函数
                paddle.metric.Accuracy()) # 评估函数

# 模型全流程训练
model_2.fit(train_dataset,  # 训练数据集
            eval_dataset,   # 评估数据集
            epochs=2,       # 训练轮次
            batch_size=64,  # 单次计算数据样本量
            verbose=1)      # 日志展示形式

3.1.5 保存模型

# 保存用于后续推理部署的模型
model_2.save('infer/mnist', training=False)

总结

今天简单认识了卷积神经网络及初等LeNet模型,图像识别领域中,卷积神经网络是基础模型。

你可能感兴趣的:(卷积神经网络)