1. 程式人生 > >AI應用開發實戰系列之四

AI應用開發實戰系列之四

最近在看機器學習和AI

轉載於:https://blog.csdn.net/SoftwareTeacher/article/details/80954568

AI應用開發實戰 - 定製化視覺服務的使用

本篇教程的目標是學會使用定製化視覺服務,並能在UWP應用中整合定製化視覺服務模型。

聯絡我們 
[email protected]

零、定製化視覺服務簡介

有的時候,在構建應用的過程中,在缺少強大計算資源與高效能演算法的情況下,我們不一定需要自己從零開始訓練模型。我們需要用的一些輪子,已經有人給我們造好了。

就比如:

微軟提供的定製化視覺服務。

在機器學習應用中,任何情況下都需要一個或大或小的模型。而怎麼得到這個模型是其中最複雜的部分。定製化視覺服務相當於在雲端提供了一個生成模型的方法,把模型相關的複雜的演算法都簡化了。同時,它不僅能夠讓使用者自己管理訓練資料,定義自己的分類問題,而且支援一鍵訓練,一鍵匯出模型;不僅能匯出適配所有主流框架的模型,而且可以生成REST介面,讓程式通過介面獲取圖片分類的結果。這樣給使用者提供了多種整合模型的方法和選擇,儘可能滿足使用者的各種需求,這也正是定製化視覺服務的強大之處。同時,通過定製化服務來生成模型,需要的資料量可以非常少,訓練過程相對來說也很快。使用上也是非常的方便。

本篇教程,就教大家如何使用定製化視覺服務。

一、準備微軟賬號

使用該服務需要準備微軟賬號,可以直接在定製化視覺服務官方地址上建立。

二、建立定製化視覺服務

截圖操作
進入官方網站,點選SIGN IN,目前定製化視覺服務提供了免費試用版,可以體驗定製化視覺服務。
登入後,然後介面會提示要求同意一些條約。
條約的大致內容就是,個人必須在微軟要求的規則下使用微軟提供的這項服務。請勾選agree
此時,介面會提示註冊Azure,因為定製化視覺服務實際上是Azure提供的一項雲服務,正式使用這項服務需要有Azure訂閱。
不過我們現在只是免費試用,所以選擇Continue With trial,如果在根據這篇部落格流程做完了一個小應用之後,你覺得確實需要使用這項服務,那麼你可以去註冊Azure賬號,獲取Azure訂閱。

三、建立定製化視覺服務專案

點選New Project,填寫專案資訊。

這裡不妨以一個熊的分類模型作為例子來實踐吧。

填寫好NameDescription,這裡Name不妨填寫為BearClassification

隨後選擇ClassificationGeneral(compact),點選Create

截圖操作
Project Type一欄,定製化視覺服務提供了識別和分類兩種服務,另外提供了多種識別場景,其中末尾帶有(compact),也即壓縮字樣的三種。
壓縮模型,顧名思義,模型佔用的空間更少,執行更快,甚至可以放到手機這種移動裝置裡。
當然,會有一個小問題就是精確度會受影響。匯出模型後,模型檔案的使用是沒有任何限制的,而其餘的幾種場景只能通過呼叫API來進行預測,由於當前屬於免費試用
,因此這種方式有10000次呼叫上限。
由於分類服務需要準備用來訓練的資料集,請自行準備幾種不同的熊的照片,將同種的熊放在以這種熊的名字命名的資料夾裡,最後再將這些資料夾放在一個data資料夾中。然後點選Add images
選擇一種熊的全部照片,然後建立對應的標籤,點選Up load xxx files
在添加了所有的資料集和標籤之後,點選網頁上方的Train,開始訓練模型。
一小會之後,點選網頁上方的performance,就可以看到這次訓練的結果了。
這裡簡單解釋一下Precision和Recall,這是兩個評估模型好壞的主要指標。
簡單來說,兩個數都是越大越好。在這個專案中,以Brown Bear為例:
Precision就是識別出來的結果的準確率,即在所有被識別為棕熊的圖片中真正有棕熊的圖片所佔的比例;而Recall則是測試結果中正確識別為棕熊的圖片佔測試集中所有棕熊圖片的比例。
這時再點選介面右上角的齒輪,可以看到免費使用者每個專案能夠使用的服務額度:
一共可以上傳5000張圖片,建立50個不同標籤,儲存10次迭代的結果。
這十次迭代有什麼用呢?當需要增刪標籤、給標籤新增或刪除訓練圖片時,這次再訓練,就會花費掉一次迭代。
這些都是當前專案的總數而不是累計值。對於一般的免費使用者,這基本上就相當於你可以隨意使用這項服務了,如果有大量的訓練資料,那麼建議您還是訂閱Azure雲服務,Azure秉持著使用多少,收費多少的原則,即使收費,也仍然良心。
然後選擇剛剛訓練好的這次迭代,點選Export
視覺認知服務一共提供了適用於四種平臺的模型匯出,對三大作業系統都能支援。
選擇ONNX,這個格式由微軟、臉書、亞馬遜等大廠鼎力支援,點選Export,等待伺服器把模型匯出,然後點選Download,即可下載模型。最後得到了一個.onnx檔案,然後就可以使用它來構建應用了。

