TensorFlow实现卷积神经网络CNN


Posted in Python onMarch 09, 2018

一、卷积神经网络CNN简介

卷积神经网络(ConvolutionalNeuralNetwork,CNN)最初是为解决图像识别等问题设计的,CNN现在的应用已经不限于图像和视频,也可用于时间序列信号,比如音频信号和文本数据等。CNN作为一个深度学习架构被提出的最初诉求是降低对图像数据预处理的要求,避免复杂的特征工程。在卷积神经网络中,第一个卷积层会直接接受图像像素级的输入,每一层卷积(滤波器)都会提取数据中最有效的特征,这种方法可以提取到图像中最基础的特征,而后再进行组合和抽象形成更高阶的特征,因此CNN在理论上具有对图像缩放、平移和旋转的不变性。

卷积神经网络CNN的要点就是局部连接(LocalConnection)、权值共享(WeightsSharing)和池化层(Pooling)中的降采样(Down-Sampling)。其中,局部连接和权值共享降低了参数量,使训练复杂度大大下降并减轻了过拟合。同时权值共享还赋予了卷积网络对平移的容忍性,池化层降采样则进一步降低了输出参数量并赋予模型对轻度形变的容忍性,提高了模型的泛化能力。可以把卷积层卷积操作理解为用少量参数在图像的多个位置上提取相似特征的过程。

更多请参见:深度学习之卷积神经网络CNN

二、TensorFlow代码实现

#!/usr/bin/env python2 
# -*- coding: utf-8 -*- 
""" 
Created on Thu Mar 9 22:01:46 2017 
 
@author: marsjhao 
""" 
 
import tensorflow as tf 
from tensorflow.examples.tutorials.mnist import input_data 
 
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) 
sess = tf.InteractiveSession() 
 
def weight_variable(shape): 
 initial = tf.truncated_normal(shape, stddev=0.1) #标准差为0.1的正态分布 
 return tf.Variable(initial) 
 
def bias_variable(shape): 
 initial = tf.constant(0.1, shape=shape) #偏差初始化为0.1 
 return tf.Variable(initial) 
 
def conv2d(x, W): 
 return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') 
 
def max_pool_2x2(x): 
 return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], 
       strides=[1, 2, 2, 1], padding='SAME') 
 
x = tf.placeholder(tf.float32, [None, 784]) 
y_ = tf.placeholder(tf.float32, [None, 10]) 
# -1代表先不考虑输入的图片例子多少这个维度,1是channel的数量 
x_image = tf.reshape(x, [-1, 28, 28, 1]) 
keep_prob = tf.placeholder(tf.float32) 
 
# 构建卷积层1 
W_conv1 = weight_variable([5, 5, 1, 32]) # 卷积核5*5,1个channel,32个卷积核,形成32个featuremap 
b_conv1 = bias_variable([32]) # 32个featuremap的偏置 
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) # 用relu非线性处理 
h_pool1 = max_pool_2x2(h_conv1) # pooling池化 
 
# 构建卷积层2 
W_conv2 = weight_variable([5, 5, 32, 64]) # 注意这里channel值是32 
b_conv2 = bias_variable([64]) 
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) 
h_pool2 = max_pool_2x2(h_conv2) 
 
# 构建全连接层1 
W_fc1 = weight_variable([7*7*64, 1024]) 
b_fc1 = bias_variable([1024]) 
h_pool3 = tf.reshape(h_pool2, [-1, 7*7*64]) 
h_fc1 = tf.nn.relu(tf.matmul(h_pool3, W_fc1) + b_fc1) 
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) 
 
# 构建全连接层2 
W_fc2 = weight_variable([1024, 10]) 
b_fc2 = bias_variable([10]) 
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) 
 
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), 
            reduction_indices=[1])) 
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) 
correct_prediction = tf.equal(tf.arg_max(y_conv, 1), tf.arg_max(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
 
tf.global_variables_initializer().run() 
 
for i in range(20001): 
 batch = mnist.train.next_batch(50) 
 if i % 100 == 0: 
  train_accuracy = accuracy.eval(feed_dict={x:batch[0], y_:batch[1], 
             keep_prob: 1.0}) 
  print("step %d, training accuracy %g" %(i, train_accuracy)) 
 train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob:0.5}) 
print("test accuracy %g" %accuracy.eval(feed_dict={x: mnist.test.images, 
         y_: mnist.test.labels, keep_prob: 1.0}))

三、代码解读

该代码是用TensorFlow实现一个简单的卷积神经网络,在数据集MNIST上,预期可以实现99.2%左右的准确率。结构上使用两个卷积层和一个全连接层。

首先载入MNIST数据集,采用独热编码,并创建tf.InteractiveSession。然后为后续即将多次使用的部分代码创建函数,包括权重初始化weight_variable、偏置初始化bias_variable、卷积层conv2d、最大池化max_pool_2x2。其中权重初始化的时候要进行含有噪声的非对称初始化,打破完全对称。又由于我们要使用ReLU单元,也需要给偏置bias增加一些小的正值(0.1)用来避免死亡节点(dead neurons)。

构建卷积神经网络之前,先要定义输入的placeholder,特征x和真实标签y_,将1*784格式的特征x转换reshape为28*28的图片格式,又由于只有一个通道且不确定输入样本的数量,故最终尺寸为[-1, 28, 28, 1]。

接下来定义第一个卷积层,首先初始化weights和bias,然后使用conv2d进行卷积操作并加上偏置,随后使用ReLU激活函数进行非线性处理,最后使用最大池化函数对卷积的输出结果进行池化操作。

