机器学习16:简单, 直观的方法理解CNN(卷积神经网络)核心原理及实现

1.CNN(卷积神经网络)的典型应用场景

1.1 WaveNet 模型:

https://deepmind.com/blog/wavenet-generative-model-raw-audio/

如果你能训练人工智能机器人唱歌,干嘛还训练它聊天?在 2017 年 4 月,研究人员使用 WaveNet 模型的变体生成了歌曲。原始论文和演示可以在此处找到。

http://www.creativeai.net/posts/W2C3baXvf2yJSLbY6/a-neural-parametric-singing-synthesizer

1.2 文本分类 CNN

http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/

你或许想注册作者的深度学习简讯!

1.3 Facebook的创新CNN方法

https://code.facebook.com/posts/1978007565818999/a-novel-approach-to-neural-machine-translation/

该方法专门用于解决语言翻译任务,准确率达到了前沿性水平,并且速度是 RNN 模型的 9 倍。

1.4 Atari 游戏

利用 CNN 和强化学习玩 Atari 游戏。你可以下载此论文附带的代码

如果你想研究一些(深度强化学习)初学者代码,建议你参阅 Andrej Karpathy 的帖子。

1.5 利用 CNN 玩看图说词游戏!

https://quickdraw.withgoogle.com/#

此外,还可以参阅 A.I.Experiments 网站上的所有其他很酷的实现。别忘了 AutoDraw!

1.6 详细了解 AlphaGo。

https://deepmind.com/research/alphago/

阅读这篇文章,其中提出了一个问题:如果掌控 Go“需要人类直觉”,那么人性受到挑战是什么感觉?_

1.7 观看这些非常酷的视频,其中的无人机都受到 CNN 的支持。

这是初创企业 Intelligent Flying Machines (IFM) (Youtube)的访谈。
户外自主导航通常都要借助全球定位系统 (GPS),但是下面的演示展示的是由 CNN 提供技术支持的自主无人机(Youtube)。

1.8 无人驾驶汽车使用的 CNN 感兴趣

我们在此项目中对德国交通标志数据集中的标志进行分类。

优达学城交通标志分类项目

德国交通标志数据集

我们在此项目中对街景门牌号数据集中的门牌号进行分类。

https://github.com/udacity/machine-learning/tree/master/projects/digit_recognition

http://ufldl.stanford.edu/housenumbers/

这些系列博客,其中详细讲述了如何训练用 Python 编写的 CNN,以便生成能够玩“侠盗猎车手”的无人驾驶 AI。

https://pythonprogramming.net/game-frames-open-cv-python-plays-gta-v/

1.9 其他应用情形

一些全球最著名的画作被转换成了三维形式,以便视力受损人士也能欣赏。虽然这篇文章没有提到是怎么做到的,我们注意到可以使用 CNN 预测单个图片的深度

参阅这篇关于使用 CNN 确定乳腺癌位置的研究论文(google research)。

CNN 被用来拯救濒危物种!

一款叫做 FaceApp 的应用使用 CNN 让你在照片中是微笑状态或改变性别。

2.CNN原理

相对于多层感知机(MLP), 当知道两个输入可能包含相同类型信息时,可以共享它们的权重,并利用这些输入共同训练权重。

统计不变量,即基本上不会随时间或空间改变的事物,无处不在;

对于图像,权重共享的思想引出了卷积网络的研究;

对于一般的文本和序列,则涉及嵌入和循环神经网络。

局部连接性

在这里插入图片描述

参数共享性

在这里插入图片描述

对于多层网络输出入

在这里插入图片描述

卷积网络本质上就是一个深度网络,但用共享权重的“卷积层”替代了一般的“全连接层”。

CNN总的想法是让整个网络形成金字塔状,金字塔底部是一个非常大而浅的图片,仅包含RGB三通道,通过卷积操作逐渐挤压空间的维度,同时不断增加深度,使深度信息大体上可以表示出复杂的语义。

