A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

这节我们利用TensorFlow建立卷积神经网络(CNN)进行图像识别,数据集还是利用MNIST图像识别数据集。在建立CNN之前我们会跑一下Softmax进行对比,有助于大家体会不同函数的用法,代码如下,具体说明见注释:





  • # -*- coding: utf-8 -*-



  • """



  • Created on Sat Apr  1 14:57:40 2017







  • @author: chenbin



  • """







  • import input_data



  • mnist = input_data.read_data_sets('MNIST_data', one_hot=True)







  • import tensorflow as tf



  • sess = tf.InteractiveSession()











  • x = tf.placeholder("float", shape=[None, 784])



  • y_ = tf.placeholder("float", shape=[None, 10])







  • W = tf.Variable(tf.zeros([784,10]))



  • b = tf.Variable(tf.zeros([10]))







  • sess.run(tf.initialize_all_variables())



  • #一次性初始化所有变量







  • y = tf.nn.softmax(tf.matmul(x,W) + b)







  • cross_entropy = -tf.reduce_sum(y_*tf.log(y))







  • train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)







  • for i in range(1000):



  •   batch = mnist.train.next_batch(50)



  •   train_step.run(feed_dict={x: batch[0], y_: batch[1]})







  • correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))



  • accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))







  • print (accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))











  • #CNN







  • #我们会建立大量权重和偏置项,为了方便,定义初始函数











  • def weight_variable(shape):



  •   initial = tf.truncated_normal(shape, stddev=0.1) #tf.truncated_normal初始函数将根据所得到的均值和标准差,生成一个随机分布



  •   return tf.Variable(initial)







  • def bias_variable(shape):



  •   initial = tf.constant(0.1, shape=shape)



  •   return tf.Variable(initial)



  • """



  • 由于我们使用的是ReLU神经元,因此比较好的做法是用一个较小的正数来初始化偏置项,



  • 以避免神经元节点输出恒为0的问题(dead neurons)



  • """







  • #卷积池化操作  



  • """



  • 我们的卷积使用1步长(stride size),0边距(padding size)的模板



  • 保证输出和输入是同一个大小。我们的池化用简单传统的2x2大小的模板做max pooling



  • """







  • def conv2d(x, W):



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



  • """



  • 1. x是输入的样本,在这里就是图像。x的shape=[batch, height, width, channels]。



  • - batch是输入样本的数量



  • - height, width是每张图像的高和宽



  • - channels是输入的通道,比如初始输入的图像是灰度图,那么channels=1,如果是rgb,那么channels=3。对于第二层卷积层,channels=32。



  • 2. W表示卷积核的参数,shape的含义是[height,width,in_channels,out_channels]。



  • 3. strides参数表示的是卷积核在输入x的各个维度下移动的步长。了解CNN的都知道,在宽和高方向stride的大小决定了卷积后图像的size。这里为什么有4个维度呢?因为strides对应的是输入x的维度,所以strides第一个参数表示在batch方向移动的步长,第四个参数表示在channels上移动的步长,这两个参数都设置为1就好。重点就是第二个,第三个参数的意义,也就是在height于width方向上的步长,这里也都设置为1。



  • 4. padding参数用来控制图片的边距,’SAME’表示卷积后的图片与原图片大小相同,’VALID’的话卷积以后图像的高为Heightout=Height原图−Height卷积核+1StrideHeight, 宽也同理。



  • """







  • def max_pool_2x2(x):



  •   return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],



  •                         strides=[1, 2, 2, 1], padding='SAME')



  • """                       



  • 这里用2∗2的max_pool。参数ksize定义pool窗口的大小,每个维度的意义与之前的strides相同



  • 第一个参数value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape



  • 第二个参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1



  • 第三个参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]



  • 第四个参数padding:和卷积类似,可以取'VALID' 或者'SAME'



  • 返回一个Tensor,类型不变,shape仍然是[batch, height, width, channels]这种形式



  • 这个函数的功能是将整个图片分割成2x2的块,



  • 对每个块提取出最大值输出。可以理解为对整个图片做宽度减小一半,高度减小一半的降采样



  • """







  • #卷积一



  • W_conv1 = weight_variable([5, 5, 1, 32])



  • b_conv1 = bias_variable([32])



  • """



  • 它由一个卷积接一个max pooling完成。卷积在每个5x5的patch中算出32个特征(理解为做了32次卷积,每次卷积中不同的神经元享有同样参数;但是不同次卷积所用的参数是不同的)。



  • 卷积的权重张量形状是[5, 5, 1, 32],前两个维度是patch的大小,接着是输入的通道数目,



  • 最后是输出的通道数目。 而对于每一个输出通道都有一个对应的偏置量



  • """











  • x_image = tf.reshape(x, [-1,28,28,1])



  • """



  • 为了用这一层,我们把x变成一个4d向量,其第2、第3维对应图片的宽、高,



  • 最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)



  • 第一维-1代表将x沿着最后一维进行变形



  • """







  • h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)



  • h_pool1 = max_pool_2x2(h_conv1)











  • #卷积二



  • """



  • 为了构建一个更深的网络,我们会把几个类似的层堆叠起来。



  • 第二层中,每个5x5的patch会得到64个特征。



  • """



  • 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)











  • #密集连接层



  • """



  • 现在,图片尺寸减小到7x7(pool两次,相当于降采样两次),我们加入一个有1024个神经元的全连接层,



  • 用于处理整个图片。我们把池化层输出的张量reshape成一些向量,乘上权重矩阵,加上偏置,



  • 然后对其使用ReLU



  • """



  • 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)







  • #droput



  • """



  • 为了减少过拟合,我们在输出层之前加入dropout。



  • 我们用一个placeholder来代表一个神经元的输出在dropout中保持不变的概率。



  • 这样我们可以在训练过程中启用dropout,在测试过程中关闭dropout。



  • TensorFlow的tf.nn.dropout操作除了可以屏蔽神经元的输出外,



  • 还会自动处理神经元输出值的scale。所以用dropout的时候可以不用考虑scale







  • Dropout是指在模型训练时随机让网络某些隐含层节点的权重不工作,



  • 不工作的那些节点可以暂时认为不是网络结构的一部分,



  • 但是它的权重得保留下来(只是暂时不更新而已),



  • 因为下次样本输入时它可能又得工作了



  • """



  • 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(3000):



  •   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}))























我们只训练了3000次,最后准确率为0.986,大家主要体会建立卷积网络的过程和各个函数的用法,尤其是特征的计算,需要的大家对卷积网络很了解,可以多看看注释及复习相关知识,欢迎讨论~




  • step 2400, training accuracy 0.98



  • step 2500, training accuracy 0.96



  • step 2600, training accuracy 0.98



  • step 2700, training accuracy 1



  • step 2800, training accuracy 0.98



  • step 2900, training accuracy 1



  • test accuracy 0.986





1 个回复

正序浏览
奈斯,加油加油
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马