如果需要上傳大量的圖片資料,那麼點選滑鼠的方式肯定不夠方便,微軟同時提供了程式碼的支援,詳見官方文件:

四、使用Windows ML構建應用

這次不寫Winform程式,而是搭建一個識別熊的UWP的AI應用,通過這個應用來教大家如何使用Windows ML匯入模型。

這部分的程式碼已經完成了,請使用git克隆samples-for-ai到本地,UWP專案的程式碼在/samples-for-ai/projects/BearClassificationUWPDemo中。

在執行程式碼之前,請先安裝開發UWP所需的工作負載,流程如下:

  1. 開啟Visual Studio Installer
  2. 在工作負載中勾選Universal Windows Platform development
  3. 在單個元件一欄中下拉到最下方,確認Windows 10 SDK(10.0.17134.0)已被勾選上,這是使用Windows ML開發的核心元件

 

另外,請將您的作業系統更新到1803版本,否則本程式將不能安裝。

如果您將進行類似的開發,請將UWP專案設定成最低執行目標版本為17134,否則對於版本低於17134的使用者,在執行時會出現:

“Requested Windows Runtime type ‘Windows.AI.MachineLearning.Preview.LearningModelPreview’ is not registered.”

Visual Studio 和 Windows 更新完畢後,我們開啟CustomVisionApp.sln,執行這個程式。

你可以從必應上查詢一些熊的圖片,複製圖片的URL,貼上到輸入框內,然後點選識別按鈕;或者,點選瀏覽按鈕,選擇一張本地圖片,點選確定,你就可以看到識別結果了:

 

現在來看看這個程式是怎麼實現的。

我們來梳理一下這個應用的邏輯,這個應用的邏輯與上一篇部落格中的手寫數字識別大體上是一樣的:

  1. 匯入模型
  2. 按下按鈕後,通過某種方式獲取要用來識別的圖片
  3. 將圖片交給模型識別
  4. 將圖片與識別結果展示在介面上

1. 檔案結構:

檔案結構見下圖:

  • Assets資料夾存放了這個專案的資產檔案,比如程式圖示等等,在本示例程式中,.onnx檔案也存放在其中。
  • Strings資料夾存放了用於本地化與全球化資原始檔,這樣可以支援不同的語言。
  • ViewModel資料夾中則存放了本專案的關鍵程式碼,整個程式執行的邏輯都在ResultViewModel.cs中
  • BearClassification.cs則是系統自動生成的模型包裝檔案
  • MainPage.xaml是程式的UI佈局檔案

2. 核心程式碼一:BearClassification.cs

  1. 將.onnx檔案新增到UWP專案的Assets資料夾中,隨後將自動生成一個對應的包裝.cs檔案,在本例中為BearClassification.cs
  2. 由於目前存在的一些BUG,生成的類名會有亂碼,需要將亂碼替換為別的字串。
  3. 修改BearClassification.onnx屬性->生成操作,將其改為內容,確保在生成時,能夠呼叫到這個模型。

生成的檔案共有三個類: 
- BearClassificationModelInput:定義了該模型的輸入格式是VideoFrame 
- BearClassificationModelOutput:定義了該模型的輸出為一個list和一個dict,list儲存了所有標籤按照probability降序排列,dict則儲存了標籤與概率的鍵值對 
- BearClassificationModel:定義了該模型的初始化函式與推理函式