在金字塔尖顶端可以放一个分类器,所有空间信息都被压缩成一个表示,仅映射到图片内容的参数被保留。

在这里插入图片描述

卷积层的stride和pad

在这里插入图片描述

3.Keras中的卷积层

导入必要的模块:

from keras.layers import Conv2D

创建卷积层

Conv2D(filters, kernel_size, strides, padding, activation=‘relu’, input_shape)

参数

必须传递以下参数:

filters - 过滤器数量。
kernel_size - 指定(方形)卷积窗口的高和宽的数字。

你可能还需要调整其他可选参数:

strides - 卷积 stride。如果不指定任何值,则 strides 设为 1。

padding - 选项包括 ‘valid’ 和 ‘same’。如果不指定任何值,则 padding 设为 ‘valid’。

activation - 通常为 ‘relu’。如果未指定任何值,则不应用任何激活函数。强烈建议你向网络中的每个卷积层添加一个 ReLU 激活函数。

注意:可以将 kernel_size 和 strides 表示为数字或元组

在模型中将卷积层当做第一层级(出现在输入层之后)时,必须提供另一个 input_shape 参数:

input_shape - 指定输入的高度、宽度和深度(按此顺序)的元组。

你还可以设置很多其他元组参数,以便更改卷积层的行为。要详细了解这些参数,建议参阅官方文档。

https://keras.io/layers/convolutional/

示例 1

假设要构建一个 CNN,输入层接受的是 200 x 200 像素(对应于高 200、宽 200、深 1 的三维数组)的灰度图片。

然后,假设我希望下一层级是卷积层,具有 16 个过滤器,每个宽和高分别为 2。

在进行卷积操作时,我希望过滤器每次跳转 2 个像素。并且,我不希望过滤器超出图片界限之外;

也就是说,我不想用 0 填充图片。要构建该卷积层,我将使用下面的代码:

Conv2D(filters=16, kernel_size=2, strides=2, activation='relu', input_shape=(200, 200, 1))

示例 2

假设我希望 CNN 的下一层级是卷积层,并将示例 1 中构建的层级作为输入。

假设新层级是 32 个过滤器,每个的宽和高都是 3。

在进行卷积操作时,我希望过滤器每次移动 1 个像素。

我希望卷积层查看上一层级的所有区域,因此不介意过滤器在进行卷积操作时是否超过上一层级的边缘。

然后,要构建此层级,我将使用以下代码:

from keras.layers import Conv2D
Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')

示例 3

如果在线查看代码,经常会在 Keras 中见到以下格式的卷积层:

Conv2D(64, (2,2), activation='relu')

在这种情况下,有 64 个过滤器,每个的大小是 2x2,层级具有 ReLU 激活函数。层级中的其他参数使用默认值,因此卷积的 stride 为 1,填充设为 ‘valid’。

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, strides=2, padding='valid', 
    activation='relu', input_shape=(200, 200, 1)))
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 100, 100, 16)      80        
=================================================================
Total params: 80
Trainable params: 80
Non-trainable params: 0
_________________________________________________________________

3.1 卷积层中的参数数量

卷积层中的参数数量取决于 filters、kernel_size 和 input_shape 的值。我们定义几个变量:

K - 卷积层中的过滤器数量

F - 卷积过滤器的高度和宽度

D_in - 上一层级的深度

注意:K = filters,F = kernel_size。类似地,D_in 是 input_shape 元组中的最后一个值。

因为每个过滤器有 FFDinF*F*D_{in} 个权重,卷积层由 K 个过滤器组成,因此卷积层中的权重总数是KFFDinK*F*F*D_{in}。因为每个过滤器有 1 个偏差项,卷积层有 K 个偏差。因此,卷积层中的参数数量是 KFFDin+KK*F*F*D_in + K

3.2 卷积层的形状

卷积层的形状取决于 kernel_size、input_shape、padding 和 stride 的值。我们定义几个变量:

K - 卷积层中的过滤器数量

