下面四张图片分别为:
- A: 原图
- B: 锐化
- C: 边缘检测
- D: 浮雕
图片来源, 该文章对卷积进行了更生动地介绍
卷积数学定义可以参考卷积总结 和 我对卷积的理解
局部感知
一般认为人的视觉认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,而距离较远的像素相关性则较弱.
同理, 每个神经元其实没有必要对全局图像进行感知, 只需要与局部图像建立连接. 在网络的更深层将神经元的局部感知进一步综合就可以了解到全局信息.
采用局部感知的方法减少了需要训练的权值数. 在实际应用中图像的分辨率和训练迭代次数都是有限的, 更少的权值数通常会带来更高精度.
权值共享
在卷积神经网络中对于同一个卷积核, 所有卷积层神经元和图像输入层的连接使用同一个权值矩阵.
权值共享进一步减少了所需训练的权值数, 一个卷积层的权值数变为了卷积核中元素个数.
权值共享隐含的原理是: 图像的一部分的统计特性与其他部分是一样的, 在图像某一部分学习到的特征也能应用到其它部分上.
从上文关于特殊卷积核的描述中可以得知, 一种卷积核通常只能提取图像中的一种特征. 且权值共享使得连接可以训练的权值数大为减少. 为了充分提取特征通常采用使用多个卷积核的方法.
池化
通过卷积学习到的图像特征仍然数量巨大, 不便直接进行分类. 池化层便用于减少特征数量.
池化操作非常简单, 比如我们使用一个卷积核对一张图片进行过滤得到一个8x8的方阵, 我们可以将方阵划分为16个2x2方阵, 每个小方阵称为邻域.
用16个小方阵的均值组成一个4x4方阵便是均值池化, 类似地还有最大值池化等操作. 均值池化对保留背景等特征较好, 最大值池化对纹理提取更好.
随机池化则是根据像素点数值大小赋予概率(权值), 然后按其加权求和.
TensorFlow实现
TensorFlow的文档Deep MNIST for Experts介绍了使用CNN在MNIST数据集上识别手写数字的方法.
完整代码可以在GitHub上找到, 本文将对其进行简单分析. 源码来自tensorflow-1.3.0版本示例.
主要有3条引入:
import tempfile
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
main(_)
函数负责网络的构建:
main
函数与其它tensorflow神经网络并无二致, 关键分析deepnn
方法如何构建cnn:
请重点关注第二个卷积层的实现
整个网络暴露的接口有3个:
- 输入层
x[n, 784]
- 输出层
y_conv[n, 10]
- dropout保留比例
keep_prob[1]
现在可以继续关注main
方法了, 完成网络构建之后main
先将网络结构缓存到硬盘:
graph_location = tempfile.mkdtemp()
print(\'Saving graph to:
接下来初始化tf.Session()
进行训练:
with tf.Session() as sess:
启动代码会处理命令行参数和选项:
if __name__ == \'__main__\':
parser = argparse.ArgumentParser()
parser.add_argument(\'--data_dir\', type=str,
default=\'/tmp/tensorflow/mnist/input_data\',
help=\'Directory for storing input data\')
FLAGS, unparsed = parser.parse_known_args()
tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)
Keep working, we will find a way out. This is Finley, welcome to join us.