此文翻譯自 Core ML and Vision: Machine Learning in iOS 11 Tutorial
注意:此教程需要 Xcode 9 Beta1 或更新的版本、Swift 4 以及 iOS 11.
機(jī)器學(xué)習(xí)正在肆虐橫行秧均。很多人都聽說過勾栗,但很少有人知道這是什么。
這篇《iOS 機(jī)器學(xué)習(xí)教程》會(huì)為你介紹 Core ML 和 Vision梢褐,iOS 11 中推出的兩個(gè)全新框架套么。
具體來說,你會(huì)學(xué)習(xí)如何借助 Places205-GoogLeNet 模型最蕾,使用新的 API 對(duì)圖像的場(chǎng)景進(jìn)行分類。
開始
下載起始項(xiàng)目老厌。它已包含了用于顯示圖片的用戶界面瘟则,并允許用戶從照片庫中選擇另一張圖片。這樣你就可以專注于實(shí)現(xiàn) App 的機(jī)器學(xué)習(xí)和視覺方面枝秤。
構(gòu)建并運(yùn)行該項(xiàng)目醋拧;可以看到一張城市夜景圖,以及一個(gè)按鈕:
從“照片” App 的照片庫中選擇另一張圖片淀弹。此起始項(xiàng)目的 Info.plist 已經(jīng)有 Privacy – Photo Library Usage Description丹壕,所以你會(huì)被提示允許使用。
圖片和按鈕之間的空隙有一個(gè) label薇溃,將會(huì)在此顯示模型對(duì)圖片場(chǎng)景的分類菌赖。
iOS 機(jī)器學(xué)習(xí)
機(jī)器學(xué)習(xí)是一種人工智能,計(jì)算機(jī)會(huì)“學(xué)習(xí)”而不是被明確編程沐序。不用編寫算法琉用,機(jī)器學(xué)習(xí)工具通過在大量數(shù)據(jù)中尋找模式,使計(jì)算機(jī)能夠開發(fā)和優(yōu)化算法策幼。
深度學(xué)習(xí)
自20世紀(jì)50年代以來邑时,AI 研究人員開發(fā)了許多機(jī)器學(xué)習(xí)方法。蘋果的 Core ML 框架支持神經(jīng)網(wǎng)絡(luò)特姐、樹組合晶丘、支持向量機(jī)、廣義線性模型唐含、特征工程和流水線模型浅浮。但是滤钱,神經(jīng)網(wǎng)絡(luò)最近已經(jīng)取得了很多極為神奇的成功,開始于 2012 年谷歌使用 YouTube 視頻訓(xùn)練 AI 來識(shí)別貓和人脑题。僅僅五年后件缸,谷歌正在贊助一場(chǎng)確定 5000 種植物和動(dòng)物的比賽。像 Siri 和 Alexa 這樣的 App 也存在它們自己的神經(jīng)網(wǎng)絡(luò)叔遂。
神經(jīng)網(wǎng)絡(luò)嘗試用節(jié)點(diǎn)層來模擬人腦流程他炊,并將節(jié)點(diǎn)層用不同的方式連接在一起。每增加一層都需要增加大量計(jì)算能力:Inception v3已艰,一個(gè)對(duì)象識(shí)別模型痊末,有48層以及大約2000萬個(gè)參數(shù)。但計(jì)算基本上都是矩陣乘法哩掺,GPU 來處理會(huì)非常有效凿叠。GPU 成本的下降使我們能夠創(chuàng)建多層深度神經(jīng)網(wǎng)絡(luò),此為深度學(xué)習(xí)嚼吞。
神經(jīng)網(wǎng)絡(luò)需要大量的訓(xùn)練數(shù)據(jù),這些訓(xùn)練數(shù)據(jù)理想化地代表了全部可能性舱禽。用戶生成的數(shù)據(jù)爆炸性地產(chǎn)生也促成了機(jī)器學(xué)習(xí)的復(fù)興炒刁。
訓(xùn)練模型意味著給神經(jīng)網(wǎng)絡(luò)提供訓(xùn)練數(shù)據(jù),并讓它計(jì)算公式誊稚,此公式組合輸入?yún)?shù)以產(chǎn)生輸出翔始。訓(xùn)練是離線的,通常在具有多個(gè) GPU 的機(jī)器上里伯。
要使用這個(gè)模型城瞎,就給它新的輸入,它就會(huì)計(jì)算輸出:這叫做推論疾瓮。推論仍然需要大量計(jì)算脖镀,以從新的輸入計(jì)算輸出。因?yàn)橛辛?Metal 這樣的框架爷贫,現(xiàn)在可以在手持設(shè)備上進(jìn)行這些計(jì)算认然。
在本教程的結(jié)尾你會(huì)發(fā)現(xiàn),深度學(xué)習(xí)遠(yuǎn)非完美漫萄。真的很難建立具有代表性的訓(xùn)練數(shù)據(jù)卷员,很容易就會(huì)過度訓(xùn)練模型,以至于它會(huì)過度重視一些古怪的特征腾务。
蘋果提供了什么毕骡?
蘋果在 iOS 5 里引入了 NSLinguisticTagger
來分析自然語言。iOS 8 出了 Metal,提供了對(duì)設(shè)備 GPU 的底層訪問未巫。
去年窿撬,蘋果在 Accelerate 框架添加了 Basic Neural Network Subroutines (BNNS),使開發(fā)者可以構(gòu)建用于推理(不是訓(xùn)練)的神經(jīng)網(wǎng)絡(luò)叙凡。
今年劈伴,蘋果給了我們 Core ML 和 Vision!
- Core ML 讓我們更容易在 App 中使用訓(xùn)練過的模型握爷。
- Vision 讓我們輕松訪問蘋果的模型跛璧,用于面部檢測(cè)、面部特征點(diǎn)新啼、文字追城、矩形、條形碼和物體燥撞。
你還可以在 Vision 模型中包裝任意的圖像分析 Core ML 模型座柱,我們?cè)谶@篇教程中就干這個(gè)。由于這兩個(gè)框架是基于 Metal 構(gòu)建的物舒,它們能在設(shè)備上高效運(yùn)行色洞,所以不需要把用戶的數(shù)據(jù)發(fā)送到服務(wù)器。
將 Core ML 模型集成到你的 App
本教程使用 Places205-GoogLeNet 模型茶鉴,可以從蘋果的“機(jī)器學(xué)習(xí)”頁面下載锋玲。往下滑找到 Working with Models,下載第一個(gè)涵叮。還在這個(gè)頁面,注意一下其它三個(gè)模型伞插,它們都用于在圖片中檢測(cè)物體——樹割粮、動(dòng)物、人等等媚污。
注意:如果你有一個(gè)訓(xùn)練過的模型舀瓢,并且是使用受支持的機(jī)器學(xué)習(xí)工具訓(xùn)練的,例如 Caffe耗美、Keras 或 scikit-learn京髓,Converting Trained Models to Core ML 介紹了如何將其轉(zhuǎn)換為 Core ML 格式。
為你的項(xiàng)目添加模型
下載 GoogLeNetPlaces.mlmodel 后商架,把它從 Finder 拖到項(xiàng)目導(dǎo)航器的 Resources 組里:
選擇該文件堰怨,然后等一會(huì)兒。Xcode 生成了模型類后會(huì)顯示一個(gè)箭頭:
點(diǎn)擊箭頭蛇摸,查看生成的類:
Xcode 已生成了輸入和輸出類以及主類 GoogLeNetPlaces
备图,主類有一個(gè) model
屬性和兩個(gè) prediction
方法。
GoogLeNetPlacesInput
有一個(gè) CVPixelBuffer
類型的 sceneImage
屬性±夸蹋哭了抠藕,這些都是什么鬼?蒋困!不要害怕盾似,Vision 框架會(huì)負(fù)責(zé)把我們熟悉的圖片格式轉(zhuǎn)換成正確的輸入類型。:]
Vision 框架還會(huì)把 GoogLeNetPlacesOutput
屬性轉(zhuǎn)換為自己的 results
類型雪标,并管理對(duì) prediction
方法的調(diào)用颜说,所以在所有生成的代碼中,我們只會(huì)使用 model
屬性汰聋。
在 Vision Model 中包裝 Core ML Model
終于门粪,要開始寫代碼了!打開 ViewController.swift烹困,并在 import UIKit
下面 import 兩個(gè)框架:
import CoreML
import Vision
下一步玄妈,在 IBActions
擴(kuò)展下方添加如下擴(kuò)展:
// 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")
}
}
}
我們上面的代碼做了這些事:
首先,給用戶顯示一條消息髓梅,讓他們知道正在發(fā)生什么事情拟蜻。
GoogLeNetPlaces 的指定初始化方法會(huì)拋出一個(gè) error,所以創(chuàng)建時(shí)必須用 try
枯饿。
VNCoreMLModel
只是用于 Vision 請(qǐng)求的 Core ML 模型的容器酝锅。
標(biāo)準(zhǔn)的 Vision 工作流程是創(chuàng)建模型,創(chuàng)建一或多個(gè)請(qǐng)求奢方,然后創(chuàng)建并運(yùn)行請(qǐng)求處理程序搔扁。我們剛剛已經(jīng)創(chuàng)建了模型,所以下一步是創(chuàng)建請(qǐng)求蟋字。
在 detectScene(image:)
的末尾添加如下幾行:
// 創(chuàng)建一個(gè)帶有 completion handler 的 Vision 請(qǐng)求
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
是一個(gè)圖像分析請(qǐng)求稿蹲,它使用 Core ML 模型來完成工作。它的 completion handler 接收 request
和 error
對(duì)象鹊奖。
檢查 request.results
是否是 VNClassificationObservation
對(duì)象數(shù)組苛聘,當(dāng) Core ML 模型是分類器,而不是預(yù)測(cè)器或圖像處理器時(shí)忠聚,Vision 框架就會(huì)返回這個(gè)设哗。而 GoogLeNetPlaces
是一個(gè)分類器,因?yàn)樗鼉H預(yù)測(cè)一個(gè)特征:圖像的場(chǎng)景分類两蟀。
VNClassificationObservation
有兩個(gè)屬性:identifier
- 一個(gè) String
网梢,以及 confidence
- 介于0和1之間的數(shù)字,這個(gè)數(shù)字是是分類正確的概率垫竞。使用對(duì)象檢測(cè)模型時(shí)澎粟,你可能只會(huì)看到那些 confidence 大于某個(gè)閾值的對(duì)象蛀序,例如 30% 的閾值。
然后取第一個(gè)結(jié)果活烙,它會(huì)具有最高的 confidence 值徐裸,然后根據(jù) identifier 的首字母把不定冠詞設(shè)置為“a”或“an”。最后啸盏,dispatch 回到主線程來更新 label重贺。你很快會(huì)明白分類工作為什么不在主線程,因?yàn)樗鼤?huì)很慢回懦。
現(xiàn)在气笙,做第三步:創(chuàng)建并運(yùn)行請(qǐng)求處理程序。
把下面幾行添加到 detectScene(image:)
的末尾:
// 在主線程上運(yùn)行 Core ML GoogLeNetPlaces 分類器
let handler = VNImageRequestHandler(ciImage: image)
DispatchQueue.global(qos: .userInteractive).async {
do {
try handler.perform([request])
} catch {
print(error)
}
}?
VNImageRequestHandler 是標(biāo)準(zhǔn)的 Vision 框架請(qǐng)求處理程序怯晕;不特定于 Core ML 模型潜圃。給它 image 作為 detectScene(image:)
的參數(shù)。然后調(diào)用它的 perform
方法來運(yùn)行處理程序舟茶,傳入請(qǐng)求數(shù)組谭期。在這個(gè)例子里,我們只有一個(gè)請(qǐng)求吧凉。
perform
方法會(huì)拋出 error隧出,所以用 try-catch 將其包住。
使用模型來分類場(chǎng)景
哇阀捅,剛剛寫了好多代碼胀瞪!但現(xiàn)在只需要在兩個(gè)地方調(diào)用 detectScene(image:)
就好了。
把下面幾行添加到 viewDidLoad()
的末端和 imagePickerController(_:didFinishPickingMediaWithInfo:)
的末端:
guard let ciImage = CIImage(image: image) else {
fatalError("couldn't convert UIImage to CIImage")
}
detectScene(image: ciImage)
現(xiàn)在構(gòu)建并運(yùn)行饲鄙。不需要多久就可以看見分類:
哈哈凄诞,是的,圖片里有 skyscrapers(摩天大樓)傍妒。還有一列火車幔摸。
點(diǎn)擊按鈕,選擇照片庫里的第一張圖片:一些樹葉上太陽光斑的特寫:
啊哈哈哈哈哈颤练,瞇起眼睛,也許可以想象尼莫或多莉正在里面游泳驱负?但至少你知道應(yīng)該用 “a” 還是 “an”嗦玖。;]
看一眼蘋果的 Core ML 示例 App
本教程的項(xiàng)目和 WWDC 2017 Session 506 Vision Framework: Building on Core ML 的示例項(xiàng)目很相似。Vision + ML Example App 使用 MNIST 分類器跃脊,可以識(shí)別手寫數(shù)字——對(duì)郵政分類自動(dòng)化非常有幫助宇挫。它還使用原生 Vision 框架方法 VNDetectRectanglesRequest
,還包括 Core Image 的代碼來矯正矩形檢測(cè)的透視酪术。
還可以從 Core ML 文檔頁面下載另一個(gè)示例項(xiàng)目器瘪。MarsHabitatPricePredictor 模型的輸入只是數(shù)字翠储,因此代碼直接使用生成的 MarsHabitatPricer
方法和屬性,而不是將模型包裝在 Vision 模型中橡疼。每次都改一下參數(shù)援所,很容易看出模型只是一個(gè)線性回歸:
137 * solarPanels + 653.50 * greenHouses + 5854 * acres
下一步?
可以從這里下載教程的完整項(xiàng)目欣除。如果模型顯示為缺失住拭,將其替換為你下載的那個(gè)。
你現(xiàn)在已經(jīng)有能力將現(xiàn)有的模型整合到你的 App 中历帚。這里有一些資源可以更詳細(xì)地介紹:
- 蘋果的 Core ML Framework 文檔
- WWDC 2017 Session 703 介紹 Core ML
- WWDC 2017 Session 710 Core ML in depth
2016 年的:
- WWDC 2016 Session 605 What’s New in Metal, Part 2: demos show how fast the app does the Inception model classification calculations, thanks to Metal.
- 蘋果的 Basic Neural Network Subroutines 文檔
想構(gòu)建自己的模型滔岳?恐怕這超出了本教程的范圍(以及我的專業(yè)知識(shí))。但這些資源可能會(huì)幫你上手:
- RWDevCon 2017 Session 3 Machine Learning in iOS: Alexis Gallagher 做了一項(xiàng)絕對(duì)精彩的工作挽牢,指導(dǎo)你一系列流程谱煤,為神經(jīng)網(wǎng)絡(luò)收集訓(xùn)練數(shù)據(jù)(你微笑或皺眉的視頻),訓(xùn)練禽拔,然后檢查它是否有效刘离。他的結(jié)論:“不需要是數(shù)學(xué)家或大公司也可以建立有效的模型∽嘧福”
-
Quartz article on Apple’s AI research paper: Dave Gershgorn’s 有關(guān) AI 的文章都很清晰和翔實(shí)寥闪。此文做了一項(xiàng)杰出的工作,總結(jié)了蘋果的第一篇 AI 研究論文:研究人員使用基于
真實(shí)
圖像訓(xùn)練的神經(jīng)網(wǎng)絡(luò)來優(yōu)化圖像合成
磨淌,從而有效地產(chǎn)生了大量高質(zhì)量的新訓(xùn)練數(shù)據(jù)疲憋,而沒有個(gè)人數(shù)據(jù)隱私問題。
最后梁只,我從 Andreessen Horowitz 的 Frank Chen 那里真的學(xué)習(xí)了很多 AI 的簡(jiǎn)史:AI and Deep Learning a16z podcast缚柳。
希望本教程對(duì)你有所幫助。隨意在下方加入討論搪锣!