本文使用的tensorflow版本:1.4
tensorflow安装:pip install tensorflow
1、CNN
哇咔咔,熟悉的味道,自己第一次接触tensorflow也是写的CNN的例子,当时对于CNN也是一知半解,经过了一年,终于差不多搞清楚了CNN的原理。CNN中需要理解的主要有两点,稀疏连接 Sparse Connectivity (每个神经元仅与前一层部分神经元相连接)以及参数共享 Parameter Sharing(同一个feature map的参数是相同的)。
举个简单的例子吧:假设有100 * 100像素 的 图片,如果下一层有100个神经元,那么全连接的神经网络,将有100 * 100 * 100=100万的参数,如果采用稀疏连接和参数共享,后一层的一个神经元只与前一层的100个神经元连接,那么需要100 * 100 = 1万个参数,如果与不同神经元连接的这100条线的参数都相同,那么只需要100个参数,这叫一个feature map或者说一个field,但是这只能学到一个特征,我们可以定义多个feature map来学习不同的特征,如果有100个feature map,那么参数就是100 * 100的量。
今天我们要学习的是官网给出的tensorflow使用CNN实现MNIST手写数字分类的代码,在这个例子中,每一张图片是28*28的,最终的输出是10维的向量,10个数字分别代表类别为0-9的概率。
网络的结构是这样的:
输入:28 * 28 -》
第一层卷积:下一层每一个神经元与5*5的区域相连,共32个feature map,所以输出为 28 * 28 * 32 -》
第一层Pooling:四个像素做一次maxpooling,输出为 14 * 14 * 32 -》
第二层卷积:同样选择5 * 5 的patch,这次选择64个feature map-》输出为 14 * 14 * 64 -》
第二层Pooling:四个像素做一次maxpooling,输出为 7 * 7 * 64 -》
全连接隐藏层:输入是7 * 7 * 64,输出为1024 -》
输出层:输出10维向量
下面,我们就来看看具体代码的实现吧!
2、代码实现
这里我们来介绍一下代码中的几个重要的部分,完整的代码在文末会给出。
卷积层实现
卷积操作是通过tf.nn.conv2d函数来实现的,我们给出了四个参数,首先是输入x和参数矩阵W,strides是步长,是一个四维的矩阵,前后两个数必须为1,中间两个数是patch每次向右和向下移动的步长,而padding=SAME则在原图像的四周填充空白值,使得经过卷积之后的图像大小跟原图像大小相同。可以想到,如果选择5*5的patch,每次向右和向下移动1步的话,如果不在四周填充一层,那么经过一个feature map卷积之后的图像大小就不会保持原样,而是宽和高都减少4维。
def conv2d(x,W):
#strides是步长,四维的列表 [1,x_movement,y_movement,1]
# must have strides[0]=strides[3]=1
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
Pooling层实现
Pooling层实现之间调用tf.nn.max_pool方法,这里ksize表明了多大范围内的元素进行pooling,这里很明显是2*2的方格进行pooling,而strides同样是移动步长,这里我们每次向右或者向下移动两个元素,这样,相当于在经过pooling之后,我们的宽高都变成了原来的一半。
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
初始输入x和Weights的定义
可以看到初始输入的x是四维的,第一位是张数的意思,二三位是图片的长和宽,第四位是channel,因为只有灰这一个channel,所以是1。而Weights的前两维表明了patch大小为5*5,第三个参数表明输入的feature map的多少,这里由于只有灰所以是1,第四个参数表明输出的feature map 的多少。
x_image = tf.reshape(xs,[-1,28,28,1])
W_conv1 = weight_variable([5,5,1,32])
分类准确率计算
我们首先得到了预测值,然后根据tf.argmax得到准确率最高的一维的下标即我们认为的分类结果,使用equal方法判断是否分类准确,最后计算我们的准确率。
def compute_accuracy(v_xs,v_ys,sess):
#prediction 变为全剧变量
global prediction
y_pre = sess.run(prediction,feed_dict={xs:v_xs,keep_prob:1})
#预测值每行是10列,tf.argmax(数据,axis),相等为1,不想等为0
correct_prediction = tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))
# 计算平均值,即计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# 运行我们的accuracy这一步
result = sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys,keep_prob:1})
return result
3、完整代码
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)
def compute_accuracy(v_xs,v_ys,sess):
#prediction 变为全剧变量
global prediction
y_pre = sess.run(prediction,feed_dict={xs:v_xs,keep_prob:1})
#预测值每行是10列,tf.argmax(数据,axis),相等为1,不想等为0
correct_prediction = tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))
# 计算平均值,即计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# 运行我们的accuracy这一步
result = sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys,keep_prob:1})
return result
def weight_variable(shape):
inital = tf.truncated_normal(shape,stddev=0.1)
return tf.Variable(inital)
def bias_variable(shape):
inital = tf.constant(0.1,shape=shape)
return tf.Variable(inital)
def conv2d(x,W):
#strides是步长,四维的列表 [1,x_movement,y_movement,1]
# must have strides[0]=strides[3]=1
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')
xs = tf.placeholder(tf.float32,[None,784])
ys = tf.placeholder(tf.float32,[None,10])
keep_prob = tf.placeholder(tf.float32)
#将图片reshape,第一位是张数的意思,二三位是图片的长和宽,第四位是channel,因为只有灰这一个channel,所以是1
x_image = tf.reshape(xs,[-1,28,28,1])
## conv1 layer ##
#patch是5 * 5 的,输入是1个,输出是32,也就是32个feature map
W_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])
h_conv1= tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1) # 输出28 * 28 * 32
h_pool1 = max_pool_2x2(h_conv1) #输出 14 * 14 * 32
## conv2 layer ##
W_conv2 = weight_variable([5,5,32,64]) # 64个feature map
b_conv2 = bias_variable([64])
h_conv2= tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2) # 输出14 * 14 * 64
h_pool2 = max_pool_2x2(h_conv2) #输出 7 * 7 * 64
## func1 layer ##
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)
h_fc1 = tf.nn.dropout(h_fc1,keep_prob)
## func2 layer ##
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1,W_fc2)+b_fc2)
#prediction = add_layer(xs,784,10,activation_function=tf.nn.softmax)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction)
,reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step,feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:0.5})
if i % 50 == 0:
print(compute_accuracy(mnist.test.images,mnist.test.labels,sess))