手把手教你使用TensorFlow搭建卷积神经网络
TensorFlow版本1.4.0
python版本>3.5.0
卷积神经网络的原理大家可以参考这篇文章
本教程使用LeNet网络对MNIST数据集进行分类。
LeNet基本结构如下
输入—>卷积层C1—>池化层P1—>卷积层C2—>池化层P2—>全连接层F1—>全连接层F2(输出)
输入参数
输入图像大小28*28
卷积层C1参数
卷积核大小5*5,步长为1,输出通道20
输出大小为(28-5+1)*(28-5+1)*20=24*24*20
池化层P1参数
池化核大小2*2,步长为2
输出大小为(24/2)*(24/2)*20=12*12*20
卷积层C2参数
卷积核大小5*5,步长为1,输出通道50
输出大小为(12-5+1)*(12-5+1)*50=8*8*50
池化层P2参数
池化核大小2*2,步长为2
输出大小为(8/2)*(8/2)*50=4*4*50=800
全连接层F1参数
输出神经元个数500
全连接层F2(输出)参数
输出神经元个数10
了解了LeNet网络结构之后,就可以动手编写代码了
1.载入MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
import tensorflow as tf
2.定义参数
learning_rate = 0.001
train_epochs = 1
batch_size = 64
n_input = 784
n_classes = 10
3.定义网络输入参数
x = tf.placeholder(tf.float32, shape=[None, n_input])
y = tf.placeholder(tf.float32, shape=[None, n_classes])
keep_prob = tf.placeholder(tf.float32) #采用dropout,防止过拟合
4.定义权重与偏置
#权重的形状为[kernel_size, kernel_size, in_channels, out_channels]
#-------------卷积核高-------卷积核宽-----输入通道数----输出通道数--
weights = {'wc1': tf.Variable(tf.random_normal([5,5,1,20])),
'wc2': tf.Variable(tf.random_normal([5,5,20,50])),
'wf1': tf.Variable(tf.random_normal([4*4*50, 500])),
'wf2': tf.Variable(tf.random_normal([500, 10]))}
biases = {'bc1': tf.Variable(tf.random_normal([20])),
'bc2': tf.Variable(tf.random_normal([50])),
'bf1': tf.Variable(tf.random_normal([500])),
'bf2': tf.Variable(tf.random_normal([10]))}
5.定义前向推断过程
def inference(x):
#将图片大小变为[batch_size, height, width, channels]
#---------------训练个数------高-----宽------通道---
x = tf.reshape(x, shape=[-1, 28, 28, 1])
#步长stride中间两个维度表示高和宽,其他两个维度默认为1即可
#卷积层C1
conv1 = tf.nn.conv2d(x, weights['wc1'], strides=[1, 1, 1, 1], padding='VALID')
conv1 = tf.nn.bias_add(conv1, biases['bc1'])
#池化层P1
conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
#卷积层C2
conv2 = tf.nn.conv2d(conv1, weights['wc2'], strides=[1, 1, 1, 1], padding='VALID')
conv2 = tf.nn.bias_add(conv2, biases['bc2'])
#池化层P2
conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
#将4*4*50变为800
fc1 = tf.reshape(conv2, [-1, weights['wf1'].get_shape().as_list()[0]])
#全连接层F1
fc1 = tf.nn.xw_plus_b(fc1, weights['wf1'], biases['bf1'])
fc1 = tf.nn.relu(fc1)
#dropout层,dropout原理参考https://yq.aliyun.com/articles/68901
fc1 = tf.nn.dropout(fc1, keep_prob)
#全连接层F2(输出)
out = tf.nn.xw_plus_b(fc1, weights['wf2'], biases['bf2'])
return out
6.构建网络
logits = inference(x)
prediction = tf.nn.softmax(logits)
7.定义损失函数与优化器
loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)
8.定义评价指标
pre_correct = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
accuracy = tf.reduce_mean(tf.cast(pre_correct, tf.float32))
9.开始训练
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
total_batch = int(mnist.train.num_examples / batch_size)
for epoch in range(train_epochs):
for batch in range(total_batch):
batch_x, batch_y = mnist.train.next_batch(batch_size)
sess.run(train_op, feed_dict={x:batch_x, y:batch_y, keep_prob:0.8})
if batch % 80 == 0:
loss, acc = sess.run([loss_op, accuracy], feed_dict={x:batch_x, y:batch_y, keep_prob:1.0})
print("epoch {}, loss {:.4f}, accuracy {:.3f}".format(epoch, loss, acc))
print("optimization finished!")
#在测试集上测试
test_acc = sess.run(accuracy, feed_dict={x:mnist.test.images, y:mnist.test.labels, keep_prob:1.0})
print('test accuracy', test_acc)
只训练1轮就达到了93.39%
github源码下载
https://github.com/gamersover/tensorflow_basic_tutorial/blob/master/basic_model/cnn_mnist.py