F - 卷积过滤器的高度和宽度

H_in - 上一层级的高度

W_in - 上一层级的宽度

注意:K = filters、F = kernel_size,以及S = stride。类似地,H_in 和 W_in 分别是 input_shape 元组的第一个和第二个值。

卷积层的深度始终为过滤器数量 K。

如果 padding = ‘same’,那么卷积层的空间维度如下:

import math
math.ceil( x ) #上入整数

height = ceil(float(H_in) / float(S))

width = ceil(float(W_in) / float(S))

如果 padding = ‘valid’,那么卷积层的空间维度如下:

height = ceil(float(H_in - F + 1) / float(S))

width = ceil(float(W_in - F + 1) / float(S))

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(filters=32, kernel_size=3, strides=2, padding='same', 
    activation='relu', input_shape=(128, 128, 3)))
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_5 (Conv2D)            (None, 64, 64, 32)        896       
=================================================================
Total params: 896
Trainable params: 896
Non-trainable params: 0
_________________________________________________________________

KFFDin+K==>33332+32=896K*F*F*D_in + K==> 3*3*3*32 + 32 = 896

可见,相对MLP全连接网络,卷积网络大量减小了参数个数。

4.池化层

卷积层,是指特征映射堆栈,每个过滤器对应一个特征映射,具有很多不同对象类别的复杂数据集,需要大量过滤器,

每个过滤器负责从图片中查找一种规律,过滤器越多,则堆栈越大,意味着卷积层维度越高,则需要使用更多参数。这样可能会导致过拟合,

在这里插入图片描述

因此,需要降低维度,这就是卷积神经网络中的池化层。

4.1最大池化层

将一组特征映射作为输入,单独处理每个特征映射,

在这里插入图片描述

则输出是一组具有相同数量的特征映射,但每个特征映射的宽和高都减小了;

在这里插入图片描述

4.2 全局平均池化层

采用更极端的降低维度方法,对每个特征映射,取平均值

在这里插入图片描述

将三维数组变成了向量

在这里插入图片描述

4.3keras其他不同池化层:

https://keras.io/layers/pooling/

论文:

https://arxiv.org/abs/1312.4400

5. Keras 中的最大池化层

导入必要的模块:

from keras.layers import MaxPooling2D

创建卷积层:

MaxPooling2D(pool_size, strides, padding)

5.1 参数

你必须包含以下参数:

pool_size - 指定池化窗口高度和宽度的数字。

你可能还需要调整其他可选参数:

strides - 垂直和水平 stride。如果不指定任何值,则 strides 默认为 pool_size。

padding - 选项包括 ‘valid’ 和 ‘same’。如果不指定任何值,则 padding 设为 ‘valid’。

注意:可以将 pool_size 和 strides 表示为数字或元组。

官方文档:https://keras.io/layers/pooling/#maxpooling2d

from keras.models import Sequential
from keras.layers import MaxPooling2D

model = Sequential()
model.add(MaxPooling2D(pool_size=2, strides=2, input_shape=(100, 100, 15)))
model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 15)        0         
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0
_________________________________________________________________

6.设计图片CNN

卷积层,可以检测图片中的区域性规律,池化层在卷积层之后,可以降低数组的维数,加上全连接层,是CNN中常用的网络层。

对于图片的CNN,必须将图片数组作为输入(一般统一大小),一般使空间维度等于2的幂次方,计算机将任何图片解读为三维数组,输入数组的宽和高始终大于深度。

CNN架构的设计目标,是获取该输入,然后逐渐使其深度大于宽和高。

在这里插入图片描述

卷积层将用于使穿过卷积层的数组更深,池化层用于减小空间维度,
在这里插入图片描述

卷积层设置:
在这里插入图片描述

池化层,一般在一个或多个卷基层后面,其经典设置:

在这里插入图片描述

这样空间维度变为上一层的一半,这样通过组合使用卷积层和最大池化层,我们就能够获得很深,且空间维度很小的数组。

