一边吃瓜看球,一边完成AI应用实践——手写体识别入门

作者 | 邹欣

编辑 | 姗姗

【人工智能头条导读】又是一个很有热度的周末,除了炎热的天气,还有火热的世界杯。今天人工智能头条为大家准备的技术干货,让大家可以在空调下,吃瓜看球两不耽误就可以轻松完成AI应用实践入门。多少次,在我们查找很多资源、技术指导后,实操时还是会被一个报错而终止了前进的道路。小编也曾经历过这样的心路历程,所以一份好的指南对于刚开始实践操作的同学来说简直太有爱了,不仅节约了很多时间,操作和思路也都是清晰的。如果你是刚入门的AI小白,想通过一些简单的应用实践对AI应用有更深入的了解,现在就开始和我们一起开始吧!

作者简介:邹欣,现任微软亚洲研究院研发经理,负责必应搜索客户端、必应输入法、必应词典、微软小娜等产品。曾出版《移山之道》、《编辑之美》(合作)、《构建之法》三部书籍。

下面为大家介绍邹欣老师的AI应用开发实践系列教程之手写识别应用入门,本次教程学习主要分三步:

  • 从零开始搭建你的开发环境,无论是Windows 还是 MAC OS 环境
  • 简单的 MNIST 模型训练
  • 入门手写体识别应用实践

这波操作大家放心可以轻松完成,教程中不仅介绍了每步需要做什么,还为你准备了有参考价值的命令行、代码、各安装软件版本号的明确说明、需要下载或者访问的链接以及截图和教程视频,可以说非常全面、到位了。

▌为你的 Windows 搭建开发环境并开始训练第一个模型

(1)准备工作:一台能联网的电脑,使用 win10 64 位操作系统,请确保鼠标、键盘、显示器都是好的

(2)安装步骤:

  • 安装 Git
  • 安装 VS,等待时间看网络状况,没准可以看半场球反正不用担心不用着急。
  • 安装 python
  • 安装 CUDA 和 cuDNN:这是教程中最繁琐的一步,这一步直接拉高教程的平均难度。
  • 配置机器学习环境:这是教程中最简单的一步,为了方便用户配置环境,微软提供了一键安装工具!简直业界良心!
  • 安装 VS Tools For AI插件

(3)离线模型的训练:注意在此过程中使用最新的 mnist.py 文件

文章链接: https://blog.csdn.net/softwareteacher/article/details/80770079

▌为你的 MAC OS 搭建开发环境并开始训练第一个模型

(1)准备工作:一台能联网的电脑,使用 MAC OS 操作系统,请确保鼠标、键盘、显示器都是好的

(2)安装步骤:

  • 安装 VS,同样时间长的小伙伴们不妨考虑去看半场球啊!
  • 安装 python
  • 安装 Tools for AI 插件
  • 安装 Git
  • 下载机器学习示例库

(3)模型训练:也是小编的第一个模型!在教程中孩子特别补充讲解了如何在远程 Linux 上进行训练。

文章链接: https://blog.csdn.net/softwareteacher/article/details/80770239

▌AI应用开发实践—手写识别应用入门

敲重点!!!环境搭建和模型训练都搞定后,接下来终于可以上手应用实践了,以下为手写识别应用教程全文,enjoy!

手写体识别的应用已经非常流行了,如输入法,图片中的文字识别等。但对于大多数开发人员来说,如何实现这样的一个应用,还是会感觉无从下手。本文从简单的 MNIST 训练出来的模型开始,和大家一起入门手写体识别。

在本教程结束后,会得到一个能用的 AI应用,也许是你的第一个AI应用。虽然离实际使用还有较大的距离(具体差距在文章后面会分析),但会让你对AI应用有一个初步的认识,有能力逐步搭建出能够实际应用的模型。

原文链接: https://blog.csdn.net/softwareteacher/article/details/80770347

▌准备工作

  • 使用 win10 64 位操作系统的计算机
  • 参考上一篇博客 AI应用开发实战 - 从零开始配置环境。在电脑上训练并导出 MNIST 模型。

▌一. 思路

