本文使用一个最简单的单隐层前馈网络实现手写数字识别,借助TensorFlow可以很容易地实现。
数据集使用MNIST,由数万张28像素×28像素的手写数字组成,这些图片只包含灰度值信息。其中包含训练集55000个样本,测试集10000个样本,以及验证集5000个样本。MNIST数据集可以在THE MNIST DATABASE下载,也可以使用下面的代码直接在python中导入:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
将28×28的图片转换成向量,长度为784,因此神经网络的输入层有784个神经元;输出层显然需要10个神经元,因为输出的是0~9这10个数字;隐含层采用15个神经元。网络结构如下:
隐层的激活函数采用 sigmoid 函数,输出层的激活函数采用 softmax 函数。常用的激活函数及其选择方法见参考文献2和3。
损失函数为实际的label与概率归一化预测输出的交叉熵,具体采用 “tf.nn.softmax_cross_entropy_with_logits” 进行计算,其原理见参考文献4。
优化算法(梯度下降算法)采用Adam算法,即tensorflow中的“tf.train.AdamOptimizer”。详见参考文献5。
程序运行版本为:python-->3.7.3,tensorflow-->1.13.1
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# move warning
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
old_v = tf.logging.get_verbosity()
tf.logging.set_verbosity(tf.logging.ERROR)
# read data
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
# create model
# input layer
x = tf.placeholder(tf.float32, [None, 784]) # input images
y_ = tf.placeholder(tf.float32, [None, 10]) # input labels
# hidden layer
hidden_layer_count = 15
w1 = tf.Variable(tf.zeros([784, hidden_layer_count]))
b1 = tf.Variable(tf.zeros([hidden_layer_count]))
y1 = tf.sigmoid(tf.matmul(x, w1) + b1)
# output layer
output_layer_count = 10
w2 = tf.Variable(tf.zeros([hidden_layer_count, output_layer_count]))
b2 = tf.Variable(tf.zeros(output_layer_count))
y2 = tf.nn.softmax(tf.matmul(y1, w2) + b2)
# loss function & optimization algorithm
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y2))
train_step = tf.train.AdamOptimizer(learning_rate=0.01).minimize(cross_entropy)
# new session
sess = tf.Session()
sess.run(tf.global_variables_initializer())
# train
for i in range(10000):
batch_xs, batch_ys = mnist.train.next_batch(50)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
if i % 1000 == 0:
loss = sess.run(cross_entropy, {x: batch_xs, y_: batch_ys})
print("Iter: %s loss: %s" % (i, loss))
# test
correct_prediction = tf.equal(tf.argmax(y_, 1), tf.argmax(y2, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print('Accuracy: ', sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
tf.logging.set_verbosity(old_v)
该方法最终的准确率约为80%。此外可以通过调整隐层神经元的个数、w和b的初始值、激活函数、学习率、每批训练样本的个数、训练的迭代次数等尝试提高准确率。