日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人工智能 > ChatGpt >内容正文

ChatGpt

AI应用开发实战(转)

發(fā)布時(shí)間:2025/3/8 ChatGpt 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AI应用开发实战(转) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境

與本篇配套的視頻教程請(qǐng)?jiān)L問(wèn):https://www.bilibili.com/video/av24421492/

建議和反饋,請(qǐng)發(fā)送到
https://github.com/Microsoft/vs-tools-for-ai/issues

聯(lián)系我們
OpenmindChina@microsoft.com

零、前提條件

  • 一臺(tái)能聯(lián)網(wǎng)的電腦,使用win10 64位操作系統(tǒng)
  • 請(qǐng)確保鼠標(biāo)、鍵盤(pán)、顯示器都是好的

一、Windows下開(kāi)發(fā)環(huán)境搭建

本教材主要參考了如下資源:

官方github教程:https://github.com/microsoft/vs-tools-for-ai

斗魚(yú)tv教程:https://v.douyu.com/show/V6Aw87OBmXZvYGkg

本教程分為五步:

  • 安裝VS:難度一星
  • 安裝python:難度一星
  • 安裝CUDA和cuDNN:這是本教程最繁瑣的一步,這一步直接拉高本教程的平均難度。
  • 配置機(jī)器學(xué)習(xí)環(huán)境:這是本教程最簡(jiǎn)單的一步,為了方便用戶配置環(huán)境,微軟提供了一鍵安裝工具!沒(méi)錯(cuò),一鍵安裝工具!業(yè)界良心阿!
  • 安裝VS Tools For AI插件:難度一星

note:本教程對(duì)各個(gè)軟件需要使用的版本都做出了明確說(shuō)明,請(qǐng)安裝指定的版本

請(qǐng)放輕松,接下來(lái)的傻瓜教程不需要?jiǎng)幽X子,你甚至可以打開(kāi)手機(jī)邊刷微博邊配置環(huán)境

0.安裝Git

訪問(wèn) https://git-scm.com/download/win

選擇64-bit Git for Windows Setup下載

雙擊.exe開(kāi)始安裝

選擇好自己的安裝路徑,一路next,直到Adjusting your PATH environment

請(qǐng)選擇Use Git from the Windows Command Prompt

這一步就已經(jīng)將Git添加到環(huán)境變量中了,然后就可以直接在命令行里使用Git啦。

然后繼續(xù)next,直到安裝結(jié)束

1.安裝VS

訪問(wèn) https://www.visualstudio.com/zh-hans/products/
在產(chǎn)品中點(diǎn)擊Visual Studio 2017

選擇Community版本下載

打開(kāi)Visual Studio Installer進(jìn)行如下的配置:

僅選擇.NET桌面開(kāi)發(fā)與Python開(kāi)發(fā)即可

僅選擇.NET桌面開(kāi)發(fā)與Python開(kāi)發(fā)即可

僅選擇.NET桌面開(kāi)發(fā)與Python開(kāi)發(fā)即可

note:請(qǐng)自行決定Visual Studio的安裝路徑

等待數(shù)分鐘,時(shí)長(zhǎng)視網(wǎng)絡(luò)狀況而定,這個(gè)時(shí)候你可以去泡一杯茶,或者聽(tīng)一首歌,如果你的網(wǎng)絡(luò)不是很好,那你可以去看集美劇或者別的什么,等待安裝結(jié)束。

note:坐 和 放寬

2.安裝python

注意!!!如果你已經(jīng)安裝了VS2017帶Python開(kāi)發(fā)的環(huán)境,就不需要再裝一遍python了。打開(kāi)vs2017, 點(diǎn)擊Tools->Python->Python Environments,應(yīng)該可以看到Python 3.6已經(jīng)安裝,在下面有個(gè)folder,大概是“c:\Program Files(x86)\Microsoft Visual Studio\Shared\Python36_64”,把這個(gè)字符串copy下來(lái)。然后打開(kāi)Settings->Home->About->System info,在彈出的窗口中選擇Advanced system settings->Advanced->Environment Variables->System variables->Path->Edit->New,把剛才的python環(huán)境變量字符串paste進(jìn)來(lái)。如果有多個(gè)python環(huán)境,建議把一些舊的版本卸載先,保證你的機(jī)器沒(méi)有那么多垃圾。
點(diǎn)擊OK后,再打開(kāi)一個(gè)command窗口,輸入Python,就可以正常使用了。

訪問(wèn) https://www.python.org/downloads/

選擇版本3.5.4或3.6.5?,Windows x86-64 executable installer下載。

打開(kāi)安裝包,在安裝前,請(qǐng)選擇Add Python 3.X to PATH,隨后按照默認(rèn)選項(xiàng)安裝即可。

點(diǎn)選后,程序?qū)⒆詣?dòng)將Python加入環(huán)境變量,這樣避免在安裝后手動(dòng)配置環(huán)境變量。

安裝結(jié)束后,請(qǐng)進(jìn)行如下操作驗(yàn)證python是否安裝成功

1.同時(shí)按下 win 與 R,在彈出的輸入框里輸入cmd 2.在彈出的窗口中輸入 python 3.輸入exit()退出 4.輸入python -m pip install -U pip以更新pip到最新版本

note: pip是一個(gè)用來(lái)管理python包的工具

自此,你已經(jīng)完成了python的安裝,在朝著AI技術(shù)大牛的路上又前進(jìn)了一步!

note:請(qǐng)伸出大拇指給自己一個(gè)贊?

3.安裝CUDA與cuDNN

如果你的電腦裝有Nvidia的顯卡,請(qǐng)進(jìn)行這一步配置,否則請(qǐng)?zhí)^(guò)。

首先通過(guò)操作系統(tǒng)更新,升級(jí)顯卡驅(qū)動(dòng)到最新版。

3.1 安裝CUDA

打開(kāi) https://developer.nvidia.com/cuda-toolkit-archive

選擇CUDA 9.0 進(jìn)行安裝。

點(diǎn)擊后,選擇如下的配置:

note:請(qǐng)選擇local版本下載,一旦失敗還可以重新再來(lái);如果使用network版本,一旦失敗,需要重新下載1.4GB的安裝包

打開(kāi)安裝包,進(jìn)行安裝,請(qǐng)自行配置CUDA的安裝路徑,并手動(dòng)將CUDA庫(kù)添加至PATH環(huán)境變量中。

note:在Windows中,CUDA的默認(rèn)安裝路徑是:

"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\bin"

3.2 安裝cuDNN

note:打起精神!這是操作最復(fù)雜的一步!

訪問(wèn) https://developer.nvidia.com/rdp/cudnn-archive 找到我們需要的cuDNN版本:

cuDNN v7.0.5 (Dec 5, 2017), for CUDA 9.0

cuDNN v7.0.5 Library for Windows 10

點(diǎn)擊鏈接,等待著你的并不是文件下載,而是:

↑這就是本教程里最麻煩的一步:在下載cuDNN之前需要注冊(cè)Nvidia會(huì)員并驗(yàn)證郵箱。不過(guò)還好可以微信登錄,省掉一些步驟。

一番令人窒息的操作之后,我們終于得到了cuDNN,我們把文件解壓,取出這個(gè)路徑的cudnn64_7.dll,復(fù)制到CUDA的bin目錄下即可。默認(rèn)的地址是:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\bin

note:到這里,我們已經(jīng)完成了本教程最復(fù)雜的一步了

4.安裝機(jī)器學(xué)習(xí)的軟件及依賴

這一步雖然是整個(gè)教程最簡(jiǎn)單的一步,甚至比把大象關(guān)進(jìn)冰箱更簡(jiǎn)單。

你只需要:

win + R ,打開(kāi)cmd,在命令行中輸入:cd c:\ //選擇一個(gè)你喜歡的路徑 md AI //在這里創(chuàng)建一個(gè)AI目錄 cd AI //打開(kāi)這個(gè)目錄 //克隆倉(cāng)庫(kù)到本地 git clone https://github.com/Microsoft/samples-for-ai.git cd samples-for-ai //打開(kāi)這個(gè)目錄 cd installer //還有這個(gè)目錄 python.exe install.py //開(kāi)始安裝

然后刷會(huì)微博,等待安裝結(jié)束即可。

