【转】机器学习教程 十四-利用tensorflow做手写数字识别


模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基于tensorflow来介绍和演示

请尊重原创,转载请注明来源网站www.shareditor.com以及原始链接地址

什么是tensorflow

tensor意思是张量,flow是流。

张量原本是力学里的术语,表示弹性介质中各点应力状态。在数学中,张量表示的是一种广义的“数量”,0阶张量就是标量(比如:0、1、2……),1阶张量就是向量(比如:(1,3,4)),2阶张量就是矩阵,本来这几种形式是不相关的,但是都归为张量,是因为他们同时满足一些特性:1)可以用坐标系表示;2)在坐标变换中遵守同样的变换法则;3)有着相同的基本运算(如:加、减、乘、除、缩放、点积、对称……)

那么tensorflow可以理解为通过“流”的形式来处理张量的一种框架,是由google开发并开源,已经应用于google大脑项目开发

tensorflow安装

sudo pip install https://storage.googleapis.com/tensorflow/mac/tensorflow-0.9.0-py2-none-any.whl
 

不同平台找对应的whl包

可能遇到的问题:

发现无法import tensorflow,问题在于protobuf版本不对,必须先卸载掉,再安装tensorflow,这样会自动安装3.0版本的protobuf

sudo pip uninstall protobuf
sudo brew remove protobuf260
sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.9.0-py2-none-any.whl
 

手写数字数据集获取

http://yann.lecun.com/exdb/mnist/可以下载手写数据集,http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz和http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz,下载解压后发现不是图片格式,而是自己特定的格式,为了说明这是什么样的数据,我写了一段程序来显示这些数字:

/************************
 * author: SharEDITor
 * date:   2016-08-02
 * brief:  read MNIST data
 ************************/
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

unsigned char *lables = NULL;

/**
 * All the integers in the files are stored in the MSB first (high endian) format
 */
void copy_int(uint32_t *target, unsigned char *src)
{
    *(((unsigned char*)target)+0) = src[3];
    *(((unsigned char*)target)+1) = src[2];
    *(((unsigned char*)target)+2) = src[1];
    *(((unsigned char*)target)+3) = src[0];
}

int read_lables()
{
    FILE *fp = fopen("./train-labels-idx1-ubyte", "r");
    if (NULL == fp)
    {
        return -1;
    }
    unsigned char head[8];
    fread(head, sizeof(unsigned char), 8, fp);
    uint32_t magic_number = 0;
    uint32_t item_num = 0;
    copy_int(&magic_number, &head[0]);
    // magic number check
    assert(magic_number == 2049);
    copy_int(&item_num, &head[4]);

    uint64_t values_size = sizeof(unsigned char) * item_num;
    lables = (unsigned char*)malloc(values_size);
    fread(lables, sizeof(unsigned char), values_size, fp);

    fclose(fp);
    return 0;
}

int read_images()
{
    FILE *fp = fopen("./train-images-idx3-ubyte", "r");
    if (NULL == fp)
    {
        return -1;
    }
    unsigned char head[16];
    fread(head, sizeof(unsigned char), 16, fp);
    uint32_t magic_number = 0;
    uint32_t images_num = 0;
    uint32_t rows = 0;
    uint32_t cols = 0;
    copy_int(&magic_number, &head[0]);
    // magic number check
    assert(magic_number == 2051);
    copy_int(&images_num, &head[4]);
    copy_int(&rows, &head[8]);
    copy_int(&cols, &head[12]);

    uint64_t image_size = rows * cols;
    uint64_t values_size = sizeof(unsigned char) * images_num * rows * cols;
    unsigned char *values = (unsigned char*)malloc(values_size);
    fread(values, sizeof(unsigned char), values_size, fp);

    for (int image_index = 0; image_index < images_num; image_index++)
    {
        // print the label
        printf("=========================================  %d  ======================================\n", lables[image_index]);
        for (int row_index = 0; row_index < rows; row_index++)
        {
            for (int col_index = 0; col_index < cols; col_index++)
            {
                // print the pixels of image
                printf("%3d", values[image_index*image_size+row_index*cols+col_index]);
            }
            printf("\n");
        }
        printf("\n");
    }

    free(values);
    fclose(fp);
    return 0;
}

int main(int argc, char *argv[])
{
    if (-1 == read_lables())
    {
        return -1;
    }
    if (-1 == read_images())
    {
        return -1;
    }
    return 0;
}

下载并解压出数据集文件train-images-idx3-ubyte和train-labels-idx1-ubyte放到源代码所在目录后,编译并执行:

gcc -o read_images read_images.c
./read_images
 

展示出来的效果如下:

一共有60000个图片,从代码可以看出数据集里存储的实际就是图片的像素

softmax模型

我们在《机器学习教程 十三-用scikit-learn做逻辑回归》中介绍了逻辑回归模型。逻辑回归是用于解决二类分类问题(使用sigmoid函数),而softmax模型是逻辑回归模型的扩展,用来解决多类分类问题。

softmax意为柔和的最大值,也就是如果某个zj大于其他z,那么这个映射的分量就逼近于1,其他的分量就逼近于0,从而将其归为此分类,多个分量对应的就是多分类,数学形式和sigmoid不同,如下:

它的特点是,所有的softmax加和为1,其实它表示的是一种概率,即x属于某个分类的概率。

在做样本训练时,这里的xi计算方法是:

其中W是样本特征的权重,xj是样本的特征值,bi是偏置量。

详细来说就是:假设某个模型训练中我们设计两个特征,他们的值分别是f1和f2,他们对于第i类的权重分别是0.2和0.8,偏置量是1,那么

xi=f1*0.2+f2*0.8+1

如果所有的类别都计算出x的值,如果是一个训练好的模型,那么应该是所属的那个类别对应的softmax值最大

softmax回归算法也正是基于这个原理,通过大量样本来训练这里的W和b,从而用于分类的

tensorflow的优点

tensorflow会使用外部语言计算复杂运算来提高效率,但是不同语言之间的切换和不同计算资源之间的数据传输耗费很多资源,因此它使用图来描述一系列计算操作,然后一起传给外部计算,最后结果只传回一次,这样传输代价最低,计算效率最高

举个例子:

import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
 

这里的x不是一个实际的x,而是一个占位符,也就是一个描述,描述成了二维浮点型,后面需要用实际的值来填充,这就类似于printf("%d", 10)中的占位符%d,其中第一维是None表示可无限扩张,第二维是784个浮点型变量

如果想定义可修改的张量,可以这样定义:

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
 

其中W的维度是[784, 10],b的形状是[10]

有了这三个变量,我们可以定义我们的softmax模型:

y = tf.nn.softmax(tf.matmul(x,W) + b)

这虽然定义,但是没有真正的进行计算,因为这只是先用图来描述计算操作

其中matmul是矩阵乘法,因为x的维度是[None, 784],W的维度是[784, 10],所以矩阵乘法得出的是[None, 10],这样可以和向量b相加

softmax函数会计算出10维分量的概率值,也就是y的形状是[10]

数字识别模型实现

基于上面定义的x、W、b,和我们定义的模型:

y = tf.nn.softmax(tf.matmul(x,W) + b)

我们需要定义我们的目标函数,我们以交叉熵(衡量预测用于描述真相的低效性)为目标函数,让它达到最小:

其中y‘是实际分布,y是预测的分布,即:

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

利用梯度下降法优化上面定义的Variable:

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

其中0.01是学习速率,也就是每次对变量做多大的修正

按照上面的思路,最终实现的代码digital_recognition.py(放在文件夹MNIST_data的上一级目录下)如下:

# coding:utf-8

import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string(‘data_dir‘, ‘MNIST_data/‘, ‘Directory for storing data‘)

mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

x = tf.placeholder(tf.float32, [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.InteractiveSession()
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, tf.float32))
print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))

运行效果如下:

[[email protected] $] python digital_recognition.py
Extracting ./train-images-idx3-ubyte.gz
Extracting ./train-labels-idx1-ubyte.gz
Extracting ./t10k-images-idx3-ubyte.gz
Extracting ./t10k-labels-idx1-ubyte.gz
0.9039
 

解释一下

flags.DEFINE_string(‘data_dir‘, ‘MNIST_data/‘, ‘Directory for storing data‘)

表示我们用MNIST_data的上一级目录作为训练数据的存储目录,如果我们没有提前下好训练数据和测试数据,程序会自动帮我们下载到./

mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

这句直接用库里帮我们实现好的读取训练数据的方法,无需自行解析

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})
 

这几行表示我们循环1000次,每次从训练样本里选取100个样本来做训练,这样我们可以修改配置来观察运行速度

最后几行打印预测精度,当调整循环次数时可以发现总训练的样本数越多,精度就越高

原文链接:http://www.shareditor.com/blogshow/?blogId=94

时间: 2024-09-28 20:42:34

【转】机器学习教程 十四-利用tensorflow做手写数字识别的相关文章

用pytorch做手写数字识别,识别l率达97.8%

pytorch做手写数字识别 效果如下: 工程目录如下 第一步  数据获取 下载MNIST库,这个库在网上,执行下面代码自动下载到当前data文件夹下 from torchvision.datasets import MNIST import torchvision mnist = MNIST(root='./data',train=True,download=True) print(mnist) print(mnist[0]) print(len(mnist)) img = mnist[0][

Tensorflow实战 手写数字识别(Tensorboard可视化)

一.前言 为了更好的理解Neural Network,本文使用Tensorflow实现一个最简单的神经网络,然后使用MNIST数据集进行测试.同时使用Tensorboard对训练过程进行可视化,算是打响学习Tensorflow的第一枪啦. 看本文之前,希望你已经具备机器学习和深度学习基础. 机器学习基础可以看我的系列博文: https://cuijiahua.com/blog/ml/ 深度学习基础可以看吴恩达老师的公开课: http://mooc.study.163.com/smartSpec/

中国mooc北京理工大学机器学习第二周(三):手写数字识别

利用sklearn中的神经网络进行数字识别. 先简单搬运占坑,暂时用不到. import numpy as np #导入numpy工具包 from os import listdir #使用listdir模块,用于访问本地文件 from sklearn.neural_network import MLPClassifier def img2vector(fileName): retMat = np.zeros([1024],int) #定义返回的矩阵,大小为1*1024 fr = open(fi

【机器学习】k-近邻算法应用之手写数字识别

上篇文章简要介绍了k-近邻算法的算法原理以及一个简单的例子,今天再向大家介绍一个简单的应用,因为使用的原理大体差不多,就没有没有过多的解释. 为了具有说明性,把手写数字的图像转换为txt文件,如下图所示(三个图分别为5.6.8): 要使用k-近邻算法,需要有足够的样本数据和测试数据,我放到了两个文件夹里(trainingDigits和testDigits),可以在这里(http://pan.baidu.com/s/1i3osO7N)下载使用 这里,每个数字有32X32个0或1,可以认为是一个维度

第三节,TensorFlow 使用CNN实现手写数字识别

上一节,我们已经讲解了使用全连接网络实现手写数字识别,其正确率大概能达到98%,着一节我们使用卷积神经网络来实现手写数字识别, 其准确率可以超过99%,程序主要包括以下几块内容 [1]: 导入数据,即测试集和验证集 [2]: 引入 tensorflow 启动InteractiveSession(比session更灵活) [3]: 定义两个初始化w和b的函数,方便后续操作 [4]: 定义卷积和池化函数,这里卷积采用padding,使得 输入输出图像一样大,池化采取2x2,那么就是4格变一格 [5]

手写数字识别——利用keras高层API快速搭建并优化网络模型

在<手写数字识别——手动搭建全连接层>一文中,我们通过机器学习的基本公式构建出了一个网络模型,其实现过程毫无疑问是过于复杂了——不得不考虑诸如数据类型匹配.梯度计算.准确度的统计等问题,但是这样的实践对机器学习的理解是大有裨益的.在大多数情况下,我们还是希望能多简单就多简单地去搭建网络模型,这同时也算对得起TensorFlow这个强大的工具了.本节,还是以手写数据集MNIST为例,利用TensorFlow2.0的keras高层API重现之前的网络. 一.数据的导入与预处理 关于这个过程,与上节

手把手教你搭建caffe及手写数字识别(全程命令提示、纯小白教程)

手把手教你搭建caffe及手写数字识别 作者:七月在线课程助教团队,骁哲.小蔡.李伟.July时间:二零一六年十一月九日交流:深度学习实战交流Q群 472899334,有问题可以加此群共同交流.另探究实验背后原理,请参看此课程:11月深度学习班. 一.前言 在前面的教程中,我们搭建了tensorflow.torch,教程发布后,大家的问题少了非常多.但另一大框架caffe的问题则也不少,加之caffe也是11月深度学习班要讲的三大框架之一,因此,我们再把caffe的搭建完整走一遍,手把手且全程命

机器学习(二)-kNN手写数字识别

一.kNN算法 1.kNN算法是机器学习的入门算法,其中不涉及训练,主要思想是计算待测点和参照点的距离,选取距离较近的参照点的类别作为待测点的的类别. 2,距离可以是欧式距离,夹角余弦距离等等. 3,k值不能选择太大或太小,k值含义,是最后选取距离最近的前k个参照点的类标,统计次数最多的记为待测点类标. 4,欧式距离公式: 二.关于kNN实现手写数字识别 1,手写数字训练集测试集的数据格式,本篇文章说明的是<机器学习实战>书提供的文件,将所有数字已经转化成32*32灰度矩阵. 三.代码结构构成

利用手写数字识别项目详细描述BP深度神经网络的权重学习

本篇文章是针对学习<深度学习入门>(由日本学者斋藤康毅所著陆羽杰所译)中关于神经网络的学习一章来总结归纳一些收获. 本书提出神经网络的学习分四步:1.mini-batch 2.计算梯度 3.更新参数 4.重复前面步骤 1.从识别手写数字项目学习神经网络 所谓“从数据中学习”是指 可以由数据#自动决定权重#.当解决较为简单的问题,使用简单的神经网络时,网络里的权重可以人为的手动设置,去提取输入信息中特定的特征.但是在实际的神经网络中,参数往往是成千上万,甚至可能上亿的权重,这个时候人为手动设置是