基于tensorflow搭建一个简单的CNN模型(code)
我们将要搭建一个简单的卷积神经网络结构去提高手写数字的预测结果精度。
# Introductory CNN Model: MNIST Digits
# In this example, we will download the MNIST handwritten
# digits and create a simple CNN network to predict the
# digit category (0-9)
主要分为以下几个步骤:导入数据;创建模型的变量;搭建模型;采用批量化训练网络;可视化loss,accuracy等结果。
1.导入必要的库和开始一个图谱会话
import tensorflow as tf
import numpy as np
import matplotlib as plt
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
sess = tf.Session()
2.导入数据集和将图片装换为28 * 28大小的矩阵
data_dir = 'temp' #数据集存放的文件夹
mnist = read_data_sets(data_dir) #读取数据集
#将训练和测试数据集图片归一化为28*28大小
train_xdata = np.array([np.reshape(x, (28,28)) for x in mnist.train.images])
test_xdata = np.array([np.reshape(x, (28,28)) for x in mnist.test.images])
train_labels = mnist.train.labels #训练数据集标签
test_labels = mnist.test.labels #测试数据集标签
3.定义模型参数
batch_size = 100 #一个批量的图片数量
learning_rate = 0.005 #学习率
evaluation_size = 500 #模型验证数据集一个批量的数量
image_width = train_xdata[0].shape[0] #图片的长 28
image_height = train_xdata[0].shape[1] #图片的宽 28
target_size = max(train_labels)+1 #输出类别的个数 10
num_channels = 1 # 通道数为1
generations = 500 #迭代代数
eval_every = 5 #每次5个generation
conv1_features = 25 #卷积核的个数
conv2_features = 50 #卷积核的个数
max_pool_size1 = 2 #池化层窗口大小
max_pool_size2 = 2 #池化层窗口大小
fully_connected_size1 = 100 #全连接层大小
4.定义数据集的占位符
#输入数据的张量大小
x_input_shape = (batch_size, image_width, image_height, num_channels)
#创建输入训练数据的占位符
x_input = tf.placeholder(tf.float32, shape=x_input_shape)
#创建一个批量训练结果的占位符
y_target = tf.placeholder(tf.int32, shape=batch_size)
#验证图片输入张量
eval_input_shape = (evaluation_size, image_width, image_height,num_channels)
#创建输入验证数据的占位符
eval_input = tf.placeholder(tf.float32, shape=eval_input_shape)
#创建一个批量验证结果的占位符
eval_target = tf.placeholder(tf.int32, shape= evaluation_size )
5.定义训练权重和偏置的变量
#定义第一个卷积核的参数,其中用tf.truncated_normal生成正太分布的数据,#stddev(正态分布标准差)为0.1
conv1_weight = tf.Variable(tf.truncated_normal([4, 4, num_channels, conv1_features], stddev=0.1, dtype = tf.float32))
#定义第一个卷积核对应的偏置
conv1_bias = tf.Variable(tf.zeros([conv1_features], dtype=tf.float32))
#定义第二个卷积核的参数,其中用tf.truncated_normal生成正太分布的数据,#stddev(正态分布标准差)为0.1
conv2_weight = tf.Variable(tf.truncated_normal([4, 4, num_channels, conv2_features], stddev=0.1, dtype = tf.float32))
#定义第二个卷积核对应的偏置
conv2_bias = tf.Variable(tf.zeros([conv2_features], dtype=tf.float32))
6.定义全连接层的权重和偏置
#输出卷积特征图的大小
resulting_width = image_width // (max_pool_size1 * max_pool_size2)
resulting_height = image_height // (max_pool_size1 * max_pool_size2)
#将卷积层特征图拉成一维向量
full1_input_size = resulting_width * resulting_height * conv2_features
#创建第一个全连接层权重和偏置
full1_weight =tf.Variable(tf.truncated_normal([full1_input_size,fully_connected_size1],
stddev=0.1, dtype=tf.float32))
full1_bias = tf.Variable(tf.truncated_normal([fully_connected_size1], stddev=0.1,
dtype=tf.float32))
#创建第二个全连接层权重和偏置
full2_weight = tf.Variable(tf.truncated_normal([fully_connected_size1,target_size],
stddev=0.1, dtype=tf.float32))
full2_bias = tf.Variable(tf.truncated_normal([target_size], stddev=0.1,
dtype=tf.float32))
7.定义网络模型
def my_conv_net(input_data):
#First Conv-relu-maxpool layer
conv1 = tf.nn.conv2d(input_data, conv1_weight, strides=[1, 1, 1, 1], padding='SAME')
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_bias))
max_pool1 = tf.nn.max_pool(relu1, ksize=[1, max_pool_size1, max_pool_size1, 1], strides=[1, max_pool_size1, max_pool_size1, 1], padding='SAME')
# Second Conv-relu-maxpool layer
conv2 = tf.nn.conv2d(max_pool1, conv2_weight, strides=[1, 1, 1, 1], padding='SAME')
relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_bias))
max_pool2 = tf.nn.max_pool(relu2, ksize=[1, max_pool_size1, max_pool_size1, 1], strides=[1, max_pool_size2, max_pool_size2, 1], padding='SAME')
#将输出转换为一个[1xN],为下一个全连接层输入做准备
final_conv_shape = max_pool2.get_shape().as_list()
final_shape = final_conv_shape[1] * final_conv_shape[2] * final_conv_shape[3]
flat_output = tf.reshape(max_pool2, [final_conv_shape[0], final_shape])
#First fully-connected layer
fully_connected1 = tf.nn.relu(tf.add(tf.add(tf.matmul(flat_output,full1_weight), full1_bias)))
# Second fully-connected layer
final_model_output = tf.add(tf.matmul(fully_connected1, full2_weight), full2_bias)
return (final_model_output)
8.定义网络的训练数据和测数据
model_output = my_conv_net(x_input)
test_model_output = my_conv_net(eval_input)
9.使用Softmax函数作为loss function
loss = loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=model_output, labels=y_target))
10.接下来创建一个训练和测试的函数
prediction = tf.nn.softmax(model_output)
test_prediction = tf.nn.softmax(test_model_output)
# Create accuracy function
def get_accuracy(logits, targets):
batch_predictions = np.argmax(logits, axis=1)
num_correct = np.sum(np.equal(batch_predictions, targets))
return(100. * num_correct/batch_predictions.shape[0])
11.创建一个optimizer function
my_optimizer = tf.train.MomentumOptimizer(learning_rate, 0.9)
train_step = my_optimizer.minimize(loss)
# Initialize Variables
init = tf.initialize_all_variables()
sess.run(init)
12.开始训练模型
train_loss = [ ]
train_acc = [ ]
test_acc = [ ]
for i in range(generations):
rand_index = np.random.choice(len(train_xdata), size=batch_size)
rand_x = train_xdata[rand_index]
rand_x = np.expand_dims(rand_x, 3)
rand_y = train_labels[rand_index]
train_dict = {x_input: rand_x, y_target: rand_y}
sess.run(train_step, feed_dict=train_dict)
temp_train_loss, temp_train_preds = sess.run([loss, prediction], feed_dict=train_dict)
temp_train_acc = get_accuracy(temp_train_preds, rand_y)
if (i+1) % eval_every == 0:
eval_index = np.random.choice(len(test_xdata), size=evaluation_size)
eval_x = test_xdata[eval_index]
eval_x = np.expand_dims(eval_x, 3)
eval_y = test_labels[eval_index]
test_dict = {eval_input: eval_x, eval_target: eval_y}
test_preds = sess.run(test_prediction, feed_dict=test_dict)
temp_test_acc = get_accuracy(test_preds, eval_y)
# Record and print results
train_loss.append(temp_train_loss)
train_acc.append(temp_train_acc)
test_acc.append(temp_test_acc)
acc_and_loss = [(i+1), temp_train_loss, temp_train_acc, temp_test_acc]
acc_and_loss = [np.round(x,2) for x in acc_and_loss]
13.输出结果
print('Generation # {}. Train Loss: {:.2f}. Train Acc (Test Acc): {:.2f} ({:.2f})'.format(*acc_and_loss))
14.使用matplotlib显示loss-accuracies曲线
图1. 左图是我们500 generations时的训练精度曲线。右图是在500 generations时的softmax loss值eval_indices = range(0, generations, eval_every)
# Plot loss over time
plt.plot(eval_indices, train_loss, 'k-')
plt.title('Softmax Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('Softmax Loss')
plt.show()
# Plot train and test accuracy
plt.plot(eval_indices, train_acc, 'k-', label='Train Set Accuracy')
plt.plot(eval_indices, test_acc, 'r--', label='Test Set Accuracy')
plt.title('Train and Test Accuracy')
plt.xlabel('Generation')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.show()
15.显示最新一个批量的预测结果
图2. 显示出6张随机图片的真实结果和预测结果# Plot the 6 of the last batch results:
actuals = rand_y[0:6]
predictions = np.argmax(temp_train_preds,axis=1)[0:6]
images = np.squeeze(rand_x[0:6])
Nrows = 2
Ncols = 3
for i in range(6):
plt.subplot(Nrows, Ncols, i+1)
plt.imshow(np.reshape(images[i], [28,28]), cmap='Greys_r')
plt.title('Actual: ' + str(actuals[i]) + ' Pred: ' + str(predi
ctions[i]),fontsize=10)
frame = plt.gca()
frame.axes.get_xaxis().set_visible(False)
frame.axes.get_yaxis().set_visible(False)