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阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容