MINIS手写体识别相当于机器学习中的Hello world,作为深度学习领域的入门任务是初学者的首选。
1. MINIST数据集
MINIST数据集是一个图片压缩包,包含大量手写数字图片;
其中一个数据样本有两部分构成:手写图片和label;
数据集每个样本都是(1,784)维度的图片,为了方便展示就像下图一样画成二维矩阵,实际上后面要将向量转换为28*28的二维矩阵;
2. 读取数据
TensorFlow为了教学MNIST而提前编制了程序,所以只需两行代码就可自动下载数据集文件
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# 从MNIST_data/中读取MNIST数据,这条语句在数据不存在时,会自动执行下载
3. 打印数据集基本信息
数据集可分为:
训练集 | 测试集 | 验证集 |
---|---|---|
minist.train | minist.test | minist.validation |
55,000 | 10,000 | 5,000 |
训练模型 | 多次使用调参 | 评估模型 |
1. 创建文件夹保存原始图片
save_dir = 'MNIST_data/raw/'
if os.path.exists(save_dir) is False: # 判断save_dir文件是否存在
os.makedirs(save_dir) # os.makedirs()方法用于递归创建目录
2. reshape图片
# 注意:mnist.train.images[i, :]就表示第i张图片(序号从0开始)
image_array = mnist.train.images[i, :]
# TensorFlow中的MNIST图片是一个784维的向量,我们重新把它还原为28x28维的图像
image_array = image_array.reshape(28, 28)
3. 文件命名
# 保存文件的格式为 mnist_train_0.jpg, mnist_train_1.jpg, ... ,mnist_train_19.jpg
filename = save_dir + 'mnist_train_%d.jpg' % i
4.转换为图片存储
# 将image_array保存为图片:array - > image
#scipy.misc.toimage(image_array, cmin=0.0, cmax=1.0).save(filename)
# AttributeError: module 'scipy.misc' has no attribute 'toimage'
Image.fromarray((image_array * 255).astype('uint8'), mode='L').convert('RGB').save(filename)
1. 独热编码
one - hot读热编码是一种稀疏向量,其中:一个向量设为1,其他元素均设为0;独热编码常用于表示拥有有限个可能值的字符串或标识符;
2. argmax(array, axis)
numpy.argmax(array, axis) 函数:
array是矩阵,axis是0或者1;axis默认为0
其中,0表示的是按行比较返回最大值的索引,1表示按列比较返回最大值的索引
eg: one_dim_array = np.array([1, 4, 5, 3, 7, 2, 6])
print(np.argmax(one_dim_array)) # 4
3. 打印label
MINIST数据集每个样本的label是(1*10)维的数组,采用独热编码表示,形如(0, 1, 0, 0, 0, 0, 0, 0, 0, 0)
# 看前20张训练图片的label
for i in range(20):
one_hot_label = mnist.train.labels[i, :]
# 通过np.argmax我们可以直接获得原始的label
label = np.argmax(one_hot_label)
print(f'mnist_train_{i}.jpg label: {label}')
# mnist_train_18.jpg label: 6
1. Softmax回归模型
Softmax回归是一个线性的多类分类模型,我们期望对输入的图片计算出它属于某个类别的概率,比如90%的概率是2,5%的概率是5,那么最终会输出这张图片的标签为5;因此,一张图片对于每一个数字的吻合度可以被softmax函数转换成为一个概率值。softmax函数可以定义为:
由下图所示,对于输入Xi加权求和,再分别加上一个偏置量,最后输入到Softmax函数中:
其矩阵表现形式如下:
下面举一个例子理解:
假设我们现在需要预估房价。输出y是房子价格,输入Xi就是多种影响因素,可能是大小,距离,教育资源等等,类比MINIST问题就是输入图片的像素值;W为各影响因素的权,b为偏移量;
2. 设置占位符
x = tf.placeholder(tf.float32, [None, 784])
# 用于得到传递进来的待识别的训练图片
W = tf.Variable(tf.zeros([784, 10]))
# 相当于一层神经网络上的参数
b = tf.Variable(tf.zeros([10]))
# 偏置向量
2. 预测函数
y是模型的输出,y_是实际的图像标签,用one-hot表示
# y=softmax(Wx + b),y表示模型的输出
y = tf.nn.softmax(tf.matmul(x, W) + b)
# tf.matmual()表示两个矩阵相乘
# y_是实际的图像标签,同样以占位符表示
y_ = tf.placeholder(tf.float32, [None, 10])
3. 损失函数
根据y和y_来构造交叉熵损失函数
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y)))
4. 梯度下降
使用梯度下降的方式去迭代使得损失函数达到最小;
GradientDescentOptimizer(0.01)是梯度下降的封装函数,设置0.01的初始学习速率;
minimize(cross_entropy)表示最小化损失函数;
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
5. 定义会话Session
上面所有的步骤只是定义了一个框架,Tensorflow中要求所有的数据计算都要在定义的会话中进行;
with tf.Session() as sess:
tf.global_variables_initializer().run()
# 初始化所有变量
for _ in range(1000):
# 迭代1000次
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) # feed_dict给使用placeholder创建出来的tensor赋值
6. 查看准确率
equal()函数:逐元素比较是否相等,返回结一个比较结果(Ture/False)
reduce_mean()函数:计算张量的各个维度上的元素的平均值
cast()函数:张量数据类型转换,将布尔型转换为float32
例如:
[True,False,True,True]可以用[1,0,1,1]表示,精度 为0.75
0.75 = 3/4
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
# 用测试集的数据去得到准确率
github源代码