tensorflow(4)---mnist问题的深度卷积神经网络(基于官网文档的实现)
来源:互联网 发布:数据库数据存储方式 编辑:程序博客网 时间:2024/05/29 09:57
导语
那么,上次我们已经使用最基本的梯度下降法实现了mnist问题,并且还原了手写数字的原始模样,那么本文就开始讲述如何调用tensorflow中的深度学习中的卷积神经网络解决mnist问题
讲解开始
首先我们还是给出源代码,然后再分析
import input_datamnist = input_data.read_data_sets('MNIST_data', one_hot=True)import tensorflow as tfsess = tf.InteractiveSession()def weight_variable(shape): initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial)def bias_variable(shape): initial = tf.constant(0.1, shape=shape) 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("float", shape=[None, 784])y_ = tf.placeholder("float", shape=[None, 10])W_conv1 = weight_variable([5, 5, 1, 32])b_conv1 = bias_variable([32])x_image = tf.reshape(x, [-1,28,28,1])h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool_2x2(h_conv1)W_conv2 = weight_variable([5, 5, 32, 64])b_conv2 = bias_variable([64])h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)h_pool2 = max_pool_2x2(h_conv2)W_fc1 = weight_variable([7 * 7 * 64, 1024])b_fc1 = bias_variable([1024])h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)keep_prob = tf.placeholder("float")h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)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_sum(y_*tf.log(y_conv))train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))sess.run(tf.initialize_all_variables())for i in range(20000): 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})
虽然说代码比较长···emmm开始分析吧~
分析:
import input_datamnist = input_data.read_data_sets('MNIST_data', one_hot=True)import tensorflow as tfsess = tf.InteractiveSession()
上面所示的这段代码大意是导入数据和定义sess,应该看了(3)的同学都大致知道他们的含义,这里就不再重新说一遍了。
接下来源代码一堆自己的函数,为保持思路的连贯,我们暂且不管这些函数的含义,继续我们看到了:
x = tf.placeholder("float", shape=[None, 784])y_ = tf.placeholder("float", shape=[None, 10])
定义了两个placeholder,就是说我们将要输入x和y_来帮助这个程序进行训练,即这两个时我们等会儿要输入的placeholder。
W_conv1 = weight_variable([5, 5, 1, 32])b_conv1 = bias_variable([32])
上面这两句代码涉及到了卷积的定义,要理解他们,我们先来看看什么是卷积~
现在假设有一张图像可以用
然后这里的
然后,我们重点关注它时如何生成这个权重矩阵的。这里使用到了一个weight_bariable()的方法,也就是它刚才定义的啦~,这个方法的具体:
def weight_variable(shape): initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial)
而其中tf.truncated_normal()这个方法,我们可以参考博客,大概就是输入一个规格,然后输出与之相应的正太分布的矩阵吧。(反正只是一种初始化的方式而已),具体是生成什么样子我们暂且不说。现在W_conv1是第一层卷积权重, 那么b_conv1是什么呢?我们可以看看b_conv1的定义是使用了bias_variable([32])这个方法,而关于这个方法的定义为:
def bias_variable(shape): initial = tf.constant(0.1, shape=shape) return tf.Variable(initial)
是使用了tf.constant()这个方法,这里所生成的这个b_conv1主要是在接下来要将的relu函数里面会用到。
接下来:
x_image = tf.reshape(x, [-1,28,28,1])
这里是把原来我们的原始数据(100行,784列的那个数据x)每一张图片转化成28×28的矩阵,最后一维表示图片的颜色通道数,因为是灰度图所以通道数为1,如果是彩色图,则为3。
接下来就要对我们已经处理好的图片和卷积矩阵和偏置项代入RELU函数之中进行卷积啦。并且进行一个叫做max pooling的操作
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool_2x2(h_conv1)
第一层卷积的实现方式就是通过一个relu卷积加上一个max pooling完成。
接下来,官网说要构造一个更深的网络,也就是进行第二层卷积,代码与我们之前所看到的类似:
W_conv2 = weight_variable([5, 5, 32, 64])b_conv2 = bias_variable([64])h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)h_pool2 = max_pool_2x2(h_conv2)
我们知道随着不断的进行卷积,图片的尺寸其实会变得原来越小,据官网说,两次卷积之后的图片大小减小到7×7,这是再将图片进行一次卷积,这个步骤被称为密集连接层:
W_fc1 = weight_variable([7 * 7 * 64, 1024])b_fc1 = bias_variable([1024])h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
并且,为了减少过拟合代码还加入了dropout的操作,详情这里暂且不具体介绍。(因为不算是重点把)
然后再从我们最后密集连接层所得到的参数中添加softmax层。
以上我们完成了tensorflow这幅图的大部分工作,包括如何一步一步卷积,到最后将密集连接层代入softmax中得到y_conv(也就是最后预测的标签),那么还需要定义我们最后的训练器和评估模型以及模型的运行,这段代码和(3)的代码差不多,只不过时把梯度下降法改成了ADAM优化器来做,所以就不再一句一句解释了,代码如下:
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))sess.run(tf.initialize_all_variables())for i in range(20000): 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})
以上便是使用卷积网络的基本流程,总结一下:
- 导入数据
- 定义x,y_等placeholder
- 生成权重矩阵和偏项的初值
- 将原数据改变形状为28×28的矩阵形式
- 将图片矩阵和权重矩阵和偏项代入RELU中,并将得到的结果使用max_pool方法,得到的结果作为下一层的图片矩阵
- 将max_pool所输出作为图片矩阵继续进行一次卷积,并max_pool,将所输出的变量修改形状后作为下一层的图片矩阵。代入RELU函数中,将输出记为h_fc1
- 使用dropout方法防止过拟合
- 将最后的W,b和h_fc1输入softmax函数中,使用交叉熵作为目标函数,定义train,和预测准确次数,精度。初始化参数,从mnist获取训练集,开始训练,从mnist中获取测试机,进行测试,输出精度。
细节
以上所述只是讲述大概,接下来将对其中某些方法进行进一步的讲解和分析~
权重矩阵和偏项到底是怎么赋的值
本部分旨在说明白在本文中所使用的函数的输入输出,对于其背后的原理及数学思想先暂时不聊。
def weight_variable(shape): initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial)def bias_variable(shape): initial = tf.constant(0.1, shape=shape) return tf.Variable(initial)W_conv1 = weight_variable([5, 5, 1, 32])b_conv1 = bias_variable([32])
首先我们注意到W_conv系列肯定都是Variable,所以是不能使用sess(W_conv)直接输出的,所以我们使用一下代码来实现weight_variable中initial的输出:
import tensorflow as tfsess = tf.Session()shape = [5, 5, 1, 32]initial = tf.truncated_normal(shape, stddev=0.1)a = sess.run(initial)print a
然后我们对a进行一些简单的命令来了解initial的样子:
现在就明白[5,5,1,32]的用处了~也就是生成一个5行5列的数组,然后其中的每个元素是1行32列的形式存在的。
那么,这句话到底是什么意思?
initial = tf.truncated_normal(shape, stddev=0.1)
这是说,在initial这个数组中的每一个元素都是服从标准差为0.1,均值为0的正态分布。
以同样的方式我们来看偏项的初始化的定义方式:
conv2d函数有什么用?
回看conv2d第一次在我们代码中出现的样子:
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
emmm,这句话中同时出现了relu和conv2d,我们先来看内层函数conv2d的定义方式:
def conv2d(x, W): return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
是使用tf.nn.conv2d方法来定义的一个方法,关于这个方法:
tf.nn.conv2d(input,filter,strides,padding,use_cudnn_on_gpu=None,name=None)
先看input的作用:
input这个位置就是用来放图像的,正如官网demo中传入的时x_image一样,这个参数要求x_image是一个张量,并且诶具有
[图片数量,图片高度,图片宽度,图片通道数]
这样的shape。还记得我们的x_image是如何定义的吗?
x_image = tf.reshape(x, [-1,28,28,1])```![这里写图片描述](http://img.blog.csdn.net/20171111151657004?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)所谓图片通道数就是,如果通道数是1,那就表明时黑白图像,如果是3,就表明时彩色图像。至于这里的图片数量,为什么取-1呢,我们来看看取-1和取1有什么区别?取-1的时候:![这里写图片描述](http://img.blog.csdn.net/20171111151453289?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)取1的时候则出现了错误:![这里写图片描述](http://img.blog.csdn.net/20171111151541552?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)取100的时候(因为我们知道batch_xs是从训练集中随机抽取100个图片出来训练):![这里写图片描述](http://img.blog.csdn.net/20171111151726207?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)那么,现在我们想知道取-1的时候和取100的时候的输出结果是否相等?经过本人用sum(a-b)验证,结果是相等的。所以现在我们就了解,当batch=-1的时候的意思就是自适应任何数量的图片输入,并且在官网的demo中,reshape将100个784的数据转化成了100个28×28的矩阵![这里写图片描述](http://img.blog.csdn.net/20171111152049117?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)还记得我们扯这么多,都是为了确认我们输入的x_image是否与input所要求的具有[图片数量,图片高度,图片宽度,图片通道数]这样的shape相吻合,我们输出x_image:![这里写图片描述](http://img.blog.csdn.net/20171111152554603?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)看到了吧,果然是具有这种形式的shape,那么input这个参数的输入我们就大致理解了~<div class="se-preview-section-delimiter"></div>###filter的作用这个地方的输入就是卷积核了,并且要求卷积核具有如[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数]这样的shape,源代码我们这里给的是:<div class="se-preview-section-delimiter"></div>
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
还记得我们W_conv1的定义:<div class="se-preview-section-delimiter"></div>
W_conv1 = weight_variable([5, 5, 1, 32])
“`
这里的[5,5,1,32]所对应的就是卷积核的高,宽,图像通道数和卷积核个数~。且不要忘记我们之前有输出过W_conv1是一个(5×5)的矩阵,其中每个元素是(1×13)的矩阵。
strides的作用
这是表明卷积在图像每一维的步长(但是在官方的源代码中没有定义这个参数)[[[待修改!!!其实是有的]]]
padding
这个只能是”SAME”或者“”
strides的作用
这是表明卷积在图像每一维的步长,原demo的写法:
def conv2d(x, W): return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
这个地方以后或许还会再详细进行补充
padding
这个只能是”SAME”或者“VALID”,一种填充方式而已。在本demo中的选择是”SAME”
接着将从conv2d中返回的东西+偏项b之后代入relu函数中:
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
输出的东西即为h_conv1…(讲实话我现在已经被各种变量搞晕了)
如何进行预测?
观察源代码,不难发现在正确率判断那里所使用的还是:
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
用y_conv和y_进行对比,那么我们是如何得到预测值y_conv的呢?
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
不难看出还是通过我们的softmax这个方法,还记得softmax是怎么用的吗?
x = tf.placeholder(tf.float32, [None, 784])W = tf.Variable(tf.zeros([784,10]))b = tf.Variable(tf.zeros([10]))y = tf.nn.softmax(tf.matmul(x,W) + b)
就是直接把代表图像的x,权重W和b进行输入,softmax即可输出预测,那么类比来看我们这里的h_fc1_drop的本质也是一张图像,只不过这一张图像经过cnn,max_pool和drop等一系列处理之后,可能特征变得更加明显吧~总之将经过处理之后得到的图像代入就可以获得更高的准确率(当然怎么样处理可以使得图像的识别度最高,也是需要tensorflow自己来搞定的)。
处理前和处理后的图像有什么区别?
emmm那么既然了解(4)的内容相比于(3)来说只是将图像重新进行处理之后再代入softmax()中,那么现在有一个我比较感兴趣的问题,即cnn等一系列操作处理之后得到的h_fc1_drop的图像跟它的原始图像的区别在哪里?
为解决这个问题,我试图将x_image和与之对应的h_fc1_drop进行输出。
补充:在对h_fc1_drop这个变量进行输出的的时候,出现了如下错误:
输入
print sess.run(h_conv1)
输出
InvalidArgumentError: You must feed a value for placeholder tensor 'Placeholder' with dtype float [[Node: Placeholder = Placeholder[dtype=DT_FLOAT, shape=[], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]Caused by op u'Placeholder'
大致的意思就是需要提供一些placeholder,故修改成:
“`
sess.run(h_fc1_drop,feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
即可。首先我们看原始图像长什么样子:![这里写图片描述](http://img.blog.csdn.net/20171114003042839?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)我看到的时候也想说···这是什么鬼,难道是9吗?然后查了这张图对应的label,结果是8。。。(目测时在录入的时候没有录完吧···哎)![这里写图片描述](http://img.blog.csdn.net/20171114003152839?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXE1cTEzNjM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后我们再看看经过cnn一堆处理之后,最终传给softmax函数的h_fc1_drop是什么样子:
forp2 = h_fc1_dropa = sess.run(h_fc1_drop,feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})b = tf.reshape(a[0], [-1,32,32,1])b = sess.run(b)[0]np.savetxt('new2.csv',b,delimiter=',')
然后打开new2.csv:
表示,根本找不到任何规律,谁能看出来这是什么数字啊。。。
总结
所以,可能cnn以及其配套的一系列操作,是把肉眼可以识别的数字,变成容易被计算机识别的数字吧~对于其内部的原理也是很感兴趣,该篇再说
- tensorflow(4)---mnist问题的深度卷积神经网络(基于官网文档的实现)
- 卷积神经网络LeNet5,基于TensorFlow的实现
- 基于tensorflow的MNIST手写字识别(一)--白话卷积神经网络模型
- 基于tensorflow的MNIST手写字识别(一)--白话卷积神经网络模型
- tensorflow官方文档 mnist进阶(卷积神经网络)
- 卷积神经网络(CNN)的简单实现(MNIST)
- 卷积神经网络(CNN)的简单实现(MNIST)
- 卷积神经网络(CNN)的简单实现(MNIST)
- TensorFlow在MNIST的卷积神经网络中例子
- Tensorflow之 CNN卷积神经网络的MNIST手写数字识别
- 深度学习笔记——TensorFlow学习笔记(三)使用TensorFlow实现的神经网络进行MNIST手写体数字识别
- tensorflow(3)---官方文档MNIST问题的实现思路解说
- (四)Tensorflow学习之旅——MNIST分类的卷积神经网络CNN示例
- TensorFlow深度学习进阶教程:TensorFlow实现CIFAR-10数据集测试的卷积神经网络
- tensorflow 经典卷积神经网络的实现
- tensorflow实现简单的卷积神经网络
- TensorFlow-6实现进阶的卷积神经网络
- 简单卷积神经网络的tensorflow实现
- CentOS7换源
- C&&C++的异常处理(一)
- 彻底把Google的安装目录从c盘迁移走
- hdu 5582 Journey of Taku
- python沙箱逃逸小结
- tensorflow(4)---mnist问题的深度卷积神经网络(基于官网文档的实现)
- 视觉智慧是人类和计算机合作沟通的桥梁——李飞飞 中国计算机大会CNCC 2017
- 微信小程序开发-配置
- expat & scew
- Brew命令
- JAVA形参和实参的区别
- 2.3Groovy灵活的参数初始化
- 第一篇帖子
- 【zookeeper】客户端 底层实现