通过上一篇文章搭建环境的介绍后,就能得到一个能识别单个手写数字的模型了,并且识别的准确度会在 98%,甚至 99% 以上了。那么我们要怎么使用这个模型来搭建应用呢?

大致的步骤如下:

  • 实现简单的界面,将用户用鼠标或者触屏的输入变成图片。
  • 将生成的模型包装起来,成为有公开数据接口的类。
  • 将输入的图片进行规范化,成为数据接口能够使用的格式。
  • 最后通过模型来推理 (inference) 出图片应该是哪个数字,并显示出来。

是不是很简单?

▌二.动手

步骤一:获取手写的数字

提问:那我们要怎么获取手写的数字呢?

回答:我们可以写一个简单的 WinForm 画图程序,让我们可以用鼠标手写数字,然后把图片保存下来。

首先,我们打开 Visual Studio,选择文件->新建->项目。

在弹出的窗口里选择 Visual C#->Windows窗体应用,项目名称不妨叫做 DrawDigit,解决方案名称不妨叫做 MnistForm,点击确定。

此时,Visual Studio 也自动弹出了一个窗口的设计图。

在 DrawDigit 项目上点击右键,选择属性,在生成一栏将平台目标从 Any CPU 改为 x 64。

否则,DrawDigit(首选32位)与它引用的 MnistForm(64位)的编译平台不一致会引发 System.BadImageFormatException 的异常。

然后我们对这个窗口做一些简单的修改:

首先我们打开 VS 窗口左侧的工具箱,这个窗口程序需要以下三种组件:

1. PictureBox:用来手写数字,并且把数字保存成图片

2. Label:用来显示模型的识别结果

3. Button:用来清理PictureBox的手写结果

那经过一些简单的选择与拖动还有调整大小,这个窗口现在是这样的:

一些注意事项

  • 这些组件都可以通过右键->查看属性,在属性里修改它们的设置
  • 为了方便把 PictureBox 里的图片转化成 Mnist 能识别的格式,PictureBox 的需要是正方形
  • 可以给这些控件起上有意义的名称。
  • 可以调整一下 label 控件大小、字体等,让它更美观。

经过一些简单的调整,这个窗口现在是这样的:

现在来让我们愉快地给这些组件添加事件!

还是在属性窗口,我们选择某个组件,右键->查看属性,点击闪电符号,给组件绑定对应的事件。每次绑定后,会跳到代码部分,生成一个空函数。点回设计视图继续操作即可。

组件类型

事件

pictureBox1

在Mouse下双击MouseDown、MouseUp、MouseMove来生成对应的响应事件函数。

button1

如上,在Action下双击Click。

Form1

如上,在Behavior下双击Load。

然后我们开始补全对应的函数体内容。

注意,如果在上面改变了控件的名称,下面的代码需要做对应的更改。

废话少说上代码!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;//用于优化绘制的结果
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MnistModel;

namespace DrawDigit
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Bitmap digitImage;//用来保存手写数字
        private Point startPoint;//用于绘制线段,作为线段的初始端点坐标
        private Mnist model;//用于识别手写数字
        private const int MnistImageSize = 28;//Mnist模型所需的输入图片大小

        private void Form1_Load(object sender, EventArgs e)
        {
            //当窗口加载时,绘制一个白色方框
            model = new Mnist();
            digitImage = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics g = Graphics.FromImage(digitImage);
            g.Clear(Color.White);
            pictureBox1.Image = digitImage;
        }

        private void clean_click(object sender, EventArgs e)
        {
            //当点击清除时,重新绘制一个白色方框,同时清除label1显示的文本
            digitImage = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics g = Graphics.FromImage(digitImage);
            g.Clear(Color.White);
            pictureBox1.Image = digitImage;
            label1.Text = "";
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            //当鼠标左键被按下时,记录下需要绘制的线段的起始坐标
            startPoint = (e.Button == MouseButtons.Left) ? e.Location : startPoint;
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //当鼠标在移动,且当前处于绘制状态时,根据鼠标的实时位置与记录的起始坐标绘制线段,同时更新需要绘制的线段的起始坐标
            if (e.Button == MouseButtons.Left)
            {
                Graphics g = Graphics.FromImage(digitImage);
                Pen myPen = new Pen(Color.Black, 40);
                myPen.StartCap = LineCap.Round;
                myPen.EndCap = LineCap.Round;
                g.DrawLine(myPen,startPoint, e.Location);
                pictureBox1.Image = digitImage;
                g.Dispose();
                startPoint = e.Location;
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            //当鼠标左键释放时
            //同时开始处理图片进行推理
            //暂时不处理这里的代码
        }
    }
}