成功之后是這樣的:

或者你覺(jué)得自己不怕麻煩,那么請(qǐng)?jiān)L問(wèn):https://github.com/Microsoft/vs-tools-for-ai/blob/master/docs/zh-hans/docs/prepare-localmachine.md

根據(jù)教程按步安裝,相信我,你會(huì)回來(lái)選擇一鍵安裝的。

note:就差一步啦!成功就在眼前!

5.安裝tools for ai插件

打開(kāi)Visual Studio,選擇工具->擴(kuò)展和更新->選擇“聯(lián)機(jī)”->搜索“AI”
就像這樣:

等待下載完成之后,關(guān)閉Visual Studio,沒(méi)錯(cuò),關(guān)閉Visual Studio,系統(tǒng)將自動(dòng)安裝AI插件。

安裝完畢后再次打開(kāi)Visual Studio,你將在界面上看到這樣的內(nèi)容:

那么恭喜你!安裝成功!

note:千里之行始于足下,恭喜你成功地完成了環(huán)境的搭建,接下來(lái)就已經(jīng)可以使用Visual Studio Tools For AI進(jìn)行開(kāi)發(fā)了?

二、離線模型的訓(xùn)練


6.14日更新
GitHub上的samples-for-ai進(jìn)行了一定的更新,目前MNIST文件夾下只有一個(gè)mnist.py文件,

下述步驟中,請(qǐng)使用最新的mnist.py文件


在進(jìn)行完環(huán)境搭建后,我們馬上就可以開(kāi)始訓(xùn)練第一個(gè)模型了,我們選擇tensorflow下的MNIST作為第一個(gè)例子。

MNIST的介紹請(qǐng)參考這個(gè)鏈接 https://www.tensorflow.org/versions/r1.1/get_started/mnist/beginners

首先我們打開(kāi)這個(gè)路徑:C:\AI\samples-for-ai\examples\tensorflow,如果你在別的目錄下克隆了目錄,那么請(qǐng)打開(kāi)你對(duì)應(yīng)的目錄。然后雙擊TensorflowExamples.sln
就像這樣:

note:如果存在多個(gè)Python環(huán)境,你需要為Visual Studio的AI項(xiàng)目設(shè)置默認(rèn)的Python環(huán)境。

例如,手動(dòng)安裝的Python 3.5與Visual Studio 2017 Python開(kāi)發(fā)負(fù)載自動(dòng)安裝了64位的Python 3.6

如果要為Visual Studio設(shè)置全局的默認(rèn)Python環(huán)境,請(qǐng)打開(kāi)工具->Python?->?Python環(huán)境。然后,選擇自己需要的Python版本,點(diǎn)擊將此作為新項(xiàng)目的默認(rèn)環(huán)境。

然后在解決方案資源管理器中,選擇MNIST,單擊右鍵,選擇設(shè)為啟動(dòng)項(xiàng)目

然后選擇MNIST中的mnist.py,單擊右鍵,選擇在不調(diào)試的情況下啟動(dòng)

然后程序就開(kāi)始運(yùn)行了,就像這樣:

等待一段時(shí)間之后,模型就訓(xùn)練好了!這個(gè)時(shí)候打開(kāi)MNIST所在的文件夾,MNIST下是否多了三個(gè)文件夾?分別是input和output還有export,這三個(gè)文件夾分別存儲(chǔ)了訓(xùn)練模型的輸入文件、訓(xùn)練時(shí)的檢查點(diǎn)文件,還有最終導(dǎo)出的模型文件

檢查點(diǎn)文件:

模型文件:

可能存在的問(wèn)題

GPU ran out of memory

方法一:
修改convolutional.py第45行或第47行的BATCH_SIZE或EVAL_BATCH_SIZE為一個(gè)更小的數(shù)字。具體修改哪一個(gè),需要視你在程序運(yùn)行的哪個(gè)部分得到了ERROR決定。

方法二:
不使用GPU訓(xùn)練,在項(xiàng)目MNIST上單擊右鍵,選擇屬性(R)

修改環(huán)境變量為CUDA_VISIBLE_DEVICES=" "

?

AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 手寫(xiě)識(shí)別應(yīng)用入門(mén)

手寫(xiě)體識(shí)別的應(yīng)用已經(jīng)非常流行了,如輸入法,圖片中的文字識(shí)別等。但對(duì)于大多數(shù)開(kāi)發(fā)人員來(lái)說(shuō),如何實(shí)現(xiàn)這樣的一個(gè)應(yīng)用,還是會(huì)感覺(jué)無(wú)從下手。本文從簡(jiǎn)單的MNIST訓(xùn)練出來(lái)的模型開(kāi)始,和大家一起入門(mén)手寫(xiě)體識(shí)別。

在本教程結(jié)束后,會(huì)得到一個(gè)能用的AI應(yīng)用,也許是你的第一個(gè)AI應(yīng)用。雖然離實(shí)際使用還有較大的距離(具體差距在文章后面會(huì)分析),但會(huì)讓你對(duì)AI應(yīng)用有一個(gè)初步的認(rèn)識(shí),有能力逐步搭建出能夠?qū)嶋H應(yīng)用的模型。

建議和反饋,請(qǐng)發(fā)送到
https://github.com/Microsoft/vs-tools-for-ai/issues

聯(lián)系我們
OpenmindChina@microsoft.com

準(zhǔn)備工作

  • 使用win10 64位操作系統(tǒng)的計(jì)算機(jī)
  • 參考上一篇博客AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境。在電腦上訓(xùn)練并導(dǎo)出MNIST模型。

一、 思路

通過(guò)上一篇文章搭建環(huán)境的介紹后,就能得到一個(gè)能識(shí)別單個(gè)手寫(xiě)數(shù)字的模型了,并且識(shí)別的準(zhǔn)確度會(huì)在98%,甚至99%以上了。那么我們要怎么使用這個(gè)模型來(lái)搭建應(yīng)用呢?

