MNIST数据集介绍
MNIST数据集是一个手写体数据集,它来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST)。训练集 (training set) 由来自 250 个不同人手写的数字构成,其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员。 测试集(test set) 也是同样比例的手写数字数据。该数据集包含60,000个用于训练的示例和10,000个用于测试的示例。这些数字已经过尺寸标准化并位于图像中心,图像是固定大小(28x28像素),其值为0到1。为简单起见,每个图像都被平展并转换为784(28 * 28)个特征的一维numpy数组。
MNIST数据集官网为:Link,官网提供下面4个文件的下载链接,分别为训练集图片、训练集图片对应标签(数字0-9)、测试集图片、测试集图片对应便签;我们发现文件的后缀名.gz,说明它们都是压缩文件。
- 训练集图片格式解析:
将上述文件下载到本机磁盘, 解压缩train-images-idx3-ubyte.gz文件并打开,拿到train-images.idx3-ubyte文件,下面来看以.idx3-ubyte结尾的文件是个什么东东,简单来说:idx3的数字表示数据维度,也就是图片为3维,这3个维度分别为:训练集每张图片长28个像素点,宽28个像素点,共60000张图片,故(
);ubyte表示每张图片以字节文件保存,我们知道MNIST数据集中每张图片中一个像素点为一通道,像素值为0到255。0表示背景(白色),255表示数字(黑色)。打开文件,格式如下:
官网数据描述如下:
这里我们取第一行:0000 0803 0000 ea60 0000 001c 0000 001c
其中 0000 0803 为该文件的前4个字节,表示文件的magic number(魔数),大概就是确定数据类型的一个标志,是随便设定的,知乎有个回答关于魔数,讲的比较好Link;随后4个字节 0000 ea60 ,对应10进制为60000,表示含有60000张数字图片;再随后4个字节 0000 001c ,对应10进制为28;再随后4个字节 0000 001c 同理对应10进制为28,表示每张图片共有28*28个像素点。再随后1个字节 0000 表示第一张图片第1个像素点值为0 ,001c 表示第一张图片第2个像素点值为24,如此下去,知道最后一张图片的最后一个像素点。
- 训练集图片对应便签格式解析:
解压缩train-labels-idx1-ubyte.gz文件并打开,拿到train-labels.idx1-ubyte文件,idx1的表示该便签数据集的数据维度为1,打开文件格式如下:
官网类别数据集描述如下:
拿第一行来说:0000 0801 0000 ea60 0500 0401 0902 0103
简单来说,该文件前4个字节 0000 0801 表示魔数,而随后4个字节 0000 ea60 表示含有的标签数量,对应10进制为60000,即含有60000个标签,随后每1个字节表示标签,05->数字5、00->数字0、04->数字4......,如此下去直到最后一个标签。
测试集图片与测试集图片对应便签数据格式同理。
读取mnist数据集并保存成图片
import os
import cv2
import numpy as np
"""
参数rb表示“以只读+二进制形式打开文件"
"""
image_dataset = open("D:/download/MNIST/t10k-images-idx3-ubyte/t10k-images.idx3-ubyte", "rb")
bytes = image_dataset.read(4)
"""
int.from_bytes()方法表示将字节数组转换成int数字
byteorder='big表示最有效的字节在字节数组的开头
"""
image_magic_number = int.from_bytes(bytes, byteorder='big', signed=False)
#image_num:文件中包含数字图片的数量
image_num = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
#image_row:单张图片包含像素点的行数
image_row = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
#image_col:单张图片包含像素点的列数
image_col = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
if not os.path.exists("D:/download/MNIST/t10k-images-idx3-ubyte/images_dir"):
os.makedirs("D:/download/MNIST/t10k-images-idx3-ubyte/images_dir")
images_dir = "D:/download/MNIST/t10k-images-idx3-ubyte/images_dir"
for i in range(image_num):
#用来保存一张图片的所有的像素点
image = []
for j in range(image_row * image_col):
#一个字节表示一个像素点
image.append(int.from_bytes(image_dataset.read(1), byteorder='big', signed=False))
#将一张图片的像素点转换成28*28的形式
image = np.array(image, dtype=np.uint8).reshape((image_row, image_col))
image_path = images_dir + "/" + str(i)+ ".jpg"
"""
千万注意路径中不能含有中文
"""
cv2.imwrite(image_path, image)
生成的图片如下:
基于Tensorflow实现逻辑回归
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
if __name__ == "__main__":
# one_hot=True是将28*28的图片展开成张量的形式
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
# 设置每个批次的大小
batch_size = 100
# 计算一个有多少个批次
num_batch = mnist.train.num_examples // batch_size
# 定义1个placehold
x = tf.placeholder(tf.float32, [None, None])
y = tf.placeholder(tf.float32, [None, None])
# 创建一个简单的神经网络
w = tf.Variable(tf.truncated_normal([784,100],stddev=0.1))
b = tf.Variable(tf.zeros([1, 100]))
# now_result--->1*10
now_result = tf.nn.relu(tf.matmul(x,w)+b)
now_result_droup = tf.nn.dropout(now_result,keep_prob=0.9)
# now_result = tf.nn.tanh(tf.matmul(x,w)+b)
'''
为了改进识别准确率,这里再添加一个隐含层
'''
h_w = tf.Variable(tf.truncated_normal([100,10],stddev=0.1))
h_b = tf.Variable(tf.zeros([1,10]))
prediction = tf.matmul(now_result_droup, h_w) + h_b
# 二次代价损失函数tf.square---->相当于对向量做2范数操作
"""
这里使用交叉熵损失函数,二次代价损失函数会出现离得距离比较远但是梯度却很小的问题
"""
# lossf = tf.reduce_mean(tf.square(y - prediction))
loss_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction,labels=y))
# 使用梯度下降算法
trai_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss_entropy)
# 结果存放在一个布尔型列表中
correct_prediction = tf.equal(tf.argmax(input=y, axis=1), tf.argmax(input=prediction, axis=1))
# print(correct_prediction)
# 求准确率--->tf.cast()函数的作用是执行 tensorflow 中张量数据类型转换
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 初始化变量
init = tf.global_variables_initializer()
# 开始创建会话执行代码
with tf.Session() as sess:
# 初始化变量
sess.run(init)
# 迭代21次
for epoch in range(21):
# 遍历每个批次
for batch in range(num_batch):
# 取出没一个批次的数据,分开取 batch_x->[100,768] batch_y->[100,10]
batch_x, batch_y = mnist.train.next_batch(batch_size)
sess.run(trai_step, feed_dict={x: batch_x, y: batch_y})
# 模型已经训练好了,用test集进行测试
acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
print("迭代次数:" + str(epoch) + " 测试集准确率:" + str(acc * 100) + "%")
结果如下: