MNIST分类入门实现代码
实现了数据的读入,并且对读入的数据进行观察的实现的代码如下:
读入MNIST数据并观察
解决方案:
tensorflow_core
就能找到这些文件了。TF2.0解决MNIST手写数据问题的博客
import tensorflow as tf
from tensorflow_core.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot = True)
mnist_not_one_hot = input_data.read_data_sets("MNIST_data/", one_hot = False)
read_data_sets()
函数是MNIST中自带的用来读取数据的函数,这里面可以研究的东西很多,暂时是从功能角度记住它能从MNIST数据中读取数据就行。"MNIST_data/"
这个是用来存放下载的数据的相对路径,下载好后的这个文件会被放到工程文件的根目录下。one_hot
这个参数用来选着标签数据是否用独热编码来表示。print('train images shape:', mnist.train.images.shape,
',labels shape', mnist.train.labels.shape)
print('validation images shape:', mnist.validation.images.shape,
',labels shape', mnist.validation.labels.shape)
print('test images shape:', mnist.test.images.shape,
',labels shape', mnist.test.labels.shape)
print(len(mnist.train.images[0]))
print(mnist.train.images[0].shape)
print(mnist.train.labels[0])
print(mnist.train.images[0].reshape(28, 28))
# 可视化
def plot_image(image):
plt.imshow(image.reshape(14, 56), cmap='binary')
plt.show()
plot_image(mnist.train.images[20000])
reshape()函数
这个函数会以行优先,先把一行的数据排满后然后再往下接数据去排。在它需要输入的两个参数中,左边的那个参数代表行数,右边的那个参数代表列数。plt.imshow()函数
这个函数用来实现图片的可视化,它的功能很强大,需要载入的参数有图形矩阵(可以控制形状),以及色彩的搭配方案。print(np.argmax(mnist.train.labels[0]))
np.argmax()函数
这个函数可以取当前列表中最大项的索引,对当前数字的10分类问题来说,可以实现把独热码转换成它的实际意义的数字。print(mnist.train.labels[0:10])
batch_images_xs, batch_labels_ys = \
mnist.train.next_batch(batch_size=10)
print(batch_images_xs)
print(batch_labels_ys)
next_batch()
会返回两个值,一个是x维度的n维数组,另一个是y维度的n维数组;并且它有一个参数batch_size
用来控制每一批次读取的数据的数量。next_batch()
的话,在全部调用完毕之前,下一次调用会在紧接在上一次调用的地方往下继续调用。norm = tf.random_normal([100])
with tf.Session() as sess:
norm_data = norm.eval()
print(norm_data[:10])
plt.hist(norm_data)
plt.show()
# 占位符的定义
x = tf.placeholder(tf.float32, [None, 784], name="images")
y = tf.placeholder(tf.float32, [None, 10], name="labels")
# 定义变量
w = tf.Variable(tf.random_normal([784,10]),name="weight")
b = tf.Variable(tf.zeros([10]),name="b")
# 此处参数带的10,可以让y的结果是一个shape为[1,10]的行向量,正好对应10分类。
# 定义前向计算
forward = tf.matmul(x, w) + b # 前向计算
# 进行结果分类
pred = tf.nn.softmax(forward) # 使用S型函数进行Softmax分类
# 损失函数的选择
loss_fuction = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),
reduction_indices=1)) # 交叉熵 / 对数损失函数
w矩阵
和b矩阵
,其中,先说w矩阵
这个矩阵最后需要和输入的每一个x向量相乘,而输入的x向量的形状是[1,784],而要满足矩阵的叉乘运算的规则,这就要求w矩阵的行数也为784,又因为本次问题是10分类的问题,最后我们表示标签的方法是用独热码的形式来表示,所以需要最后得到的结果是一个形状为[1,10]的行向量,所以w矩阵的形状需要被确定为[784,10],这里使用的是tf.random_normal()
对矩阵进行数据的初始化。tf.zeros([10])
这个函数实现的是对给定形状的n维数组赋0的初值。交叉熵损失和对数损失之间的关系
交叉熵中未知真实分布\large p(x)相当于对数损失中的真实标记\large y,寻找的近似分布\large q(x)相当于我们的预测值。如果把所有样本取均值就把交叉熵转化成了对数损失函数。
在该模型中我们本质上使用的是对数损失函数,而之所以提出交叉熵损失函数的原因是对数损失函数是交叉熵损失函数把所有样本取均值所得到的结果,所以用交叉熵的函数式来写,最后再取所有样本的均值就可以实现对数损失函数。这样来构造函数会比较方便。
loss_fuction = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred), reduction_indices=1)) # 交叉熵 / 对数损失函数
reduction_indices=1
表示按行来计算,简单说就是求总和是取一整行的数据求一次总和。
reduction_indices的用法
# 超参数的定义
learning_rate = 0.01 # 学习率
train_epoches = 50 # 训练的轮数
batch_size = 100 # 单次训练的样本数(批次大小)
display_step = 1 # 显示的粒度
total_batch = int(mnist.train.images.shape[0]/batch_size)
# 优化器的选择,此处依然使用梯度下降优化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_fuction)
# 定义准确率(用于验证集验证情况的反馈)
# 检查预测的类别与实际类别的匹配情况
correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
# 准确率,将布尔值转化为浮点数,并计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 声明会话
sess = tf.Session()
init = tf.global_variables_initializer() # 全变量初始化
sess.run(init)
all_loss = []
all_accuracy = []
# 训练模型
for epoch in range(train_epoches):
for batch in range(total_batch):
xs, ys = mnist.train.next_batch(batch_size) # 读取批次的数据
sess.run(optimizer,feed_dict={x: xs, y: ys}) # 执行批次训练
# 所有的批次完成之后,使用验证数据集来计算误差和准确率; 验证集没有进行分批而是一次型传入
loss, acc = sess.run([loss_fuction, accuracy],
feed_dict={x: mnist.validation.images,y: mnist.validation.labels})
all_loss.append(loss)
all_accuracy.append(acc)
# 打印训练过程中的详细信息(损失值和准确率)
if (epoch+1) % display_step == 0:
print("Train Epoch:", "%02d" % (epoch+1), "Loss=", "{:.9f}".format(loss),\
"Accuracy=", "{:.4f}".format(acc))
print("Train Finished")
# 损失值和准确值的可视化
plt.plot(all_loss, label="loss")
plt.plot(all_accuracy, label="accuracy")
plt.legend(loc=2)
依然选择梯度下降优化器。
tf.equal()
实现的是逐个比较(一一对应)两个输入源的值,如果相同的话,就返回True,如果不相同的话,就返回False。tf.equal()
next_batch()函数
# 损失值和准确值的可视化
plt.plot(all_loss, label="loss")
plt.plot(all_accuracy, label="accuracy")
plt.legend(loc=2)
# 评估模型
# 测试集
accu_test = sess.run(accuracy,
feed_dict={x: mnist.test.images, y: mnist.test.labels})
print("Test Accuracy: ", accu_test)
# 验证集
accu_validation = sess.run(accuracy,
feed_dict={x: mnist.validation.images, y: mnist.validation.labels})
print("Validation Accuracy: ", accu_validation)
# 训练集
accu_train = sess.run(accuracy,
feed_dict={x: mnist.train.images, y: mnist.train.labels})
print("Train Accuracy: ", accu_train)
plt.show()
# 在建立模型并进行训练后,若认为准确率可以接受,则可以使用此模型进行预测
# 模型应用与可视化
# 由于pred的预测结果是one-hot编码格式,所以需要转换为0~9数字
prediction_result = sess.run(tf.argmax(pred, 1),
feed_dict={x: mnist.test.images})
print(prediction_result[0:10])
# 定义可视化函数
def plot_images_labels_prediction(images, # 图像的列表
labels, # 标签的列表
prediction, # 预测值的列表
index, # 从第index个下标开始显示
num=10): # 默认一次显示10幅
# 获取图表,并设置尺寸。
fig = plt.gcf() # 获取当前的图表,Get Current Figure
fig.set_size_inches(10, 12) # 1英寸等于2.54cm
# 控制展示的峰值
if num > 25:
num = 25
# 处理每一个要展示的子图
for i in range(0, num):
ax = plt.subplot(5, 5, i+1) # 获取当前要处理的子图
ax.imshow(np.reshape(images[index], (28, 28)), # 显示第index个图像
cmap="binary")
title = "label=" + str(np.argmax(labels[index])) # 构建图上要显示的title信息
if len(prediction) > 0: # 如果有预测信息的话
title += ",predict=" + str(prediction[index])
ax.set_title(title,fontsize=10) # 显示图上的title信息
ax.set_xticks([])
ax.set_yticks([])
index += 1
plt.show()
print("_________________________________分割线_____________________________________")
plot_images_labels_prediction(
mnist.test.images,
mnist.test.labels,
prediction_result, 10, 10)
print("_________________________________分割线_____________________________________")
plot_images_labels_prediction(
mnist.test.images,
mnist.test.labels,
prediction_result, 10, 25)
这一部分是我自己加上去的内容,关键是想看看损失值和准确值的变化趋势。
使用subplot绘制子图的一些特点
fontsize
控制字体大小的参数。set_xticks()
python_matplotlib改变横坐标和纵坐标上的刻度(ticks)
主要参考资料:
深度学习应用开发-TensorFlow实践----吴明晖 、李卓蓉 、金苍宏