Core ML 與 Vision:iOS 11 機器學習教程

此文翻譯自 Core ML and Vision: Machine Learning in iOS 11 Tutorial

注意:此教程需要 Xcode 9 Beta1 或更新的版本、Swift 4 以及 iOS 11.

機器學習正在肆虐橫行。很多人都聽說過,但很少有人知道這是什么。

這篇《iOS 機器學習教程》會為你介紹 Core MLVision,iOS 11 中推出的兩個全新框架。

具體來說,你會學習如何借助 Places205-GoogLeNet 模型,使用新的 API 對圖像的場景進行分類。

開始

下載起始項目。它已包含了用于顯示圖片的用戶界面,并允許用戶從照片庫中選擇另一張圖片。這樣你就可以專注于實現 App 的機器學習和視覺方面。

構建并運行該項目;可以看到一張城市夜景圖,以及一個按鈕:

從“照片” App 的照片庫中選擇另一張圖片。此起始項目的 Info.plist 已經有 Privacy – Photo Library Usage Description,所以你會被提示允許使用。

圖片和按鈕之間的空隙有一個 label,將會在此顯示模型對圖片場景的分類。

iOS 機器學習

機器學習是一種人工智能,計算機會“學習”而不是被明確編程。不用編寫算法,機器學習工具通過在大量數據中尋找模式,使計算機能夠開發和優化算法。

深度學習

自20世紀50年代以來,AI 研究人員開發了許多機器學習方法。蘋果的 Core ML 框架支持神經網絡、樹組合、支持向量機、廣義線性模型、特征工程和流水線模型。但是,神經網絡最近已經取得了很多極為神奇的成功,開始于 2012 年谷歌使用 YouTube 視頻訓練 AI 來識別貓和人。僅僅五年后,谷歌正在贊助一場確定 5000 種植物和動物的比賽。像 Siri 和 Alexa 這樣的 App 也存在它們自己的神經網絡。

神經網絡嘗試用節點層來模擬人腦流程,并將節點層用不同的方式連接在一起。每增加一層都需要增加大量計算能力:Inception v3,一個對象識別模型,有48層以及大約2000萬個參數。但計算基本上都是矩陣乘法,GPU 來處理會非常有效。GPU 成本的下降使我們能夠創建多層深度神經網絡,此為深度學習

神經網絡,circa 2016

神經網絡需要大量的訓練數據,這些訓練數據理想化地代表了全部可能性。用戶生成的數據爆炸性地產生也促成了機器學習的復興。

訓練模型意味著給神經網絡提供訓練數據,并讓它計算公式,此公式組合輸入參數以產生輸出。訓練是離線的,通常在具有多個 GPU 的機器上。

使用這個模型,就給它新的輸入,它就會計算輸出:這叫做推論。推論仍然需要大量計算,以從新的輸入計算輸出。因為有了 Metal 這樣的框架,現在可以在手持設備上進行這些計算。

在本教程的結尾你會發現,深度學習遠非完美。真的很難建立具有代表性的訓練數據,很容易就會過度訓練模型,以至于它會過度重視一些古怪的特征。

蘋果提供了什么?

蘋果在 iOS 5 里引入了 NSLinguisticTagger 來分析自然語言。iOS 8 出了 Metal,提供了對設備 GPU 的底層訪問。

去年,蘋果在 Accelerate 框架添加了 Basic Neural Network Subroutines (BNNS),使開發者可以構建用于推理(不是訓練)的神經網絡。

今年,蘋果給了我們 Core ML 和 Vision!

  • Core ML 讓我們更容易在 App 中使用訓練過的模型。
  • Vision 讓我們輕松訪問蘋果的模型,用于面部檢測、面部特征點、文字、矩形、條形碼和物體。

你還可以在 Vision 模型中包裝任意的圖像分析 Core ML 模型,我們在這篇教程中就干這個。由于這兩個框架是基于 Metal 構建的,它們能在設備上高效運行,所以不需要把用戶的數據發送到服務器。