相同的步骤定义第二个卷积层,不同的地方是卷积核的数量为64,也就是说这一层的卷积会提取64种特征。经过两层不变尺寸的卷积和两次尺寸减半的池化,第二个卷积层后的输出尺寸为7*7*64。将其reshape为长度为7*7*64的1-D向量。经过ReLU后,为了减轻过拟合,使用一个Dropout层,在训练时随机丢弃部分节点的数据减轻过拟合,在预测的时候保留全部数据来追求最好的测试性能。

最后加一个Softmax层,得到最后的预测概率。随后的定义损失函数、优化器、评测准确率不再详细赘述。

训练过程首先进行初始化全部参数,训练时keep_prob比率设置为0.5,评测时设置为1。训练完成后,在最终的测试集上进行全面的测试,得到整体的分类准确率。

经过实验,这个CNN的模型可以得到99.2%的准确率,相比于MLP又有了较大幅度的提高。

四、其他解读补充

1. tf.nn.conv2d(x,W, strides=[1, 1, 1, 1], padding='SAME')

tf.nn.conv2d是TensorFlow的2维卷积函数,x和W都是4-D的tensors。x是输入input shape=[batch,in_height, in_width, in_channels],W是卷积的参数filter / kernel shape=[filter_height, filter_width, in_channels,out_channels]。strides参数是长度为4的1-D参数,代表了卷积核(滑动窗口)移动的步长,其中对于图片strides[0]和strides[3]必须是1,都是1表示不遗漏地划过图片的每一个点。padding参数中SAME代表给边界加上Padding让卷积的输出和输入保持相同的尺寸。

2. tf.nn.max_pool(x,ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

tf.nn.max_pool是TensorFlow中的最大池化函数,x是4-D的输入tensor shape=[batch, height, width, channels],ksize参数表示池化窗口的大小,取一个4维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1,strides与tf.nn.conv2d相同,strides=[1, 2, 2, 1]可以缩小图片尺寸。padding参数也参见tf.nn.conv2d。

Python 相关文章推荐
py中的目录与文件判别代码
Jul 16 Python
python实现获取序列中最小的几个元素
Sep 25 Python
详解Python3中的Sequence type的使用
Aug 01 Python
详解TensorFlow查看ckpt中变量的几种方法
Jun 19 Python
Python3中函数参数传递方式实例详解
May 05 Python
Python3列表内置方法大全及示例代码小结
May 10 Python
django认证系统实现自定义权限管理的方法
Aug 28 Python
快速查找Python安装路径方法
Feb 06 Python
三步解决python PermissionError: [WinError 5]拒绝访问的情况
Apr 22 Python
pytorch 中forward 的用法与解释说明
Feb 26 Python
拒绝盗图!教你怎么用python给图片加水印
Jun 04 Python
Python中的 No Module named ***问题及解决
Jul 23 Python
新手常见6种的python报错及解决方法
Mar 09 #Python
Python 函数基础知识汇总
Mar 09 #Python
Python 使用with上下文实现计时功能
Mar 09 #Python
TensorFlow搭建神经网络最佳实践
Mar 09 #Python
TensorFlow实现Batch Normalization
Mar 08 #Python
用Django实现一个可运行的区块链应用
Mar 08 #Python
Python pyinotify日志监控系统处理日志的方法
Mar 08 #Python
You might like
用PHP实现递归循环每一个目录
2010/08/08 PHP
完美实现GIF动画缩略图的php代码
2011/01/02 PHP
深入理解PHP之require/include顺序 推荐
2011/01/02 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
2019/10/16 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
Javascript 中的类和闭包
2010/01/08 Javascript
jquery简单瀑布流实现原理及ie8下测试代码
2013/01/23 Javascript
JS window对象的top、parent、opener含义介绍
2013/12/03 Javascript
JS中使用sort结合localeCompare实现中文排序实例
2014/07/23 Javascript
js和jquery中循环的退出和继续学习记录
2014/09/06 Javascript
一步步教大家编写酷炫的导航栏js+css实现
2016/03/14 Javascript
knockoutjs模板实现树形结构列表
2017/07/31 Javascript
详解微信小程序开发用户授权登陆
2019/04/24 Javascript
详解在HTTPS 项目中使用百度地图 API
2019/04/26 Javascript
SSM+layUI 根据登录信息显示不同的页面方法
2019/09/20 Javascript
JS实现简单随机3D骰子
2019/10/24 Javascript
Vue 中 a标签上href无法跳转的解决方式
2019/11/12 Javascript
js 函数性能比较方法
2020/08/24 Javascript
JavaScript前后端JSON使用方法教程
2020/11/23 Javascript
[01:02:09]Liquid vs TNC 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21
2020/07/19 DOTA
Django中URLconf和include()的协同工作方法
2015/07/20 Python
举例讲解Python的lambda语句声明匿名函数的用法
2016/07/01 Python
Python实现简单的获取图片爬虫功能示例
2017/07/12 Python
python之Character string(实例讲解)
2017/09/25 Python
python中lambda()的用法
2017/11/16 Python
Python实现pdf文档转txt的方法示例
2018/01/19 Python
python中实现字符串翻转的方法
2018/07/11 Python
Python中pass的作用与使用教程
2020/11/13 Python
Python3使用Selenium获取session和token方法详解
2021/02/16 Python
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
全民健身日活动方案
2014/01/29 职场文书
2015年财务人员个人工作总结
2015/07/27 职场文书
儿童诗两首教学反思
2016/02/23 职场文书
nginx中proxy_pass各种用法详解
2021/11/07 Servers
解决persistence.xml配置文件修改存放路径的问题
2022/02/24 Java/Android
利用Apache Common将java对象池化的问题
2022/06/16 Servers