// 模型的輸入格式為VideoFrame
public sealed class BearClassificationModelInput
{
    public VideoFrame data { get; set; }
}

// 模型的輸出格式,其中包含了一個列表:classLabel和一個字典:loss
// 列表中包含每種熊的標籤,按照概率降序排列
// 字典中則包含了每種熊的標籤和其概率,按照使用者在建立模型時的新增順序排列
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>(){...}
    }
}

// 模型的包裝類,提供了兩個函式
// CreateBearClassificationModel:從.onnx檔案中建立模型
// EvaluateAsync:對輸入物件進行評估,並返回結果
public sealed class BearClassificationModel
{
    private LearningModelPreview learningModel;
    public static async Task<BearClassificationModel> CreateBearClassificationModel(StorageFile file)
    {
        ...
    }

    public async Task<BearClassificationModelOutput> EvaluateAsync(BearClassificationModelInput input)
    {
        ...
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

3. 核心程式碼二:ResultViewModel.cs

通過之前的執行可以發現:每次識別圖片,UI中的內容需要進行頻繁地更新,為了簡化更新控制元件內容的程式碼邏輯,這個程式使用UWP開發中常用的MVVM(model-view-viewmodel)這一組合模式開發,使用“繫結”的方式,將UI控制元件與資料繫結起來,讓資料與介面自動地同步更新,簡化了程式碼邏輯,保證了ResultViewModel職責單一。

繫結源(ResultViewMode.cs)繫結目標(MainPage.xaml)
string BearUrlTextBox InputUriBox
ObservableCollection ResultsListView ResultArea
BitmapImage BearImageImage DisplayArea
string DescriptionTextBox DescribeArea
ICommand RecognizeCommandButton RecognizeButton
ICommand BrowseCommandButton BrowseButton

繫結好之後,程式還需要一系列邏輯才能執行,這裡就包括:

匯入與初始化模型:

在程式一開始,需要呼叫LoadModel進行模型初始化工作。

private async void LoadModel()
{
    //匯入模型檔案,例項化模型物件
    StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/BearClassification.onnx"));
    model = await BearClassificationModel.CreateBearClassificationModel(modelFile);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

圖片推理:

本程式提供了兩種方式訪問圖片資源: 
1. 通過URL訪問網路圖片 
2. 通過檔案選取器訪問本地圖片

private async void EvaluateNetPicAsync()
{
    try
    {
        ...
        //BearClassification要求的輸入格式為VideoFrame
        //程式需要以stream的形式從URL中讀取資料,生成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交給函式進行識別
        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交給函式進行識別
        EvaluateAsync(imageFrame);
    }
    catch (Exception ex){ ... }
}

private async void EvaluateAsync(VideoFrame imageFrame)
{
    //將VideoFrame包裝進BearClassificationModelInput中,交給模型識別
    //模型的輸出格式為BearClassificationModelOutput
    //其中包含一個列表,儲存了每種熊的標籤名稱,按照probability降序排列
    //和一個字典,儲存了每種熊的標籤,和對應的probability
    //這裡取出輸出中的字典,並對其進行降序排列
    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();

    //根據結果生成圖片描述
    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"));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

五、使用其他方法構建應用

同樣,用之前使用Visual Studio Tools for AI提供的推理類庫生成器也能夠構建相似的應用,請看:

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

根據模型瀏覽工具與推理類庫生成器來生成模型呼叫介面。

六、下一步?

本篇部落格我們學會了使用定製化視覺服務與在UWP應用中整合定製化視覺服務模型。這裡我提兩個課後習題:(想不到吧)

  1. 當訓練含有多個標籤、大量圖片資料時,如何做到一鍵上傳圖片並訓練?

  2. 如何通過呼叫REST介面的方式完成對圖片的推理?

加油!


相關推薦

AI應用開發實戰系列

最近在看機器學習和AI轉載於:https://blog.csdn.net/SoftwareTeacher/article/details/80954568AI應用開發實戰 - 定製化視覺服務的使用本篇教程的目標是學會使用定製化視覺服務,並能在UWP應用中整合定製化視覺服務模型

MongoDB實戰系列:mongodb副本集部署

簡述:副本集合(Replica Sets),是一個基於主/從複製機制的複製功能,但增加了自動故障轉移和恢復特性。一個叢集最多可以支援7個伺服器,並且任意節點都可以是主節點。所有的寫操作都被分發到主節點,而讀操作可以在任何節點上進行。 環境:CentOS 5.5 x64

AI應用開發實戰

擴充套件手寫數字識別應用 識別並計算簡單手寫數學表示式 主要知識點 瞭解MNIST資料集 瞭解如何擴充套件資料集 實現手寫算式計算器 簡介 本文將介紹一例支援識別手寫數學表示式並對其進行計算的人工智慧應用的開發案例。本文的應用是基於前文“手寫識別應用入門”中的基礎應用進行擴充套件實現的。本文將通過這一案

學習《spring 3.x企業應用開發實戰使用OXM進行物件XML對映

1、認識XML解析技術 1.1、XML相關概念 (1)DTD:XML語法規則,是XML檔案的驗證機制,可以通過比較XML文件和DTD檔案看文件是否符合規範,元素和標籤是否使用正確。 (2)XML是SOA的基礎。 1.2、XML處理技術 (1)為了使用XML,我們需要通過X

企慧Q5快速開發平臺系列:“零”程式碼理念

之所以在現有開發工具的基礎上能夠誕生開發平臺,就是因為要實現無程式碼開發,畢竟使用開發工具開發,要想獲得任何一個功能,哪怕是個簡單如Hello World的功能,都必須Coding,都會產生原始碼。一旦有了原始碼,就得debug,debug,debug…,然後是

學習《spring 3.x企業應用開發實戰Spring的事務管理

1、資料庫事務基礎知識 1.1、資料庫事務的概念 (1)資料庫事物的4個特性(ACID): 原子性(Atomic):表示組成一個事務的多個數據庫操作是一個不可分割的原子單元,所有的操作要麼全部成功,要麼全部失敗。一致性(Consistency):事務操作成功之後,資料庫所

後端開發實踐系列——簡單可用的CQRS編碼實踐

本文只講了一件事情:軟體模型中存在讀模型和寫模型之分,CQRS便為此而生。 20多年前,Bertrand Meyer在他的《Object-Oriented Software Construction》一書中提出了CQS(Command Query Seperation,命令查詢分離)的概念,指出: Ever

大資料開發實戰系列電信客服(1)

大資料實戰開發系列,以實戰為主,輔以一些基礎知識,關於電信客服,在網上也有很多的資料,這裡我自然會去參考網上的資料,程式的整體設計是在今天開始的,老夫儘量在本週末錢結束這個電信客服的程式編寫。因為我也是一個學習者,所以在程式編寫過程中難免會存在問題,有問題還請大家指出,有則改之,無則加勉。大家共同進步。本教程

Kubernetes系列:使用yaml檔案建立deployment來部署一個應用程式到k8s叢集

目的 從零開始開發一個超小的應用,將它打包成一個image,利用yaml檔案部署到kube叢集中。 具體的思路是:在開發環境中,打算建立一個node.js應用程式,因為使用它可以讓我的程式足夠簡單,然後使用dockerfile去建立一個docker image,再將它push到doc

AI應用開發基礎傻瓜書系列3-損失函式

全套教程請點選:微軟 AI 開發教程 第三篇:啟用函式和損失函式(二) 在這一章,我們將簡要介紹一下損失函式~ 損失函式 作用 在有監督的學習中,需要衡量神經網路輸出和所預期的輸出之間的差異大小。這種誤差函式需要能夠反映出當前網路輸出和實際結果之間一種量化之後的不一致程度,也就是說函式值越大,反映出

AI應用開發基礎傻瓜書系列3-啟用函式

全套教程請點選:微軟 AI 開發教程 第三篇:啟用函式和損失函式(一) 在這一章,我們將簡要介紹一下啟用函式~ 啟用函式 看神經網路中的一個神經元,為了簡化,假設該神經元接受三個輸入,分別為\(x_1, x_2, x_3\),那麼\(z=\sum\limits_{i}w_ix_i+b_i\),

AI應用開發基礎傻瓜書系列1-神經網路的基本工作原理

第一篇:神經網路的基本工作原理 看過很多部落格、文章,東一榔頭西一棒子的,總覺得沒有一個系列的文章把問題從頭到尾說清楚,找東西很困難。有的部落格、文章的質量還不算很理想,似是而非,或者重點不明確,或者直接把別人的部落格抄襲過來......種種不靠譜,讓小白們學習起來很困難,增加了學習曲線的陡峭程度。當然也有

AI應用開發基礎傻瓜書系列2-神經網路中反向傳播與梯度下降的基本概念

第二篇:神經網路中反向傳播與梯度下降的基本概念 預警:本篇部落格中會涉及到偏導數的概念,但是非常初級,很容易理解,建議硬著頭皮看,跟著算一遍,看完之後保證會覺得人生美好了很多。 反向傳播和梯度下降這兩個詞,第一眼看上去似懂非懂,不明覺厲。這兩個概念是整個神經網路中的重要組成部分,是和誤差函式/損失函式的概念

AI應用開發基礎傻瓜書系列附錄-基本數學導數公式

基本函式導數公式 附錄:基本數學導數公式 這篇文章的內容更多的是一些可能要用到的數學公式的導數公式和推導,是一種理論基礎,感興趣的同學可以仔細瞅瞅,想直接上手的同學也可以直接跳過這一篇~ 大家可以mark一下,以便以後用到時過來查一下,當成字典。 下面進入正題! \(y=c\) \[y'=0 \tag

AI應用開發基礎傻瓜書系列目錄

AI應用開發基礎傻瓜書系列的目錄~ 寫在前面,為啥要出這個系列的教程呢? 總的說來,我們現在有了很多非常厲害的深度學習框架,比如tensorflow,pytorch,paddlepaddle,caffe2等等等等。然而,我們用這些框架在搭建我們自己的深度學習模型的時候,到底做了一些什麼樣的操作呢?我們試圖去閱

AI應用開發基礎傻瓜書系列3-啟用函式和損失函式

第三篇:啟用函式和損失函式 在這一章,我們將簡要介紹一下啟用函式和損失函式~ 啟用函式 看神經網路中的一個神經元,為了簡化,假設該神經元接受三個輸入,分別為\(x_1, x_2, x_3\),那麼\(z=\sum\limits_{i}w_ix_i+b_i\), 啟用函式也就是\(A=\sigma(Z)\)

AI應用開發基礎傻瓜書系列4-用線性迴歸來理解神經網路的訓練過程

下面我們舉一個簡單的線性迴歸的例子來說明實際的反向傳播和梯度下降的過程。完全看懂此文後,會對理解後續的文章有很大的幫助。 為什麼要用線性迴歸舉例呢?因為\(y = wx+b\) (其中,y,w,x,b都是標量)這個函式的形式和神經網路中的\(Y = WX + B\)(其中,Y,W,X,B等都是矩陣)非常近似,

敏捷開發使用者故事系列:優先順序排序

這是敏捷開發使用者故事系列的第四篇。(欄目目錄)優先順序排序聽起來是一個很簡單的工作,一個欄位無外乎“重要/一般……”,調整一下然後按排序,就出來了。但其實裡邊有不少名堂:誰應該負責排序工作?誰最終拍板?研發因素要不要考慮?需求依賴關係導致的順序如何處理?持續交付的考慮?商業

敏捷外包工程系列:外包與敏捷開發專訪(IIOM獨家專訪)

本文是敏捷外包工程系列的第四篇。(之一,之二,之三,之四)本文是2012年05月初IIOM(國際外包管理學院)的專訪。傳統認為敏捷開發是面向產品研發的,在外包專案裡邊比較難用,因為需求由客戶牽制,而“擁抱變化”極有可能導致專案延期超支,等等。本文提及了敏捷開發對外包專案的幫助

Flask旅《Flask Web開發:基於Python的Web應用開發實戰》學習筆記

《Flask Web開發:基於Python的Web應用開發實戰》 點選上方的“目錄”快速到達哦! 雖然簡單的網站(Flask+Python+SAE)已經上線,但只是入門。開發大型網站,系統地學習一遍還是有必要的。 1 虛擬環境 2016-6-8 書上介紹了