AI应用开发实战系列之三:手写识别应用入门
AI應(yīng)用開發(fā)實戰(zhàn) - 手寫識別應(yīng)用入門
手寫體識別的應(yīng)用已經(jīng)非常流行了,如輸入法,圖片中的文字識別等。但對于大多數(shù)開發(fā)人員來說,如何實現(xiàn)這樣的一個應(yīng)用,還是會感覺無從下手。本文從簡單的MNIST訓(xùn)練出來的模型開始,和大家一起入門手寫體識別。
在本教程結(jié)束后,會得到一個能用的AI應(yīng)用,也許是你的第一個AI應(yīng)用。雖然離實際使用還有較大的距離(具體差距在文章后面會分析),但會讓你對AI應(yīng)用有一個初步的認(rèn)識,有能力逐步搭建出能夠?qū)嶋H應(yīng)用的模型。
建議和反饋,請發(fā)送到
https://github.com/Microsoft/vs-tools-for-ai/issues
聯(lián)系我們
OpenmindChina@microsoft.com
準(zhǔn)備工作
- 使用win10 64位操作系統(tǒng)的計算機
- 參考上一篇博客AI應(yīng)用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境。在電腦上訓(xùn)練并導(dǎo)出MNIST模型。
一、 思路
通過上一篇文章搭建環(huán)境的介紹后,就能得到一個能識別單個手寫數(shù)字的模型了,并且識別的準(zhǔn)確度會在98%,甚至99%以上了。那么我們要怎么使用這個模型來搭建應(yīng)用呢?
大致的步驟如下:
是不是很簡單?
二、動手
步驟一:獲取手寫的數(shù)字
提問:那我們要怎么獲取手寫的數(shù)字呢?
回答:我們可以寫一個簡單的WinForm畫圖程序,讓我們可以用鼠標(biāo)手寫數(shù)字,然后把圖片保存下來。
首先,我們打開Visual Studio,選擇文件->新建->項目。
在彈出的窗口里選擇Visual C#->Windows窗體應(yīng)用,項目名稱不妨叫做DrawDigit,解決方案名稱不妨叫做MnistForm,點擊確定。
此時,Visual Studio也自動彈出了一個窗口的設(shè)計圖。
在DrawDigit項目上點擊右鍵,選擇屬性,在生成一欄將平臺目標(biāo)從Any CPU改為x64。
否則,DrawDigit(首選32位)與它引用的MnistForm(64位)的編譯平臺不一致會引發(fā)System.BadImageFormatException的異常。
然后我們對這個窗口做一些簡單的修改:
首先我們打開VS窗口左側(cè)的工具箱,這個窗口程序需要以下三種組件:
1. PictureBox:用來手寫數(shù)字,并且把數(shù)字保存成圖片
2. Label:用來顯示模型的識別結(jié)果
3. Button:用來清理PictureBox的手寫結(jié)果
那經(jīng)過一些簡單的選擇與拖動還有調(diào)整大小,這個窗口現(xiàn)在是這樣的:
一些注意事項
經(jīng)過一些簡單的調(diào)整,這個窗口現(xiàn)在是這樣的:
現(xiàn)在來讓我們愉快地給這些組件添加事件!
還是在屬性窗口,我們選擇某個組件,右鍵->查看屬性,點擊閃電符號,給組件綁定對應(yīng)的事件。每次綁定后,會跳到代碼部分,生成一個空函數(shù)。點回設(shè)計視圖繼續(xù)操作即可。
| pictureBox1 | 在Mouse下雙擊MouseDown、MouseUp、MouseMove來生成對應(yīng)的響應(yīng)事件函數(shù)。 |
| button1 | 如上,在Action下雙擊Click。 |
| Form1 | 如上,在Behavior下雙擊Load。 |
然后我們開始補全對應(yīng)的函數(shù)體內(nèi)容。
注意,如果在上面改變了控件的名稱,下面的代碼需要做對應(yīng)的更改。
廢話少說上代碼!
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D;//用于優(yōu)化繪制的結(jié)果 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;//用來保存手寫數(shù)字private Point startPoint;//用于繪制線段,作為線段的初始端點坐標(biāo)private Mnist model;//用于識別手寫數(shù)字private const int MnistImageSize = 28;//Mnist模型所需的輸入圖片大小private void Form1_Load(object sender, EventArgs e){//當(dāng)窗口加載時,繪制一個白色方框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){//當(dāng)點擊清除時,重新繪制一個白色方框,同時清除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){//當(dāng)鼠標(biāo)左鍵被按下時,記錄下需要繪制的線段的起始坐標(biāo)startPoint = (e.Button == MouseButtons.Left) ? e.Location : startPoint;}private void pictureBox1_MouseMove(object sender, MouseEventArgs e){//當(dāng)鼠標(biāo)在移動,且當(dāng)前處于繪制狀態(tài)時,根據(jù)鼠標(biāo)的實時位置與記錄的起始坐標(biāo)繪制線段,同時更新需要繪制的線段的起始坐標(biāo)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){//當(dāng)鼠標(biāo)左鍵釋放時//同時開始處理圖片進(jìn)行推理//暫時不處理這里的代碼}} }步驟二:把模型包裝成一個類
將模型包裝成一個C#是整個過程中比較麻煩的一步。所幸的是,Tools for AI對此提供了很好的支持。進(jìn)一步了解,可以看這里。
首先,我們在解決方案MnistForm下點擊鼠標(biāo)右鍵,選擇添加->新建項目,在彈出的窗口里選擇AI Tools->Inference->模型推理類庫,名稱不妨叫做MnistModel,點擊確定,于是我們又多了一個項目,
然后自己配置好這個項目的名稱、位置,點擊確定。
然后彈出一個模型推理類庫創(chuàng)建向?qū)?#xff0c;這個時候就需要我們選擇自己之前訓(xùn)練好的模型了~
首先在模型路徑里選擇保存的模型文件的路徑。這里我們使用在AI應(yīng)用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境博客中訓(xùn)練并導(dǎo)出的模型
note:模型可在/samples-for-ai/examples/tensorflow/MNIST目錄下找到,其中output文件夾保存了檢查點文件,export文件夾保存了模型文件。
對于TensorFlow,我們可以選擇檢查點的.meta文件,或者是保存的模型的.pb文件
這里我們選擇在AI應(yīng)用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境這篇博客最后生成的export目錄下的檢查點的SavedModel.pb文件,這時程序?qū)⒆詣优渲煤门渲猛评斫涌?#xff0c;見下圖:
類名可以自己定義,因為我們用的是MNIST,那么類名就叫Mnist好了,然后點擊確定。
這樣,在解決方案資源管理器里,在解決方案MnistForm下,就多了一個MnistModel:
雙擊Mnist.cs,我們可以看到項目自動把模型進(jìn)行了封裝,生成了一個公開的infer函數(shù)。
然后我們在MnistModel上右擊,再選擇生成,等待一會,這個項目就可以使用了~
步驟三:連接兩個部分
這一步差不多就是這么個感覺:
I have an apple , I have a pen. AH~ , Applepen
首先,我們來給DrawDigit添加引用,讓它能使用MnistModel。在DrawDigit項目的引用上點擊鼠標(biāo)右鍵,點擊添加引用,在彈出的窗口中選擇MnistModel,點擊確定。
然后,由于MNIST的模型的輸入是一個28×28的白字黑底的灰度圖,因此我們首先要對圖片進(jìn)行一些處理。
首先將圖片轉(zhuǎn)為28×28的大小。
然后將RGB圖片轉(zhuǎn)化為灰階圖,將灰階標(biāo)準(zhǔn)化到[-0.5,0.5]區(qū)間內(nèi),轉(zhuǎn)換為黑底白字。
最后將圖片用mnist模型要求的格式包裝起來,并傳送給它進(jìn)行推理。
于是,我們在pictureBox1_MouseUp中添加上這些代碼,并且在文件最初添加上using MnistModel;:
最后讓我們嘗試一下運行~
三、效果展示
現(xiàn)在我們就有了一個簡單的小程序,可以識別手寫的數(shù)字了。
趕緊試試效果怎么樣~
注意
進(jìn)階
那么,如果要識別多個連寫的數(shù)字,或支持字母該怎么做呢?大家多用用也會發(fā)現(xiàn),如果數(shù)字寫得很小,或者沒寫到正中,識別起來正確率也會不高。要解決這些問題,做成真正的產(chǎn)品,就不止這一個模型了。比如在多個數(shù)字識別中,可能要根據(jù)經(jīng)驗來切分圖,或者訓(xùn)練另一個模型來檢測并分割數(shù)字。要支持字母,則需要重新訓(xùn)練一個包含手寫字母的模型,并準(zhǔn)備更多的字母的數(shù)據(jù)。要解決字太小的問題,還要檢測一下字的大小,做合適的放大等等。
我們可以看到,一個訓(xùn)練出來的模型本身到一個實際的應(yīng)用之間還有不少的功能要實現(xiàn)。希望我們這一系列的介紹,能夠幫助大家將機器學(xué)習(xí)的概念帶入到傳統(tǒng)的編程領(lǐng)域中,做出更聰明的產(chǎn)品。
總結(jié)
以上是生活随笔為你收集整理的AI应用开发实战系列之三:手写识别应用入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 创建模式语句,ORACLE
- 下一篇: c语言case接收字符,switch-c