模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下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个图片,从代码可以看出数据集里存储的实际就是图片的像素

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

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如下:

# 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', './', '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}))

运行效果如下:

[root@mymac $] 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', './', 'Directory for storing 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个样本来做训练,这样我们可以修改配置来观察运行速度

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

利用Tensorflow实现手写字符识别的更多相关文章

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

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

  2. 利用TensorFlow识别手写的数字---基于Softmax回归

    1 MNIST数据集 MNIST数据集主要由一些手写数字的图片和相应的标签组成,图片一共有10类,分别对应从0-9,共10个阿拉伯数字.原始的MNIST数据库一共包含下面4个文件,见下表. 训练图像一 ...

  3. 利用TensorFlow识别手写的数字---基于两层卷积网络

    1 为什么使用卷积神经网络 Softmax回归是一个比较简单的模型,预测的准确率在91%左右,而使用卷积神经网络将预测的准确率提高到99%. 2 卷积网络的流程 3 代码展示 # -*- coding ...

  4. OpenCV+TensorFlow图片手写数字识别(附源码)

    初次接触TensorFlow,而手写数字训练识别是其最基本的入门教程,网上关于训练的教程很多,但是模型的测试大多都是官方提供的一些素材,能不能自己随便写一串数字让机器识别出来呢?纸上得来终觉浅,带着这 ...

  5. 仅用200个样本就能得到当前最佳结果:手写字符识别新模型TextCaps

    由于深度学习近期取得的进展,手写字符识别任务对一些主流语言来说已然不是什么难题了.但是对于一些训练样本较少的非主流语言来说,这仍是一个挑战性问题.为此,本文提出新模型TextCaps,它每类仅用200 ...

  6. TensorFlow 之 手写数字识别MNIST

    官方文档: MNIST For ML Beginners - https://www.tensorflow.org/get_started/mnist/beginners Deep MNIST for ...

  7. 利用SpringBoot+Logback手写一个简单的链路追踪

    目录 一.实现原理 二.代码实战 三.测试 最近线上排查问题时候,发现请求太多导致日志错综复杂,没办法把用户在一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简 ...

  8. 一文全解:利用谷歌深度学习框架Tensorflow识别手写数字图片(初学者篇)

    笔记整理者:王小草 笔记整理时间2017年2月24日 原文地址 http://blog.csdn.net/sinat_33761963/article/details/56837466?fps=1&a ...

  9. 【Keras篇】---Keras初始,两种模型构造方法,利用keras实现手写数字体识别

    一.前述 Keras 适合快速体验 ,keras的设计是把大量内部运算都隐藏了,用户始终可以用theano或tensorflow的语句来写扩展功能并和keras结合使用. 二.安装 Pip insta ...

随机推荐

  1. SPOJ 10628 Count on a tree (lca+主席树)

    题意:给定一棵有n个结点的树,每一个点有一个权值.共同拥有m个询问.对于每一个询问(u,v,k),回答结点u至v之间第k小的点的权值. 思路:主席树+lca.首先指定一个根结点dfs一次并在此过程中建 ...

  2. Android 安装应用后点击打开带来的问题

    今天安装完APP的时候.界面会显示两个button,一个完毕键,一个打开键,点击Open键之后,外部打开应用.此时,我们点击HOME键.程序将会在后台. 然后再点击该桌面上应用程序的图标,app会自己 ...

  3. HDU 5412 CRB and Queries(区间第K大 树套树 按值建树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5412 Problem Description There are N boys in CodeLan ...

  4. Oracle 与 MySql 区别

    一.并发性 并发性是oltp数据库最重要的特性,但并发涉及到资源的获取.共享与锁定. mysql:mysql以表级锁为主,对资源锁定的粒度很大,如果一个session对一个表加锁时间过长,会让其他se ...

  5. 如何让 ssh 允许以 root 身份登录

    默认情况下,Pack 上的 root 用户不能用通过密码来远程登录,可以用一下命令来做:(注意要在 root 权限下) sed -i 's/PermitRootLogin\swithout-passw ...

  6. Python多线程学习(一、线程的使用)

    Python中使用线程有两种方式:函数或者用类来包装线程对象. 1.  函数式:调用thread模块中的start_new_thread()函数来产生新线程.如下例: import thread de ...

  7. C# 数组动态添加新元素的 方法

    经常在开发中  会对字符串 进行split 拆分操作.. 得到数组后再去做相应的事情! 但有时候,需求决定了 数组的长度 不是固定的, 而C# 数组 是不允许动态添加新的元素的.. 这事情让我也纠结了 ...

  8. OpenCV+VS 2015开发环境配置

    最近跑C程序,头文件中用到了OpenCV中的文件,找了很多篇OpenCV+VS的环境配置,发现如下这篇写的最为详细,特转载来自己的博客中留存,并附上原博客地址如下 OpenCV学习笔记(一)——Ope ...

  9. showdialog

    在C#中窗口的显示有两种方式:模态显示(showdialog)和非模态显示(show). 区别: 模态与非模态窗体的主要区别是窗体显示的时候是否可以操作其他窗体.模态窗体不允许操作其他窗体,非模态窗体 ...

  10. CSS——清除浮动的六种解决方案

    内容的高度撑起父元素容器的高度,效果图如下 HTML和CSS代码如下 给p标签加上浮动以后,p{float:left:},此时DIV塌陷,两段内容同行显示,效果如下: 解决方案一:给前面一个父元素设置 ...