步骤二:把模型包装成一个类

将模型包装成一个 C# 是整个过程中比较麻烦的一步。所幸的是,Tools for AI 对此提供了很好的支持。进一步了解,可以看这里(https://github.com/Microsoft/vs-tools-for-ai/blob/master/docs/zh-hans/docs/model-inference.md)。

首先,我们在解决方案 MnistForm 下点击鼠标右键,选择添加->新建项目,在弹出的窗口里选择 AI Tools->Inference->模型推理类库,名称不妨叫做 MnistModel,点击确定,于是我们又多了一个项目。

然后自己配置好这个项目的名称、位置,点击确定。

然后弹出一个模型推理类库创建向导,这个时候就需要我们选择自己之前训练好的模型了~

首先在模型路径里选择保存的模型文件的路径。这里我们使用在AI应用开发实战 - 从零开始配置环境博客中训练并导出的模型

note:模型可在 /samples-for-ai/examples/tensorflow/MNIST 目录下找到,其中 output 文件夹保存了检查点文件,export 文件夹保存了模型文件。

对于TensorFlow,我们可以选择检查点的 .meta 文件,或者是保存的模型的 .pb 文件

这里我们选择在AI应用开发实战 - 从零开始配置环境这篇博客最后生成的 export 目录下的检查点的 SavedModel.pb 文件,这时程序将自动配置好配置推理接口,见下图:

类名可以自己定义,因为我们用的是 MNIST,那么类名就叫 Mnist 好了,然后点击确定。

这样,在解决方案资源管理器里,在解决方案 MnistForm 下,就多了一个 MnistModel:

双击 Mnist.cs,我们可以看到项目自动把模型进行了封装,生成了一个公开的 infer 函数。

然后我们在 MnistModel 上右击,再选择生成,等待一会,这个项目就可以使用了~

步骤三:连接两个部分

这一步差不多就是这么个感觉:

I have an apple , I have a pen. AH~ , Applepen

首先,我们来给 DrawDigit 添加引用,让它能使用 MnistModel。在 DrawDigit 项目的引用上点击鼠标右键,点击添加引用,在弹出的窗口中选择 MnistModel,点击确定。

然后,由于 MNIST 的模型的输入是一个 28×28 的白字黑底的灰度图,因此我们首先要对图片进行一些处理。

首先将图片转为 28×28 的大小。

然后将 RGB 图片转化为灰阶图,将灰阶标准化到 [-0.5,0.5] 区间内,转换为黑底白字。

最后将图片用 mnist 模型要求的格式包装起来,并传送给它进行推理。

于是,我们在 pictureBox1_MouseUp 中添加上这些代码,并且在文件最初添加上 using MnistModel;:

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            //当鼠标左键释放时
            //开始处理图片进行推理
            if (e.Button == MouseButtons.Left)
            {
                Bitmap digitTmp = (Bitmap)digitImage.Clone();//复制digitImage
                                                             //调整图片大小为Mnist模型可接收的大小:28×28
                using (Graphics g = Graphics.FromImage(digitTmp))
                {
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.DrawImage(digitTmp, 0, 0, MnistImageSize, MnistImageSize);
                }
                //将图片转为灰阶图,并将图片的像素信息保存在list中
                var image = new List<float>(MnistImageSize * MnistImageSize);
                for (var x = 0; x < MnistImageSize; x++)
                {
                    for (var y = 0; y < MnistImageSize; y++)
                    {
                        var color = digitTmp.GetPixel(y, x);
                        var a = (float)(0.5 - (color.R + color.G + color.B) / (3.0 * 255));
                        image.Add(a);
                    }
                }
                //将图片信息包装为mnist模型规定的输入格式
                var batch = new List<IEnumerable<float>>();
                batch.Add(image);
                //将图片传送给mnist模型进行推理
                var result = model.Infer(batch);
                //将推理结果输出
                label1.Text = result.First().First().ToString();
            }
        }

