MNIST机器学习入门——Tensorflow手写字识别_机器学习

MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片0,1,2。。。9:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_02

它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。

MNIST数据集

机器学习模型旨在根据以前未见过的新数据做出良好预测。但是,如果您要根据数据集构建模型,如何获得以前未见过的数据呢?一种方法是将您的数据集分成两个子集:

  • 训练集 - 用于训练模型的子集。

  • 测试集 - 用于测试模型的子集。

MNIST数据集包含:60000行的训练数据集(mnist.train)和10000行的测试数据集(mnist.test)。训练数据集和测试数据集都包含有一张手写的数字,和对应的标签,比如训练数据集的图片是 mnist.train.images ,训练数据集的标签是 mnist.train.labels。。

每一张图片都是28*28像素,可以用点矩阵来表示每张图片。下面左图表示数字“1”图片,右图表示其对应的数字矩阵。

MNIST机器学习入门——Tensorflow手写字识别_机器学习_03

为了方便起见,需要把这个二维数组展开为一个一维的28*28=784的向量。怎么展开无所谓,只要所有图片展开方式都一样即可。虽然展开后丢失了图片的二维结构信息,但是由于这里使用的也是简单的softmax回归模型,不会利用这些结构信息。

MNIST训练数据集,mnist.train.images是一个[60000*784]的张量,行用来索引图片,每一行数据表示对应图片展开后的784个像素点,值0或者1.

MNIST机器学习入门——Tensorflow手写字识别_机器学习_04

MNIST训练数据集的标签是对应的数字,每一行是一个one-hot向量,取值为1的下标索引即为对应的数字,[0,0,1,0,0,0,0,0,0,0],表示这张数字图片写的是"2",mnist.train.labels是一个[60000,10]的数字矩阵张量。

MNIST机器学习入门——Tensorflow手写字识别_机器学习_05

用softmax回归来分析问题

softmax回归主要是计算对应标签取值的概率,这里标签有10个值,需要用模型训练出图片对应每个数字的概率,比如写的是6的图片判定为6的概率是80%,判定为8的概率为10%,因为6和8它们的下半部分相似。也就是说,对于特定一张图片每个像素点,对于每一个标签的取值都会有一个概率Wij,i表示标签取值为i(0,1,2...,9),j表示像素点,取值(0,1,2,...,784)。

第一步

一张图片有784个像素点,我们对784个像素点进行加权求和。权值正负表示属于每个标签的证据是否有利。

下面的图片显示了一个模型学习到的图片上每个像素对于特定数字类的权值。红色代表负数权值,蓝色代表正数权值。

MNIST机器学习入门——Tensorflow手写字识别_机器学习_06

比如”0“的周围,蓝色部分像素点就会为0提供有利证据,而0这个图片红色部分几乎没有像素点,加权求和,自然为0的概率最大。

对于给定的图片x,代表数字i的证据表示为:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_07

Wij表示第j个像素点对于数字i的权重,Xj表示图片X的第j个像素点,bi表示偏置量。

使用softmax函数将这个值转换为概率y:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_08

这里的softmax可以看成是一个激励(activation)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布。

softmax回归模型可以表示为:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_09

比如对于y1标签来说,就是x1w11+x2w12+x3w12+...+xjw1j,j = 1,2,...784。与前面的“Wij,i表示标签取值为i(0,1,2...,9),j表示像素点,取值(0,1,2,...,784)”一致。

这里用矩阵乘法与向量加法来表示为:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_10

这里1,2,3假设只有3个像素点,其实我们可以推广到784个像素点。

写成数学表达式:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_11

实现回归模型

为了用python实现高效的数值计算,我们通常会使用函数库,比如NumPy,会把类似矩阵乘法这样的复杂运算使用其他外部语言实现。不幸的是,从外部计算切换回Python的每一个操作,仍然是一个很大的开销。TensorFlow也把复杂的计算放在python之外完成,但是为了避免前面说的那些开销,它做了进一步完善。Tensorflow不单独地运行单一的复杂计算,而是让我们可以先用图描述一系列可交互的计算操作,然后全部一起在Python之外运行。

初始化w,x,b

import tensorflow as tf
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

x:不是一个特定的值,而是一个占位符placeholder,我们在TensorFlow运行计算时输入这个值。我们希望能够输入任意数量的MNIST图像,x可以表示输入50张图片,也可以表示输入100张图片,而每张图片都是784维,所以列数为784。

w和b:我们赋予tf.Variable不同的初值来创建不同的Variable:在这里,我们都用全为零的张量来初始化W和b。因为我们要学习W和b的值,它们的初值可以随意设置。w是权重,一个标签对于784个点总共有784个权重,一共有0,1,2。。。9这样10个数字,所以有10列。

训练模型

我们希望我们训练出来的模型,总的误差最小。在机器学习中国,我们通常定义指标来表示一个模型是坏的,这个指标称为成本(cost)或损失(loss),然后尽量最小化这个指标。这里用交叉熵,定义为:

MNIST机器学习入门——Tensorflow手写字识别_机器学习_12

y 是我们预测的概率分布, y' 是实际的分布。更多关于交叉熵的理解可以参考信息论。

为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:

y_ = tf.placeholder("float", [None,10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))

在这里,我们要求TensorFlow用梯度下降算法(gradient descent algorithm)以0.01的学习速率最小化交叉熵。

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

评估我们的模型

计算所学习到的模型在测试数据集上面的正确率。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

这个最终结果值应该大约是91%。

这个结果好吗?嗯,并不太好。事实上,这个结果是很差的。这是因为我们仅仅使用了一个非常简单的模型。

完整代码

数据及代码目录结构(通过cmd的tree -F 命令):

 1D:\我的文件\Codes\PyCode\tensorflow>tree . /F
 2
 3D:\我的文件\CODES\PYCODE\TENSORFLOW
 4│  hello_world.py
 5│  input_data.py
 6│  test.py
 7│
 8└─MNIST_data
 9        t10k-images-idx3-ubyte.gz
10        t10k-labels-idx1-ubyte.gz
11        train-images-idx3-ubyte.gz
12        train-labels-idx1-ubyte.gz

input_data.py

"""Functions for downloading and reading MNIST data."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import gzip
import os
import tempfile

import numpy
from six.moves import urllib
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets

hello_word.py

import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

import tensorflow as tf


def run():
    x = tf.placeholder("float", [None, 784])
    W = tf.Variable(tf.zeros([784,10]))
    b = tf.Variable(tf.zeros([10]))
    y = tf.nn.softmax(tf.matmul(x,W) + b)
    y_ = tf.placeholder("float", [None,10])
    cross_entropy = -tf.reduce_sum(y_*tf.log(y))
    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
    init = tf.initialize_all_variables()
    sess = tf.Session()
    sess.run(init)
    for i in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

    correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

if __name__ == '__main__':
    run()

执行命令:

python3 hello_world.py

使用训练数据集学习的模型在测试数据集上面的正确率为0.9119。

代码的github地址:https://github.com/ddxygq/PyCode/tree/master/tensorflow

猜你可能喜欢

MNIST机器学习入门——Tensorflow手写字识别_机器学习_13