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 相关文章推荐
pydev使用wxpython找不到路径的解决方法
Feb 10 Python
python字符串连接方式汇总
Aug 21 Python
Python实现对比不同字体中的同一字符的显示效果
Apr 23 Python
利用django如何解析用户上传的excel文件
Jul 24 Python
Python删除Java源文件中全部注释的实现方法
Aug 30 Python
transform python环境快速配置方法
Sep 27 Python
Django 路由控制的实现代码
Nov 08 Python
pycharm debug功能实现跳到循环末尾的方法
Nov 29 Python
python matplotlib包图像配色方案分享
Mar 14 Python
Python中使用filter过滤列表的一个小技巧分享
May 02 Python
Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告
Jan 27 Python
Pycharm 跳转回之前所在页面的操作
Feb 05 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
thinkPHP框架实现图像裁剪、缩放、加水印的方法
2017/03/14 PHP
PHP的反射机制实例详解
2017/03/29 PHP
PHP使用CURL实现下载文件功能示例
2019/06/03 PHP
Laravel框架Blade模板简介及模板继承用法分析
2019/12/03 PHP
JS获取当前网址、主机地址项目根路径
2013/11/19 Javascript
简介AngularJS中$http服务的用法
2016/02/06 Javascript
基于javascript实现tab选项卡切换特效调试笔记
2016/03/30 Javascript
jQuery 获取多选框的值及多选框中文的函数
2016/05/16 Javascript
jquery ezUI 双击行记录弹窗查看明细的实现方法
2016/06/01 Javascript
学习Javascript闭包(Closure)知识
2016/08/07 Javascript
jQuery联动日历的实例解析
2016/12/02 Javascript
详解使用JS如何制作简单的ASCII图与单极图
2017/03/31 Javascript
Node.js模块全局安装路径配置方法
2018/05/17 Javascript
Vue2.0 实现移动端图片上传功能
2018/05/30 Javascript
详解几十行代码实现一个vue的状态管理
2019/01/28 Javascript
vue 对axios get pust put delete封装的实例代码
2020/01/05 Javascript
Vue为什么要谨慎使用$attrs与$listeners
2020/08/27 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
[01:00:04]DOTA2上海特级锦标赛B组小组赛#1 Alliance VS Spirit第二局
2016/02/26 DOTA
[49:41]NB vs NAVI Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
[01:25:33]完美世界DOTA2联赛PWL S3 INK ICE vs Magma 第二场 12.20
2020/12/23 DOTA
Python获取命令实时输出-原样彩色输出并返回输出结果的示例
2019/07/11 Python
Python搭建代理IP池实现检测IP的方法
2019/10/27 Python
css3中仿放大镜效果的几种方式原理解析
2020/12/03 HTML / CSS
如何查看在weblogic中已经发布的EJB
2012/06/01 面试题
摄影实习自我鉴定
2013/09/20 职场文书
专科毕业生自我鉴定
2013/12/01 职场文书
最经典的商业地产项目广告词
2014/03/13 职场文书
入党思想汇报怎么写
2014/04/03 职场文书
活动总结报告怎么写
2014/07/03 职场文书
语文教师求职信范文
2015/03/20 职场文书
身份证丢失证明
2015/06/19 职场文书
队列队形口号
2015/12/25 职场文书
导游词之镇江焦山
2019/11/21 职场文书
浅谈Redis的几个过期策略
2021/05/27 Redis
微信小程序基础教程之echart的使用
2021/06/01 Javascript