最后让我们尝试一下运行~

▌三.效果展示

现在我们就有了一个简单的小程序,可以识别手写的数字了。

赶紧试试效果怎么样~

▌注意

1.路径中不能有中文字符,否则可能找不到模型。

▌进阶

那么,如果要识别多个连写的数字,或支持字母该怎么做呢?大家多用用也会发现,如果数字写得很小,或者没写到正中,识别起来正确率也会不高。要解决这些问题,做成真正的产品,就不止这一个模型了。比如在多个数字识别中,可能要根据经验来切分图,或者训练另一个模型来检测并分割数字。要支持字母,则需要重新训练一个包含手写字母的模型,并准备更多的字母的数据。要解决字太小的问题,还要检测一下字的大小,做合适的放大等等。

我们可以看到,一个训练出来的模型本身到一个实际的应用之间还有不少的功能要实现。希望我们这一系列的介绍,能够帮助大家将机器学习的概念带入到传统的编程领域中,做出更聪明的产品。

原文链接: https://blog.csdn.net/softwareteacher/article/details/80770347

原文发布于微信公众号 - 人工智能头条(AI_Thinker)

原文发表时间:2018-06-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WeTest质量开放平台团队的专栏

UPA深度性能报告解读

原文链接:http://wetest.qq.com/lab/view/403.html

1172
来自专栏Python中文社区

利用人工智能实现小程序自动答题

之前有看到有人用python实现自动运行微信小程序《跳一跳》,后来看到别人用hash码实现《加减大师》的自动答题领取娃娃,最近一直在研究深度学习,为啥不用机器学...

1.2K2
来自专栏机器之心

TensorFlow初学者指南:如何为机器学习项目创建合适的文件架构

选自MetaFlow 作者:Morgan 机器之心编译 参与:李亚洲、蒋思源 在这篇文章中,作者根据自己的经验为 TensorFlow 初学者给出了设计文件、文...

3816
来自专栏腾讯IVWEB团队的专栏

前端识别验证码思路分析

相信很多前端同学对于二维码识别、图像对比等这类高大上的图像识别技术望而生畏,觉得此类识别技术只能通过更加底仓的高级语言才能实现(诸如c等),本文试图从前端的角度...

1.2K0
来自专栏编程坑太多

简单爬虫,突破复杂验证码和IP访问限制

5621
来自专栏我是极客人

图片去霾算法实践】NDK下二维数组的传递

最近看到了一篇关于图片“去霾算法”的文章,一下子就有了兴趣,所以想着能不能实现。由于数学能力捉急,无法理解文章的思想和相关论文。于是在Github上找到了相关的...

1133
来自专栏PPV课数据科学社区

《Kaggle项目实战》 泰坦尼克:从R开始数据挖掘(一)

摘要: 你是否为研究数据挖掘预测问题而感到兴奋?那么如何开始呢,本案例选自Kaggle上的数据竞赛的一个数据竞赛项目《泰坦尼克:灾难中的机器学习》,案例涉及一...

3486
来自专栏数据小魔方

R语言可视化——REmap动态地图

今天开始,要跟着大家学习一个新的可视化R包——REmap包。 说起来,这个包要归功于百度的可视化开源项目——echarts,它是国内为数不多的高水平开源可视化j...

7626
来自专栏深度学习入门与实践

用Tensorflow让神经网络自动创造音乐

本文禁止转载,禁止用于各类讲座及ppt中,违者必究   前几天看到一个有意思的分享,大意是讲如何用Tensorflow教神经网络自动创造音乐。听起来好好玩有木有...

3299
来自专栏葡萄城控件技术团队

ActiveReports 报表应用教程 (7)---交叉报表及数据透视图实现方案

在葡萄城ActiveReports报表中可以通过矩阵控件非常方便的实现交叉报表,同时还可以设置数据的分组、排序、过滤、小计、合计等操作,可以满足您报表的智能数据...

1895

扫码关注云+社区

领取腾讯云代金券