参考:http://www.tensorfly.cn/tfdoc/tutorials/mnist_pros.html
网上已经有很多相关内容的博客、资料,有很多也写得挺好的,我也是参考别人的,这里就不再写原理上的东西了。附一下我做实验的代码,简单记录一下遇到的问题。
实验环境:spyder + python + tensorflow
代码:
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("data/", one_hot=True, validation_size=0) # 下载并加载mnist数据
print("mnist训练集大小:", len(mnist.train.images))
print("mnist测试集大小:", len(mnist.test.images))
x = tf.placeholder(tf.float32, [None, 784], name="x") # 输入的数据占位符
y_actual = tf.placeholder(tf.float32, shape=[None, 10], name="y_actual") # 输入的标签占位符
# 定义一个函数,用于初始化所有的权值 W
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
# 定义一个函数,用于初始化所有的偏置项 b
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(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 构建网络
x_image = tf.reshape(x, [-1, 28, 28, 1]) # 转换输入数据shape,以便于用于网络中
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) # 第一个卷积层
h_pool1 = max_pool(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(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]) # reshape成向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) # 第一个全连接层
keep_prob = tf.placeholder("float", name="keep_prob")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # dropout层
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_predict = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2, name="y_predict") # softmax层
cross_entropy = -tf.reduce_sum(y_actual * tf.log(y_predict),name = "cross_entropy") # 交叉熵
train_step = tf.train.GradientDescentOptimizer(1e-3).minimize(cross_entropy) # 梯度下降法
correct_prediction = tf.equal(tf.argmax(y_predict, 1), tf.argmax(y_actual, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) # 精确度计算
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
print("开始训练:")
for i in range(3000):
batch = mnist.train.next_batch(20)
if i % 500 == 0:
train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_actual: batch[1], keep_prob:1.0})
print('step', i, 'train_accuracy', train_accuracy)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
print("训练结束")
print("开始测试:")
test_accuracy = 0.0
for i in range(100):
batch = mnist.test.next_batch(100)
test_accuracy_i = accuracy.eval(feed_dict={x:batch[0], y_actual:batch[1], keep_prob:1.0})
test_accuracy += test_accuracy_i
if (i+1) % 20 == 0:
print('step', i+1, 'test accuracy: ', test_accuracy_i)
print("训练集准确度: ", test_accuracy/100)
print("测试结束")
sess.close()
实验结果:
在训练的时候,讲batch size改为50再训练一次。
修改训练部分的代码:
print("开始训练")
for i in range(1200):
batch = mnist.train.next_batch(50)
if i % 500 == 0:
train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_actual: batch[1], keep_prob:1.0})
print('step', i, 'train_accuracy', train_accuracy)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
print("训练结束")
运行结果:
- 问题1:
运行的 时候,CPU几乎满负荷的在跑!!刚开始用测试集进行测试的时候,像其他博客一样,我把整个测试集一次性都传进去进行测试,然后,电脑就死机了,还一测一个死,不强制关机都不行T_T(应该是性能太差了,CPU和内存资源支持不了规模大一点的计算T_T)
然后我就把测试集也分成几个小的batch去进行测试,然后结果很快就跑出来了~
感觉有必要倒腾一下,弄个GPU版的了~
- 问题2
我本来想把训练好的模型保存下来,下次测试的时候只需要导入模型就可以了。代码是写了,但是实测结果发现好像不太对。这里就先不附代码了,后续跟进~
- 问题3
刚开始也觉得迷惑,为什么这个网络经过卷积操作之后,feature map的大小竟然不减小?后来才get到,因为在卷积的时候我们选择了参数SAME,指明了卷积后尺寸不变(通过填充和裁剪实现)。然后突然想起《数字图像处理》3.4.2中也提到过,看过就能大概明白了(如下图)。所以在这个CNN模型中,feature map的size只有在池化层的时候发生变化,28*28经过第一次池化后大小为14*14,经过第二次池化后大小为7*7~
- 问题4
感觉跑出来的正确率好像,有点......低啊,好像别人都有99%~
我发现我训练的时候,每个训练样本都只用了一次~而其他的一些博客,会将一个样本反复用来多训练几遍~
比如,这篇https://blog.csdn.net/chenhaifeng2016/article/details/62221544博文,其训练部分代码和实验结果如下:
然后我也尝试了一下,多训练几次,精确度也提提升到了将近99%~
修改代码:
print("开始训练:")
for i in range(10000):
batch = mnist.train.next_batch(20)
if i % 1000 == 0:
train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_actual: batch[1], keep_prob:1.0})
print('step', i, 'train_accuracy', train_accuracy)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
print("训练结束")
运行结果