將 Core ML 模型集成到你的 App

本教程使用 Places205-GoogLeNet 模型,可以從蘋果的“機器學習”頁面下載。往下滑找到 Working with Models,下載第一個。還在這個頁面,注意一下其它三個模型,它們都用于在圖片中檢測物體——樹、動物、人等等。

注意:如果你有一個訓練過的模型,并且是使用受支持的機器學習工具訓練的,例如 Caffe、Keras 或 scikit-learn,Converting Trained Models to Core ML 介紹了如何將其轉換為 Core ML 格式。

為你的項目添加模型

下載 GoogLeNetPlaces.mlmodel 后,把它從 Finder 拖到項目導航器的 Resources 組里:

選擇該文件,然后等一會兒。Xcode 生成了模型類后會顯示一個箭頭:

點擊箭頭,查看生成的類:

Xcode 已生成了輸入和輸出類以及主類 GoogLeNetPlaces,主類有一個 model 屬性和兩個 prediction 方法。

GoogLeNetPlacesInput 有一個 CVPixelBuffer 類型的 sceneImage 屬性。哭了,這些都是什么鬼?!不要害怕,Vision 框架會負責把我們熟悉的圖片格式轉換成正確的輸入類型。:]

Vision 框架還會把 GoogLeNetPlacesOutput 屬性轉換為自己的 results 類型,并管理對 prediction 方法的調用,所以在所有生成的代碼中,我們只會使用 model 屬性。

在 Vision Model 中包裝 Core ML Model

終于,要開始寫代碼了!打開 ViewController.swift,并在 import UIKit 下面 import 兩個框架:

import CoreML
import Vision

下一步,在 IBActions 擴展下方添加如下擴展:

// MARK: - Methods
extension ViewController {

  func detectScene(image: CIImage) {
    answerLabel.text = "detecting scene..."
  
    // 從生成的類中加載 ML 模型
    guard let model = try? VNCoreMLModel(for: GoogLeNetPlaces().model) else {
      fatalError("can't load Places ML model")
    }
  }
}

我們上面的代碼做了這些事:

首先,給用戶顯示一條消息,讓他們知道正在發生什么事情。

GoogLeNetPlaces 的指定初始化方法會拋出一個 error,所以創建時必須用 try

VNCoreMLModel 只是用于 Vision 請求的 Core ML 模型的容器。

標準的 Vision 工作流程是創建模型,創建一或多個請求,然后創建并運行請求處理程序。我們剛剛已經創建了模型,所以下一步是創建請求。

detectScene(image:) 的末尾添加如下幾行:

// 創建一個帶有 completion handler 的 Vision 請求
let request = VNCoreMLRequest(model: model) { [weak self] request, error in
  guard let results = request.results as? [VNClassificationObservation],
    let topResult = results.first else {
      fatalError("unexpected result type from VNCoreMLRequest")
  }

  // 在主線程上更新 UI
  let article = (self?.vowels.contains(topResult.identifier.first!))! ? "an" : "a"
  DispatchQueue.main.async { [weak self] in
    self?.answerLabel.text = "\(Int(topResult.confidence * 100))% it's \(article) \(topResult.identifier)"
  }
}

VNCoreMLRequest 是一個圖像分析請求,它使用 Core ML 模型來完成工作。它的 completion handler 接收 requesterror 對象。

檢查 request.results 是否是 VNClassificationObservation 對象數組,當 Core ML 模型是分類器,而不是預測器或圖像處理器時,Vision 框架就會返回這個。而 GoogLeNetPlaces 是一個分類器,因為它僅預測一個特征:圖像的場景分類。

VNClassificationObservation 有兩個屬性:identifier - 一個 String,以及 confidence - 介于0和1之間的數字,這個數字是是分類正確的概率。使用對象檢測模型時,你可能只會看到那些 confidence 大于某個閾值的對象,例如 30% 的閾值。

