阅读书籍为《Hands-On Machine Learning with Scikit-Learn & TensorFlow》王静源等翻译的中文译版《机器学习实战,基于 Scikit-Learn 和 TensorFlow》,本文中所有图片均来自于书籍相关部分截图。
CNN相关介绍
- 卷积神经网络起源于1958年David H.Hubel &Torsten Wiesel两人对动物视觉神经元的研究。80年代后开始用于图像识别领域。
- CNN可以用于语音识别,自然语言处理,图像搜索,视频分类和自动驾驶等多个领域,不过目前我们所讨论的CNN主要用于图像视觉等方面的研究和应用。
- 视觉皮层组织结构:
1958,1959年David H.Hubel &Torsten Wiesel两人通过对猫和猴子的一系列视觉刺激实验后得出:动物视觉皮层神经元有一个小的局部接受野(receptive field).简单来说就是,每个神经元只能在看到一定的范围。
我们的视觉皮层中有很多个视觉神经元,这些神经元功能有高阶低阶,作用范围有大有小,看的方向有横有竖。由于作用范围的不同,所以这些神经元的作用范围有可能重叠。所有的神经元交叠后覆盖整个视觉范围帮我们获得一个完整的视野。 - 1980年,关于视觉皮层组织结构的演技引入新认知机,后来逐渐演化为我们现在所讲的卷积神经网络。
- 1998年Yann LeCun,Leon Bottou,Yoshua Bengio和Patrick Haffner等人发表论文介绍了用于识别手写支票号码的LeNet-5的CNN框架,其中介绍了全连接层,S形激活函数,以及首次提出现在CNN中十分重要的卷积层,池化层。
卷积层介绍
- 什么是卷积?
卷积的目的在于提取低阶图像特征;
上左右两图为一层卷积的过程原理:
1.两幅图中可见在低层图像中,接受野为fn×fw=3×3单位范围,配高层图像提取为11单位范围,这点模拟动物的视觉形成中最后的结果是基于所有视觉神经元的结果基础之上的过程。
2.之所以要0填充(不够的地方用0填充) 的意义在于:如果不填充按照33的接受野范围不够上层提取;也可以不填充(多余的地方直接抛弃) 但是会造成图像损失。
填充原理如下(padding 属性代表TF现实时采用何种填充方式):
3.sh和sw代表接受野移动步长,可以对比左右两图来观察。左图中移动步长为1和1,右图中为2和2.在实现过程中可自行指定,但明显的移动步长不应大于接受野范围。 - 卷积的数学表示
- 过滤器(卷积内核)是做什么的
模拟不同作用的视觉神经元(比如作用于水平和垂直方向的视觉神经元):
垂直过滤器:上图垂直过滤器是一个7*7大小的核,除了其中第四列为1,剩下都为0。使用核对图像进行垂直特征提取(神经元经过计算就只会保留与第四列计算过的点,从而达到只提取垂直特征忽略其他信息的功能)得到特征图1;
水平过滤器:同理;
卷积层使用过滤器时一般会同时使用多个过滤器检测输入图像的多个特征然后叠加,如下图所示:
- 用TF实现卷积
一下代码运行的结果就是上图展示过滤器的图片import numpy as np from sklearn.datasets import load_sample_images import tensorflow as tf import matplotlib.pyplot as plt //加载图片 data = np.array(load_sample_images().images, dtype=np.float32) batch_size, height, width, channels = data.shape //创建两个过滤器(卷积内核) filter_test = np.zeros(shape=(7,7,channels,2), dtype=np.float32) filter_test[:, 3, :, 0] = 1 //垂直过滤器 filter_test[3, :, :, 1] = 1 //水平过滤器 //X表示一个小批次的四维张量【一次加载的数据量, 高, 宽, 通道数】 X = tf.placeholder(tf.float32, shape=(None, height, width, channels)) //卷积网络函数,padding的值表示为选择SAME零填充还是VALID不填充 //conv2d:表示我们要创建一个二维输入的卷积层网络 conv = tf.nn.conv2d(X, filter_test, strides=[1, 2, 2, 1], padding="SAME") with tf.Session() as sess: //运行卷积神经网络 output = sess.run(conv, feed_dict={X, data}) plt.imshow(output[0, :, :, 1]) plt.show()
池化层介绍
- 什么是池化?
池化的目的在于降低图像尺寸,减少计算资源的消耗。分为最大池化和平均池化。
上图展示了池化过程原理及池化效果:
a.上图中采取最大池化(抽取低层图像接受野中最大值)。平均池化(抽取底层图像接受野中平均值,以上图为例,结果应该是2.75)。
b.池化权重也就是低层图像接受野为2*2,接受野移动步长为2和2.
c.采用无填充直接抛弃多余图像的方法。
显而易见:池化在降低图像尺寸的过程中会抛弃大量信息造成图像损失。
池化层通常独立工作在各个输入通道。可以选在在深度维度上进行叠加,从而保持空间维度(高宽)不变,只减少通道数。 - TF实现
[...] # load the image dataset, just like above # Create a graph with input X plus a max pooling layer X = tf.placeholder(tf.float32, shape=(None, height, width, channels)) max_pool = tf.nn.max_pool(X, ksize=[1,2,2,1], strides=[1,2,2,1],padding="VALID") with tf.Session() as sess: output = sess.run(max_pool, feed_dict={X: dataset}) plt.imshow(output[0].astype(np.uint8)) # plot the output for the 1st image plt.show()
CNN常见架构
典型的CNN架构如下:
我们接下来展示5种流行架构的结构:
- 1998年,LeNet-5:广泛应用于手写字体识别
- 2012年,AlexNet:比LeNet-5层数更深,创新多个卷积层叠加工作的模式(Top5错误率17%)
- 2014年,GoogleNet:比AlexNet更深(Top5错误率7%)
- 2015年,ResNet:比GoogleNet更深,152层(Top5错误率3.7%)
ResNet如此深但却效果喜人是因为器使用了跳过连接(快捷链接):如果将输入数据直接加到了某一层(比如a层)的输出上则就是跳过a层的神经训练,网络的模型也变成了f(x) = h(x) - x,而不是原来的h(x),这种操作被称为残差学习;
其他
除了我们上述TF中使用的conv2d()是用于二维卷积层,图像处理常用;
还有conv1d():用于一维卷积层,NLP等一维数据常用;
conv3d():用于三维卷积层,一般三维扫描会用到;
atrous_conv2d():用于创建带孔卷积层,会使得卷积层在没有计算代价和额外参数的情况下扩大接受野。简单来说就是为行和列插入0值,比如一个三维的[1,2,3]过滤器,就会扩大四倍变成[1,0,0,0,2,0,0,0,3],从而间接的扩大了接受野的范围,而不增加计算代价。
conv2d_transpose():用于创建转置(去)卷积层,用来进行图像提升采样。
depthwise_conv2d():用于创建深度卷积层,使得过滤器可以应用在各个通道;
separable_conved():用于创建可分离卷积层,首先类似于一个深度卷积层,然后应用一个卷积层来输出特征图。这样就可以使得过滤器应用在各个通道。