亲宝软件园·资讯

展开

卷积神经网络

renyuzhuo 人气:3

​卷积神经网络这个词,应该在你开始学习人工智能不久后就听过了,那究竟什么叫卷积神经网络,今天我们就聊一聊这个问题。

不用思考,左右两张图就是两只可爱的小狗狗,但是两张图中小狗狗所处的位置是不同的,左侧图片小狗在图片的左侧,右侧图片小狗在图片的右下方,这样如果去用图片特征识别出来的结果,两张图的特征很大部分是不同的,这不是我们希望的,那思考一下,为什么我们人就可以把它们都看成是可爱的小狗狗呢?这是因为平移不变性和空间层次结构,这两个概念是卷积神经网络中的概念。

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

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

我们的人脑在识别人脸的时候,脑神经不同部分也处理的是不同的信息,像素点-线条边缘-对象部分-对象整体。

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

卷积运算

给了我们一张彩色图片,我们用长、宽和深度(用于存储每个像素点 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)

加载全部内容

相关教程
猜你喜欢
用户评论