深度学习笔记(二)卷积神经网络
在接触卷积神经网络以前,我们学习的神经网络,叫全连接神经网络,见深度学习笔记(一)感知器、梯度下降、反向传播。并且,我们用全连接神经网络做了MNIST,用来识别手写数字,见【深度学习 Hello World系列(二)】 用TensorFlow实现MNIST。
大家可能会觉得全连接神经网络不是挺好的么,为啥还要搞其他有的没的,下面我们先谈一谈全连接神经网络在图像识别时的弊端,以及为啥要用卷积神经网络。
全连接神经网络在图像识别时的弊端
全连接神经网络,图片来自Michael Nielsen的博客-
用全连接神经网络识别图片,参数太多了。我们在做MNIST时图片大小是28*28,可能感觉不出来,但是现实中的图片远不止这个大小,比如1000*1000,假设隐藏层有100个节点,那么这个隐藏层就有超过1亿的参数,这样量级的参数会让训练和扩展都变得极其艰难。
-
全连接神经网络没有利用图片的空间结构。比如说,有一张猫的图片,猫在上面还是下面并不会改变我们识别这个图片的结果,也就是说,猫的位置不会给我们的结果带来影响。
从上面我们可以看出,用神经网络做图像识别,最大的难点在于参数太多,导致模型难以训练并且效果很差,那么卷积神经网络(Convolutional Neural Networks)是如何利用图像自身的特点来减少参数的?
卷积神经网络
在谈卷积神经网络如何减少参数之前,我们先了解下卷积神经网络是个啥。
图片来自hanbingtao的博客一个卷积神经网络一般会由数个卷积层(Convolution Layer),池化层(Pooling Layer),全连接层(Fully Connected Layer)组成。上图就是由,两个卷积+池化,再加两个全连接层组成。
卷积神经网络减参三宝
对卷积神经网络有了一个大概的印象后,我们来看卷积神经网络减少参数的三宝:
1. 局部连接(local receptive fields)
之前全连接神经网络,会将每一个隐藏层的节点与输入层的节点连接,而卷积神经网络,使用卷积核(kernal)或者叫过滤器(filter),比如下图的5*5的卷积核,与输入层的节点连接。通过卷积核的平移(扫描)来获取隐藏层节点,平移的跨距叫做strides。
局部连接,图片来自Michael Nielsen的博客
2. 权值共享(Shared weights and biases)
权值共享是指,在输入层和隐藏层之间连接的权值(w),就是卷积核的大小。为什么能有这种操作?这是由图片的特征觉得的,图片是由很多细节组成的,比如一个狗,它有眼睛、鼻子、毛发,各种各样的特征,并且特征的位置不会影响最后的结果。
而我们用卷积核来在输入层扫描来获取小的特征,所以通过卷积核扫描得到的叫feature map,多个feature map就可以表示这个图片,这个操作就是局部连接。由于特征的位置不会影响识别的结果,在左边的狗鼻子和在右边的狗鼻子都是狗鼻子,这样使得我们可以权值共享。
feature map,图片来自Michael Nielsen的博客经过这两步操作,我们可以感觉到,参数会有明显的减少。我们举个例子:
- 输入数据,维度为 32 * 32 *3
20个卷积核,维度为8 * 8 * 3
stride宽和高都为2
padding为1
输出层为 14 * 14 * 20
如果没有局部连接和权重共享,参数将有:
(32 * 32 * 3 + 1)*(14 * 14 * 20) = 12046160
经过局部连接和权重共享操作后,参数有:
(8 * 8 * 3 + 1) * 20 = 3860
减少了3120倍。
3.等变表示(equivariant representations)
池化(pooling)就是一种常见的等变表示,并且很容易理解,用一个图就可以表示清楚。
Max Pooling,图片来自cs231上图中的Max Pooling就是找到范围的最大值,比如红色区域有1,1,5,6四个值,就取6。这样也行?这又回到了图片的特征,如果这个区域有某个特征,我们就抓住它就可以了,并且实践表明,这并不会改变图片的形状。
图片来自cs231用TensorFlow实现卷积神经网络
上面讲了那么多,我们来实战一下,用卷积神经网络来对 CIFAR-10 数据集进行图像分类,该数据集包含飞机、狗、猫等十种图片。
下面贴一些我认为重点的代码,完整的代码在:https://github.com/freeman93/dlnd-image-classification。里面的notebook,有详细的指引与说明。代码可能比较丑,原谅我还是个初学者。
我们构建一个函数conv2d_maxpool来完成卷积与池化的操作。
def conv2d_maxpool(x_tensor, conv_num_outputs, conv_ksize, conv_strides, pool_ksize, pool_strides):
"""
Apply convolution then max pooling to x_tensor
:param x_tensor: TensorFlow Tensor
:param conv_num_outputs: Number of outputs for the convolutional layer
:param conv_ksize: kernal size 2-D Tuple for the convolutional layer
:param conv_strides: Stride 2-D Tuple for convolution
:param pool_ksize: kernal size 2-D Tuple for pool
:param pool_strides: Stride 2-D Tuple for pool
: return: A tensor that represents convolution and max pooling of x_tensor
"""
# x_tensor shape
shape = x_tensor.get_shape().as_list()
# weight
weight = tf.Variable(tf.truncated_normal([*conv_ksize, shape[3], \
conv_num_outputs],stddev=0.05,mean=0.0))
# bias
bias = tf.Variable(tf.zeros(conv_num_outputs))
# convolution
x_tensor = tf.nn.conv2d(x_tensor, weight, strides=[1,*conv_strides,1], padding='SAME')
x_tensor = tf.nn.bias_add(x_tensor, bias)
x_tensor = tf.nn.relu(x_tensor)
# pooling
x_tensor = tf.nn.max_pool(x_tensor,
ksize=[1,*pool_ksize, 1],
strides=[1, *pool_strides, 1],
padding='SAME')
return x_tensor
以上是用TensorFlow比较低阶的api实现的,当然你也可以用TensorFlow Layers or TensorFlow Layers (contrib) ,事情会变得非常简单。
比如我们用TensorFlow Layers 来实现全连接层的函数。
def fully_conn(x_tensor, num_outputs):
"""
Apply a fully connected layer to x_tensor using weight and bias
: x_tensor: A 2-D tensor where the first dimension is batch size.
: num_outputs: The number of output that the new tensor should be.
: return: A 2-D tensor where the second dimension is num_outputs.
"""
# 低阶函数实现
# shape = x_tensor.get_shape().as_list()
# weight = tf.Variable(tf.truncated_normal([shape[1], num_outputs], stddev=0.05, mean=0.0))
# bias = tf.Variable(tf.zeros(num_outputs))
# fc = tf.add(tf.matmul(x_tensor, weight), bias)
# fc = tf.nn.relu(fc)
# 用tf.layers实现
return tf.layers.dense(x_tensor, num_outputs, activation=tf.nn.relu)
完整的代码在:https://github.com/freeman93/dlnd-image-classification
总结一下
- 全连接神经网络在做图片识别时,主要问题在于参数太多
- 卷积神经网络在做图片识别时有优势,因为它利用了图片空间性的特点
- 卷积神经网络减参三宝:局部连接、权值共享、等变表示
- 用TensorFlow实现时,使用基础函数可以设置更多参数,对神经网络拥有完整的控制,而使用高阶api会让事情变得简单很多
参考资料
优达学城深度学习课程
TensorFlow 官网
零基础入门深度学习(4) - 卷积神经网络
Neural Networks and Deep Learning By Michael Nielsen / Aug 2017
Deep Learning By Ian Goodfellow and Yoshua Bengio and Aaron Courville
CS231n Convolutional Neural Networks for Visual Recognition