然后取第一個結果,它會具有最高的 confidence 值,然后根據 identifier 的首字母把不定冠詞設置為“a”或“an”。最后,dispatch 回到主線程來更新 label。你很快會明白分類工作為什么不在主線程,因為它會很慢。

現在,做第三步:創建并運行請求處理程序。

把下面幾行添加到 detectScene(image:) 的末尾:

// 在主線程上運行 Core ML GoogLeNetPlaces 分類器
let handler = VNImageRequestHandler(ciImage: image)
DispatchQueue.global(qos: .userInteractive).async {
  do {
    try handler.perform([request])
  } catch {
    print(error)
  }
}?

VNImageRequestHandler 是標準的 Vision 框架請求處理程序;不特定于 Core ML 模型。給它 image 作為 detectScene(image:) 的參數。然后調用它的 perform 方法來運行處理程序,傳入請求數組。在這個例子里,我們只有一個請求。

perform 方法會拋出 error,所以用 try-catch 將其包住。

使用模型來分類場景

哇,剛剛寫了好多代碼!但現在只需要在兩個地方調用 detectScene(image:) 就好了。

把下面幾行添加到 viewDidLoad() 的末端和 imagePickerController(_:didFinishPickingMediaWithInfo:) 的末端:

guard let ciImage = CIImage(image: image) else {
  fatalError("couldn't convert UIImage to CIImage")
}

detectScene(image: ciImage)

現在構建并運行。不需要多久就可以看見分類:

哈哈,是的,圖片里有 skyscrapers(摩天大樓)。還有一列火車。

點擊按鈕,選擇照片庫里的第一張圖片:一些樹葉上太陽光斑的特寫:

75%這是一個水族池

啊哈哈哈哈哈,瞇起眼睛,也許可以想象尼莫或多莉正在里面游泳?但至少你知道應該用 “a” 還是 “an”。;]

看一眼蘋果的 Core ML 示例 App

本教程的項目和 WWDC 2017 Session 506 Vision Framework: Building on Core ML示例項目很相似。Vision + ML Example App 使用 MNIST 分類器,可以識別手寫數字——對郵政分類自動化非常有幫助。它還使用原生 Vision 框架方法 VNDetectRectanglesRequest,還包括 Core Image 的代碼來矯正矩形檢測的透視。

還可以從 Core ML 文檔頁面下載另一個示例項目。MarsHabitatPricePredictor 模型的輸入只是數字,因此代碼直接使用生成的 MarsHabitatPricer 方法和屬性,而不是將模型包裝在 Vision 模型中。每次都改一下參數,很容易看出模型只是一個線性回歸:

137 * solarPanels + 653.50 * greenHouses + 5854 * acres

下一步?

可以從這里下載教程的完整項目。如果模型顯示為缺失,將其替換為你下載的那個。

你現在已經有能力將現有的模型整合到你的 App 中。這里有一些資源可以更詳細地介紹:

2016 年的:

想構建自己的模型?恐怕這超出了本教程的范圍(以及我的專業知識)。但這些資源可能會幫你上手:

  • RWDevCon 2017 Session 3 Machine Learning in iOS: Alexis Gallagher 做了一項絕對精彩的工作,指導你一系列流程,為神經網絡收集訓練數據(你微笑或皺眉的視頻),訓練,然后檢查它是否有效。他的結論:“不需要是數學家或大公司也可以建立有效的模型。”
  • Quartz article on Apple’s AI research paper: Dave Gershgorn’s 有關 AI 的文章都很清晰和翔實。此文做了一項杰出的工作,總結了蘋果的第一篇 AI 研究論文:研究人員使用基于真實圖像訓練的神經網絡來優化圖像合成,從而有效地產生了大量高質量的新訓練數據,而沒有個人數據隱私問題。

最后,我從 Andreessen Horowitz 的 Frank Chen 那里真的學習了很多 AI 的簡史:AI and Deep Learning a16z podcast

希望本教程對你有所幫助。隨意在下方加入討論!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容