欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

卷积神经网络

程序员文章站 2022-07-06 13:42:26
...

​卷积神经网络这个词,应该在你开始学习人工智能不久后就听过了,那究竟什么叫卷积神经网络,今天我们就聊一聊这个问题。
卷积神经网络
不用思考,左右两张图就是两只可爱的小狗狗,但是两张图中小狗狗所处的位置是不同的,左侧图片小狗在图片的左侧,右侧图片小狗在图片的右下方,这样如果去用图片特征识别出来的结果,两张图的特征很大部分是不同的,这不是我们希望的,那思考一下,为什么我们人就可以把它们都看成是可爱的小狗狗呢?这是因为平移不变性和空间层次结构,这两个概念是卷积神经网络中的概念。

平移不变性与模式的空间层次结构

这很好理解,我们要观察或者识别的物体,在图片上平行移动,我们都可以识别出来,因为无论他们在任何地方,都有相同的特征;我们识别物体的时候,先识别物体的局部特征信息,然后再脑袋中将局部信息组合起来,组合而成更高层次的特征信息,最终形成整体信息。比如上图,我们认出他们是可爱的狗狗,但脑袋在实际运转的过程中,是先看到了一些像素点(黑白红等),然后将像素点连接起来形成轮廓或特征(耳朵、眼睛、舌头),最后组合这些特征形成最后的结论(可爱的狗狗)。这就给我们了启发,我们在计算机图片识别的识别的时候,是不是可以借鉴这种机制呢,不一定需要图片全部的信息,而是识别图片的特征信息,再由这些特征,我们会将其组合成更大的特征,再组合,最终得出整体的特征信息,如下看一个经典的图:
卷积神经网络
我们的人脑在识别人脸的时候,脑神经不同部分也处理的是不同的信息,像素点-线条边缘-对象部分-对象整体。

上面这种识别方式就与之前我们采用的各种识别方式不同了,我们之前都是将每张图作为一个整体,去识别其特征,这里更多的分析局部信息,这种方式叫卷积运算。

卷积运算

给了我们一张彩色图片,我们用长、宽和深度(用于存储每个像素点 RGB 三种颜色的值)三个维度的张量去表示,用一个小的过滤器分别去取特征值:
卷积神经网络
这里面的黄色的小框是一种过滤器,我们在做卷积运算的时候,往往需要选择多种过滤器,这样就可以得到不同的卷积特征,这里的过滤器是一个权重矩阵,与每个图片小块做张量积,得到的就是一维向量,过滤器在卷积神经网络中的术语叫卷积核。我们还可以看到,原图的尺寸是 5x5,处理后的尺寸是 3x3,缩小了一些,如果我们每次把黄色的小格子向右移动两个格子,那我们就会得到 2x2 的输出,这种移动几个格子的影响输出尺寸的术语叫做步幅。

我们这里卷积层可以处理学习图片特征的问题,但是这些特征如何去进行学习得到这是一只可爱的小狗狗的结论,还是需要以前我们用到的全连接的方法,可是对于图片来说,全连接的方法要用到的参数太多了,看下图中密密麻麻的线,这每一层还不到十个节点神经元,换成图片,动辄几千个元素,几百万几千万个参数,这样训练出的网络,只会得出过拟合的结果,需要调整,改变步幅可以,但是效果不好,因此这里我们引入一个新的概念——池化。
卷积神经网络
池化

池化可以理解为某种情况的采样。比如最大池化的操作方法是:从输入的特征值中,提取窗口,输出每个通道的最大值,这样说有点不好理解,可以理解为就是卷积层输出的结果,再用一个上面黄色的 2x2 的小窗口,步幅是 2,每次取窗口中最大值,这样就可以减少很大一部分数据量。当然,还有很多池化的方法,比如最大池化改为平均值等,当然其目的都是一样的,减少数据量。

随后,数据就可以交给全连接层,进行学习,输出结果了。

这里我们说明几个问题:我们的网络一般不会只有一个卷积层和池化层,就像全连接层不会只有一个 Dense 层,往往是:卷积层-池化层-卷积层-池化层-卷积层-全连接层(多个 Dense);我们上面虽然拿图片识别举例子,但是卷积神经网络的应用可不仅仅是图片识别,还包括目标定位、人脸识别和目标分割等,应用非常广泛;卷积神经网络的简称是 CNN,平常与他人交流的时候,很多人喜欢用 CNN。

手写数字图片识别例子优化

我们之前多分类问题中就提到了手写图片数字识别的例子,当时的准确率不到 97.8%,这里我们将其优化为卷积神经网络的写法,精度会达到 99.3%,这个提升还是很可观的呀,具体的代码解释上面都已经将理论讲清楚了,这里我就不写那么多代码的解释了,直接写在注释中,还有很多代码是之前代码,不再赘述了,看网络架构:

卷积神经网络
看代码:

#!/usr/bin/env python3

import time

from keras import layers
from keras import models
from keras.datasets import mnist
from keras.utils import to_categorical


def cat():
    model = models.Sequential()

    # filters       输出空间的维数
    # kernel_size   窗口大小,就是上面黄色窗口的大小
    # activation    **函数
    # input_shape   输入
    model.add(layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))

    # 最大池化
    # pool_size 窗口大小
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))

    model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))

    # 展平一个张量
    model.add(layers.Flatten())

    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(10, activation='softmax'))

    # 查看神经网络架构
    # model.summary()

    (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
    train_images = train_images.reshape((60000, 28, 28, 1))
    train_images = train_images.astype('float32') / 255
    test_images = test_images.reshape((10000, 28, 28, 1))
    test_images = test_images.astype('float32') / 255
    train_labels = to_categorical(train_labels)
    test_labels = to_categorical(test_labels)
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    model.fit(train_images, train_labels, epochs=5, batch_size=64)
    test_loss, test_acc = model.evaluate(test_images, test_labels)
    print(test_acc)


if __name__ == "__main__":
    time_start = time.time()
    cat()
    time_end = time.time()
    print('Time Used: ', time_end - time_start)