大致的步驟如下:

  • 實(shí)現(xiàn)簡(jiǎn)單的界面,將用戶用鼠標(biāo)或者觸屏的輸入變成圖片。
  • 將生成的模型包裝起來(lái),成為有公開(kāi)數(shù)據(jù)接口的類。
  • 將輸入的圖片進(jìn)行規(guī)范化,成為數(shù)據(jù)接口能夠使用的格式。
  • 最后通過(guò)模型來(lái)推理(inference)出圖片應(yīng)該是哪個(gè)數(shù)字,并顯示出來(lái)。
  • 是不是很簡(jiǎn)單?

    二、動(dòng)手

    步驟一:獲取手寫(xiě)的數(shù)字

    提問(wèn):那我們要怎么獲取手寫(xiě)的數(shù)字呢?

    回答:我們可以寫(xiě)一個(gè)簡(jiǎn)單的WinForm畫(huà)圖程序,讓我們可以用鼠標(biāo)手寫(xiě)數(shù)字,然后把圖片保存下來(lái)。

    首先,我們打開(kāi)Visual Studio,選擇文件->新建->項(xiàng)目。

    在彈出的窗口里選擇Visual C#->Windows窗體應(yīng)用,項(xiàng)目名稱不妨叫做DrawDigit,解決方案名稱不妨叫做MnistForm,點(diǎn)擊確定。

    此時(shí),Visual Studio也自動(dòng)彈出了一個(gè)窗口的設(shè)計(jì)圖。

    在DrawDigit項(xiàng)目上點(diǎn)擊右鍵,選擇屬性,在生成一欄將平臺(tái)目標(biāo)從Any CPU改為x64。

    否則,DrawDigit(首選32位)與它引用的MnistForm(64位)的編譯平臺(tái)不一致會(huì)引發(fā)System.BadImageFormatException的異常。

    然后我們對(duì)這個(gè)窗口做一些簡(jiǎn)單的修改:

    首先我們打開(kāi)VS窗口左側(cè)的工具箱,這個(gè)窗口程序需要以下三種組件:

  • PictureBox:用來(lái)手寫(xiě)數(shù)字,并且把數(shù)字保存成圖片
  • Label:用來(lái)顯示模型的識(shí)別結(jié)果
  • Button:用來(lái)清理PictureBox的手寫(xiě)結(jié)果
  • 那經(jīng)過(guò)一些簡(jiǎn)單的選擇與拖動(dòng)還有調(diào)整大小,這個(gè)窗口現(xiàn)在是這樣的:

    一些注意事項(xiàng)

  • 這些組件都可以通過(guò)右鍵->查看屬性,在屬性里修改它們的設(shè)置
  • 為了方便把PictureBox里的圖片轉(zhuǎn)化成Mnist能識(shí)別的格式,PictureBox的需要是正方形
  • 可以給這些控件起上有意義的名稱。
  • 可以調(diào)整一下label控件大小、字體等,讓它更美觀。
  • 經(jīng)過(guò)一些簡(jiǎn)單的調(diào)整,這個(gè)窗口現(xiàn)在是這樣的:

    現(xiàn)在來(lái)讓我們愉快地給這些組件添加事件!

    還是在屬性窗口,我們選擇某個(gè)組件,右鍵->查看屬性,點(diǎn)擊閃電符號(hào),給組件綁定對(duì)應(yīng)的事件。每次綁定后,會(huì)跳到代碼部分,生成一個(gè)空函數(shù)。點(diǎn)回設(shè)計(jì)視圖繼續(xù)操作即可。

    組件類型事件
    pictureBox1在Mouse下雙擊MouseDown、MouseUp、MouseMove來(lái)生成對(duì)應(yīng)的響應(yīng)事件函數(shù)。
    button1如上,在Action下雙擊Click。
    Form1如上,在Behavior下雙擊Load。

    然后我們開(kāi)始補(bǔ)全對(duì)應(yīng)的函數(shù)體內(nèi)容。

    注意,如果在上面改變了控件的名稱,下面的代碼需要做對(duì)應(yīng)的更改。

    廢話少說(shuō)上代碼!

    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;//用來(lái)保存手寫(xiě)數(shù)字 private Point startPoint;//用于繪制線段,作為線段的初始端點(diǎn)坐標(biāo) private Mnist model;//用于識(shí)別手寫(xiě)數(shù)字 private const int MnistImageSize = 28;//Mnist模型所需的輸入圖片大小 private void Form1_Load(object sender, EventArgs e) { //當(dāng)窗口加載時(shí),繪制一個(gè)白色方框 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)點(diǎn)擊清除時(shí),重新繪制一個(gè)白色方框,同時(shí)清除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)左鍵被按下時(shí),設(shè)置isPainting為true,并記錄下需要繪制的線段的起始坐標(biāo) startPoint = (e.Button == MouseButtons.Left) ? e.Location : startPoint; } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { //當(dāng)鼠標(biāo)在移動(dòng),且當(dāng)前處于繪制狀態(tài)時(shí),根據(jù)鼠標(biāo)的實(shí)時(shí)位置與記錄的起始坐標(biāo)繪制線段,同時(shí)更新需要繪制的線段的起始坐標(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)左鍵釋放時(shí) //同時(shí)開(kāi)始處理圖片進(jìn)行推理 //暫時(shí)不處理這里的代碼 } } }

    步驟二:把模型包裝成一個(gè)類

    將模型包裝成一個(gè)C#是整個(gè)過(guò)程中比較麻煩的一步。所幸的是,Tools for AI對(duì)此提供了很好的支持。進(jìn)一步了解,可以看這里。

    首先,我們?cè)诮鉀Q方案MnistForm下點(diǎn)擊鼠標(biāo)右鍵,選擇添加->新建項(xiàng)目,在彈出的窗口里選擇AI Tools->Inference->模型推理類庫(kù),名稱不妨叫做MnistModel,點(diǎn)擊確定,于是我們又多了一個(gè)項(xiàng)目,

    然后自己配置好這個(gè)項(xiàng)目的名稱、位置,點(diǎn)擊確定。

    然后彈出一個(gè)模型推理類庫(kù)創(chuàng)建向?qū)?#xff0c;這個(gè)時(shí)候就需要我們選擇自己之前訓(xùn)練好的模型了~

    首先在模型路徑里選擇保存的模型文件的路徑。這里我們使用在AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境博客中訓(xùn)練并導(dǎo)出的模型

    note:模型可在/samples-for-ai/examples/tensorflow/MNIST目錄下找到,其中output文件夾保存了檢查點(diǎn)文件,export文件夾保存了模型文件。

    對(duì)于TensorFlow,我們可以選擇檢查點(diǎn)的.meta文件,或者是保存的模型的.pb文件

    這里我們選擇在AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境這篇博客最后生成的export目錄下的檢查點(diǎn)的SavedModel.pb文件,這時(shí)程序?qū)⒆詣?dòng)配置好配置推理接口,見(jiàn)下圖:

    類名可以自己定義,因?yàn)槲覀冇玫氖荕NIST,那么類名就叫Mnist好了,然后點(diǎn)擊確定。

    這樣,在解決方案資源管理器里,在解決方案MnistForm下,就多了一個(gè)MnistModel:

    雙擊Mnist.cs,我們可以看到項(xiàng)目自動(dòng)把模型進(jìn)行了封裝,生成了一個(gè)公開(kāi)的infer函數(shù)。

    然后我們?cè)贛nistModel上右擊,再選擇生成,等待一會(huì),這個(gè)項(xiàng)目就可以使用了~

    步驟三:連接兩個(gè)部分

    這一步差不多就是這么個(gè)感覺(jué):

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

    首先,我們來(lái)給DrawDigit添加引用,讓它能使用MnistModel。在DrawDigit項(xiàng)目的引用上點(diǎn)擊鼠標(biāo)右鍵,點(diǎn)擊添加引用,在彈出的窗口中選擇MnistModel,點(diǎn)擊確定。

    然后,由于MNIST的模型的輸入是一個(gè)28×28的白字黑底的灰度圖,因此我們首先要對(duì)圖片進(jìn)行一些處理。
    首先將圖片轉(zhuǎn)為28×28的大小。
    然后將RGB圖片轉(zhuǎn)化為灰階圖,將灰階標(biāo)準(zhǔn)化到[-0.5,0.5]區(qū)間內(nèi),轉(zhuǎn)換為黑底白字。
    最后將圖片用mnist模型要求的格式包裝起來(lái),并傳送給它進(jìn)行推理。
    于是,我們?cè)趐ictureBox1_MouseUp中添加上這些代碼,并且在文件最初添加上using MnistModel;:

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { //當(dāng)鼠標(biāo)左鍵釋放時(shí) //同時(shí)開(kāi)始處理圖片進(jìn)行推理 if (e.Button == MouseButtons.Left) { // 復(fù)制pictureBox中的圖片并縮放到28*28成為新的圖片(tmpBmp) Bitmap tmpBmp = new Bitmap(digitImage, MinstImageSize, MinstImageSize); //將圖片轉(zhuǎn)為灰階圖,并將圖片的像素信息保存在list中 var imageData = new List<float>(MnistImageSize * MnistImageSize); for (var y = 0; y < MnistImageSize; y++) { for (var x = 0; x < MnistImageSize; x++) { var color = tmpBmp.GetPixel(x, y); var pixel = (float)(0.5 - (color.R + color.G + color.B) / (3.0 * 255)); imageData.Add(pixel); } } //將圖片信息包裝為mnist模型規(guī)定的輸入格式 var batchData = new List<IEnumerable<float>>(); batchData.Add(imageData); //將圖片傳送給mnist模型進(jìn)行推理 var result = model.Infer(batchData); //將推理結(jié)果輸出 label1.Text = result.First().First().ToString(); } }

    最后讓我們嘗試一下運(yùn)行~

    三、效果展示

    現(xiàn)在我們就有了一個(gè)簡(jiǎn)單的小程序,可以識(shí)別手寫(xiě)的數(shù)字了。

    趕緊試試效果怎么樣~

    注意

  • 路徑中不能有中文字符,否則可能找不到模型。
  • 擴(kuò)展

    嘗試識(shí)別多個(gè)數(shù)字

    我們已經(jīng)支持了單個(gè)手寫(xiě)數(shù)字的識(shí)別,那能不能支持多個(gè)手寫(xiě)數(shù)字的識(shí)別呢?同時(shí)寫(xiě)下多個(gè)數(shù)字,正是現(xiàn)實(shí)中更為常見(jiàn)的情形。相比之下,如果只能一次識(shí)別一個(gè)手寫(xiě)數(shù)字,應(yīng)用就會(huì)有比較大的局限性。
    首先,我們可以嘗試在現(xiàn)有的應(yīng)用里一次寫(xiě)下兩個(gè)數(shù)字,看看識(shí)別效果(為了更好的展示效果,將筆畫(huà)的寬度由40調(diào)整為20。這一改動(dòng)對(duì)單個(gè)數(shù)字的識(shí)別并無(wú)大的影響):

    識(shí)別效果不盡人意。
    右上角展示的結(jié)果準(zhǔn)確地反應(yīng)了模型對(duì)我們手寫(xiě)輸入的推理結(jié)果(即result.First().First().ToString()),然而這一結(jié)果并不像我們期望的那樣是“42”。
    了解MNIST數(shù)據(jù)集的讀者們可能已經(jīng)意識(shí)到了,這是“理所當(dāng)然”的。歸根結(jié)底,這一問(wèn)題的癥結(jié)在于:作為我們AI應(yīng)用核心的AI模型,本身并不具備識(shí)別多個(gè)數(shù)字的能力——當(dāng)前案例中我們使用的AI模型是基于MNIST數(shù)據(jù)集訓(xùn)練的(訓(xùn)練過(guò)程請(qǐng)回顧我們之前的博客AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境),而MNIST數(shù)據(jù)集只覆蓋了單個(gè)的手寫(xiě)數(shù)字;并且,我們并未對(duì)筆跡圖形作額外的處理。
    結(jié)果是在寫(xiě)下多個(gè)數(shù)字的情況下,我們實(shí)際上在“強(qiáng)行”讓AI模型做超出其適應(yīng)性范圍的判斷。這屬于AI模型的誤用。其結(jié)果自然難以令人滿意。
    那么,為了增強(qiáng)應(yīng)用的可用性,我們能不能改善它、讓它能識(shí)別多個(gè)數(shù)字呢?我們很自然地想到,既然MNIST模型已經(jīng)能很好地識(shí)別單個(gè)數(shù)字,那我們只需要把多個(gè)數(shù)字分開(kāi),一個(gè)一個(gè)地讓MNIST模型進(jìn)行識(shí)別就好了。這樣,我們就引入了一個(gè)新的子問(wèn)題,即是“多個(gè)手寫(xiě)數(shù)字的分割”。

    子問(wèn)題:分割多個(gè)手寫(xiě)數(shù)字

    我們注意到本文介紹的應(yīng)用有一個(gè)特點(diǎn),那就是最終用作輸入的圖形,是用戶當(dāng)場(chǎng)寫(xiě)下的,而非通過(guò)圖片文件導(dǎo)入的靜態(tài)圖片,即我們擁有筆畫(huà)產(chǎn)生過(guò)程中的全部動(dòng)態(tài)信息,比如筆畫(huà)的先后順序,筆畫(huà)的重疊關(guān)系等等??紤]到這些信息,我們可以設(shè)計(jì)一種基本的分割規(guī)則:在水平面上的投影相重疊的筆畫(huà),我們就認(rèn)為它們同屬于一個(gè)數(shù)字。
    筆畫(huà)和水平方向上投影的關(guān)系示意如下圖:

    因此書(shū)寫(xiě)時(shí),就要求不同的數(shù)字之間盡量隔開(kāi)。當(dāng)然為了盡可能處理不經(jīng)意的重疊,我們還可以為重疊部分相對(duì)每一筆畫(huà)的位置設(shè)定一個(gè)閾值,如至少進(jìn)入筆畫(huà)一端的10%以內(nèi)。
    應(yīng)用這樣的規(guī)則后,我們就能比較好的把多個(gè)手寫(xiě)數(shù)字分割開(kāi),并能利用Visual Studio Tools for AI提供的批量推理功能,一次性對(duì)所有分割出的圖形做推理。
    多個(gè)手寫(xiě)數(shù)字識(shí)別的最終效果如圖:

    當(dāng)然,我們對(duì)問(wèn)題的定義還是非常理想化,分割算法也比較簡(jiǎn)單。在實(shí)際應(yīng)用中,我們還經(jīng)常要考慮非二值圖形、噪點(diǎn)、非數(shù)字的判別等等。并且對(duì)手寫(xiě)數(shù)字的分割可能比我們?cè)O(shè)定的規(guī)則要復(fù)雜,因?yàn)樵诂F(xiàn)實(shí)場(chǎng)景中,水平方向上的重疊可能會(huì)影響圖形的涵義。
    將兩個(gè)手寫(xiě)數(shù)字分割開(kāi)這一問(wèn)題,實(shí)際上和經(jīng)典的圖像分割問(wèn)題非常類似。雖然本文示例中的圖像非常簡(jiǎn)單,但仍然可能具有相當(dāng)復(fù)雜的語(yǔ)義需要處理。為此,我們可能需要引入更多的模型,或者擴(kuò)展現(xiàn)有的模型來(lái)正確判斷多個(gè)圖形之間的關(guān)系。

    進(jìn)階

    那么,如果要識(shí)別多個(gè)連寫(xiě)的數(shù)字,或支持字母該怎么做呢?大家多用用也會(huì)發(fā)現(xiàn),如果數(shù)字寫(xiě)得很小,或者沒(méi)寫(xiě)到正中,識(shí)別起來(lái)正確率也會(huì)不高。要解決這些問(wèn)題,做成真正的產(chǎn)品,就不止這一個(gè)模型了。比如在多個(gè)數(shù)字識(shí)別中,可能要根據(jù)經(jīng)驗(yàn)來(lái)切分圖,或者訓(xùn)練另一個(gè)模型來(lái)檢測(cè)并分割數(shù)字。要支持字母,則需要重新訓(xùn)練一個(gè)包含手寫(xiě)字母的模型,并準(zhǔn)備更多的字母的數(shù)據(jù)。要解決字太小的問(wèn)題,還要檢測(cè)一下字的大小,做合適的放大等等。

    我們可以看到,一個(gè)訓(xùn)練出來(lái)的模型本身到一個(gè)實(shí)際的應(yīng)用之間還有不少的功能要實(shí)現(xiàn)。希望我們這一系列的介紹,能夠幫助大家將機(jī)器學(xué)習(xí)的概念帶入到傳統(tǒng)的編程領(lǐng)域中,做出更聰明的產(chǎn)品。

    ?

    ?

    此時(shí),界面會(huì)提示注冊(cè)Azure,因?yàn)槎ㄖ苹曈X(jué)服務(wù)實(shí)際上是Azure提供的一項(xiàng)云服務(wù),正式使用這項(xiàng)服務(wù)需要有Azure訂閱。
    不過(guò)我們現(xiàn)在只是免費(fèi)試用,所以選擇Continue With trial,如果在根據(jù)這篇博客流程做完了一個(gè)小應(yīng)用之后,你覺(jué)得確實(shí)需要使用這項(xiàng)服務(wù),那么你可以去注冊(cè)Azure賬號(hào),獲取Azure訂閱。

    三、創(chuàng)建定制化視覺(jué)服務(wù)項(xiàng)目

    點(diǎn)擊New Project,填寫(xiě)項(xiàng)目信息。

    這里不妨以一個(gè)熊的分類模型作為例子來(lái)實(shí)踐吧。

    填寫(xiě)好Name和Description,這里Name不妨填寫(xiě)為BearClassification。

    隨后選擇Classification和General(compact),點(diǎn)擊Create

    截圖操作
    在Project Type一欄,定制化視覺(jué)服務(wù)提供了識(shí)別和分類兩種服務(wù),另外提供了多種識(shí)別場(chǎng)景,其中末尾帶有(compact),也即壓縮字樣的三種。
    壓縮模型,顧名思義,模型占用的空間更少,運(yùn)行更快,甚至可以放到手機(jī)這種移動(dòng)設(shè)備里。
    當(dāng)然,會(huì)有一個(gè)小問(wèn)題就是精確度會(huì)受影響。導(dǎo)出模型后,模型文件的使用是沒(méi)有任何限制的,而其余的幾種場(chǎng)景只能通過(guò)調(diào)用API來(lái)進(jìn)行預(yù)測(cè),由于當(dāng)前屬于免費(fèi)試用,因此這種方式有10000次調(diào)用上限。
    由于分類服務(wù)需要準(zhǔn)備用來(lái)訓(xùn)練的數(shù)據(jù)集,請(qǐng)自行準(zhǔn)備幾種不同的熊的照片,將同種的熊放在以這種熊的名字命名的文件夾里,最后再將這些文件夾放在一個(gè)data文件夾中。然后點(diǎn)擊Add images
    選擇一種熊的全部照片,然后創(chuàng)建對(duì)應(yīng)的標(biāo)簽,點(diǎn)擊Up load xxx files
    在添加了所有的數(shù)據(jù)集和標(biāo)簽之后,點(diǎn)擊網(wǎng)頁(yè)上方的Train,開(kāi)始訓(xùn)練模型。
    一小會(huì)之后,點(diǎn)擊網(wǎng)頁(yè)上方的performance,就可以看到這次訓(xùn)練的結(jié)果了。
    這里簡(jiǎn)單解釋一下Precision和Recall,這是兩個(gè)評(píng)估模型好壞的主要指標(biāo)。
    簡(jiǎn)單來(lái)說(shuō),兩個(gè)數(shù)都是越大越好。在這個(gè)項(xiàng)目中,以Brown Bear為例:
    Precision就是識(shí)別出來(lái)的結(jié)果的準(zhǔn)確率,即在所有被識(shí)別為棕熊的圖片中真正有棕熊的圖片所占的比例;而Recall則是測(cè)試結(jié)果中正確識(shí)別為棕熊的圖片占測(cè)試集中所有棕熊圖片的比例。
    這時(shí)再點(diǎn)擊界面右上角的齒輪,可以看到免費(fèi)用戶每個(gè)項(xiàng)目能夠使用的服務(wù)額度:
    一共可以上傳5000張圖片,創(chuàng)建50個(gè)不同標(biāo)簽,保存10次迭代的結(jié)果。
    這十次迭代有什么用呢?當(dāng)需要增刪標(biāo)簽、給標(biāo)簽添加或刪除訓(xùn)練圖片時(shí),這次再訓(xùn)練,就會(huì)花費(fèi)掉一次迭代。
    這些都是當(dāng)前項(xiàng)目的總數(shù)而不是累計(jì)值。對(duì)于一般的免費(fèi)用戶,這基本上就相當(dāng)于你可以隨意使用這項(xiàng)服務(wù)了,如果有大量的訓(xùn)練數(shù)據(jù),那么建議您還是訂閱Azure云服務(wù),Azure秉持著使用多少,收費(fèi)多少的原則,即使收費(fèi),也仍然良心。
    然后選擇剛剛訓(xùn)練好的這次迭代,點(diǎn)擊Export。
    視覺(jué)認(rèn)知服務(wù)一共提供了適用于四種平臺(tái)的模型導(dǎo)出,對(duì)三大操作系統(tǒng)都能支持。
    選擇ONNX,這個(gè)格式由微軟、臉書(shū)、亞馬遜等大廠鼎力支持,點(diǎn)擊Export,等待服務(wù)器把模型導(dǎo)出,然后點(diǎn)擊Download,即可下載模型。最后得到了一個(gè).onnx文件,然后就可以使用它來(lái)構(gòu)建應(yīng)用了。

    如果需要上傳大量的圖片數(shù)據(jù),那么點(diǎn)擊鼠標(biāo)的方式肯定不夠方便,微軟同時(shí)提供了代碼的支持,詳見(jiàn)官方文檔:

    https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/home

    四、使用Windows ML構(gòu)建應(yīng)用

    這次不寫(xiě)Winform程序,而是搭建一個(gè)識(shí)別熊的UWP的AI應(yīng)用,通過(guò)這個(gè)應(yīng)用來(lái)教大家如何使用Windows ML導(dǎo)入模型。

    這部分的代碼已經(jīng)完成了,請(qǐng)使用git克隆samples-for-ai到本地,UWP項(xiàng)目的代碼在/samples-for-ai/projects/BearClassificationUWPDemo中。

    在運(yùn)行代碼之前,請(qǐng)先安裝開(kāi)發(fā)UWP所需的工作負(fù)載,流程如下:

  • 打開(kāi)Visual Studio Installer
  • 在工作負(fù)載中勾選Universal Windows Platform development
  • 在單個(gè)組件一欄中下拉到最下方,確認(rèn)Windows 10 SDK(10.0.17134.0)已被勾選上,這是使用Windows ML開(kāi)發(fā)的核心組件



  • 另外,請(qǐng)將您的操作系統(tǒng)更新到1803版本,否則本程序?qū)⒉荒馨惭b。

    如果您將進(jìn)行類似的開(kāi)發(fā),請(qǐng)將UWP項(xiàng)目設(shè)置成最低運(yùn)行目標(biāo)版本為17134,否則對(duì)于版本低于17134的用戶,在運(yùn)行時(shí)會(huì)出現(xiàn):

    "Requested Windows Runtime type 'Windows.AI.MachineLearning.Preview.LearningModelPreview' is not registered."

    詳見(jiàn):https://github.com/MicrosoftDocs/windows-uwp/issues/575

    安裝需要的時(shí)間比較長(zhǎng),可以先看看UWP的視頻教程,做一做頭腦預(yù)熱: https://www.bilibili.com/video/av7997007

    Visual Studio 和 Windows 更新完畢后,我們打開(kāi)CustomVisionApp.sln,運(yùn)行這個(gè)程序。

    你可以從必應(yīng)上查找一些熊的圖片,復(fù)制圖片的URL,粘貼到輸入框內(nèi),然后點(diǎn)擊識(shí)別按鈕;或者,點(diǎn)擊瀏覽按鈕,選擇一張本地圖片,點(diǎn)擊確定,你就可以看到識(shí)別結(jié)果了:




    現(xiàn)在來(lái)看看這個(gè)程序是怎么實(shí)現(xiàn)的。

    我們來(lái)梳理一下這個(gè)應(yīng)用的邏輯,這個(gè)應(yīng)用的邏輯與上一篇博客中的手寫(xiě)數(shù)字識(shí)別大體上是一樣的:

  • 導(dǎo)入模型
  • 按下按鈕后,通過(guò)某種方式獲取要用來(lái)識(shí)別的圖片
  • 將圖片交給模型識(shí)別
  • 將圖片與識(shí)別結(jié)果展示在界面上
  • 1. 文件結(jié)構(gòu):

    文件結(jié)構(gòu)見(jiàn)下圖:

    • Assets文件夾存放了這個(gè)項(xiàng)目的資產(chǎn)文件,比如程序圖標(biāo)等等,在本示例程序中,.onnx文件也存放在其中。
    • Strings文件夾存放了用于本地化與全球化資源文件,這樣可以支持不同的語(yǔ)言。
    • ViewModel文件夾中則存放了本項(xiàng)目的關(guān)鍵代碼,整個(gè)程序運(yùn)行的邏輯都在ResultViewModel.cs中
    • BearClassification.cs則是系統(tǒng)自動(dòng)生成的模型包裝文件
    • MainPage.xaml是程序的UI布局文件

    2. 核心代碼一:BearClassification.cs

    這部分的代碼是自動(dòng)生成的,教程詳見(jiàn)鏈接:https://docs.microsoft.com/zh-cn/windows/uwp/machine-learning/

  • 將.onnx文件添加到UWP項(xiàng)目的Assets文件夾中,隨后將自動(dòng)生成一個(gè)對(duì)應(yīng)的包裝.cs文件,在本例中為BearClassification.cs。
  • 由于目前存在的一些BUG,生成的類名會(huì)有亂碼,需要將亂碼替換為別的字符串。
  • 修改BearClassification.onnx的屬性->生成操作,將其改為內(nèi)容,確保在生成時(shí),能夠調(diào)用到這個(gè)模型。
  • 生成的文件共有三個(gè)類:

    • BearClassificationModelInput:定義了該模型的輸入格式是VideoFrame
    • BearClassificationModelOutput:定義了該模型的輸出為一個(gè)list和一個(gè)dict,list存儲(chǔ)了所有標(biāo)簽按照probability降序排列,dict則存儲(chǔ)了標(biāo)簽與概率的鍵值對(duì)
    • BearClassificationModel:定義了該模型的初始化函數(shù)與推理函數(shù)
    // 模型的輸入格式為VideoFrame public sealed class BearClassificationModelInput { public VideoFrame data { get; set; } } // 模型的輸出格式,其中包含了一個(gè)列表:classLabel和一個(gè)字典:loss // 列表中包含每種熊的標(biāo)簽,按照概率降序排列 // 字典中則包含了每種熊的標(biāo)簽和其概率,按照用戶在創(chuàng)建模型時(shí)的添加順序排列 public sealed class BearClassificationModelOutput { public IList<string> classLabel { get; set; } public IDictionary<string, float> loss { get; set; } public BearClassificationModelOutput() { this.classLabel = new List<string>(); this.loss = new Dictionary<string, float>(){...} } } // 模型的包裝類,提供了兩個(gè)函數(shù) // CreateBearClassificationModel:從.onnx文件中創(chuàng)建模型 // EvaluateAsync:對(duì)輸入對(duì)象進(jìn)行評(píng)估,并返回結(jié)果 public sealed class BearClassificationModel { private LearningModelPreview learningModel; public static async Task<BearClassificationModel> CreateBearClassificationModel(StorageFile file) { ... } public async Task<BearClassificationModelOutput> EvaluateAsync(BearClassificationModelInput input) { ... } }

    3. 核心代碼二:ResultViewModel.cs

    通過(guò)之前的運(yùn)行可以發(fā)現(xiàn):每次識(shí)別圖片,UI中的內(nèi)容需要進(jìn)行頻繁地更新,為了簡(jiǎn)化更新控件內(nèi)容的代碼邏輯,這個(gè)程序使用UWP開(kāi)發(fā)中常用的MVVM(model-view-viewmodel)這一組合模式開(kāi)發(fā),使用“綁定”的方式,將UI控件與數(shù)據(jù)綁定起來(lái),讓數(shù)據(jù)與界面自動(dòng)地同步更新,簡(jiǎn)化了代碼邏輯,保證了ResultViewModel職責(zé)單一。

    綁定源(ResultViewMode.cs)綁定目標(biāo)(MainPage.xaml)
    string BearUrlTextBox InputUriBox
    ObservableCollection?ResultsListView ResultArea
    BitmapImage BearImageImage DisplayArea
    string DescriptionTextBox DescribeArea
    ICommand RecognizeCommandButton RecognizeButton
    ICommand BrowseCommandButton BrowseButton

    綁定好之后,程序還需要一系列邏輯才能運(yùn)行,這里就包括:

    導(dǎo)入與初始化模型:

    在程序一開(kāi)始,需要調(diào)用LoadModel進(jìn)行模型初始化工作。

    private async void LoadModel() { //導(dǎo)入模型文件,實(shí)例化模型對(duì)象 StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/BearClassification.onnx")); model = await BearClassificationModel.CreateBearClassificationModel(modelFile); }

    圖片推理:

    本程序提供了兩種方式訪問(wèn)圖片資源:

  • 通過(guò)URL訪問(wèn)網(wǎng)絡(luò)圖片
  • 通過(guò)文件選取器訪問(wèn)本地圖片
  • private async void EvaluateNetPicAsync() { try { ... //BearClassification要求的輸入格式為VideoFrame //程序需要以stream的形式從URL中讀取數(shù)據(jù),生成VideoFrame var response = await new HttpClient().GetAsync(BearUrl); var stream = await response.Content.ReadAsStreamAsync(); BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream.AsRandomAccessStream()); VideoFrame imageFrame = VideoFrame.CreateWithSoftwareBitmap(await decoder.GetSoftwareBitmapAsync()); //將videoframe交給函數(shù)進(jìn)行識(shí)別 EvaluateAsync(imageFrame); } catch (Exception ex){ ... } } private async void EvaluateLocalPicAsync() { try { ... // 從文件選取器中獲得文件 StorageFile file = await openPicker.PickSingleFileAsync(); var stream = await file.OpenReadAsync(); ... // 生成videoframe BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); VideoFrame imageFrame = VideoFrame.CreateWithSoftwareBitmap(await decoder.GetSoftwareBitmapAsync()); // 將videoframe交給函數(shù)進(jìn)行識(shí)別 EvaluateAsync(imageFrame); } catch (Exception ex){ ... } } private async void EvaluateAsync(VideoFrame imageFrame) { //將VideoFrame包裝進(jìn)BearClassificationModelInput中,交給模型識(shí)別 //模型的輸出格式為BearClassificationModelOutput //其中包含一個(gè)列表,存儲(chǔ)了每種熊的標(biāo)簽名稱,按照probability降序排列 //和一個(gè)字典,存儲(chǔ)了每種熊的標(biāo)簽,和對(duì)應(yīng)的probability //這里取出輸出中的字典,并對(duì)其進(jìn)行降序排列 var result = await model.EvaluateAsync(new BearClassificationModelInput() { data = imageFrame }); var resultDescend = result.loss.OrderByDescending(p => p.Value).ToDictionary(p => p.Key, o => o.Value).ToList(); //根據(jù)結(jié)果生成圖片描述 Description = DescribResult(resultDescend.First().Key, resultDescend.First().Value); Results.Clear(); foreach (KeyValuePair<string, float> kvp in resultDescend) { Results.Add(resourceLoader.GetString(kvp.Key) + " : " + kvp.Value.ToString("0.000")); } }

    五、使用其他方法構(gòu)建應(yīng)用

    同樣,用之前使用Visual Studio Tools for AI提供的推理類庫(kù)生成器也能夠構(gòu)建相似的應(yīng)用。想看視頻教程的請(qǐng)移步:

    【教程】普通程序員一小時(shí)入門(mén)AI應(yīng)用——看圖識(shí)熊(不含公式,包會(huì))

    該教程講解了如何使用模型瀏覽工具Netron

    想看圖文教程請(qǐng)繼續(xù)往下看:

    1. 界面設(shè)計(jì)

    創(chuàng)建Windows窗體應(yīng)用(.NET Framework)項(xiàng)目,這里給項(xiàng)目起名ClassifyBear。

    注意,項(xiàng)目路徑不要包含中文。

    在解決方案資源管理器中找到Form1.cs,雙擊,打開(kāi)界面設(shè)計(jì)器。從工具箱中向Form中依次拖入控件并調(diào)整,最終效果如下圖所示:

    左側(cè)從上下到依次是:

    • Label控件,將內(nèi)容改為“輸入要識(shí)別的圖片地址:”
    • TextBox控件,可以將控件拉長(zhǎng)一些,方便輸入U(xiǎn)RL
    • Button控件,將內(nèi)容改為“識(shí)別”
    • Lable控件,將label的內(nèi)容清空,用來(lái)顯示識(shí)別后的結(jié)果。因?yàn)閘abel也沒(méi)有邊框,所以在界面看不出來(lái)??梢詫⒋丝丶淖煮w調(diào)大一些,能更清楚的顯示推理結(jié)果。

    右側(cè)的控件是一個(gè)PictureBox,用來(lái)預(yù)覽輸入的圖片,同時(shí),我們也從這個(gè)控件中取出對(duì)應(yīng)的圖片數(shù)據(jù),傳給我們的模型推理類庫(kù)去推理。建議將控件屬性的SizeMode更改為StretchImage,并將控件長(zhǎng)和寬設(shè)置為同樣的值,保持一個(gè)正方形的形狀,這樣可以方便我們直觀的了解模型的輸入,因?yàn)樵谇懊娌榭茨P托畔⒌臅r(shí)候也看到了,該模型的輸入圖片應(yīng)是正方形。

    2. 查看模型信息

    在將模型集成到應(yīng)用之前,我們先來(lái)看一看模型的基本信息,比如模型需要什么樣的輸入和輸出。打開(kāi)Visual Studio中的AI工具菜單,選擇模型工具下的查看模型,會(huì)啟動(dòng)Netron模型查看工具。該工具默認(rèn)不隨Tools for AI擴(kuò)展一起安裝,第一次使用時(shí)可以按照提示去下載并安裝。

    Netron打開(kāi)后,點(diǎn)擊Open model選擇打開(kāi)之前下載的BearModel.onnx文件。然后點(diǎn)擊左上角的漢堡菜單顯示模型的輸入輸出。

    上圖中可以看到該模型需要的輸入data是一個(gè)float數(shù)組,數(shù)組中要求依次放置227*227圖片的所有藍(lán)色分量、綠色分量和紅色分量,后面程序中調(diào)用時(shí)要對(duì)輸入圖片做相應(yīng)的處理。

    上圖中還可以看到輸出有兩個(gè)值,第一個(gè)值loss包含所有分類的得分,第二個(gè)值classLabel是確定的分類的標(biāo)簽,這里只需用到第二個(gè)輸出即可。

    3. 封裝模型推理類庫(kù)

    由于目前模型推理用到的庫(kù)只支持x64,所以這里需要將解決方案平臺(tái)設(shè)置為x64。打開(kāi)解決方案資源管理器,在解決方案上點(diǎn)右鍵,選擇配置管理器。

    在配置管理器對(duì)話框中,點(diǎn)開(kāi)活動(dòng)解決方案平臺(tái)下拉框,選擇新建

    在新建解決方案平臺(tái)對(duì)話框中,輸入新平臺(tái)名x64,點(diǎn)擊確定即可

    下面添加模型推理類庫(kù),再次打開(kāi)解決方案資源管理器,在解決方案上點(diǎn)右鍵,選擇添加,然后選擇新建項(xiàng)目。

    添加新項(xiàng)目對(duì)話框中,將左側(cè)目錄樹(shù)切換到AI Tools下的Inference,右側(cè)選擇模型推理類庫(kù),下方填入項(xiàng)目名稱,這里用Model作為名稱。

    確定以后會(huì)出現(xiàn)檢查環(huán)境的進(jìn)度條,耐心等待一會(huì)就可以出現(xiàn)模型推理類庫(kù)創(chuàng)建向?qū)?duì)話框。

    點(diǎn)擊模型路徑后面的瀏覽按鈕,選擇前面下載的BearModel.onnx模型文件。

    注意,這里會(huì)出現(xiàn)幾處錯(cuò)誤提示,我們需要手動(dòng)修復(fù)一下。首先會(huì)看到“發(fā)現(xiàn)不支持的張量的數(shù)據(jù)類型”提示,可以直接點(diǎn)確定。

    確定后如果彈出“正在創(chuàng)建項(xiàng)目…”的進(jìn)度條,一直不消失,這里只需要在類名后面的輸入框內(nèi)點(diǎn)一下,切換下焦點(diǎn)即可。

    然后,我們來(lái)手動(dòng)配置一下模型的相關(guān)信息。類名輸入框中填入模型推理類的名字,這里用Bear。然后點(diǎn)擊推理接口右側(cè)的添加按鈕,在彈出的編輯接口對(duì)話框中,隨便起個(gè)方法名,這里用Infer。輸入節(jié)點(diǎn)的變量名和張量名填入data,輸出節(jié)點(diǎn)的變量名和張量名填入classLabel,字母拼寫(xiě)要和之前查看模型時(shí)看到的拼寫(xiě)一模一樣。然后一路確定,再耐心等待一會(huì),就可以在解決方案資源管理器看到新建的模型推理類庫(kù)了。

    還有一處錯(cuò)誤需要手動(dòng)修復(fù)一下,切換到解決方案資源管理器,在Model項(xiàng)目的Bear目錄下找到Bear.cs雙擊打開(kāi),將函數(shù)Infer的最后一行

    return r0;

    替換為

    List<List<string>> results = new List<List<string>>(); results.Add(r0); return results;

    至此,模型推理類庫(kù)封裝完成。相信Tools for AI將來(lái)的版本中會(huì)修復(fù)這些問(wèn)題,直接選擇模型文件創(chuàng)建模型推理類庫(kù)就可以了。

    4. 使用模型推理類庫(kù)

    首先添加對(duì)模型推理類庫(kù)的引用,切換到解決方案資源管理器,在ClassifyBear項(xiàng)目的引用上點(diǎn)右鍵,選擇添加引用。

    在彈出的引用管理器對(duì)話框中,選擇項(xiàng)目、解決方案,右側(cè)可以看到剛剛創(chuàng)建的模型推理類庫(kù),勾選該項(xiàng)目,點(diǎn)擊確定即可。

    在Form1.cs上點(diǎn)右鍵,選擇查看代碼,打開(kāi)Form1.cs的代碼編輯窗口。

    添加兩個(gè)成員變量

    // 使用Netron查看模型,得到模型的輸入應(yīng)為227*227大小的圖片 private const int imageSize = 227; // 模型推理類 private Model.Bear model;

    回到Form1的設(shè)計(jì)界面,雙擊Form的標(biāo)題欄,會(huì)自動(dòng)跳轉(zhuǎn)到代碼頁(yè)面并添加了Form1_Load方法,在其中初始化模型推理對(duì)象

    private void Form1_Load(object sender, EventArgs e) { // 初始化模型推理對(duì)象 model = new Model.Bear(); }

    回到Form1的設(shè)計(jì)界面,雙擊識(shí)別按鈕,會(huì)自動(dòng)跳轉(zhuǎn)到代碼頁(yè)面并添加了button1_Click方法,在其中添加以下代碼:

    首先,每次點(diǎn)擊識(shí)別按鈕時(shí)都先將界面上顯示的上一次的結(jié)果清除

    // 識(shí)別之前先重置界面顯示的內(nèi)容 label1.Text = string.Empty; pictureBox1.Image = null; pictureBox1.Refresh();

    然后,讓圖片控件加載圖片

    bool isSuccess = false; try {pictureBox1.Load(textBox1.Text);isSuccess = true; } catch (Exception ex) { MessageBox.Show($"讀取圖片時(shí)出現(xiàn)錯(cuò)誤:{ex.Message}"); throw; }

    如果加載成功,將圖片數(shù)據(jù)傳給模型推理類庫(kù)來(lái)推理。

    if (isSuccess) {// 圖片加載成功后,從圖片控件中取出227*227的位圖對(duì)象Bitmap bitmap = new Bitmap(pictureBox1.Image, imageSize, imageSize);float[] imageArray = new float[imageSize * imageSize * 3]; // 按照先行后列的方式依次取出圖片的每個(gè)像素值 for (int y = 0; y < imageSize; y++) { for (int x = 0; x < imageSize; x++) { var color = bitmap.GetPixel(x, y); // 使用Netron查看模型的輸入發(fā)現(xiàn) // 需要依次放置227 *227的藍(lán)色分量、227*227的綠色分量、227*227的紅色分量 imageArray[y * imageSize + x] = color.B; imageArray[y * imageSize + x + 1* imageSize * imageSize] = color.G; imageArray[y * imageSize + x + 2* imageSize * imageSize] = color.R; } } // 模型推理類庫(kù)支持一次推理多張圖片,這里只使用一張圖片 var inputImages = new List<float[]>(); inputImages.Add(imageArray); // 推理結(jié)果的第一個(gè)First()是取第一張圖片的結(jié)果 // 之前定義的輸出只有classLabel,所以第二個(gè)First()就是分類的名字 label1.Text = model.Infer(inputImages).First().First(); }

    注意,這里的數(shù)據(jù)轉(zhuǎn)換一定要按照前面查看的模型的信息來(lái)轉(zhuǎn)換,圖片大小需要長(zhǎng)寬都是227像素,并且要依次放置所有的藍(lán)色分量、所有的綠色分量、所有的紅色分量,如果順序不正確,不能達(dá)到最佳的推理結(jié)果。

    5. 測(cè)試

    編譯運(yùn)行,然后在網(wǎng)上找一張熊的圖片,把地址填到輸入框內(nèi),然后點(diǎn)擊識(shí)別按鈕,就可以看到識(shí)別的結(jié)果了。注意,這個(gè)URL應(yīng)該是圖片的URL,而不是包含該圖片的網(wǎng)頁(yè)的URL。

    六、下一步?

    本篇博客我們學(xué)會(huì)了使用定制化視覺(jué)服務(wù)與在UWP應(yīng)用中集成定制化視覺(jué)服務(wù)模型。這里我提兩個(gè)課后習(xí)題:(想不到吧)

  • 當(dāng)訓(xùn)練含有多個(gè)標(biāo)簽、大量圖片數(shù)據(jù)時(shí),如何做到一鍵上傳圖片并訓(xùn)練?

  • 如何通過(guò)調(diào)用REST接口的方式完成對(duì)圖片的推理?

  • 提示:請(qǐng)看看定制化視覺(jué)服務(wù)給我們提供的API,這一題肯定是要寫(xiě)代碼做的
    https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/home

    加油!

    七、內(nèi)容預(yù)告

    接下來(lái)我們將會(huì)陸續(xù)推出:

  • 微軟認(rèn)知服務(wù)使用教程
  • 模型訓(xùn)練及推理的通常流程及原理
  • 模型轉(zhuǎn)換工具的使用
  • 開(kāi)放AI平臺(tái)-大規(guī)模計(jì)算資源調(diào)度系統(tǒng)
  • 請(qǐng)?jiān)谙路搅粞?#xff0c;告知我們您最想閱讀哪個(gè)教程,我們將優(yōu)先考慮。

    如果您有別的想要了解的內(nèi)容,也可以在評(píng)論區(qū)留言。

    ?

    AI應(yīng)用開(kāi)發(fā)基礎(chǔ)傻瓜書(shū)系列的目錄~

    寫(xiě)在前面,為啥要出這個(gè)系列的教程呢?

    總的說(shuō)來(lái),我們現(xiàn)在有了很多非常厲害的深度學(xué)習(xí)框架,比如tensorflow,pytorch,paddlepaddle,caffe2等等等等。然而,我們用這些框架在搭建我們自己的深度學(xué)習(xí)模型的時(shí)候,到底做了一些什么樣的操作呢?我們?cè)噲D去閱讀框架的源碼來(lái)理解框架到底幫助我們做了些什么,但是……很難!很難!很難!因?yàn)樯疃葘W(xué)習(xí)是需要加速啦,分布式計(jì)算啦,所以框架做了很多很多的優(yōu)化,也讓像我們這樣的小白難以理解這些框架的源碼。所以,為了幫助大家更進(jìn)一步的了解神經(jīng)網(wǎng)絡(luò)模型的具體內(nèi)容,我們整理了這樣一個(gè)系列的教程。

    對(duì)于這份教程的內(nèi)容,如果沒(méi)有額外的說(shuō)明,我們通常使用如下表格的命名約定

    符號(hào)含義
    X輸入樣本
    Y輸入樣本的標(biāo)簽
    Z各層運(yùn)算的結(jié)果
    A激活函數(shù)結(jié)果
    大寫(xiě)字母矩陣或矢量,如A,W,B
    小寫(xiě)字母變量,標(biāo)量,如a,w,b

    適用范圍

    沒(méi)有各種基礎(chǔ)想學(xué)習(xí)卻無(wú)從下手哀聲嘆氣的玩家,請(qǐng)按時(shí)跟蹤最新博客,推導(dǎo)數(shù)學(xué)公式,跑通代碼,并及時(shí)提出問(wèn)題,以求最高療效;

    深度學(xué)習(xí)小白,有直觀的人工智能的認(rèn)識(shí),強(qiáng)烈的學(xué)習(xí)欲望和需求,請(qǐng)?jiān)诓┛偷幕A(chǔ)上配合代碼食用,效果更佳;

    調(diào)參師,訓(xùn)練過(guò)模型,調(diào)過(guò)參數(shù),想了解框架內(nèi)各層運(yùn)算過(guò)程,給玄學(xué)的調(diào)參之路添加一點(diǎn)心理保障;

    超級(jí)高手,提出您寶貴的意見(jiàn),給廣大初學(xué)者指出一條明路!

    前期準(zhǔn)備

    環(huán)境:

    windows(Linux也行),python(最好用3),anaconda(或者自己裝numpy之類的),tensorflow(嫌麻煩地請(qǐng)看這里《AI應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn) - 從零開(kāi)始配置環(huán)境》,tools for AI(按照鏈接教程走的就不用管這個(gè)了)。

    自己:

    清醒的頭腦(困了的同學(xué)請(qǐng)自覺(jué)泡茶),紙和筆(如果像跟著推公式的話),鬧鐘(防止久坐按時(shí)起來(lái)轉(zhuǎn)轉(zhuǎn)),厚厚的衣服(有暖氣的同學(xué)請(qǐng)忽略)

    目錄

    • 1-神經(jīng)網(wǎng)絡(luò)的基本工作原理
    • 2-神經(jīng)網(wǎng)絡(luò)中反向傳播與梯度下降的基本概念
    • 3-基本數(shù)學(xué)導(dǎo)數(shù)公式
    • 4-激活函數(shù)
    • 5-損失函數(shù)
    • 6-單入單出的單層神經(jīng)網(wǎng)絡(luò)能做什么
    • 7-單入單出的雙層神經(jīng)網(wǎng)絡(luò)能做什么
    • 徒手搭建神經(jīng)網(wǎng)絡(luò)
    • 徒手搭建CNN網(wǎng)絡(luò)
    • 徒手搭建RNN網(wǎng)絡(luò)
    • 模型內(nèi)部

    ?

    ?

    與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的AI应用开发实战(转)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日韩三级一区二区 | 精品伦理一区二区 | 在线观看国产网站 | 美女爱爱视频 | 久久久久无码国产精品 | 毛片黄色一级 | 天天撸天天操 | 老司机在线观看视频 | 人妻精品久久久久中文 | 黄色大片黄色大片 | 日韩欧美中文字幕精品 | av资源中文在线 | www.色午夜.com| 国产精品一区在线观看你懂的 | 国精产品99永久一区一区 | 五月天三级 | 粉嫩小箩莉奶水四溅在线观看 | 欧美精品一级片 | 久久久久麻豆 | 屁屁影院一区二区三区 | 日本伊人久久 | av一区二区三区四区 | 日本呦呦 | 无码一区二区波多野结衣播放搜索 | 污视频网址 | 激情视频区 | 亚洲欧美日韩精品色xxx | 天天做天天爱 | 精品国产999久久久免费 | 无码一区二区三区视频 | 欧美jjzz | 精品一区二区三区久久 | 国内毛片视频 | 亚洲国产精品成人综合色在线婷婷 | 久久久久久av无码免费网站下载 | 九一爱爱| 刘亦菲国产毛片bd | 亚洲精品国产一区 | 久久久久久无码精品人妻一区二区 | 91一区二区三区四区 | 男女深夜福利 | 亚洲中文字幕一区二区在线观看 | 日韩avav | 亚洲精品视频大全 | 久久国产精品影院 | 黄频在线看 | 超碰888| 欧美视频一区二区三区在线观看 | 亚洲精品高清在线观看 | 空姐毛片 | 欧美日韩国产中文 | 成人久久久精品国产乱码一区二区 | 激情国产在线 | 国产crm系统91在线 | 免费在线观看一区二区 | 肉丝超薄少妇一区二区三区 | 超级碰碰97 | 电影寂寞少女免费观看 | 黄色a区 | 亚洲精品中文字幕乱码三区 | 少妇久久久久久久 | 天天草av | 亚洲黄色av| 好吊日免费视频 | 国产日韩在线观看一区 | 国产精品一区在线播放 | 国产av无码专区亚洲a∨毛片 | 国产婷婷色一区二区在线观看 | 在线视频亚洲 | 国产原创在线播放 | 91在线精品入口 | 91丨九色丨海角社区 | 日本一区二区三区免费在线观看 | 久草视频在线观 | 宅男噜噜噜666在线观看 | 精品国产乱码久久久久久牛牛 | 性欧美丰满熟妇xxxx性仙踪林 | 艳母动漫在线播放 | 国产日韩欧美中文字幕 | 91爱爱网站 | 欧美 日韩 综合 | 国产激情成人 | 黄色一级视屏 | 国产自偷自拍视频 | 香蕉视频成人在线 | 免费久久 | 国产视频不卡 | av在线免费观看一区 | 婷婷777| 九七伦理电影 | 最新天堂在线视频 | 成人性做爰aaa片免费 | 日本不卡专区 | 亚洲香蕉视频 | 亲嘴扒胸摸屁股激烈网站 | heyzo朝桐光一区二区 | 亚洲av无码精品色午夜果冻不卡 | 欧美黄色a | 精品国产中文字幕 |