这种层级序列发现了图片中包含的空间规律,它逐渐获取空间数据,并将数组准换为包含图片内容的表示,所有空间信息最终会丢失,

在原始图片中很容易知道各个像素与其他哪些像素相邻,在最末尾层会发现数组中的条目与哪个项目相邻已经不重要了。
在这里插入图片描述

一旦获得不再具有图片中的空间信息的数组,我们就可以扁平化该数组,并将其提供给一个或多个全连接层,判断图片中包含什么对象。

在这里插入图片描述
设计一个简单的CNN分类网络

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, padding='same', activation='relu', input_shape=(32, 32, 3)))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=32, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Flatten())
model.add(Dense(500, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_6 (Conv2D)            (None, 32, 32, 16)        208       
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 16, 16, 16)        0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 16, 16, 32)        2080      
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 8, 8, 64)          8256      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1024)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 500)               512500    
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5010      
=================================================================
Total params: 528,054
Trainable params: 528,054
Non-trainable params: 0
_________________________________________________________________

该网络以三个卷积层(后面跟着最大池化层)序列开始。前 6 个层级旨在将图片像素数组输入转换为所有空间信息都丢失、仅保留图片内容信息的数组 。然后在 CNN 的第七个层级将该数组扁平化为向量。后面跟着两个密集层,旨在进一步说明图片中的内容。最后一层针对数据集中的每个对象类别都有一个条目,并具有一个 softmax 激活函数,使其返回概率。

注意事项

始终向 CNN 中的 Conv2D 层添加 ReLU 激活函数。但是网络的最后层级除外,密集层也应该具有 ReLU 激活函数。

在构建分类网络时,网络中的最后层级应该是具有 softmax 激活函数的密集层。最后层级的节点数量应该等于数据集中的类别总数。

要开心!如果你觉得有点泄气,建议参阅 Andrej Karpathy 的 tumblr(来自外网,可能打不开),其中包含了用户提交的损失函数,对应的是本身有问题的模型。损失函数在训练期间应该是减小的,但是这些图表显示的却是非常不同的行为 😃。

要设计自己的模型,你需要亲自尝试各种架构和不同的超参数,深度学习是一种需要实践操作的领域,所以不要怕麻烦,去实践,并且不要担心违背了规则,尽量去尝试不同的事物。提出问题,并通过实验来回答你的问题,而不仅仅是思考。

课外资料

这是用于在 Keras 中指定神经网络(包括 CNN)的备忘单。

https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Keras_Cheat_Sheet_Python.pdf

参阅 CIFAR-10 竞赛的获胜架构!

http://blog.kaggle.com/2015/01/02/cifar-10-competition-winners-interviews-with-dr-ben-graham-phil-culliton-zygmunt-zajac/

7.突破性的cnn架构

7.1 AlexNet

2012年多伦多大学团队完成,采用Relu激活函数和Dropout来避免过拟合。

在这里插入图片描述

参阅 AlexNet 论文!

http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf

7.2 VGG

2014年,牛津大学视觉集合小组开发,包括VGG16,VGG19两个版本

在这里插入图片描述

在此处详细了解 VGGNet

https://arxiv.org/pdf/1409.1556.pdf

7.3 ResNet

2015微软开发,在ImageNet数据库的图片分类方面取得了惊人的效果;

在这里插入图片描述

此处是 ResNet 论文。
https://arxiv.org/pdf/1512.03385v1.pdf

其他文档:

这是用于访问一些著名 CNN 架构的 Keras 文档。
https://keras.io/applications/

阅读这一关于梯度消失问题的详细处理方案。

http://neuralnetworksanddeeplearning.com/chap5.html

这是包含不同 CNN 架构的基准的 GitHub 资源库。
https://github.com/jcjohnson/cnn-benchmarks

访问 ImageNet Large Scale Visual Recognition Competition (ILSVRC) 网站。

http://www.image-net.org/challenges/LSVRC/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章