移动端的机器学习-全-
移动端的机器学习(全)
原文:
annas-archive.org/md5/b2afb00edd44c73b679c7855edee1ccf译者:飞龙
前言
这本书将通过简单的实际示例帮助你使用移动设备进行机器学习。你将从机器学习的基础知识开始,等你完成这本书的时候,你将很好地掌握移动机器学习的概念,了解有哪些工具/SDKs 可用于实现移动机器学习,并且能够将各种机器学习算法应用于可以在 iOS 和 Android 上运行的应用程序中。
你将了解什么是机器学习,并理解推动移动机器学习的原因以及它的独特之处。你将接触到所有移动机器学习工具和 SDK:TensorFlow Lite、Core ML、ML Kit 和 Android 和 iOS 上的 Fritz。这本书将探讨每个工具包的高级架构和组件。到本书结束时,你将广泛了解机器学习模型,并能够进行设备上的机器学习。你将深入了解诸如回归、分类、线性支持向量机(SVM)和随机森林等机器学习算法。你将学习如何进行自然语言处理和实现垃圾邮件检测。你将学习如何将使用 Core ML 和 TensorFlow 创建的现有模型转换为 Fritz 模型。你还将接触到神经网络。你还将提前了解机器学习的未来,本书还包含了一个常见问题解答部分,以回答你关于移动机器学习的所有疑问。它将帮助你构建一个有趣的应用程序,该应用程序可以提供相机捕获的食品项目的卡路里值,该应用程序在 iOS 和 Android 上都可以运行。
这本书面向的对象
如果你是希望利用机器学习并在移动和智能设备上使用它的移动开发者或机器学习用户,那么《移动机器学习》这本书适合你。你最好具备机器学习的基本知识以及移动应用程序开发的入门级经验。
这本书涵盖了以下内容
第一章,移动机器学习简介,解释了什么是机器学习以及为什么我们应该在移动设备上使用它。它介绍了不同的机器学习方法及其优缺点。
第二章,监督学习和无监督学习算法,涵盖了机器学习算法的监督和无监督方法。我们还将学习不同的算法,如朴素贝叶斯、决策树、SVM、聚类、关联映射等。
第三章,iOS 上的随机森林,深入探讨了随机森林和决策树,并解释了如何将它们应用于解决机器学习问题。我们还将创建一个使用决策树来诊断乳腺癌的应用程序。
第四章,TensorFlow Mobile 在 Android 中,介绍了 TensorFlow 移动应用。我们还将了解移动机器学习应用程序的架构,并使用 TensorFlow 在 Android 中编写应用程序。
第五章,在 iOS 中使用 Core ML 进行回归,探讨了回归和 Core ML,并展示了如何将其应用于解决机器学习问题。我们将创建一个使用 scikit-learn 预测房价的应用程序。
第六章,ML Kit SDK,探讨了 ML Kit 及其优势。我们将使用 ML Kit 和设备以及云 API 创建一些图像标签应用程序。
第七章,iOS 中的垃圾邮件检测 - Core ML,介绍了自然语言处理和 SVM 算法。我们将解决大量短信的问题,即消息是否为垃圾邮件。
第八章,Fritz,介绍了 Fritz 移动机器学习平台。我们将使用 Fritz 和 iOS 中的 Core ML 创建应用程序。我们还将了解 Fritz 如何与我们在本书早期创建的示例数据集一起使用。
第九章,移动设备上的神经网络,涵盖了神经网络、Keras 的概念及其在移动机器学习领域的应用。我们将创建一个识别手写数字的应用程序,以及 TensorFlow 图像识别模型。
第十章,使用 Google Cloud Vision 的移动应用程序,介绍了在 Android 应用程序中使用的 Google Cloud Vision 标签检测技术,以确定相机拍摄的图片中有什么内容。
第十一章,移动应用程序中机器学习的未来,涵盖了移动应用程序的关键特性和它们为利益相关者提供的机遇。
附录,问答,包含了您可能关心的问题,并试图为这些问题提供答案。
为了充分利用本书
读者需要具备机器学习、Android Studio 和 Xcode 的先验知识。
下载示例代码文件
您可以从www.packt.com的账户下载本书的示例代码文件。如果您在其他地方购买了此书,您可以访问www.packt.com/support并注册,以便将文件直接通过电子邮件发送给您。
您可以通过以下步骤下载代码文件:
- 
在www.packt.com上登录或注册。 
- 
选择 SUPPORT 选项卡。 
- 
点击代码下载与勘误表。 
- 
在搜索框中输入书籍名称,并遵循屏幕上的说明。 
下载文件后,请确保您使用最新版本的软件解压缩或提取文件夹:
- 
Windows 上的 WinRAR/7-Zip 
- 
Zipeg/iZip/UnRarX for Mac 
- 
7-Zip/PeaZip for Linux 
书籍的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Machine-Learning-for-Mobile。如果代码有更新,它将在现有的 GitHub 仓库中更新。
我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/找到。查看它们吧!
下载彩色图像
我们还提供了一份包含本书中使用的截图/图表彩色图像的 PDF 文件。您可以从这里下载:www.packtpub.com/sites/default/files/downloads/9781788629355_ColorImages.pdf。
使用的约定
本书使用了多种文本约定。
CodeInText:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“现在您可以将生成的SpamMessageClassifier.mlmodel文件用于您的 Xcode。”
代码块如下设置:
# importing required packages
import numpy as np
import pandas as pd
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
# Reading in and parsing data
raw_data = open('SMSSpamCollection.txt', 'r')
sms_data = []
for line in raw_data:
    split_line = line.split("\t")
    sms_data.append(split_line)
任何命令行输入或输出都如下所示:
pip install scikit-learn pip install numpy pip install coremltools pip install pandas
粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词在文本中如下所示。以下是一个示例:“从管理面板中选择系统信息。”
警告或重要注意事项看起来是这样的。
小贴士和技巧看起来是这样的。
联系我们
我们欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请在邮件主题中提及书名,并通过customercare@packtpub.com发送邮件给我们。
勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,如果您能向我们报告,我们将不胜感激。请访问www.packt.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入详细信息。
盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过copyright@packt.com与我们联系,并提供材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com。
评论
请留下您的评价。一旦您阅读并使用过这本书,为何不在购买它的网站上留下评价呢?潜在读者可以查看并使用您的客观意见来做出购买决定,我们 Packt 可以了解您对我们产品的看法,而我们的作者也可以看到他们对书籍的反馈。谢谢!
如需了解 Packt 的更多信息,请访问packt.com.
第一章:移动机器学习入门
我们生活在一个移动应用的世界里。它们已经成为我们日常生活中的一个重要组成部分,以至于我们很少关注它们背后的数字。(这包括它们创造的收益、业务的实际市场规模以及推动移动应用增长的定量数据。)让我们来看看这些数字:
- 
《福布斯》预测,到 2020 年,移动应用收入预计将达到 1890 亿美元。 
- 
我们还看到,全球智能手机的安装基础正在呈指数级增长。因此,安装在这些设备上的应用收入也在以难以想象的速度增长。 
移动设备和服务现在已成为人们娱乐、商业生活和沟通的中心,智能手机已经取代了个人电脑,成为最重要的智能连接设备。移动创新、新的商业模式和移动技术正在改变人类生活的方方面面。
现在,让我们谈谈机器学习。为什么机器学习最近如此火爆?机器学习并不是一个新课题。它早在 10-20 年前就存在了,那么为什么现在会成为焦点,为什么每个人都谈论它?原因很简单:数据爆炸。社交网络和移动设备使得用户数据的生成达到了前所未有的规模。十年前,你不会像现在这样将图片上传到云端,因为那时的手机普及率无法与今天相比。4G 连接使得现在甚至可以实现按需视频数据流(VDO),这意味着现在全球范围内流动的数据比以往任何时候都要多。下一个时代预计将是物联网(IOT)的时代,届时将有更多基于数据传感器的数据。
所有这些数据只有在我们可以将其用于适当用途、从中提取出对我们有价值的信息、并揭示出新的数据模式,从而提供新的商业机会时才有价值。因此,为了实现这一点,机器学习是解锁每天积累的这些堆积如山的数据中存储价值的正确工具。
因此,很明显,现在是成为一名移动应用开发者以及机器学习数据科学家的大好时机。但如果我们能将机器学习的力量带到移动设备上,并开发出真正酷炫的、利用机器学习力量的移动应用,那会多么酷啊?这正是我们通过这本书所尝试做的事情:为移动应用开发者提供机器学习基础知识的见解,向他们介绍各种机器学习算法和移动机器学习 SDK/工具,并指导他们使用这些 SDK/工具开发移动机器学习应用。
移动空间中的机器学习是一个关键的创新领域,移动开发者必须正确理解,因为它正在改变用户可视化和利用移动应用的方式。那么,机器学习如何改变移动应用并将它们转化为任何用户的梦想应用?让我给你举一些例子,让你从宏观的角度了解机器学习可以为移动应用做什么:
- 
Facebook 和 YouTube 移动应用使用机器学习——推荐或你可能认识的人不过是机器学习的实际应用。 
- 
苹果和谷歌读取每个用户行为的行为或措辞,并推荐适合您打字风格的下一个单词。他们已经在 iOS 和 Android 设备上实施了这一功能。 
- 
Oval Money 分析用户的先前交易,并为他们提供不同的方式来避免额外支出。 
- 
Google Maps 正在使用机器学习使你的生活更轻松。 
- 
Django 使用机器学习来解决问题,寻找完美的表情符号。它是一个可以集成到不同通讯工具中的浮动助手。 
机器学习可以应用于属于任何领域的移动应用——医疗保健、金融、游戏、通信或任何阳光下的东西。因此,让我们了解机器学习究竟是什么。
在本章中,我们将涵盖以下主题:
- 
什么是机器学习? 
- 
在什么情况下适合采用使用机器学习实现的解决方案? 
- 
机器学习的分类 
- 
机器学习中的关键算法 
- 
实施机器学习需要遵循的过程 
- 
一些值得了解的机器学习关键概念 
- 
实施机器学习面临的挑战 
- 
为什么在移动应用中使用机器学习? 
- 
在移动应用中实现机器学习的方法 
机器学习的定义
机器学习专注于编写可以从以往经验中学习的软件。机器学习的一个标准定义,由卡内基梅隆大学(CMU)的教授 Tom Mitchell 给出,如下所示:
如果一个计算机程序在执行某些任务 T 和性能指标 P 方面从经验 E 中学习,那么它的性能随着经验 E 的提高而提高。
例如,一个学习下棋的计算机程序可能会通过与自己下棋获得的经验来提高其性能,即提高在涉及下棋的任务类别中获胜的能力。一般来说,为了有一个明确的学习问题,我们必须确定任务类别、要改进的性能指标和经验来源。考虑一下,一个学习下棋的问题包括以下内容:任务、性能指标和训练经验,其中:
- 
任务 T是下棋 
- 
性能指标 P是战胜对手的百分比 
- 
训练经验 E 是程序与自己进行实战棋局练习 
用简单的话来说,如果一个计算机程序能够借助以往的经验改进其完成任务的方式,那么这种方式你就可以知道计算机已经学会了。这种情况与一个程序能够执行特定任务的情况非常不同,因为它的程序员已经定义了所有参数,并提供了执行所需的数据。一个普通的程序可以执行下棋的任务,因为程序员已经编写了带有内置胜利策略的代码来玩棋。然而,机器学习程序没有内置的策略;实际上,它只有一套游戏合法移动的规则,以及什么是胜利场景。在这种情况下,程序需要通过反复玩游戏来学习,直到它能够获胜。
在什么情况下适合采用机器学习系统?
机器学习是否适用于所有场景?我们究竟在什么情况下应该让机器学习而不是直接用指令编程机器来执行任务?
机器学习系统不是基于知识的系统。在基于知识的系统中,我们可以直接使用知识来编码所有可能的规则,以推断出解决方案。当我们遇到这种指令编码不是直接可行的情况时,我们会选择机器学习。在以下场景中,机器学习程序将更加适用:
- 
难以编程的非常复杂任务:人类执行的一些常规任务,如说话、驾驶、看和识别事物、品尝,以及通过观察来对事物进行分类,对我们来说似乎很简单。但是,我们不知道我们的大脑是如何连接或编程的,或者需要定义哪些规则才能无缝地执行所有这些任务,为此我们可以创建一个程序来复制这些动作。通过机器学习可以执行其中的一些任务,虽然不能达到人类那样,但机器学习在这里有很大的潜力。 
- 
处理大量数据的非常复杂任务:有些任务包括分析大量数据,寻找隐藏的模式,或者在数据中提出新的相关性,这些任务对于人类来说是不可能的。机器学习对于那些我们不知道如何通过人类步骤到达解决方案的任务,以及由于各种解决方案的可能性而非常复杂的任务,是有帮助的。 
- 
适应环境和数据的变化:硬编码了一组指令的程序无法适应环境的变化,并且无法扩展到新的环境。这两者都可以通过机器学习程序实现。 
机器学习是一门艺术,专门从事机器学习的数据科学家需要具备数学、统计学、数据分析、工程、创意艺术、簿记、神经科学、认知科学、经济学等方面的技能。他需要是万事通,并且是机器学习的专家。
机器学习过程
机器学习过程是一个迭代过程。不能一蹴而就。对于机器学习解决方案,最重要的活动如下:
- 
定义机器学习问题(它必须是定义良好的)。 
- 
收集、准备和增强所需的数据。 
- 
使用这些数据来构建模型。这一步骤是循环进行的,包括以下子步骤。有时,它还可能导致重新访问步骤 2(数据)甚至需要重新定义问题陈述: - 
选择合适的模型/机器学习算法 
- 
在训练数据上训练机器学习算法并构建模型 
- 
测试模型 
- 
评估结果 
- 
继续此阶段,直到评估结果令人满意并最终确定模型 
 
- 
- 
使用最终确定的模型来对未来问题陈述进行预测。 
整个过程中涉及四个主要步骤,这是一个迭代和重复的过程,直到达到目标。接下来,我们将详细讨论每个步骤。以下图表将给出整个过程的快速概述,以便更容易进入细节:

定义机器学习问题
如汤姆·米切尔所定义,问题必须是一个定义良好的机器学习问题。在这个阶段需要解决的三个重要问题包括以下内容:
- 
我们是否有正确的问题? 
- 
我们是否有正确的数据? 
- 
我们是否有正确的成功标准? 
问题应该是这样的,即作为解决问题的结果将获得的成果对业务有价值。应该有足够的历史数据可用于学习/训练目的。目标应该是可衡量的,并且我们应该知道在任何时间点已经实现了多少目标。
例如,如果我们打算从一组在线交易中识别欺诈交易,那么确定此类欺诈交易对于业务肯定是有价值的。我们需要有足够的一组在线交易。我们还应该有足够的一组属于各种欺诈类别的交易。我们还应该有一个机制来确定预测为欺诈或非欺诈交易的预测结果是否可以验证和验证预测的准确性。
为了让用户了解实施机器学习所需的数据量,我们可以说,至少有 100 个项目的数据集对于初学者来说应该足够好,而 1000 个则更理想。我们拥有的数据越多,可能覆盖所有现实场景的问题域,对学习算法来说就越好。
准备数据
数据准备活动对于学习解决方案的成功至关重要。数据是机器学习所需的关键实体,必须正确准备以确保获得适当的结果和目标。
数据工程师通常将他们大约 80-90%的时间花在数据准备阶段,以获取正确的数据,因为这是基础且对于机器学习程序实施成功最关键的任务。
为了准备数据,需要执行以下操作:
- 
识别所有数据来源:我们需要识别所有可以解决当前问题的数据来源,并从多个来源——文件、数据库、电子邮件、移动设备、互联网等——收集数据。 
- 
探索数据:这一步骤涉及理解数据的性质,如下所述: - 
整合来自不同系统的数据并对其进行探索。 
- 
理解数据的特征和性质。 
- 
检查数据实体之间的相关性。 
- 
识别异常值。异常值有助于识别数据中的任何问题。 
- 
应用各种统计原理,如计算中位数、平均值、众数、范围和标准差,以得出数据偏斜。这将有助于理解数据的性质和分布。 
- 
如果数据有偏斜或我们看到的范围值超出了预期边界,我们知道数据存在问题,我们需要重新审视数据来源。 
- 
通过图表可视化数据也将有助于理解数据的分布和质量。 
 
- 
- 
预处理数据:这一步骤的目标是创建可以用于下一步的数据格式: - 
数据清洗: - 
处理缺失值。一种常用的处理缺失值的方法是将缺失值替换为平均值或中位数。定义一个替换缺失值的策略是很重要的。 
- 
处理重复值、无效数据、不一致数据、异常值等问题。 
 
- 
- 
特征选择:选择最适合当前问题的数据特征。移除冗余或不相关的特征以简化过程。 
- 
特征转换:这一阶段将数据从一种格式映射到另一种格式,这将有助于进行机器学习的下一步。这包括数据归一化和降维。这涉及到将各种特征组合成一个特征或创建新的特征。例如,假设我们有日期和时间作为属性。 将它们转换为星期、月份和年份会更具有意义,这将提供更有意义的洞察: - 
创建一个变量与另一个变量的笛卡尔积。例如,如果我们有两个变量,例如人口密度(数学、物理和商业)和性别(女孩和男孩),这两个变量的笛卡尔积可能包含有用的信息,从而形成如( maths_girls、physics_girls、commerce_girls、maths_boys、physics_boys和commerce_boys)这样的特征。
- 
将数值变量分箱到类别中。例如,臀围/肩宽的大小值可以分箱到如小、中、大和超大等类别。 
- 
领域特定特征,例如,将数学、物理和化学科目组合成一个数学组,将物理、化学和生物学组合成一个生物学组。 
 
- 
 
- 
- 
将数据分为训练集和测试集:一旦数据被转换,我们就需要选择所需的测试集和训练集。在训练数据集上训练后,算法将针对测试数据集进行评估。这种将数据分为训练集和测试集的方法可能非常直接,比如对数据进行随机分割(66%用于训练,34%用于测试),或者可能涉及更复杂的采样方法。 
66%/34%的分割只是一个指南。如果您有 100 万条数据,90%/10%的分割应该足够。对于 1 亿条数据,甚至可以降低到 99%/1%。
训练好的模型在训练期间不会接触到测试数据集,对该数据集所做的任何预测都是为了表明模型的整体性能。因此,我们需要确保数据集的选择能够代表我们正在解决的问题。
构建模型
模型构建阶段由许多子步骤组成,如前所述,包括选择合适的机器学习算法、训练模型、测试模型、评估模型以确定是否达到目标,如果没有,则通过选择不同的数据集或选择全新的算法重新训练,直到达到目标。
选择合适的机器学习算法
构建模型的第一步是选择可能解决问题的正确机器学习算法。
此步骤涉及选择合适的机器学习算法并构建模型,然后使用训练集对其进行训练。算法将从训练数据中学习将变量映射到目标的模式,并输出一个捕捉这些关系的模型。然后,可以使用机器学习模型对新数据(您不知道其目标答案的数据)进行预测。
训练机器学习模型
目标是选择最合适的算法来构建机器学习模型,对其进行训练,然后分析得到的结果。我们首先选择合适的机器学习技术来分析数据。下一章,即第二章,iOS 上的随机森林,将讨论不同的机器学习算法,并详细介绍它们适合解决的问题类型。
训练过程和分析结果也取决于所选择的训练算法。
训练阶段通常使用转换数据中存在的所有数据属性,这包括预测属性和目标属性。所有数据特征都在训练阶段被使用。
模型测试
一旦在训练数据中训练了机器学习算法,下一步就是在测试数据中运行模型。
数据集的所有属性或特征被分为预测属性和目标属性。数据集的预测属性/特征作为输入馈送到机器学习模型中,模型使用这些属性来预测目标属性。测试集仅使用预测属性。现在,算法使用预测属性并在目标属性上输出预测。一旦提供了输出,就会将其与实际数据进行比较,以了解算法输出的质量。
结果应该得到适当的展示,以便进行进一步分析。在结果中展示什么以及如何展示是至关重要的。它们也可能揭示新的业务问题。
模型评估
应该有一个过程来测试机器学习算法,以确定我们是否选择了正确的算法,并验证算法提供的输出是否符合问题陈述。
这是机器学习过程的最后一步,我们检查与定义的成功标准阈值相比的准确性,如果准确性大于或等于阈值,那么我们就完成了。如果不是,我们需要重新开始,使用不同的机器学习算法、不同的参数设置、更多数据和改变的数据转换。整个机器学习过程中的所有步骤都可以重复,或者可以重复其中的一部分。这些步骤会一直重复,直到我们达到“完成”的定义,并对结果感到满意。
机器学习过程是一个非常迭代的。一个步骤的发现可能需要重复前一个步骤,并使用新的信息。例如,在数据转换步骤中,我们可能会发现一些数据质量问题,这可能会要求我们回到不同的来源获取更多数据。
每一步也可能需要多次迭代。这尤其有趣,因为数据准备步骤可能需要多次迭代,模型选择也可能需要多次迭代。在整个执行机器学习的活动序列中,任何活动都可以重复多次。例如,在继续测试模型之前,尝试不同的机器学习算法来训练模型是很常见的。因此,重要的是要认识到这是一个高度迭代的过程,而不是线性的。
测试集创建:我们必须明确定义测试数据集。测试数据集的目标如下:
- 
快速且一致地测试所选算法以解决问题 
- 
测试各种算法以确定它们是否能够解决问题 
- 
确定哪种算法值得用于解决问题 
- 
确定用于评估的数据是否存在问题,因为如果所有算法都一致地无法产生正确的结果,那么数据本身可能需要重新审视。 
性能度量:性能度量是评估创建的模型的一种方式。需要使用不同的性能指标来评估不同的机器学习模型。这些是标准性能度量,我们可以从中选择来测试我们的模型。可能不需要为我们的模型定制性能度量。
以下是一些需要了解的重要术语,以便理解算法的性能度量:
- 
过拟合:当我们在训练数据上看到模型表现良好,但在评估数据上表现不佳时,我们称机器学习模型对训练数据过拟合。这是因为模型在记忆它所看到的数据,并且无法推广到未见过的例子。 
- 
欠拟合:当模型在训练数据上表现不佳时,我们称机器学习模型对训练数据欠拟合。这是因为模型无法捕捉输入例子(通常称为X)和目标值(通常称为Y)之间的关系。 
- 
交叉验证:交叉验证是一种通过将原始样本划分为训练集来训练模型,以及测试集来评估它的技术。在 k 折交叉验证中,原始样本被随机划分为k个大小相等的子样本。 
- 
混淆矩阵:在机器学习领域,特别是统计分类问题中,混淆矩阵,也称为错误矩阵,是一种特定的表格布局,它允许可视化算法的性能。 
- 
偏差:偏差是模型以一致方式做出预测的倾向。 
- 
方差:方差是模型预测与参数和标签之间真实关系差异的倾向。 
- 
准确率:正确结果除以总结果。 
- 
错误率:错误结果除以总结果。 
- 
精确率:机器学习算法返回的正确结果数量除以所有返回的结果数量。 
- 
召回率:机器学习算法返回的正确结果数量除以应该返回的结果数量。 
预测/现场部署
一旦模型准备就绪,就可以部署到现场使用。可以使用在现场构建和部署的模型对即将到来的数据集进行预测。
学习类型
对于如何定义机器学习算法的类型,有一些不同的定义方式。最常见的算法分类是根据算法的学习者类型进行的,分类如下:
- 
监督学习 
- 
无监督学习 
- 
半监督学习 
- 
强化学习 
监督学习
监督学习是一种学习类型,其中模型被提供足够的信息和知识,并受到密切监督以学习,这样,基于它所完成的学习,它可以预测新数据集的输出结果。
在这种情况下,模型在监督模式下进行训练,类似于教师的监督,其中我们向模型提供足够的训练数据,包含输入/预测因子,对其进行训练并展示正确的答案或输出。因此,基于此,它学习并最终能够预测未来可能出现的未见数据。
这里的一个经典例子是标准的鸢尾花数据集。鸢尾花数据集包括三种鸢尾花,对于每种鸢尾花,给出了其花瓣长度、花瓣宽度、萼片长度和萼片宽度。对于这四个参数的特定模式,提供了标签,说明这样的集合应该属于哪个物种。有了这种学习,模型将能够预测标签——在这种情况下,是鸢尾花物种,基于特征集——在这种情况下,是四个参数。
监督学习算法试图建模目标预测输出和输入特征之间的关系和依赖性,以便我们可以根据从先前数据集中学习到的这些关系来预测新数据的输出值。
下面的图表将向您展示什么是监督学习。带有标签的数据作为输入,通过监督学习算法构建模型,这是训练阶段。然后,模型被用来预测没有标签的任何输入数据的类别标签。这是测试阶段:

在监督学习算法中,预测的输出可能是一个离散/分类值,或者根据考虑的情景和数据集的类型,它可能是一个连续值。如果预测的输出是一个离散/分类值,那么这类算法属于分类算法,如果预测的输出是一个连续值,那么这类算法属于回归算法。
如果有一组电子邮件,你想从它们中学习并能够判断哪些电子邮件属于垃圾邮件类别,哪些电子邮件属于非垃圾邮件类别,那么用于此目的的算法将是一个属于分类类型的监督学习算法。在这里,你需要向模型提供一组电子邮件,并向模型提供足够的关于属性的知识,基于这些知识它将把电子邮件归类到垃圾邮件或非垃圾邮件类别。因此,预测的输出将是一个分类值,即垃圾邮件或非垃圾邮件。
让我们考虑这样一个用例,基于一组给定的参数,我们需要预测在特定区域的房价。这不能是一个分类值。它将是一个范围或连续值,并且会定期发生变化。在这个问题中,模型还需要提供足够的知识,基于这些知识它将预测定价值。这类算法属于监督学习回归算法类别。
有各种算法属于机器学习家族的监督类别:
- 
K-最近邻算法 
- 
朴素贝叶斯 
- 
决策树 
- 
线性回归 
- 
逻辑回归 
- 
支持向量机 
- 
随机森林 
无监督学习
在这种学习模式中,没有对模型进行任何监督以使其学习。模型通过自身根据提供的数据学习,并为我们提供它所学习的模式。它不预测任何离散的分类值或连续值,而是通过查看输入的数据提供它所理解的模式。输入的训练数据是无标签的,并且不提供足够的信息供模型学习。
在这里,没有任何监督;实际上,模型在学会数据后可能会教会我们新事物。这些算法在特征集太大且人类用户不知道在数据中寻找什么时非常有用。
这类算法主要用于模式检测和描述性建模。描述性建模从数据中总结相关信息并呈现已经发生的事件的摘要,而预测建模总结数据并呈现可能发生的事件的摘要。
无监督学习算法可以用于这两类预测。它们使用输入数据来提出不同的模式、数据点的摘要以及人类肉眼无法看到的信息。它们提出对最终用户有帮助的有意义派生数据或数据模式。
下面的图表将向您展示什么是无监督学习。无标签的数据作为输入,通过无监督学习算法构建模型。这是训练阶段。然后,模型被用来预测任何无标签输入数据的适当模式。这是测试阶段:

在这个算法家族中,它也基于模型接收到的输入数据和模型采用的方法来推断数据集中的模式,出现了两种常见的算法类别。这些是聚类和关联规则映射算法。
聚类是分析输入数据集并将具有相似性的数据项分组到同一聚类的模型。它产生不同的聚类,每个聚类将包含比属于其他聚类的数据项更相似的数据项。可以用来创建这些聚类的机制有很多种。
客户细分是聚类的一个例子。我们有一个庞大的客户数据集,并捕捉所有客户特征。模型可以提出对人类眼睛来说可能非常明显的有趣的客户聚类模式。这样的聚类对于有针对性的活动和营销非常有帮助。
另一方面,关联规则学习是一个用于发现大型数据集中变量之间关系的模型。一个经典的例子是市场篮子分析。在这里,模型试图找到市场篮子中不同项目之间强烈的关系。它预测项目之间的关系,并确定用户在购买另一个项目时购买特定项目的可能性或不可能性。例如,它可能会预测购买面包的用户也会购买牛奶,或者购买酒的用户也会购买尿布,等等。
属于这一类别的算法包括以下内容:
- 
聚类算法: - 
基于质心的算法 
- 
基于连接性的算法 
- 
基于密度的算法 
- 
概率论 
- 
维度约简 
- 
神经网络/深度学习 
 
- 
- 
关联规则学习算法 
半监督学习
在前两种类型中,数据集中的所有观测值可能都没有标签,或者标签存在于所有观测值中。半监督学习介于这两者之间。在许多实际情况下,标记的成本相当高,因为它需要熟练的人类专家来完成。因此,如果大多数观测值没有标签,但少数有标签,那么半监督算法是模型构建的最佳候选者。
语音分析是半监督学习模型的一个例子。对音频文件进行标注成本很高,并且需要非常高水平的人力。应用半监督学习模型确实可以帮助提高传统的语音分析模型。
在这类算法中,基于预测的输出,可能是分类的或连续的,算法家族可以是回归或分类。
强化学习
强化学习是基于与环境交互的面向目标的 学习。强化学习算法(称为智能体)以迭代的方式从环境中持续学习。在这个过程中,智能体从其与环境的经验中学习,直到探索所有可能的状态并能够达到目标状态。
让我们以一个孩子学习骑自行车的例子。孩子试图通过骑行来学习,他可能会摔倒,他会理解如何保持平衡,如何继续流动而不摔倒,如何坐在正确的位置以便重量不会移到一边,研究表面,并根据表面、斜坡、山丘等制定行动计划。因此,他将学习所有可能的场景和状态,这些是学习骑自行车所必需的。一次摔倒可以被视为负反馈,而沿着步伐骑行的能力可能对孩子来说是一个正面的奖励。这是经典的强化学习。这与模型在特定环境中确定理想行为以最大化其性能的方式相同。需要简单的奖励反馈来让智能体学习其行为;这被称为强化信号:

现在,我们将通过一个图表来总结我们所看到的类型学习算法,这样它将便于您作为参考点来决定针对给定问题选择算法:

机器学习中的挑战
我们在机器学习中面临的一些挑战如下:
- 
缺乏一个明确定义的机器学习问题。如果问题没有根据所需的准则明确定义,那么机器学习问题很可能会失败。 
- 
特征工程。这涉及到与数据及其特征相关的每一项活动,这些特征对于机器学习问题的成功至关重要。 
- 
训练集和测试集之间没有清晰性。通常模型在训练阶段表现良好,但由于训练集中缺少所有可能的数据,在实地应用中表现糟糕。为了使模型在实地成功,这一点应该得到妥善处理。 
- 
算法的正确选择。有大量的算法可供选择,但哪一个最适合我们的问题?这应该在迭代中正确选择,并使用适当的参数。 
为什么要在移动设备上使用机器学习?
需要机器学习从大量数据中提取有意义的和可操作的信息。分析大量数据并得出推论需要大量的计算。这种处理非常适合云环境。然而,如果我们能在移动设备上进行机器学习,以下将是优势:
- 
机器学习可以在离线状态下进行,因为不需要将移动设备上的所有数据发送到网络并等待服务器返回结果。 
- 
避免了由于将移动数据传输到服务器而产生的网络带宽成本。 
- 
通过本地处理数据可以避免延迟。移动机器学习具有很高的响应性,因为我们不必等待连接和从服务器返回的响应。服务器响应可能需要 1-2 秒,但移动机器学习可以立即完成。 
- 
隐私——这是移动机器学习的另一个优势。无需将用户数据发送到移动设备之外,从而实现更好的隐私。 
机器学习始于计算机,但新兴趋势表明,在移动设备上实现机器学习的移动应用开发是下一个大趋势。现代移动设备显示出足够的生产能力水平,足以执行适当的任务,与传统计算机一样。此外,还有一些来自全球企业的信号证实了这一假设:
- 
谷歌推出了 TensorFlow for Mobile。开发者社区对此也表现出极大的兴趣。 
- 
苹果推出了 Siri SDK 和 Core ML,现在所有开发者都可以将此功能集成到他们的应用中。 
- 
联想正在研发他们的新智能手机,该手机在没有互联网连接的情况下也能运行,并执行室内地理定位和增强现实。 
- 
大多数移动芯片制造商正在进行显著的研究,无论是苹果、高通、三星,甚至是谷歌本身,都在致力于为移动设备加速机器学习的专用硬件。 
- 
在硬件层有许多创新正在发生,以实现硬件加速,这将使移动设备上的机器学习变得容易。 
- 
许多针对移动设备优化的模型,如 MobileNets、Squeeze Net 等,都已经开源。 
- 
物联网设备和智能硬件设备的可用性正在增加,这将有助于创新。 
- 
人们对于离线场景的兴趣越来越多。 
- 
越来越多的关注集中在用户数据隐私上,用户希望他们的个人信息不要离开他们的移动设备。 
移动设备上机器学习的经典例子如下:
- 
语音识别 
- 
计算机视觉和图像分类 
- 
手势识别 
- 
从一种语言翻译成另一种语言 
- 
在设备上检测文本的交互式检测 
- 
自动驾驶汽车、无人机导航和机器人技术 
- 
患者监控系统与医疗设备交互的移动应用程序 
在移动应用程序中实现机器学习的方法
现在,我们清楚地理解了机器学习是什么以及在学习问题中需要执行的关键任务。对于任何机器学习问题,需要执行的四项主要活动如下:
- 
定义机器学习问题 
- 
收集所需的数据 
- 
使用那些数据来构建/训练一个模型 
- 
使用模型进行预测 
训练模型是整个过程中最困难的部分。一旦我们训练了模型并且模型准备好了,使用它对新数据集进行推理或预测就非常容易了。
对于前面提到的四个步骤,我们显然需要明确我们打算在哪里使用它们——在设备上还是在云端。
我们需要决定的主要事项如下:
- 
首先,我们是打算训练和创建一个自定义模型,还是使用预构建的模型? 
- 
如果我们想要训练自己的模型,我们是将其在桌面机器上训练还是在云端训练?在移动设备上训练模型是否有可能性? 
- 
一旦模型可用,我们是将其部署到本地设备上进行推理,还是将其部署到云端并从那里进行推理? 
以下是在移动应用程序中实现机器学习的广泛可能性。我们将在接下来的章节中详细介绍:

利用机器学习服务提供商进行机器学习模型
有许多服务提供商提供机器学习服务。我们只需利用它们即可。
提供机器学习服务的此类提供商的例子如下。这个列表每天都在增加:
- 
Clarifai 
- 
谷歌云视觉 
- 
微软 Azure 认知服务 
- 
IBM Watson 
- 
亚马逊网络服务 
如果我们采用这种模型,训练已经完成,模型已经构建,模型特性已作为网络服务公开。因此,我们只需从移动应用程序中调用模型服务,使用所需的数据集,从云提供商那里获取结果,然后根据我们的要求在移动应用程序中显示结果:

一些提供商提供了 SDK,使得集成工作变得非常简单。
我们可能需要向云服务提供商支付费用以利用他们的机器学习网络服务。根据不同的模型,可能存在各种收费方式,例如调用的次数、模型的类型等等。
因此,这是一个非常简单的方式来使用机器学习服务,实际上无需对模型做任何事情。在此基础上,机器学习服务提供商通过不断的重新训练来保持模型更新,包括在需要时添加新的数据集等。因此,模型的维护和改进在常规基础上自动得到处理。
因此,这种模型对于在移动领域是专家但对机器学习一无所知但想构建 ML 功能应用的人来说很容易。
因此,这种基于云的机器学习服务的明显好处如下:
- 
它易于使用。 
- 
不需要机器学习的知识,训练的困难部分由服务提供商完成。 
- 
重新训练、模型更新、支持和维护由提供商完成。 
- 
仅按使用付费。无需维护模型、训练数据等额外费用。 
这种方法的缺点如下:
- 
预测将在云端进行。因此,需要进行预测或推理的数据集必须发送到云端。数据集必须保持在最优大小。 
- 
由于数据通过网络传输,应用程序中可能会出现一些性能问题,因为现在整个系统都依赖于网络。 
- 
移动应用程序不会在离线模式下工作,而是作为完全在线应用程序运行。 
- 
主要来说,按请求付费。因此,如果应用程序的用户数量呈指数级增长,机器学习服务的成本也会增加。 
- 
训练和重新训练由云服务提供商控制。因此,他们可能已经为常见的数据集进行了训练。如果我们的移动应用程序将要使用一些非常独特的东西,那么预测可能不会工作。 
要开始使用 ML(机器学习)功能的应用程序,从成本和技术可行性来看,模型都是合适的。对于机器学习新手来说绝对完美。
训练机器学习模型的方法
训练我们自己的机器学习模型有各种方法。在探讨如何训练我们的模型之前,为什么我们要选择自己训练模型呢?
主要情况下,如果我们的数据在某些方面是特殊的或独特的,并且非常具体于我们的需求,当现有的解决方案不能用来解决我们的问题时,我们可能会决定训练自己的模型。
为了训练自己的模型,需要一个良好的数据集。一个好的数据集是那些在质量和数量上都很好且规模较大的数据集。
根据我们的需求和数据量,我们可以以多种方式/地点训练我们的模型。
- 
在桌面(云端训练): - 
通用云计算 
- 
托管机器学习 
- 
私有云/简单服务器机器 
 
- 
- 
在设备上:这不太可行。我们只能在移动设备上部署训练好的模型,并从移动设备上调用它。到目前为止,从移动设备上进行训练过程本身是不可行的。 
在桌面(云中训练)
如果我们决定在桌面上进行训练过程,我们必须根据我们的需求在云中或在我们谦逊的本地服务器上进行。
如果我们决定使用云服务,我们又有以下两种选择:
- 
通用云计算 
- 
托管机器学习 
通用云计算类似于利用云服务提供商来完成我们的工作。我们想要进行机器学习训练。因此,为了执行这项工作,无论需要什么,比如硬件、存储等,都必须从他们那里获得。我们可以使用这些资源做任何需要的事情。我们需要在这里放置我们的训练数据集,运行训练逻辑/算法,构建模型等。
一旦训练完成并且模型创建成功,模型就可以在任何地方使用。对于云服务提供商,我们只需支付使用硬件和存储的费用。
亚马逊网络服务(AWS)和 Azure 是一些云计算供应商。
使用这种方法的好处如下:
- 
硬件/存储可以在需要时采购和使用。当训练数据量增加时,无需担心存储增加等问题。需要时可以通过支付费用来增加。 
- 
一旦训练完成并且模型创建成功,我们可以释放计算资源。计算资源产生的费用仅限于训练期间,因此如果我们能够快速完成训练,我们可以节省很多。 
- 
我们可以自由下载训练好的模型并在任何地方使用它。 
当我们采取这种方法时,需要注意以下事项:
- 
我们需要负责整个训练工作和模型创建。我们只将使用执行这项工作所需的计算资源。 
- 
因此,我们需要了解如何训练和构建模型。 
现在,像亚马逊、微软和谷歌这样的公司现在在他们的现有云服务之上提供机器学习服务。在托管机器学习模型中,我们既不需要担心计算资源,也不需要担心机器学习模型。我们需要上传我们的问题集数据,从可用的模型列表中选择我们想要为我们的数据训练的模型,这就足够了。机器学习服务将负责训练模型,并将训练好的模型提供给我们使用。
当我们不太擅长编写自己的自定义模型并进行训练,但又不想完全依赖机器学习提供商使用他们的服务,而想在两者之间做点什么时,这种方法非常有效。我们可以选择模型,上传我们独特的数据集,然后根据我们的需求进行训练。
在这种类型的方案中,提供商通常会使我们绑定到他们的平台上。我们可能无法下载模型并在其他地方部署以供使用。我们可能需要绑定到他们,并从我们的应用程序中利用他们的平台来使用训练好的模型。
另一点需要注意的是,如果我们决定在以后的时间点转移到另一个提供商,训练好的模型不能导出到其他提供商。我们可能需要在新的提供商平台上再次进行训练过程。
在这种方法中,我们可能需要为计算资源——硬件/存储——付费,而且在训练后,为了使用训练好的模型,我们可能需要按使用情况进行持续付费,即按需付费;每次我们使用时,都需要为我们使用的部分付费。
使用这种方法的好处如下:
- 
我们不需要担心为训练数据所需的计算资源/存储。 
- 
我们不需要担心理解机器学习模型的细节来构建和训练定制模型。 
- 
只需上传数据,选择用于训练的模型,然后就可以了。获取用于使用的训练好的模型。 
- 
我们不需要担心将模型部署到任何地方供移动应用程序使用。 
在采用这种方法时,我们需要注意以下几点:
- 
主要的是,在训练过程结束后,我们可能会被绑定到他们的平台上,以便使用训练后获得的模型。然而,也有一些例外,比如谷歌的云平台。 
- 
我们可能只能从提供商提供的模型中进行选择。我们只能从可用的列表中进行选择。 
- 
从一个平台训练好的模型不能移动到另一个平台。因此,如果我们决定以后更换平台,我们可能需要在他们的平台上重新训练。 
- 
我们可能需要为计算资源付费,并且还需要为模型的持续使用付费。 
使用我们自己的私有云/简单服务器与在通用云上进行训练相似,只是我们需要管理计算资源/存储。在这种方法中,我们唯一错过的就是通用云解决方案提供商提供的灵活性,包括增加/减少计算和存储资源,维护和管理这些计算资源的开销等等。
这种方法给我们带来的主要优势是关于我们获得的数据的安全性。如果我们认为我们的数据非常独特并且需要完全保密,这是一个很好的选择。在这里,所有的事情都是使用我们自己的资源在内部完成的。
使用这种方法的好处如下:
- 
绝对一切都在我们的控制之下,包括计算资源、训练数据、模型等等。 
- 
它更加安全。 
在采用这种方法时,我们需要注意的如下:
- 
所有一切都需要我们管理。 
- 
我们应该对机器学习概念、数据、模型和训练过程有清晰的认识。 
- 
计算资源/硬件的持续可用性需要我们管理。 
- 
如果我们的数据集将要变得非常大,这可能不是非常有效,因为我们可能需要根据数据集大小的增加来扩展计算资源和存储。 
在设备上
在设备上的训练过程还没有流行起来。对于非常小的数据集可能是可行的。由于训练数据所需的计算资源以及存储数据所需的存储空间更多,通常移动不是执行训练过程的首选平台。
如果我们将移动作为训练过程的平台,重新训练阶段也会变得复杂。
执行推理——做出预测的方法
一旦创建了模型,我们需要使用该模型对新数据集进行推理或做出预测。类似于我们执行训练过程的各种方式,我们也可以有多种方法来执行推理过程:
- 
在服务器上: - 
通用云计算 
- 
托管机器学习 
- 
私有云/简单服务器机器 
 
- 
- 
在设备上 
在服务器上的推理需要网络请求,并且应用程序必须在线才能使用这种方法。但是,在设备上的推理意味着应用程序可以是一个完全离线的应用程序。因此,显然,对于在线应用程序的所有开销,在速度/性能等方面,对于离线应用程序来说更好。
然而,对于推理,如果需要更多的计算资源——即,需要处理能力/内存——则推理不能在设备上完成。
在服务器上执行推理
在这种方法中,一旦模型训练完成,我们就将模型托管在服务器上,以便从应用程序中利用它。
模型可以托管在云机器上或本地服务器上,或者可以是托管机器学习提供商的模型。服务器将发布端点 URL,需要访问它以利用它进行所需的预测。所需的数据集应作为输入传递给服务。
在服务器上执行推理使移动应用程序变得简单。模型可以定期改进,而无需重新部署移动客户端应用程序。可以轻松地将新功能添加到模型中。不需要升级移动应用程序以进行任何模型更改。
使用这种方法的好处如下:
- 
移动应用程序变得相对简单。 
- 
模型可以在任何时候更新,而无需重新部署客户端应用程序。 
- 
在不编写特定于操作系统的复杂推理逻辑的情况下,很容易支持多个操作系统平台。所有操作都在后端完成。 
当我们采用这种方法时,需要注意以下事项:
- 
应用程序只能在线模式下工作。应用程序必须连接到后端组件以执行推理逻辑。 
- 
需要维护服务器硬件和软件,并确保其正常运行。它需要为用户进行扩展。为了可扩展性,需要额外的成本来管理多个服务器并确保它们始终正常运行。 
- 
用户需要将数据传输到后端进行推理。如果数据量很大,他们可能会遇到性能问题,以及需要为传输数据付费的用户。 
设备上的推理
在这种方法中,机器学习模型被加载到客户端移动应用程序中。为了进行预测,移动应用程序在设备上本地运行所有推理计算,在自己的 CPU 或 GPU 上。它不需要与服务器进行任何与机器学习相关的通信。
速度是直接在设备上进行推理的主要原因。我们不需要通过服务器发送请求并等待回复。事情几乎瞬间发生。
由于模型与移动应用程序捆绑在一起,因此在一个地方升级模型并重用并不容易。必须进行移动应用程序升级。必须向所有活跃用户提供升级推送。所有这些都是一个很大的开销,并将消耗大量的努力和时间。
即使是微小的变化,使用非常少的额外参数重新训练模型也将涉及一个复杂的应用程序升级过程,将升级推送到活跃用户,并维护所需的基础设施。
使用这种方法的好处如下:
- 
用户可以在离线模式下使用移动应用程序。网络的可用性不是操作移动应用程序所必需的。 
- 
由于模型与应用程序源代码一起存在,预测和推理可以非常快速地进行。 
- 
预测所需的数据不需要通过网络发送,因此用户不需要涉及带宽成本。 
- 
运行和维护服务器基础设施没有开销,并且可以管理多个服务器以实现用户可扩展性。 
在采用这种方法时,我们需要注意以下事项:
- 
由于模型与应用程序一起包含,因此很难更改模型。虽然可以进行更改,但要让所有客户端应用程序都进行更改是一个成本高昂的过程,需要消耗努力和时间。 
- 
如果模型文件很大,可能会显著增加应用程序的大小。 
- 
预测逻辑应该为应用程序支持的每个操作系统平台编写,例如 iOS 或 Android。 
- 
所有模型都必须正确加密或混淆,以确保不会被其他开发者破解。 
在这本书中,我们将探讨如何利用可用的 SDK 和工具在移动设备本身上执行与机器学习相关的任务。
流行的移动机器学习工具和 SDK
以下是本书将要探讨的关键机器学习 SDK:
- 
谷歌的 TensorFlow Lite 
- 
苹果的 Core ML 
- 
来自 Facebook 的 Caffe2Go 
- 
Google 的 ML Kit 
- 
Fritz.ai 
我们将详细介绍 SDK 的细节,以及使用这些 SDK 构建的示例移动机器学习应用程序,利用不同类型的机器学习算法。
实现设备上机器学习所需的技能
为了在移动设备上实现机器学习,不需要对机器学习算法、整个过程以及如何构建机器学习模型有深入的了解。对于一个知道如何使用 iOS 或 Android SDK 创建移动应用的移动应用开发者来说,就像他们利用后端 API 调用后端业务逻辑一样,他们需要了解从他们的移动应用中调用机器学习模型进行预测的机制。他们需要了解将机器学习模型导入移动资源文件夹并调用模型的各种功能以进行预测的机制。
总结来说,以下图表显示了移动开发者实现设备上机器学习的步骤:
在移动设备上实现机器学习可以被视为类似于后端 API 集成。你单独构建 API,然后在需要的地方进行集成。同样,你在外部设备上单独构建模型,然后将其导入移动应用并在需要的地方进行集成。

摘要
在本章中,我们介绍了机器学习,包括机器学习的类型、它们的应用场景以及它们可以应用的实用场景。我们还看到了一个定义良好的机器学习问题是什么,以及何时需要寻求机器学习解决方案。然后我们看到了机器学习过程以及构建机器学习模型涉及的步骤,从定义问题到将模型部署到现场。我们还看到了在机器学习命名空间中使用的某些重要术语,这些术语值得了解。
我们看到了实现机器学习所面临的挑战,特别是我们看到了在移动设备上实现机器学习的必要性以及围绕这一挑战的问题。我们看到了实现移动应用中机器学习的不同设计方法。我们还看到了使用每种设计方法的好处,并注意到了我们在决定使用每种解决方案方法实现移动设备上的机器学习时需要分析和记住的重要考虑因素。最后,我们简要介绍了我们将在后续章节中详细介绍的几个重要的移动机器学习 SDK。这些包括 TensorFlow lite、Core ML、Fritz、ML Kit,最后是云端的 Google Vision。
在下一章中,我们将学习更多关于监督学习和无监督学习以及如何在移动设备上实现它们。
第二章:监督学习和无监督学习算法
在上一章中,我们了解了机器学习的各个方面,并介绍了机器学习算法的分类方法。在本章中,我们将进一步探讨机器学习算法,并尝试理解监督学习和无监督学习算法。这种分类基于算法的学习机制,是最流行的。
在本章中,我们将涵盖以下主题:
- 
以详细实际案例的形式介绍监督学习算法,以帮助理解其原理和指导原则 
- 
关键的监督学习算法及其应用领域: - 
朴素贝叶斯 
- 
决策树 
- 
线性回归 
- 
逻辑回归 
- 
支持向量机 
- 
随机森林 
 
- 
- 
以详细实际案例的形式介绍无监督学习算法,以帮助理解它 
- 
关键的无监督学习算法及其应用领域: - 
聚类算法 
- 
关联规则映射 
 
- 
- 
对不同移动 SDK 和工具的广泛概述,这些工具可用于在移动设备上实现这些算法 
监督学习算法简介
让我们来看看简单的日常生活中的监督学习。一位父亲要求他们的 15 岁儿子去商店买一些蔬菜。他们给他一份蔬菜清单,比如说甜菜、胡萝卜、豆类和番茄,他们希望他去买。他去了商店,能够根据母亲提供的清单识别出蔬菜,并将它们放入购物车中,然后去结账。这是怎么做到的?
简单。父亲通过提供每种蔬菜的实例来为儿子提供了足够的训练,这使他具备了足够的蔬菜知识。儿子使用他获得的知识来选择正确的蔬菜。他使用蔬菜的各种属性来确定蔬菜的正确类别标签,在这种情况下,是蔬菜的名称。以下表格给出了列表中蔬菜的一些属性,通过这些属性,儿子能够识别出类别标签,即蔬菜名称:
| 蔬菜名称 = 类别标签 | 胡萝卜 | 甜菜 | 豆类 | 番茄 | 
|---|---|---|---|---|
| 属性 1 = 颜色 | 橙色 | 粉色 | 绿色 | 红色 | 
| 属性 2 = 形状 | 圆锥形 | 圆形 | 棒状 | 圆形 | 
| 属性 3 = 纹理 | 硬 | 硬 | 软 | 软且多汁 | 
| 属性 4 = 大小 | 10 厘米长 | 3 厘米半径 | 10 厘米长 | 3 厘米半径 | 
| 属性 5 = 味道 | 甜 | 甜 | 平淡 | 甜酸 | 
我们刚刚介绍了监督学习。我们将此活动与机器学习的关键步骤联系起来:
- 
定义机器学习问题:根据在蔬菜的不同属性上已经获得的经验和训练,从商店中所有类别的蔬菜中购买正确的蔬菜类别。 
- 
准备/收集数据并训练模型:15 岁的儿子已经接受了关于所有蔬菜的充分知识训练。他对所见所吃的各种蔬菜及其属性和特征的知识,构成了该问题的历史训练数据,对于模型——15 岁的儿子来说。 
- 
评估模型:儿子被要求从商店购买一些蔬菜。这是提供给他的测试集,用于评估模型。模型现在的任务是根据提供的列表识别商店中蔬菜的正确类别标签。 
在某些情况下,识别和购买正确蔬菜时可能会出现错误。例如,儿子可能会购买双豆(豆类的一种变种)而不是普通豆子。这可能是由于他缺乏足够的关于豆子和双豆之间区别特征的训练。如果出现这样的错误,家长会重新用新的蔬菜类型对他进行训练,以便下次他不会犯同样的错误。
因此,我们看到了监督机器学习问题的基本概念和功能。现在让我们深入了解监督学习的细节。
深入了解监督学习算法
假设有预测属性,x1,x2,... xn,以及一个目标属性,y,对于给定的数据集。那么,监督学习就是机器学习任务,寻找一个预测函数,它接受来自数据集的预测属性和目标属性作为输入,并且能够将预测属性映射到目标属性,对于当前不在训练数据集中的未见数据,以最小的误差进行映射。
用于得出预测函数的数据集中的数据被称为训练数据,它由一组训练示例组成,每个示例包含一个输入对象,x(通常是向量),以及一个期望的输出值,Y。监督学习算法分析训练数据,并产生一个推断函数,该函数将输入映射到输出,也可以用于映射新的、未见的数据示例:
Y = f(X) + error
整个算法类别被称为监督学习,因为在这里我们考虑了学习和输出变量。所以,通过提供训练数据中所有实例的输入以及预期的输出,学习是监督算法。
监督算法既有预测属性又有目标函数。数据集中的预测属性是那些被认为可以预测目标函数的项。目标函数是机器学习的目标。这通常需要预测属性,可能还有一些其他计算功能,并且通常会输出一个单一的数值。
一旦我们定义了一个需要监督学习的适当机器学习问题,下一步就是选择解决该问题的机器学习算法。这是一个最困难的任务,因为存在大量的学习算法,从其中选择最合适的一个是一个噩梦。
彼得·多明戈斯教授提供了一个简单的参考架构 (homes.cs.washington.edu/~pedrod/papers/cacm12.pdf),基于此架构,我们可以使用三个对于任何机器学习算法都至关重要的关键组件来进行算法选择,如下所示:
- 
表示:模型被表示的方式,以便计算机可以理解。这也可以被视为模型将在其中起作用的假设空间。 
- 
评估:对于每个算法或模型,都需要一个评估或评分函数来确定哪个表现更好。评分函数会因算法类型的不同而不同。 
- 
优化:一种在模型中搜索最高评分的方法。优化技术的选择对于学习者的效率至关重要,并且有助于确定如果评估函数有多个最优解时产生的模型。 
监督学习问题可以进一步分为回归和分类问题:
- 
分类:当输出变量是一个类别,例如绿色或红色,或者好或坏时。 
- 
回归:当输出变量是一个实数值,例如美元或重量时。 
在本节中,我们将通过易于理解的示例介绍以下监督学习算法:
- 
Naive Bayes 
- 
决策树 
- 
线性回归 
- 
逻辑回归 
- 
支持向量机 
- 
随机森林 
Naive Bayes
Naive Bayes 是一种强大的分类算法,基于贝叶斯定理的原理实现。它假设数据集中考虑的特征变量之间不存在依赖关系。
贝叶斯定理描述了基于先前关于可能与事件相关的事件条件的知识来描述事件的概率。例如,如果癌症与年龄相关,那么,使用贝叶斯定理,一个人的年龄可以用来更准确地评估他们患癌症的概率,与不知道这个人年龄的情况下评估癌症概率相比。
朴素贝叶斯分类器假设一个特定特征在类别中的存在与任何其他特征的存在无关。例如,一个蔬菜如果它是橙色的、锥形的,并且大约三英寸长,就可以被认为是胡萝卜。该算法之所以被称为朴素,是因为它独立地考虑所有这些属性来贡献这个蔬菜是胡萝卜的概率。通常,特征不是独立的,但朴素贝叶斯在预测时将它们视为独立。
让我们看看朴素贝叶斯算法的实际应用。假设我们有一些新闻源,我们想要将这些新闻源分类为文化事件和非文化事件。让我们考虑以下句子:
- 
戏剧性事件进行得很顺利——文化事件 
- 
这个良好的公共集会有大量人群——非文化事件 
- 
音乐展示很棒——文化事件 
- 
戏剧性事件吸引了大量人群——文化事件 
- 
政治辩论非常有信息量——非文化事件 
当我们使用贝叶斯定理时,我们只想使用概率来计算句子是否属于文化事件或非文化事件。
就像胡萝卜的情况一样,我们有颜色、形状和大小的特征,我们将它们都视为独立特征来决定所考虑的蔬菜是否是胡萝卜。
同样,为了确定一个新闻源是否与文化事件相关,我们取一个句子,然后从句子中考虑每个词作为一个独立的特征。
贝叶斯定理指出 p(A|B) = p(B|A). P(A)/ P(B),其中 P(文化事件|戏剧性展示良好) = P(戏剧性展示良好|文化事件).P(文化事件)/P(戏剧性展示良好)。
我们可以忽略分母,因为我们正在确定文化类别和非文化类别中哪个标签有更高的概率。文化事件和非文化事件的分母将是整个数据集,因此是相同的。
P(戏剧性展示良好) 无法找到,因为这个句子在训练数据中没有出现。所以这就是朴素贝叶斯定理真正发挥作用的地方:
P(戏剧性展示良好) = P(戏剧).P(展示).P(良好)
P(戏剧性展示良好/文化事件) = P(戏剧|文化事件).P(展示|文化事件)|P(良好|文化事件)
现在很容易计算这些并确定新的新闻源是否是文化新闻源或政治新闻源:
P(文化事件) = 3/5 (在总共 5 个句子中有 3 个)
P(非文化事件) = 2/5
*P(戏剧/文化事件) = 计算戏剧在文化事件标签中出现的次数 *= 2/13 (戏剧在文化事件标签的总词数中出现 2 次)
P(展示/文化事件) = 1/13
P(良好/文化事件) =1/13
有各种技术,如去除停用词、词干提取、n-gram 和 TF-IDF,可以使文本分类的特征识别更加有效。我们将在接下来的章节中介绍其中的一些。
这里是最终的计算总结:
| 词 | **P(word | 文化事件)** | **P(word | 非文化事件)** | 
|---|---|---|---|---|
| 戏剧性 | 2/13 | 0 | ||
| 显示 | 1/13 | 0 | ||
| 好 | 1/13 | 1/13 | 
现在,我们只需将概率相乘,看看哪个更大,然后将句子拟合到那个标签类别中。
因此,我们可以从表中知道,该标签将属于文化事件类别,因为当个体概率相乘时,这将导致更大的产品。
这些例子为我们介绍了朴素贝叶斯定理,它可以应用于以下领域:
- 
文本分类 
- 
邮件过滤 
- 
文档分类 
- 
社交媒体中的情感分析 
- 
根据体裁对新闻文章进行分类 
决策树
决策树算法用于根据某些条件做出决策。决策树是倒置的,其根在顶部.
让我们以一个组织的为例,其特征集包括某些软件产品及其属性——构建产品的耗时 T,构建产品的努力 E,以及构建产品的成本 C。需要决定这些产品是在公司内部构建还是直接从公司外部购买。
现在,让我们看看如何创建这个决策树。以下图表中,黑色粗体文本代表条件/内部节点,根据这个节点,树分为分支/边。分支的末端不再分裂的是决策/叶子节点。
决策树在项目管理、项目管理和风险规划中使用。让我们看看一个实际例子。以下图表显示了组织用于决定其哪些软件需要内部构建或直接从外部购买产品的决策树。在做出决定之前需要考虑各种决策点,这可以表示为树的形式。三个特征,成本、努力和进度参数,被考虑用于决定购买或构建:

上述树被称为分类树,因为目标是根据购买或构建来对产品性质进行分类。回归树以相同的方式表示,只是它们预测连续值,例如房屋的价格。通常,决策树算法被称为CART或分类和回归树。
决策树可以应用于以下领域:
- 
风险识别 
- 
贷款处理 
- 
选举结果预测 
- 
流程优化 
- 
可选定价 
线性回归
回归分析 线性回归是一种统计分析方法,它寻找变量之间的关系。它帮助我们理解输入和输出数值变量之间的关系。
在此方法中,确定因变量非常重要。例如,房屋的价值(因变量)根据房屋的大小而变化;也就是说,其面积是多少平方英尺(自变量)。房屋的价值根据其位置而变化。线性回归技术可用于预测。
当响应是连续变量时,使用线性回归。以下图表清楚地显示了单变量线性回归的工作原理。房屋的价格根据其大小而变化,并在以下图表中表示:

线性回归可以应用于以下领域:
- 
营销 
- 
定价 
- 
推广 
- 
分析消费者行为 
逻辑回归
逻辑回归是一种分类算法,最适合预测的输出是二元类型——真或假、男或女、赢或输等。二元类型意味着只有两种可能的结果。
逻辑回归之所以称为逻辑回归,是因为算法中使用了 S 形函数。
对数函数或对数曲线是一种常见的 S 形(S 形曲线),由以下方程表示:

S 形曲线在此处展示。它是一条 S 形曲线:

此曲线的有限极限如下:
- 
当x趋近于−∞时的0 
- 
当x趋近于+∞时的1 
当x=0时,S 形函数的输出为0.5。
因此,如果输出大于0.5,我们可以将结果分类为 1(或是),如果小于0.5,我们可以将其分类为 0(或否)。例如:如果输出为0.65,从概率的角度来看,它可以解释为—今天下雨的概率是 65%。
因此,S 形函数的输出不仅可以用作是/否的分类,还可以用来确定是/否的概率。它可以应用于以下领域:
- 
图像分割和分类 
- 
地理图像处理 
- 
手写识别 
- 
医疗保健,用于疾病预测和基因分析 
- 
预测在预期有二元结果的各种领域 
支持向量机
支持向量机(SVM)是一种监督机器学习算法,可用于分类和回归。SVMs 更常用于分类。
给定一些数据点,每个数据点属于两个二进制类别之一,目标是决定新的数据点将属于哪个类别。我们需要将数据点可视化为一个 p 维向量,并确定我们是否可以用一个(p-1)维超平面将两个这样的数据点分开。
可能存在许多超平面可以分离这样的数据点,而这个算法将帮助我们找到提供最大分离的最佳超平面。这个超平面被称为最大间隔超平面,而这个分类器被称为最大间隔分类器。我们可以将分离超平面的概念扩展到几乎分离类别的超平面,使用所谓的软间隔。最大间隔分类器对不可分情况的一般化称为支持向量分类器。
让我们来看第一个例子。在这个例子中,有一个超平面将红色点和蓝色点分开:

但想象一下,如果点分布如下——我们将如何识别将红色点和蓝色点分开的超平面:

解决方案是使用支持向量机(SVM)来识别超平面。它可以执行变换以识别用于分类的两个类别之间的超平面。它将引入一个新的特征,z,其值为z=x²+y²。让我们用x和z轴绘制图形,并识别用于分类的超平面:

现在我们已经了解了支持向量机(SVM)的基本概念,让我们看看它可以在哪些领域应用:
- 
人脸检测 
- 
图像分类 
- 
生物信息学 
- 
地球和环境科学 
- 
遗传学 
- 
蛋白质研究 
- 
手写识别 
随机森林
我们已经看到了决策树是什么。在理解了决策树之后,让我们来看看随机森林。随机森林将许多决策树组合成一个单一模型。单个决策树(或人类)做出的预测可能并不准确,但结合起来,平均而言,预测将更接近目标。
下面的图示展示了一个随机森林,其中包含多个树,每棵树都在进行预测:

随机森林是由许多决策树组合而成的,因此,从森林中的所有树中获得多个视角以到达最终期望的结果/预测的可能性更大。如果只考虑单个决策树进行预测,用于预测的信息就较少。但在随机森林中,当涉及许多树时,信息来源是多样化和广泛的。与决策树不同,随机森林没有偏差,因为它们不依赖于单一来源。
下面的图示展示了随机森林的概念:

随机森林可以应用于以下领域:
- 
风险识别 
- 
贷款处理 
- 
选举结果预测 
- 
流程优化 
- 
可选定价 
无监督学习算法简介
考虑一个场景,孩子被给了一袋大小、颜色、形状各异且由不同材料制成的珠子。我们让孩子随意处理整个珠子袋。
根据孩子的兴趣,他们可以做很多事情:
- 
根据大小将珠子分类 
- 
根据形状将珠子分类 
- 
根据颜色和形状的组合将珠子分类 
- 
根据材料、颜色和形状的组合将珠子分类 
可能性是无限的。然而,没有任何先前教导的孩子能够通过手头的珠子并揭示出他们不需要任何先前知识的模式。他们纯粹是基于手头的珠子,即手头的数据来发现模式的。我们刚刚接触到了无监督机器学习!
我们将把前面的活动与机器学习的关键步骤联系起来:
- 
定义机器学习问题:从给定的珠子袋中揭示珠子的隐藏模式。 
- 
准备/收集数据和训练模型:孩子打开装满珠子的袋子,了解袋子里有什么。他们发现不同珠子的属性: - 
颜色 
- 
形状 
- 
大小 
- 
材料 
 
- 
- 
评估模型:如果给孩子一组新的珠子,他们将如何根据他们之前的聚类珠子经验对这些珠子进行聚类? 
在分组珠子时可能存在需要纠正/修复的错误,以防止它们在未来再次发生。
因此,现在我们已经了解了无监督机器学习的基本概念和函数,让我们深入了解无监督学习的细节。
深入了解无监督学习算法
无监督机器学习处理的是未标记的数据——也就是说,尚未分类或归类的数据,并据此得出结论/模式。
这些类别从未标记、未分类或未归类的测试数据中学习。无监督学习不是响应反馈,而是识别数据中的共性,并根据每份数据中这种共性的存在与否做出反应。
传递给学习算法的输入是无标签的,因此没有直接的方法来评估算法产生的输出结构的准确性。这是无监督学习与监督学习区别的一个特征。
无监督算法具有预测属性,但没有目标函数。
没有目标函数意味着什么?考虑以下情况:
- 
探索数据中的自然分组。 
- 
学习关联规则,然后检查它们是否有任何用处。 
这里有一些经典的例子:
- 
执行市场篮子分析,然后优化货架分配和摆放 
- 
级联或相关机械故障 
- 
超出已知类别的人口统计分组 
- 
规划产品捆绑优惠 
在本节中,我们将通过易于理解的示例介绍以下无监督学习算法:
- 
聚类算法 
- 
关联规则映射 
主成分分析(PCA)和奇异值分解(SVD)如果您想深入了解这些概念,可能也会很有兴趣。
聚类算法
聚类算法的作用是将数据集聚类成有用的组。聚类的目标是创建数据点的组,使得不同簇中的点不相似,而簇内的点相似。
对于聚类算法能够工作,有两个基本要素:
- 
相似度函数:这决定了我们如何决定两个点相似。 
- 
聚类方法:这是观察到的用于达到簇的方法。 
需要有一个机制来确定点之间的相似性,基于此,它们可以被分类为相似或不相似。存在各种相似度度量。以下是一些:
- 欧几里得:

- 余弦:

- KL 散度:

聚类方法
一旦我们知道了相似度度量,接下来就需要选择聚类方法。我们将介绍两种聚类方法:
- 
层次聚类方法 
- 
K-means 聚类 
层次聚类方法
聚类层次聚类是来自统计学领域的一个经典聚类算法。它涉及迭代合并两个最相似的组,最初这些组包含单个元素。算法的名称指的是其工作方式,因为它以聚合或自下而上的方式创建层次结果,即通过将较小的组合并成较大的组。
这是用于文档聚类的这种聚类方法的高级算法。
- 
通用聚合过程(Salton, G: 《自动文本处理:计算机对信息的转换、分析和检索》,Addison-Wesley,1989)通过迭代产生嵌套簇。 
- 
计算所有成对文档之间的相似度系数 
- 
将每份n文档放入一个自己的类别中 
- 
将两个最相似的簇合并成一个: - 
用新的簇替换这两个簇 
- 
重新计算关于新聚类的簇间相似度得分 
- 
如果簇半径大于 maxsize,则阻止进一步合并 
 
- 
- 
重复前面的步骤,直到只剩k个簇(注意:k可能等于1) 
K-means 聚类
此 K 均值聚类算法的目的是在数据中找到 K 个组,每个组都有相似的数据点。该算法通过迭代地根据提供的特征将每个数据点分配到K个组中的一个。数据点根据特征相似性进行聚类。
K 值在算法开始时随机分配,通过改变 K 值可以获得不同的结果变体。一旦选择了 K 值并启动了算法的活动序列,如以下各点所示,我们发现有两个主要步骤会不断重复,直到簇中不再有变化的空间。
重复的两个主要步骤如下所示:步骤 2和步骤 3:
- 
步骤 2:将数据集中的数据点分配到 K 个簇中的任何一个。这是通过计算数据点到簇质心的距离来完成的。如指定,我们可以使用我们之前讨论的任何距离函数来进行这个计算。 
- 
步骤 3:在这里再次发生质心的重新校准。这是通过取分配给该质心簇的所有数据点的平均值来完成的。 
算法的最终输出是具有相似数据点的 K 个簇:
- 
选择 k-seeds d(k[i],kj) > d[min] 
- 
根据最小距离分配点到簇: 

- 计算新的簇质心:

- 
将点重新分配到簇(如步骤 2) 
- 
迭代直到没有点改变簇。 
下面是一些聚类算法被使用的领域:
- 
城市规划 
- 
地震研究 
- 
保险 
- 
营销 
- 
医学,用于分析抗菌活性和医学成像 
- 
犯罪分析 
- 
机器人学,用于异常检测和自然语言处理 
关联规则学习算法
关联规则挖掘对于分类的非数值数据更有用。关联规则挖掘主要关注在一系列物品中寻找频繁共现的关联。有时它也被称为市场篮子分析。
在购物篮中,目标是确定哪些物品经常一起出现。这显示了从随机抽样方法中很难找到的相关性。这个经典的例子是著名的啤酒和尿布关联,这在数据挖掘书籍中经常被提及。场景是这样的:去商店买尿布的男性也倾向于买啤酒。这个场景很难通过随机抽样直观或确定。
另一个例子是在 2004 年由沃尔玛发现的,当时一系列飓风横扫佛罗里达州。沃尔玛想知道在飓风来临前购物者通常会购买什么。他们发现有一个特定商品的销售量在正常购物日增加了七倍;这个商品不是瓶装水、电池、啤酒、手电筒、发电机或我们可能想象到的任何常见物品。这个商品是草莓泡芙!可以设想许多原因来解释为什么这是飓风来临前最想要的产品——泡芙不需要冷藏,不需要烹饪,它们是独立包装的,保质期长,它们是零食,也是早餐食品,孩子们喜欢它们,我们也喜欢它们,理由还有很多。尽管有这些明显的理由,这仍然是一个巨大的惊喜!
在挖掘关联时,以下内容可能有用:
- 
搜索非数值项的罕见和异常共现关联。 
- 
如果数据是时间序列数据,在数据挖掘实验中引入时间延迟的影响,看看相关性的强度是否会在更晚的时间达到峰值。 
市场篮子分析可以应用于以下领域:
- 
零售管理 
- 
店铺管理 
- 
库存管理 
- 
美国国家航空航天局和环境影响研究 
- 
医疗诊断 
摘要
在本章中,我们通过一个简单的例子了解了什么是监督学习,并深入探讨了监督学习的概念。我们通过实际例子和它们的应用领域,逐一介绍了各种监督学习算法,然后我们开始通过简单的例子介绍无监督学习。我们也涵盖了无监督学习的概念,然后通过实际例子和它们的应用领域,逐一介绍了各种无监督学习算法。
在随后的章节中,我们将通过使用本章介绍的一些监督学习和无监督学习算法来解决移动机器学习问题。我们还将向您介绍移动机器学习 SDK,这些 SDK 将用于实现移动机器学习解决方案。
参考文献
- 彼得罗·多明戈博士的论文——homes.cs.washington.edu/~pedrod/papers/cacm12.pdf, 总结了机器学习研究人员和实践者学到的十二个关键教训,包括要避免的陷阱、要关注的重要问题和该领域常见问题的答案。
第三章:iOS 上的随机森林
本章将为您概述随机森林算法。我们首先将探讨决策树算法,一旦我们掌握了它,我们将尝试理解随机森林算法。然后,我们将使用 Core ML 创建一个利用随机森林算法的机器学习程序,根据给定的一组乳腺癌患者数据预测患者被诊断为乳腺癌的可能性。
正如我们在第一章,“移动机器学习简介”中已经看到的,任何机器学习程序都有四个阶段:定义机器学习问题、准备数据、构建/重建/测试模型以及部署使用。在本章中,我们将尝试将这些与随机森林联系起来,并解决背后的机器学习问题。
问题定义:提供了某些患者的乳腺癌数据,我们想要预测新数据项被诊断为乳腺癌的可能性。
我们将涵盖以下主题:
- 
理解决策树及其如何应用于解决机器学习问题 
- 
通过示例数据集和 Excel 理解决策树 
- 
理解随机森林 
- 
在 Core ML 中使用随机森林解决问题: - 
技术要求 
- 
使用 scikit-learn 和 pandas 库创建模型文件 
- 
测试模型 
- 
将 scikit-learn 模型导入 Core ML 项目 
- 
编写 iOS 移动应用程序并在其中使用 scikit-learn 模型进行乳腺癌预测 
 
- 
算法简介
在本节中,我们将探讨决策树算法。我们将通过一个示例来理解该算法。一旦我们对算法有了清晰的认识,我们将通过示例尝试理解随机森林算法。
决策树
要理解随机森林模型,我们首先必须了解决策树,这是随机森林的基本构建块。我们每天都在使用决策树,即使你不认识这个名字。一旦我们开始通过示例进行讲解,你将能够与决策树的概念联系起来。
想象一下,您去银行申请贷款。银行会在批准贷款之前对您的一系列资格标准进行审查。对于每个人,他们提供的贷款金额将根据他们满足的不同资格标准而有所不同。
他们可能会通过一系列决策点来做出最终决定,以确定是否批准贷款以及可以提供的金额,例如以下内容:
- 
收入来源:受雇还是自雇? 
- 
如果受雇,工作地点:私营部门还是政府部门? 
- 
如果私营部门,薪资范围:低、中或高? 
- 
如果政府部门,薪资范围:低、中或高? 
可能会有更多问题,例如你在那家公司工作了多少年,或者你是否有任何未偿还的贷款。这个过程在最基本的形式上是一个决策树:

如前图所示,决策树是非参数有效机器学习建模技术,广泛用于分类问题。为了找到解决方案,决策树根据预测数据对结果进行顺序、分层决策。
对于任何给定的数据项,会问一系列问题,这些问题会导致一个类别标签或值。该模型对传入的数据项提出一系列预定义的问题,并根据这些答案分支到那个系列,并继续进行,直到到达最终的数据值或类别标签。该模型基于观察到的数据构建,没有对错误分布或数据本身的分布做出任何假设。
在决策树模型中,如果目标变量使用一组离散值,这被称为分类树。在这些树中,每个节点或叶子代表类别标签,而分支代表导致类别标签的特征。
目标变量取连续值(通常是数字)的决策树称为回归树。
这些决策树可以用有向无环图(DAGs)很好地表示。在这些图中,节点代表决策点,边是节点之间的连接。在前面的贷款场景中,$30,000-$70,000 的薪资范围将是一条边,而中等将是节点。
决策树算法的优点
决策树的目标是为给定的问题找到最佳选择。最终的叶子节点应该是手头问题的最佳选择。算法行为贪婪,试图在每个决策中都做出最佳选择。
整个问题被划分为多个子问题,每个子问题又分支出其他子问题。这些子集是基于一个称为纯度的参数。当一个节点的所有决策都将导致属于同一类别的数据时,该节点被认为是 100%纯的。如果有可能将其子集分割成类别,则将是 100%不纯的。算法的目标是使树中的每个节点达到 100%的纯度。
节点的纯度使用 Gini 不纯度来衡量,Gini 不纯度是一个标准指标,有助于分割决策树的节点。
在决策树中还会使用另一个指标,即信息增益,它将用于决定在树的每个步骤中应该使用数据集的哪个特征进行分割。信息增益是在数据集根据属性分割后的熵(随机性)的减少。构建决策树就是寻找能够返回最高信息增益的属性,即最同质的分支,这意味着所有属于同一子集或类的数据。
决策树的缺点
模型仅在所有数据点都可以适合单个类别时停止。因此,它可能不适合复杂问题,并且偏差的可能性很高。
这些问题可以通过定义树的最大深度或指定在树中进一步分割节点所需的最小数据点数量来解决。
决策树的优势
以下列出了优势:
- 
简单易懂且易于可视化 
- 
非常容易构建,可以处理定性和定量数据 
- 
容易验证 
- 
从计算角度来看,这并不昂贵 
总结决策树模型,我们可以得出结论,它基本上是一个通向预测的问题流程图。
随机森林
现在,让我们从单个决策树转向随机森林。如果你想要猜测下一位总统是谁,你会如何进行预测?让我们看看预测这个问题我们会问的不同类型的问题:
- 
有多少候选人?他们是谁? 
- 
现任总统是谁? 
- 
他们表现如何? 
- 
他们属于哪个政党? 
- 
是否有任何针对该党的当前运动? 
- 
在多少个州政治党派有获胜的概率 
- 
他们是否是现任总统? 
- 
主要的投票问题有哪些? 
我们脑海中会涌现出许多类似的问题,并且我们会为它们分配不同的权重/重要性。
每个人对先前问题的预测可能不同。需要考虑的因素太多,每个人的猜测可能不同。每个人带着不同的背景和知识水平来到这些问题面前,可能会对问题有不同的解读。
因此,答案的方差可能很高。如果我们分别取不同个体给出的所有预测并平均它们,就变成了随机森林。
随机森林将多个决策树组合成一个单一模型。单个决策树(或人类)做出的预测可能并不准确,但结合在一起,预测的平均值将更接近真实值。
以下图表将帮助我们理解使用随机森林算法进行投票预测:

以下图表给出了前一个图表的流程图视图:

让我们看看为什么随机森林比决策树更好:
- 
随机森林是由许多决策树组合而成的,因此,最终预测会有更多观点的可能性更大。 
- 
如果只考虑单个决策树进行预测,则考虑的预测信息较少。但是,在随机森林中,当涉及许多树时,信息更多且更多样化。 
- 
随机森林可能不会像决策树那样有偏差,因为它不依赖于单一来源。 
为什么叫随机森林?嗯,尽管人们可能依赖于不同的来源来做出预测,但森林中的每个决策树在形成问题时都会考虑特征的一个随机子集,并且只能访问训练数据点的随机集合。这增加了森林的多样性,导致更稳健的整体预测,因此得名随机森林。
在 Core ML 中使用随机森林解决问题
在本节中,我们将通过一个具体的示例数据集的详细示例来了解随机森林。我们将使用相同的数据集来处理 iOS Core ML 示例。
数据集
我们将使用乳腺癌数据集来处理随机森林问题。特征是从乳腺肿块细针吸取(FNA)的数字化图像中计算的。它们描述了图像中存在的细胞核的特征。数据集可以在archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+(Diagnostic)找到。
命名数据集
我们将使用乳腺癌数据集。以下列表包含了数据集中使用的各种约定:
- 
身份编号 
- 
诊断(M = 恶性,B = 良性) 
- 
每个细胞核计算 10 个实值特征: - 
半径(从中心到轮廓上点的距离的平均值) 
- 
纹理(灰度值的标准差) 
- 
周长 
- 
面积 
- 
平滑度(半径长度的局部变化) 
- 
紧凑度(周长²/面积 - 1.0) 
- 
凸度(轮廓凹部分的严重程度) 
- 
凸点(轮廓凹部分的数量) 
- 
对称性 
- 
分形维度(海岸线近似-1) 
 
- 
我们将通过 Excel 使用随机森林,应用乳腺癌数据集,以详细了解随机森林。在分析目的上,我们只考虑来自乳腺癌数据集的 569 个样本数据中的数据元素。
技术要求
需要在开发者机器上安装以下软件:
- 
Python 
- 
macOS 环境下的 Xcode 
本章的练习程序可以在 GitHub 仓库(github.com/PacktPublishing/Machine-Learning-for-Mobile)的Chapter03文件夹中找到。让我们先输入安装 Python 包的命令:
pip install pandas
pip install -U scikit-learn
pip install -U pandas
然后,发出安装coremltools的命令:
pip install -U coremltools
使用 scikit-learn 创建模型文件
本节将解释我们将如何使用 scikit-learn 创建随机森林模型文件并将其转换为与 Core ML 兼容的.mlmodel文件。我们将使用乳腺癌数据集来创建模型。以下是一个 Python 程序,它使用 scikit-learn 和乳腺癌数据集创建一个简单的随机森林模型。然后,Core ML 工具将其转换为 Core ML 兼容的模型文件。让我们详细地审查这个程序。
首先,我们需要导入所需的包:
# importing required packages
 import numpy as np
NumPy 是 Python 科学计算的基础包。它包含一个强大的 N 维数组对象。这个numpy数组将在这个程序中用于存储数据集,该数据集有 14 个维度:
import pandas as pd
 from pandas.core import series
在这里,我们使用 pandas(pandas.pydata.org/pandas-docs/stable/10min.html),这是一个开源的 BSD 许可库,为 Python 编程语言提供高性能、易于使用的数据结构和数据分析工具。使用 pandas,我们可以创建一个数据框。您可以假设 pandas 数据框是一个 Excel 表,其中每个表都有标题和数据。
现在,让我们继续了解为解决当前机器学习问题编写的程序:
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import sklearn.datasets as dsimport sklearn.datasets as ds
上一行导入了sklearn包。现在,我们将导入sklearn包中的内置数据集:
dataset = ds.load_breast_cancer()
上一行从sklearn数据集包中加载了乳腺癌数据集:
 cancerdata = pd.DataFrame(dataset.data)
这将创建一个从数据集中现有数据生成的数据框。假设数据集是一个 Excel 表,其中包含行和列,列有标题:
 cancerdata.columns = dataset.feature_names
以下代码将添加列标题到数据集的列中:
for i in range(0,len(dataset.feature_names)):
if ['mean concave points', 'mean area', 'mean radius', 'mean perimeter', 'mean concavity'].\
__contains__(dataset.feature_names[i]):
continue
else:
cancerdata = cancerdata.drop(dataset.feature_names[i], axis=1)
上一行将删除除以下列之外的所有列:
- 
平均凹点 
- 
平均面积 
- 
平均半径 
- 
平均周长 
- 
平均凹度 
为了减少数据集中特征列的数量,我正在删除一些对模型影响较小的列:
cancerdata.to_csv("myfile.csv")
这行代码将数据保存到 CSV 文件中;您可以在 Excel 中打开它,查看数据集包含的内容:
 cancer_types = dataset.target_names
在 Excel 数据集中,当您检查它时,您将知道诊断将包括 0 或 1 的值,其中 0 是恶性,1 是良性。为了将这些数值转换为真实名称,我们编写以下代码:
cancer_names = []
//getting all the corresponding cancer types with name [string] format.
for i in range(len(dataset.target)):
cancer_names.append(cancer_types[dataset.target[i]])
x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(cancerdata,cancer_names,test_size=0.3, random_state=5)
这行代码将数据集分成两个——一个用于训练,一个用于测试,并将其保存到为该目的定义的相应变量中:
 classifier = RandomForestClassifier()
下面的代码将创建一个分类器:
classifier.fit(x_train, y_train)
这段代码将提供训练数据并训练模型:
//testing the model with test data
print(classifier.predict(x_test))
上一行将打印测试数据的预测癌症类型到控制台,如下所示:

将 scikit 模型转换为 Core ML 模型
让我通过一个例子来解释:假设你是法国人,只会说法语和英语。想象一下你去印度度假。然后你去了酒店餐厅,服务员给你提供了一份用当地语言写的菜单。现在,你会怎么做?让我猜猜,你会问服务员,或者另一个顾客/你的导游,解释这些项目给你听,或者你简单地扫描 Google 翻译中的图片。
我的观点是,你需要一个翻译器。就是这样。同样,为了让 scikit 模型被 iOS 移动应用程序理解,需要一个将其转换为 Core ML 格式的转换器。
以下代码完成了所有的工作。它将 scikit-learn 格式转换为 Core ML 格式:
//converting the fitted model to a Core ML Model file
model = coremltools.converters.sklearn.convert(classifier, input_features=list(cancerdata.columns.values), output_feature_names='typeofcancer')
model.save("cancermodel.mlmodel")
为了使这个工作正常,你必须使用你的pip安装coremltools。然后,在顶部写下以下代码来导入它:
import coremltools
一旦运行这个程序,你将在你的磁盘上得到一个名为cancermodel.mlmodel的模型文件,你将在 iOS 项目中用它来进行推理。
使用 Core ML 模型创建 iOS 移动应用程序
在本节中,我们将创建一个 iOS 项目来使用 Core ML,为此你需要 Xcode(版本必须是 9+)。
让我们从打开 Xcode 并创建一个带有故事板的空 swift 应用程序开始。在主故事板设计中,屏幕将如下所示。然后,将生成的模型文件添加到你的项目中。这应该给你以下结构:

现在,在你的主故事板文件中创建 UI,如下所示:

为每个文本字段创建出口。并为每个文本字段添加事件监听器。现在,你的视图控制器将如下所示:
import UIKit
import Core ML 
class ViewController: UIViewController {
    let model = cancermodel()
    @IBOutlet weak var meanradius: UITextField!
    @IBOutlet weak var cancertype: UILabel!
    @IBOutlet weak var meanperimeter: UITextField!
    @IBOutlet weak var meanarea: UITextField!
    @IBOutlet weak var meanconcavity: UITextField!
    @IBOutlet weak var meanconcavepoints: UITextField!
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    override func viewDidLoad() {
        super.viewDidLoad();
        updated(meanconcavepoints);
        //This line is to fire the initial update of the cancer type.
    }
    /*
This method will send the input data to your generated model class and display the returned result to the label.
*/
    @IBAction func updated(_ sender: Any) {
        guard let modeloutput = try? model.prediction(mean_radius: 
        Double(meanradius.text!)!, mean_perimeter: 
        Double(meanperimeter.text!)!, mean_area: Double(meanarea.text!)!, 
        mean_concavity: Double(meanconcavity.text!)!, mean_concave_points: 
        Double(meanconcavepoints.text!)!) else {
            fatalError("unexpected runtime error")
        }
        cancertype.text = modeloutput.typeofcancer;
    }
}
你可以在本书的 GitHub 仓库中找到相同的代码。
如果你在构建过程中遇到任何问题,比如签名或证书,请谷歌搜索或给我们写信。
一旦你在 Xcode 中设置了项目,你就可以在模拟器中运行它。结果将如下所示:

摘要
在本章中,我们学习了决策树和随机森林,以及它们之间的区别。我们还通过一个样本数据集和 Excel 探索了一个决策树,并使用随机森林算法来建立预测。我们使用 Core ML 编写 iOS 程序,然后我们应用 scikit-learn 创建模型,并使用 Core ML 工具将 scikit 模型转换为 Core ML 模型。
在下一章中,我们将学习更多关于 TensorFlow 及其在 Android 中的应用。
进一步阅读
通过访问他们的官方网站,我们可以进一步了解 Core ML 及其提供的服务:developer.apple.com/documentation/coreml。
第四章:Android 中的 TensorFlow Mobile
在上一章中,我们专注于监督学习和无监督学习,并学习了不同类型的机器学习算法。在本章中,我们将介绍 TensorFlow for mobile,并通过使用 TensorFlow for mobile 的示例程序进行实现。在第九章 神经网络的移动应用中,我们将使用它来实现一个分类算法。但在我们能够使用它实现机器学习算法之前,我们需要了解 TensorFlow for mobile 的工作原理,并能够编写使用它的示例。本章的目标是介绍 TensorFlow、TensorFlow Lite、TensorFlow for mobile 及其工作方式,并尝试使用 TensorFlow for mobile 在 Android 上的实际操作示例。
在本章中,我们将涵盖以下主题:
- 
TensorFlow、TensorFlow Lite 和 TensorFlow for mobile 简介 
- 
TensorFlow for Mobile 的组件 
- 
移动机器学习应用程序的架构 
- 
使用 TensorFlow 在 Android 中构建示例程序 
到本章结束时,你将了解如何使用 TensorFlow for mobile 在 Android 中构建应用程序。我们将通过使用它来实现第九章 神经网络的移动应用中的分类算法。
TensorFlow 简介
TensorFlow 是由 Google 开发的一种用于实现机器学习的工具,于 2015 年开源。它是一种可以安装在桌面上的产品,可以用来创建机器学习模型。一旦模型在桌面上构建并训练完毕,开发者可以将这些模型转移到移动设备上,并通过将其集成到 iOS 和 Android 移动应用程序中来预测移动应用程序中的结果。目前有两种 TensorFlow 版本可用于在移动和嵌入式设备上实现机器学习解决方案:
- 
移动设备:TensorFlow for Mobile 
- 
移动和嵌入式设备:TensorFlow Lite 
下表将帮助您了解 TensorFlow for mobile 和 TensorFlow Lite 之间的关键区别:
| TensorFlow for Mobile | TensorFlow Lite | 
|---|---|
| 设计用于与大型设备协同工作。 | 设计用于与非常小的设备协同工作。 | 
| 二进制文件针对移动设备进行了优化。 | 二进制文件针对移动和嵌入式设备进行了非常小的优化,具有最小依赖性和增强的性能。 | 
| 支持在 Android、iOS 和 Raspberry Pi 上的 CPU、GPU 和 TPU 部署。 | 支持硬件加速。可在 iOS、Android 和 Raspberry Pi 上部署。 | 
| 建议现在在移动设备上进行生产部署。 | 目前仍处于测试版,正在改进中。 | 
| 支持更广泛的操作符和机器学习模型。 | 支持的操作符有限,并非所有机器学习模型都受支持。 | 
TensorFlow Lite 组件
在本节中,我们将详细介绍 TensorFlow Lite:整体架构、关键组件及其功能。
以下图表提供了关键组件及其如何相互作用以将机器学习带到移动设备的高级概述:

在设备上实现机器学习时需要遵循以下关键步骤:
- 
使用 TensorFlow 或任何其他机器学习框架在桌面创建训练好的 TensorFlow/ML 模型。该训练模型也可以使用任何云 ML 引擎创建。 
- 
使用 TensorFlow Lite 转换器将训练好的机器学习模型转换为 TensorFlow Lite 模型文件。 
- 
使用这些文件编写一个移动应用程序,并将其转换为部署和执行在移动设备上的包。这些轻量级文件可以直接在内核或硬件加速器中解释和执行,如果设备中可用的话。 
以下是 TensorFlow Lite 的关键组件:
- 
模型文件格式 
- 
解释器 
- 
Ops/内核 
- 
硬件加速接口 
模型文件格式
以下是该模型文件格式的亮点:
- 
它轻量级且具有非常少的软件依赖。 
- 
它支持量化。 - 此格式基于 FlatBuffer,因此提高了执行速度。FlatBuffer 是谷歌的一个开源项目,最初是为视频游戏设计的。
 
- 
FlatBuffer 是一个跨平台序列化库,类似于协议缓冲区。 
- 
此格式更节省内存,因为它在数据访问之前不需要解析/解包步骤来执行二级表示。没有序列化步骤,因此它使用更少的代码。 
解释器
以下是对解释器的亮点:
- 
它是一个针对移动优化的解释器。 
- 
它有助于保持移动应用轻量化和快速。 
- 
它使用静态图排序和自定义(较少动态)内存分配器,以确保最小化负载、初始化和执行延迟。 
- 
解释器具有静态内存计划和静态执行计划。 
Ops/内核
一组核心算子,包括量化和浮点数,其中许多已经针对移动平台进行了调整。这些可以用来创建和运行自定义模型。开发者也可以编写自己的自定义算子并在模型中使用它们。
硬件加速接口
TensorFlow Lite 具有对硬件加速器的接口;在 Android 中,它是通过 Android Neural Network API,而在 iOS 中,则是通过 CoreML。
以下是在 TensorFlow Lite 中预测试的模型,保证开箱即用:
- 
Inception V3:一种流行的模型,用于检测图像中存在的占主导地位的对象。 
- 
MobileNets:可用于分类、检测和分割的计算机视觉模型。MobileNet 模型比 Inception V3 模型更小,但精度较低。 
- 
设备端智能回复:一个设备端模型,通过建议上下文相关的消息,为传入的文本消息提供一键回复。 
移动机器学习应用程序的架构
现在我们已经了解了 TensorFlow Lite 的组件,我们将探讨移动应用程序是如何与 TensorFlow 组件协同工作以提供移动机器学习解决方案的。
移动应用程序应利用 TensorFlow Lite 模型文件对未来的数据进行推理。TensorFlow Lite 模型文件可以与移动应用程序一起打包并部署,或者与移动应用程序部署包保持分离。以下图表描述了两种可能的部署场景:

每种部署方式都有其优缺点。在第一种情况下,如果两者耦合在一起,模型文件将拥有更高的安全性,可以保持安全并得到保护。这是一个更为直接的方法。然而,由于模型文件的大小,应用包的大小也会增加。在第二种情况下,如果两者保持分离,可以单独更新模型文件,而无需进行应用升级。因此,可以避免与应用升级、部署到应用商店等相关活动,以实现模型升级。由于这种分离,应用包的大小也可以最小化。然而,由于模型文件是独立的,应该更加小心地处理,以免使其容易受到安全威胁。
在对使用 TensorFlow Lite 模型文件的移动应用程序有一个概述之后,让我们看看整个图景。移动应用程序与 TensorFlow Lite 模型文件一起打包。这种交互是通过 TensorFlow Lite Interpreter 实现的,它是 Android NDK 层的一部分。通过移动应用程序暴露给 SDK 层的接口调用 C 函数,以使用与移动应用程序一起部署的已训练 TensorFlow Lite 模型进行预测或推理。以下图表提供了一个清晰的视图,展示了 Android 生态系统中将参与典型机器学习程序的 SDK 和 NDK 层。执行也可以通过 android NN 层在 GPU 或任何专用处理器上触发:

理解模型概念
在使用 TensorFlow 编写第一个程序之前,我们将简要地回顾一下那些有助于我们理解 TensorFlow Lite 模型工作原理的概念。我们不会深入细节,但仅仅一个概念性的高层次概述就能更好地理解。
MobileNet 和 Inception V3 是基于 卷积神经网络(CNNs)的内置模型。
在最基本层面上,卷积神经网络(CNN)可以被视为一种使用许多相同神经元副本的神经网络。这使得网络可以拥有大量神经元并表达计算上庞大的模型,同时保持需要学习的实际参数数量——描述神经元行为的值——相对较低。
这个概念可以通过类比拼图和通常解决拼图的方式来理解。以下是需要解决的拼图:

如果我们必须从提供的碎片中组装这个拼图,请考虑您将如何开始解决它。您可能会将所有不同颜色的碎片放在一起。然后在同一颜色中,您会检查模式并将它们组装起来。这就是卷积网络在图像分类和识别中训练的方式。因此,只有一小部分,每个神经元都记得。但是父神经元理解其范围内的事物需要如何组装才能得到整体图景。
在 Inception V3 和 MobileNet 模型中,两者都基于 CNN 概念。模型已经相当训练有素且稳定。我们使用我们的图像集使用我们的图像重新训练模型即可。所以,在概念和理论已经足够之后,我们将继续编写我们的第一个使用 TensorFlow Lite for Android 的示例程序。
我们将在第九章(3e97f92b-a2d9-4618-9a3b-91552fa3fc3d.xhtml)的“移动设备上的神经网络”中使用 TensorFlow 移动进行分类应用。
使用 TensorFlow 模型编写移动应用程序
我们将做什么?
在本节中,我们将构建一个小的(a+b)2模型,将其部署到 Android 移动应用程序中,并在 Android 移动设备上运行它。
您需要了解什么?
要继续本节内容,您需要一个可工作的 Python 安装、TensorFlow 依赖项和 Android Studio,以及一些 Python 和 Java Android 的知识。您可以在这里找到如何安装 TensorFlow 的说明。
如果您需要 Windows 的详细安装程序,请参阅本书第十一章(d7ddae2d-9276-461e-9526-73448159e26b.xhtml)中提供的带有截图的“移动应用程序上机器学习的未来”。
我们已经看到了 TensorFlow 的细节。简单来说,TensorFlow 不过是将用 Python 编写的 TensorFlow 程序保存到一个小的文件中,这个文件可以被我们将要安装到 Android 应用程序中的 C++本地库读取并执行,从移动端进行推理。为此,JNI(Java 本地接口)作为 Java 和 C++之间的桥梁工作。
要了解更多关于 TensorFlow Lite 背后的想法,请查看www.tensorflow.org/mobile/tflite/。
编写我们的第一个程序
为了编写 TensorFlow 移动应用程序,我们需要遵循几个步骤:
- 
创建 TF(TensorFlow)模型 
- 
保存模型 
- 
冻结图 
- 
优化模型 
- 
编写 Android 应用程序并执行它 
我们现在将详细讲解每个步骤。
创建和保存 TF 模型
首先,我们首先创建一个简单的模型并将其计算图保存为一个序列化的GraphDef文件。在训练模型后,我们将其变量的值保存到一个检查点文件中。我们必须将这些两个文件转换为一个优化的独立文件,这是我们需要在 Android 应用程序中使用的所有内容。
对于这个教程,我们创建一个非常简单的 TensorFlow 图,它实现了一个小用例,将计算(a+b)²=c。在这里,我们将输入保存为a和b,输出保存为c。
为了实现这个示例程序,我们将使用 Python。因此,作为先决条件,你需要在你的机器上安装 Python,并使用pip在你的机器上安装 TensorFlow 库。
请参阅本书的软件安装/附录部分,了解如何安装 Python 的说明。pip是 Python 的包管理器,它随 Python 一起提供。
一旦你安装了 Python 并正确设置了路径,你就可以从命令提示符中运行pip命令。要安装 TensorFlow,请运行以下命令:
pip install tensorflow
这个示例可能看起来太简单,可能不包含与机器学习相关的内容,但这个示例应该是一个很好的起点,以了解 TensorFlow 的概念及其工作原理:
import tensorflow as tf 
a = tf.placeholder(tf.int32, name='a') # input 
b = tf.placeholder(tf.int32, name='b') # input 
times = tf.Variable(name="times", dtype=tf.int32, initial_value=2) 
c = tf.pow(tf.add(a, b), times, name="c") 
saver = tf.train.Saver()
init_op = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init_op) tf.train.write_graph(sess.graph_def, '.', 'tfdroid.pbtxt')
sess.run(tf.assign(name="times", value=2, ref=times)) # save the graph 
# save a checkpoint file, which will store the above assignment saver.save(sess, './tfdroid.ckpt')
在前面的程序中,我们创建了两个名为a和b的占位符,它们可以存储整数值。现在,你可以想象占位符就像决策树中的节点。在下一行,我们创建了一个名为 times 的变量。我们创建这个变量是为了存储我们需要乘以输入的次数。在这种情况下,我们给出两个,因为目标是做(a+b)^(2).
在下一行,我们在a和b节点上应用加法操作。对于这个和,我们应用幂操作并将结果保存到一个名为 c 的新节点中。要运行代码,首先将其保存为具有.py扩展名的文件。然后使用python命令执行程序,如下所示:
python (filename)
运行上一段代码将生成两个文件。首先,它将 TF 计算图保存为一个名为tfdroid.pbtxt的GraphDef文本文件。接下来,它将执行一个简单的赋值操作(这通常是通过实际学习来完成的)并将模型变量的检查点保存到tfdroid.ckpt中。
冻结图
现在我们有了这些文件,我们需要通过将检查点文件中的变量转换为包含变量值的Const Ops并将它们与 GraphDef 结合到一个独立文件中来冻结图。使用这个文件使得在移动应用程序中加载模型变得更加容易。TensorFlow 在tensorflow.python.tools中提供了freeze_graph来完成这个目的:
import sys import tensorflow as tf from tensorflow.python.tools 
import freeze_graph from tensorflow.python.tools 
import optimize_for_inference_lib MODEL_NAME = 'tfdroid'
# Freeze the graph
input_graph_path = MODEL_NAME+'.pbtxt' checkpoint_path = './'+MODEL_NAME+'.ckpt' input_saver_def_path = "" input_binary = False output_node_names = "c" restore_op_name = "save/restore_all" filename_tensor_name = "save/Const:0" output_frozen_graph_name = 'frozen_'+MODEL_NAME+'.pb' output_optimized_graph_name = 'optimized_'+MODEL_NAME+'.pb' clear_devices = True freeze_graph.freeze_graph(input_graph_path, input_saver_def_path, input_binary, checkpoint_path, output_node_names, restore_op_name, filename_tensor_name, output_frozen_graph_name, clear_devices, "")
优化模型文件
一旦我们有了冻结的图,我们可以进一步优化文件以用于推理目的,通过移除仅在训练期间需要的图的部分。根据文档,这包括:
- 
移除仅用于训练的操作,例如检查点保存 
- 
移除图中从未到达的部分 
- 
移除调试操作,例如 CheckNumerics
- 
将批归一化操作融合到预计算的权重中 
- 
将常见操作融合到统一版本中 
TensorFlow 在tensorflow.python.tools中提供了optimize_for_inference_lib用于此目的:
# Optimize for inference 
input_graph_def = tf.GraphDef() with tf.gfile.Open(output_frozen_graph_name, "r") as f: data = f.read() input_graph_def.ParseFromString(data) 
output_graph_def = optimize_for_inference_lib.optimize_for_inference( input_graph_def, ["a", "b"], 
# an array of the input node(s) ["c"], 
# an array of output nodes tf.int32.as_datatype_enum)
# Save the optimized graph f = tf.gfile.FastGFile(output_optimized_graph_name, "w") f.write(output_graph_def.SerializeToString()) tf.train.write_graph(output_graph_def, './', output_optimized_graph_name)
注意前述代码中的输入和输出节点。我们的图只有一个输入节点,命名为 I,一个输出节点,命名为 O。这些名称对应于你定义张量时使用的名称。如果你使用的是不同的图,你应该根据你的图调整这些名称。
现在我们有一个名为optimized_tfdroid.pb的二进制文件,这意味着我们已准备好构建我们的 Android 应用。如果你在创建optimized_tfdroid.pb时遇到了异常,你可以使用tfdroid.somewhat,这是模型的非优化版本——它相当大。
创建 Android 应用
我们需要获取 Android 的 TensorFlow 库,创建一个 Android 应用,配置它以使用这些库,然后在应用内部调用 TensorFlow 模型。
虽然你可以从头开始编译 TensorFlow 库,但使用预构建库更容易。
现在使用 Android Studio 创建一个带有空活动的 Android 项目。
一旦项目创建完成,将 TF 库添加到项目的libs文件夹中。你可以从 GitHub 仓库获取这些库:github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/tensorflow%20simple/TensorflowSample/app/libs。
现在项目中的libs/文件夹应该看起来像这样:
libs
|____arm64-v8a
| |____libtensorflow_inference.so
|____armeabi-v7a
| |____libtensorflow_inference.so
|____libandroid_tensorflow_inference_java.jar
|____x86
| |____libtensorflow_inference.so
|____x86_64
| |____libtensorflow_inference.so
你需要通过在app/build.gradle中的 Android 块内放置以下行来让构建系统知道这些库的位置:
sourceSets { main { jniLibs.srcDirs = ['libs'] } }
复制 TF 模型
为应用创建一个 Android Asset 文件夹,并将我们刚刚创建的optimized_tfdroid.pb或tfdroid.pb文件放入其中(app/src/main/assets/)。
创建活动
点击项目并创建一个名为MainActivity的空活动。在该活动的布局中,粘贴以下 XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.vavinash.tensorflowsample.MainActivity">
<EditText
android:id="@+id/editNum1"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="13dp"
android:layout_marginTop="129dp"
android:layout_toStartOf="@+id/button"
android:ems="10"
android:hint="a"
android:inputType="textPersonName"
android:textAlignment="center" />
<EditText
android:id="@+id/editNum2"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/editNum1"
android:layout_alignBottom="@+id/editNum1"
android:layout_toEndOf="@+id/button"
android:ems="10"
android:hint="b"
android:inputType="textPersonName"
android:textAlignment="center" />
<Button
android:text="Run"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_below="@+id/editNum2"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Output"
android:id="@+id/txtViewResult"
android:layout_marginTop="85dp"
android:textAlignment="center"
android:layout_alignTop="@+id/button"
android:layout_centerHorizontal="true" />
</RelativeLayout>
在mainactivity.java文件中,粘贴以下代码:
package com.example.vavinash.tensorflowsample;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Button;
import android.view.View;
import org.tensorflow.contrib.android.TensorFlowInferenceInterface;public class MainActivity extends AppCompatActivity {
    //change with the file name of your own model generated in python tensorflow.
    private static final String MODEL_FILE = "file:///android_asset/tfdroid.pb";
    //here we are using this interface to perform the inference with our generated model. It internally     uses c++ libraries and JNI.
    private TensorFlowInferenceInterface inferenceInterface;
    static {
        System.loadLibrary("tensorflow_inference");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        inferenceInterface = new TensorFlowInferenceInterface();
        //instantiatind and setting our model file as input.
        inferenceInterface.initializeTensorFlow(getAssets(), MODEL_FILE);
        final Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                final EditText editNum1 = (EditText) findViewById(R.id.editNum1);
                final EditText editNum2 = (EditText) findViewById(R.id.editNum2);
                float num1 = Float.parseFloat(editNum1.getText().toString());
                float num2 = Float.parseFloat(editNum2.getText().toString());
                int[] i = {1};
                int[] a = {((int) num1)};
                int[] b = {((int) num2)};
                //Setting input for variable a and b in our model.
                inferenceInterface.fillNodeInt("a",i,a);
                inferenceInterface.fillNodeInt("b",i,b);
                //performing the inference and getting the output in variable c
                inferenceInterface.runInference(new String[] {"c"});
                //reading received output
                int[] c = {0};
                inferenceInterface.readNodeInt("c", c);
                //projecting to user.
                final TextView textViewR = (TextView) findViewById(R.id.txtViewResult);
                textViewR.setText(Integer.toString(c[0]));
            }
        });
    }
}
在前述程序中,我们使用以下代码片段加载 TensorFlow 的二进制文件:
System.loadLibrary("tensorflow_inference");
在创建 Bundle 的方法中,我们有主要的逻辑。在这里,我们通过提供 TensorFlow 模型的.pb文件来创建 TensorFlow 推理对象,这个文件已经被生成,我们已经在创建和保存模型的章节中看到了它。
然后,我们为运行按钮注册了一个点击事件。在这个过程中,我们将值输入到 TensorFlow 中的 a 和 b 节点,并运行推理,然后我们从 C 节点获取值并展示给用户。
现在运行应用程序,查看(a+b)2 = c表达式的结果:

在左侧,它显示了应用程序的启动屏幕。在提供的文本框中,我们需要输入a和b的值。一旦您点击运行按钮,您将在输出区域看到结果。
您可以从 GitHub 仓库获取前面的应用程序代码:github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/tensorflow%20simple.
摘要
在本章中,我们介绍了谷歌的移动机器学习工具,并探讨了工具包的各种版本——TensorFlow for Mobile 和 TensorFlow Lite。我们还探讨了 TensorFlow-ML 启用移动应用程序的架构。然后我们讨论了 TensorFlow Lite 的架构和细节及其组件,甚至演示了一个使用 TensorFlow for Mobile 的简单用例,用于 android 移动应用程序。
在下一章中,我们将使用这里讨论的 TensorFlow for Mobile 来实现一个分类算法。
第五章:在 iOS 中使用 Core ML 进行回归
本章将为您提供一个关于回归算法的概述,以及 Core ML 基础知识的洞察,并介绍如何利用回归算法创建机器学习程序,并使用 iOS 中的 Core ML 预测一组相关住房数据的房价。
正如我们在第一章,“移动机器学习简介”中看到的,任何机器学习程序都有四个阶段。我们将看到在四个阶段中我们将要涵盖的内容,以及我们将使用什么工具来解决潜在的机器学习问题。
问题定义:提供某个区域的住房信息,我们想要预测该区域房屋的中位数价值。
本章我们将涵盖以下主题:
- 
理解什么是回归以及如何将其应用于解决 ML 问题 
- 
使用样本数据集和 Excel 理解回归 
- 
理解 Core ML 的基础知识 
- 
使用 Core ML 中的回归解决问题: - 
技术要求 
- 
如何使用 scikit-learn 创建模型文件 
- 
测试模型 
- 
理解如何将 scikit-learn 模型导入 Core ML 项目 
- 
编写 iOS 移动应用程序,并在其中使用 scikit-learn 模型进行房价预测 
 
- 
回归简介
回归分析是数据统计分析的基本方法。它是一种统计方法,有助于找出变量之间的关系。它基本上用于理解输入和输出数值变量之间的关系。我们首先应确定因变量,它将根据自变量的值而变化。例如,房屋的价值(因变量)根据房屋的平方英尺(自变量)而变化。回归分析对于预测非常有用。
在一个简单的回归问题(一个x和一个y),模型的形态如下:
y = A + Bx*
在高维空间中,当我们有多个输入(x)时,这条线被称为平面或超平面。
在我们的例子中,我们根据可能影响该特定区域数据价格的各个参数预测房屋价格。
在解决回归问题时需要考虑的一些重要点包括:
- 
预测结果应为一个数值量。 
- 
输入变量可以是实值或离散值。 
- 
如果有多个输入变量,则称为多元回归问题。 
- 
当输入变量按时间顺序排列时,回归问题被称为时间序列预测问题。 
- 
回归不应与分类混淆。分类是预测离散类标签的任务,而回归是预测连续量的任务。 
能够学习回归预测模型的算法被称为回归算法。
线性回归
在本节中,我们将通过一个具体的详细示例来尝试理解线性回归。我们还将使用相同的示例数据集来处理 iOS Core ML 示例。
数据集
我们将使用波士顿数据集来解决回归问题。这个数据集包含了美国人口普查局收集的有关马萨诸塞州波士顿地区住房的信息。它是从 StatLib 存档(lib.stat.cmu.edu/datasets/boston)获得的,并在文献中被广泛用作算法的基准。该数据集规模较小,只有 506 个案例。
数据集命名
这个数据集的名称很简单,叫波士顿。它有两个照片任务:现在,需要预测一氧化二氮的水平;价格,需要预测房屋的中位数价值。
关于数据集的其他细节如下:
- 
来源:波士顿住房数据来源于自然。 
- 
用途:此数据集可用于评估。 
- 
案例数量:该数据集包含总共 506 个案例。 
- 
顺序:案例的顺序是神秘的。 
- 
变量:数据集中的每个案例有 14 个属性。它们如下: - 
CRIM:城镇的人均犯罪率 
- 
ZN:超过 25,000 平方英尺地块的住宅用地比例 
- 
INDUS:城镇非零售商业地块的比例 
- 
CHAS:查尔斯河虚拟变量(如果地块边界是河流则为 1,否则为 0) 
- 
NOX:一氧化氮浓度(每千万分之一) 
- 
RM:每套住宅的平均房间数 
- 
AGE:1940 年之前建造的业主自住单元的比例 
- 
DIS:到五个波士顿就业中心的加权距离 
- 
RAD:通往放射状高速公路的可达性指数 
- 
TAX:每 10,000 美元的全值财产税税率 
- 
PTRATIO:城镇的师生比例 
- 
B: 1000(Bk - 0.63)²,其中Bk是城镇的黑人比例
- 
LSTAT:人口中低阶层百分比 
- 
MEDV:业主自住房屋的中位数价值(单位为 1000 美元) 
 
- 
我们将尝试使用 Excel 对数据集进行简单线性回归和多变量回归,并了解其细节。我们将仅考虑从波士顿数据集的 506 个样本数据空间中以下 20 个数据元素进行分析:

现在,我们可以使用 Excel 中提供的数据分析选项,尝试仅考虑依赖变量DIS来预测MV。在数据分析中,选择回归,并将MV作为Y值,DIS作为X值。这是一个只有一个依赖变量来预测输出的简单回归。以下是 Excel 生成的输出:

以 DIS 作为因变量的 MV 预测的线性回归方程将是 Y = 1.11X + 17.17 (DIS 的 DIS 系数 + 截距值):
R2 =0.0250
现在,我们可以看到分析所考虑的 20 个数据样本的 MV 预测输出:

预测 DIS 作为因变量的 MV 的输出图表如下:

现在,我们了解了线性回归如何对一个单一的自变量进行工作。同样地,我们可以有任意数量的自变量,通过将它们包括为 X1、X2、X3、... XN。
在我们的数据集中,总共有 14 个变量,我们可以让 MV 依赖于剩余的所有 13 个变量,并以之前为单个变量指定的方式创建回归方程。
现在我们已经了解了如何使用 Excel 对波士顿数据集进行回归,我们将使用 Core ML 进行相同的操作。在继续在 Core ML 中实现之前,我们必须了解 Core ML 是什么,并查看 Core ML 的基础知识。
理解 Core ML 的基础知识
Core ML 允许 iOS 移动应用程序在移动设备上本地运行机器学习模型。它使开发者能够将各种机器学习模型类型集成到移动应用程序中。开发者不需要广泛的机器学习或深度学习知识,就可以使用 Core ML 编写机器学习移动应用程序。他们只需要知道如何将 ML 模型包含到移动应用中,就像其他资源一样,并在移动应用程序中使用它。数据科学家或机器学习专家可以使用他们熟悉的任何技术创建 ML 模型,例如 Keras、scikit-learn 等。Core ML 提供了工具,可以将使用其他工具(tensor、scikit-learn 等)创建的 ML 数据模型转换为 Core ML 所要求的格式。
这种转换为 Core ML 模型发生在应用程序开发阶段。当应用程序被使用时,不会实时发生转换。转换是通过使用 coremltools Python 库来完成的。当应用程序反序列化 Core ML 模型时,它成为一个具有 prediction 方法的对象。Core ML 并非真正用于训练,而是用于运行预训练模型。
Core ML 支持广泛的深度学习能力,支持超过 30 层。深度学习中的层实际上表示数据经过转换的层数。它还支持标准模型:树集成、SVM 和线性模型。它建立在低级技术如 Metal 之上。Core ML 无缝利用 CPU 和 GPU 以提供最大性能和效率。它能够根据任务的强度在 CPU 和 GPU 之间切换。由于 Core ML 允许机器学习在设备上本地运行,因此数据不需要离开设备进行分析。
使用 Core ML,我们可以将训练好的机器学习模型集成到我们的应用程序中:

训练好的模型是将机器学习算法应用于一组训练数据的结果。该模型根据新的输入数据进行预测。例如,在一个地区的房价历史数据上训练的模型,在给出卧室和浴室数量时,可能能够预测房屋的价格。
Core ML 针对设备上的性能进行了优化,这最小化了内存占用和功耗。严格在设备上运行确保了用户数据的隐私,并保证在网络连接不可用时,我们的应用程序仍然功能齐全且响应迅速。
Core ML 是特定领域框架和功能的基础。Core ML 支持Vision进行图像分析、Foundation进行自然语言处理,以及Gameplaykit评估学习决策树。Core ML本身建立在低级原语如Accelerate和BNNS以及Metal Performance Shaders之上:

准备使用 Core ML 编写 ML 程序的 iOS 开发者需要了解以下基本步骤:
- 
在 iOS 之外创建模型。这可以通过 scikit-learn、TensorFlow 或开发者感到舒适的任何其他方式完成。创建机器学习模型文件。为了创建机器学习模型文件,他们需要了解之前讨论过的机器学习的四个关键阶段。 
- 
一旦模型构建、测试并准备好使用,就需要将该模型转换为与 Core ML 兼容的格式。Core ML 工具实际上可以帮助将使用任何工具创建的模型文件转换为 Core ML 要求的格式( .mlmodel文件格式)。
- 
一旦创建了 Core ML 特定的模型文件,就可以将其导入 iOS 程序中,并使用 Core ML 提供的 API 与模型文件交互,以提取 iOS 应用程序可能需要的信息,基本上是将 .mlmodel文件导入 Xcode 项目的resources文件夹中。
Core ML 的最大优势是它极其简单易用。只需几行代码就可以帮助集成一个完整的 ML 模型。Core ML 只能帮助将预训练的 ML 模型集成到应用程序中。无法进行模型训练。
使用 Core ML 中的回归解决问题
本节将详细介绍创建回归模型和使用 iOS 移动应用程序中的回归模型。它将提供创建 iOS 回归 ML 应用程序以解决定义的问题所涉及的各个步骤的详细说明。
技术要求
需要在开发者机器上安装以下软件:
- 
Python 
- 
Mac 环境下的 Xcode 
本章的练习程序可以从我们的 GitHub 仓库下载,地址为github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/housing%20price%20prediction。
在下面的程序中,我们将使用pandas、numpy和scikit-learn来创建模型。因此,请使用以下命令从命令提示符/终端使用pip包管理器安装这些包:
pip install scikit-learn
pip install numpy
pip install pandas
为了将创建的模型转换为 Core ML 格式,我们需要使用 Apple 提供的 Core ML scikit-learn Python 转换器:
pip install -U coremltools
如何使用 scikit-learn 创建模型文件
本节将解释我们将如何使用scikit-learn创建线性回归模型文件,并将其转换为与 Core ML 兼容的.mlmodel文件。我们将使用波士顿数据集来创建模型。以下是一个简单的 Python 程序,它使用scikit-learn和波士顿数据集创建了一个简单的线性回归模型。然后,Core ML 工具将其转换为与 Core ML 兼容的模型文件。让我们详细地过一遍这个程序。
首先,我们需要导入程序所需的所需包:
# importing required packages
 import numpy as np
前面的行导入 NumPy 包。NumPy 是 Python 科学计算的基础包。它包含一个强大的 N 维数组对象。这个numpy数组将在这个程序中用于存储具有 14 个维度的数据集:
import pandas as pd
 from pandas.core import series
前面的行导入pandas包,这是一个开源的 BSD 许可库,为 Python 编程语言提供高性能、易于使用的数据结构和数据分析工具。使用 pandas,我们可以创建一个数据框。你可以假设一个pandas数据框就像一个 Excel 电子表格,其中每个工作表都有标题和数据:
import coremltools
 from coremltools.converters.sklearn import _linear_regression
前面的行导入了我们在这个程序中使用的线性回归模型的 Core ML Tools 转换包。Core ML Tools 是一个用于创建、检查和测试.mlmodel格式模型的 Python 包。特别是,它可以用于以下操作:
- 
将现有模型从流行的机器学习工具(包括 Keras、Caffe、scikit-learn、libsvm和XGBoost)转换为.mlmodel格式
- 
通过简单的 API 以 .mlmodel格式表达模型
- 
使用 .mlmodel进行预测(在选定平台用于测试目的):
from sklearn import datasets, linear_model
 from sklearn.metrics import mean_squared_error, r2_score
前一行导入sklearn包。数据集用于导入sklearn包中的内置数据集。在这个程序中,我们使用的是在上一节中解释的波士顿房价数据集。linear_model包用于访问线性回归函数,而metrics包用于计算我们模型的测试指标,如均方误差:
boston = datasets.load_boston()
前一行是从sklearn数据集包中加载波士顿数据集:
 bos = pd.DataFrame(boston.data)
现在,从整个数据集中,我们需要提取数据:
 bos.columns = boston.feature_names
获取列名,即数据的标题:
bos['price'] = boston.target
现在,让我们定义我们想要预测的目标列。定义为目标的列将是预测的那个列:
 x = bos.drop('price', axis=1)
一旦我们定义了目标列,我们将从目标列中删除数据,使其变为x:
 y = bos.price
由于我们定义价格为目标列,y是数据集中的价格列:
 X_train,X_test,Y_train,Y_test = sklearn.model_selection.train_test_split(x,y,test_size=0.3,random_state=5)
然后,我们根据 70/30 的规则将数据分为训练数据和测试数据:
 lm = sklearn.linear_model.LinearRegression() 
一旦我们有了训练数据和测试数据,我们就可以初始化一个线性回归对象:
 lm.fit(X_train, Y_train)
使用初始化的线性回归对象,我们只需将训练数据和测试数据输入到回归模型中:
Y_pred = lm.predict(X_test)
前一行预测了目标:
mse = sklearn.metrics.mean_squared_error(Y_test, Y_pred)
print(mse);
前一行将计算拟合模型和预测结果中的均方误差。
由于回归预测模型预测一个数量,因此模型的技能必须以那些预测中的误差来报告。
评估回归预测模型技能的方法有很多,但最常见的是计算均方根误差(RMSE)。
例如,如果一个回归预测模型做出了两个预测,一个是1.5(预期值为1.0),另一个是 3.3(预期值为3.0),那么RMSE将如下所示:
| 1 | RMSE = sqrt(average(error²)) | 
|---|---|
| 2 | RMSE = sqrt(((1.0 - 1.5)² + (3.0 - 3.3)²) / 2) | 
| 3 | RMSE = sqrt((0.25 + 0.09) / 2) | 
| 4 | RMSE = sqrt(0.17) | 
| 5 | RMSE = 0.412 | 
RMSE的一个好处是误差得分的单位与预测值相同:
 model = coremltools.converters.sklearn.convert(
     sk_obj=lm,input_features=boston.feature_names,
     output_feature_names='price')
在前一行中,我们将拟合模型转换为 Core ML 格式。基本上,这是创建.mlmodel文件的行。我们还在指定输入和输出列名:
 model.save('HousePricer.mlmodel')
在前一行中,我们将模型保存到磁盘。这可以在我们的 iOS 程序中稍后使用。
运行和测试模型
当scikit-learn创建的模型在转换为 Core ML 格式之前独立执行和测试时,发现了以下方差和均方误差:
- 
准备好的模型的均方误差为 30.703232
- 
方差分数为 0.68
- 
进程以退出代码 0完成
以下图表展示了预测值与实际值之间的关系:

将模型导入 iOS 项目
以下是在 Xcode 项目中导入并用于预测的 .mlmodel 文件的工程结构:

ViewCcontroller.swift 文件是使用创建的模型文件的地方,并在移动应用程序中执行房价预测。
housePricer.mlmodel 文件是使用 scikit-learn 创建并使用 Core ML 转换工具转换为 ML 模型文件的模型文件。此文件包含在 iOS Xcode 项目的 resources 文件夹中。
编写 iOS 应用程序
本节提供了使用 .mlmodel 格式的模型进行房价预测的 Swift 代码的详细信息:
//  ViewController.swift
import UIKit
import CoreML
class ViewController: UIViewController {
    let model = HousePricer()
这一行是为了初始化我们已导入项目的模型类。以下行定义了与文本字段交互的出口/变量:
 @IBOutlet weak var crim: UITextField!
    @IBOutlet weak var zn: UITextField!
    @IBOutlet weak var price: UILabel!
    @IBOutlet weak var b: UITextField!
    @IBOutlet weak var ptratio: UITextField!
    @IBOutlet weak var medv: UITextField!
    @IBOutlet weak var lstat: UITextField!
    @IBOutlet weak var rad: UITextField!
    @IBOutlet weak var tax: UITextField!
    @IBOutlet weak var dis: UITextField!
    @IBOutlet weak var age: UITextField!
    @IBOutlet weak var rm: UITextField!
    @IBOutlet weak var nox: UITextField!
    @IBOutlet weak var chas: UITextField!
    @IBOutlet weak var indus: UITextField!
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    override func viewDidLoad() {
        super.viewDidLoad();
        updated(rad);
    }
    @IBAction func updated(_ sender: Any) {
        guard let modeloutput = try? model.prediction(CRIM: Double(crim.text!)!, ZN: Double(zn.text!)!, INDUS: Double(indus.text!)!, CHAS: Double(chas.text!)!, NOX: Double(nox.text!)!, RM: Double(rm.text!)!, AGE: Double(age.text!)!, DIS: Double(dis.text!)!, RAD: Double(rad.text!)!, TAX: Double(tax.text!)!, PTRATIO: Double(ptratio.text!)!, B: Double(b.text!)!, LSTAT: Double(lstat.text!)!) else {
            fatalError("unexpected runtime error")
     }
        price.text = "$" + String(format: "%.2f",modeloutput.price);
    }
}
之前的功能被添加为所有之前文本字段的 onchange 监听器。在这里,我们使用之前创建的模型对象,并预测文本字段中给定值的房价。
运行 iOS 应用程序
创建的 Xcode 项目在模拟器中执行,以下是我们得到的样本:

进一步阅读
通过访问其官方网站 developer.apple.com/documentation/coreml,我们可以更深入地了解 Core ML 和它提供的服务。
摘要
在本章中,我们涵盖了以下主题:
- 
线性回归:理解算法并在波士顿房价数据集上使用电子表格实现它。 
- 
Core ML:我们探讨了 Core ML 的高级细节以及它提供的各种功能。 
- 
使用 Core ML 实现的线性回归示例应用:我们使用了波士顿房价数据集,并使用 Core ML 在 iOS 移动应用程序中实现了线性回归模型,并在移动应用程序中查看结果。 
第六章:ML Kit SDK
在本章中,我们将讨论由 Firebase 在 2018 年 Google I/O 大会上宣布的 ML Kit。此 SDK 将 Google 的移动机器学习产品打包在一个统一的框架下。
移动应用开发者可能希望在他们的移动应用中实现需要机器学习功能的功能。然而,他们可能没有机器学习概念和算法的知识,不知道在哪种场景下使用哪种算法,如何构建模型,训练模型等等。
ML Kit 通过识别移动设备上下文中所有潜在的机器学习用例,并提供现成的 API 来解决这个问题。如果将这些正确的输入传递给它们,就会接收到所需输出,无需进一步编码。
此外,此套件还允许将输入传递到离线工作的设备端 API,或者传递到托管在云端的在线 API。
更重要的是,ML Kit 还为具有机器学习专业知识的开发者提供了选项,允许他们使用 TensorFlow/TensorFlow Lite 构建自己的模型,并将它们导入应用程序中,然后使用 ML Kit API 调用它们。
ML Kit 还提供了其他有用的功能,例如模型升级和监控能力(如果与 Firebase 托管)。
我们在本章中将涵盖以下主题:
- 
ML Kit 及其功能 
- 
使用 ML Kit 设备端 API 创建图像标注示例 
- 
使用 ML Kit 云 API 创建相同的示例 
- 
创建人脸检测应用 
理解 ML Kit
ML Kit 包含了 Google 在移动设备上提供的所有现有机器学习产品。它将 Google Cloud Vision API、TensorFlow Lite 和 Android Neural Networks API 捆绑在一个 SDK 中,如下所示:

ML Kit 使开发者能够以非常简单的方式在 Android 和 iOS 应用中利用机器学习。推理可以通过调用设备端或云端的 API 来完成。
设备端 API 的优势在于它们完全离线工作,并且更安全,因为没有数据被发送到云端。相比之下,云 API 确实需要网络连接,并将数据发送到设备外,但允许更高的精度。
ML Kit 提供了覆盖以下机器学习场景的 API,这些场景可能被移动应用开发者所需要:
- 
图像标注 
- 
文本识别 
- 
地标检测 
- 
人脸检测 
- 
条形码扫描 
所有这些 API 都是使用复杂的机器学习算法实现的。然而,这些细节都被封装了。移动开发者不需要深入了解用于实现这些 API 的算法细节;他们需要做的只是将所需数据传递给 SDK,然后根据使用的 ML Kit 部分,将接收到正确的输出。
如果提供的 API 没有涵盖特定的用例,你可以构建自己的 TensorFlow Lite 模型。ML Kit 将帮助托管该模型,并将其服务于你的移动应用程序。
由于 Firebase ML Kit 提供设备上和云上的功能,开发者可以根据具体问题提出创新的解决方案,利用其中之一或两者。他们需要知道的是,设备上的 API 速度快,可以离线工作,而云 API 利用 Google Cloud 平台提供更高准确度的预测。
以下图表描述了在决定使用设备上或云上的 API 时需要考虑的问题:

ML Kit API
并非 ML Kit 提供的所有 API 都支持设备上和云上模式。以下表格显示了每种模式下支持哪些 API:

让我们看看每个 API 的详细信息。
文本识别
ML Kit 的文本识别 API 通过使用移动设备摄像头帮助识别任何基于拉丁字母的语言中的文本。它们既可以在设备上使用,也可以在云上使用。
设备上的 API 允许识别稀疏文本或图像中存在的文本。云 API 执行相同的操作,但还允许识别大量文本,如文档中的文本。云 API 还支持比设备 API 能够识别的更多语言。
这些 API 的可能用例包括在图像中识别文本、扫描可能嵌入在图像中的字符,或自动化繁琐的数据输入。
人脸检测
ML Kit 的人脸检测 API 允许在图像或视频中检测人脸。一旦检测到人脸,我们可以应用以下改进:
- 
地标检测:确定人脸内的特定兴趣点(地标),如眼睛 
- 
分类:根据某些特征(如眼睛是睁开还是闭合)对脸部进行分类 
- 
人脸追踪:识别和追踪视频不同帧中的同一人脸(在不同位置) 
人脸检测只能在设备上实时进行。在移动设备应用程序中可能有多种用例,其中摄像头捕捉图像并根据地标或分类进行操作,以生成自拍、头像等。
条形码扫描
ML Kit 的条形码扫描 API 有助于读取使用大多数标准条形码格式编码的数据。它支持线性格式,如 Codabar、Code 39、Code 93、Code 128、EAN-8、EAN-13、ITF、UPC-A 或 UPC-E,以及二维格式,如 Aztec、Data Matrix、PDF417 或 QR 码。
该 API 可以识别和扫描无论其方向如何的条形码。任何存储为条形码的有序数据都可以被识别。
图像标签
ML Kit 的图像标注 API 帮助识别图像中的实体。对于此实体识别,无需提供任何其他元数据信息。图像标注可以深入了解图像内容。ML Kit API 提供了图像中的实体,并为每个实体提供置信度分数。
图像标注既可在设备上使用,也可在云端使用,区别在于支持的标签数量。设备端 API 支持大约 400 个标签,而基于云的 API 支持多达 10,000 个。
地标识别
ML Kit 的地标识别 API 帮助识别图像中的知名地标。
当此 API 以图像作为输入时,将提供图像中找到的地标,包括地理坐标和区域信息。同时还会返回地标的知识图谱实体 ID。此 ID 是一个字符串,唯一标识已识别的地标。
自定义模型推理
如果提供的现成 API 不足以满足您的用例,ML Kit 还提供了创建您自己的自定义模型并通过 ML Kit 部署它的选项。
使用 Firebase 在设备上创建文本识别应用
要开始使用 ML Kit,您需要登录您的 Google 账户,激活您的 Firebase 账户,并创建一个 Firebase 项目。按照以下步骤操作:
- 
登录您的 Google 账户,如果您尚未登录。 
- 
在菜单栏中点击“转到控制台”。 
- 
点击“添加项目”以创建项目并打开它。 
现在打开 Android Studio,创建一个带有空活动的项目。记下您在创建项目时给出的应用包名——例如,com.packt.mlkit.textrecognizationondevice。
接下来,转到 Firebase 控制台。在项目概览菜单中,点击“添加应用”并输入所需信息。它将提供一个 JSON 文件供您下载。将此文件添加到 Android Studio 项目视图中的项目应用文件夹中,如图所示:

接下来,将以下代码行添加到清单文件中:
<uses-feature android:name="android.hardware.camera2.full" /<
<uses-permission android:name="android.permission.CAMERA" /<
<uses-permission android:name="android.permission.INTERNET" /<
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /<
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /<
我们需要这些权限使我们的应用能够运行。下一行告诉 Firebase 依赖项从 Google 服务器下载文本识别(OCR)模型,并将其保存在设备上进行推理:
<meta-data
   android:name="com.google.firebase.ml.vision.DEPENDENCIES"
    android:value="ocr" /<
整个清单文件将如下所示:
<?xml version="1.0" encoding="utf-8"?<
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.packt.mlkit.testrecognizationondevice"<
    <uses-feature android:name="android.hardware.camera2.full" /<
    <uses-permission android:name="android.permission.CAMERA" /<
    <uses-permission android:name="android.permission.INTERNET" /<
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /<
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /<
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"<
        <meta-data
            android:name="com.google.firebase.ml.vision.DEPENDENCIES"
            android:value="ocr" /<
        <activity android:name=".MainActivity"<
            <intent-filter<
                <action android:name="android.intent.action.MAIN" /<
                <category android:name="android.intent.category.LAUNCHER" /<
            </intent-filter<
        </activity<
    </application<
</manifest<
现在,我们需要将 Firebase 依赖项添加到项目中。为此,我们需要在项目的 build.gradle 文件中添加以下行:
buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.4' //this version will defer dependeds on your environment.
        classpath 'com.google.gms:google-services:4.0.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
然后打开模块应用 build.gradle 文件,并添加以下依赖项:
implementation 'com.google.firebase:firebase-ml-vision:17.0.0'
implementation 'com.google.firebase:firebase-core:16.0.3'
还需要在文件的底部添加以下行:
apply plugin: 'com.google.gms.google-services'
现在,在您的布局文件中,编写以下 .xml 代码以定义元素:
<?xml version="1.0" encoding="utf-8"?<
<RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="(main activity)"< <!-- Here your fully qualified main activity class name will come. --<
    <TextureView
        android:id="@+id/preview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/btn_takepic"
        android:layout_alignParentTop="true"/<
    <Button
        android:id="@+id/btn_takepic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:text="Start Labeling"
        /<
</RelativeLayout<
现在,是时候编写您应用程序的主活动类了。
请从 Packt Github 仓库下载应用程序代码:github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/mlkit。
我们假设你已经熟悉 Android——因此,我们将使用 Firebase 功能讨论代码:
import com.google.firebase.FirebaseApp;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer;
import com.google.firebase.ml.vision.text.*;
上一行代码将导入 firebase 库。
private FirebaseVisionTextRecognizer textRecognizer;
上一行将声明 firebase 文本识别器。
FirebaseApp fapp= FirebaseApp.initializeApp(getBaseContext());
上一行将初始化 Firebase 应用程序上下文。
        textRecognizer = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
上一行将获取设备上的文本识别器。
       takePictureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture();
                //In this function we are having the code to decode the characters in the picture
            }
        });
    }
上一段代码片段为拍照按钮注册了点击事件监听器。
Bitmap bmp = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
从字节数组创建位图。
FirebaseVisionImage firebase_image = FirebaseVisionImage.fromBitmap(bmp);
上一行创建了一个 firebase 图像对象以传递给识别器。
 textRecognizer.processImage(firebase_image)
上一行将创建的图像对象传递给识别器进行处理。
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText<() {
                                    @Override
                                    public void onSuccess(FirebaseVisionText result) {
//On receiving the results displaying to the user.                                       Toast.makeText(getApplicationContext(),result.getText(),Toast.LENGTH_LONG).show();
                                    }
                                })
上一段代码块将添加 on-success 监听器。它将接收一个 firebase 视觉文本对象,然后将其以Toast消息的形式显示给用户。
.addOnFailureListener(
            new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) 
                    {
                        Toast.makeText(getApplicationContext(),"Unable to read the text",Toast.LENGTH_LONG).show();
                    }
                  });
上一段代码块将添加on-failure监听器。它将接收一个异常对象,然后将其转换为以Toast消息形式显示给用户的错误信息。
当你运行上一行代码时,你将在设备上得到以下输出:

注意,在安装此应用时,你必须连接到互联网,因为 Firebase 需要将模型下载到你的设备上。
使用 Firebase 云端 API 创建文本识别应用
在本节中,我们将把设备上的应用转换为云端应用。区别在于设备上的应用会下载模型并存储在设备上。这允许有更低的推理时间,使得应用能够快速做出预测。
相比之下,基于云的应用会将图像上传到 Google 服务器,这意味着推理将在那里进行。如果你没有连接到互联网,则不会工作。
在这种情况下,为什么使用基于云的模型?因为设备上的模型空间和处理硬件有限,而 Google 的服务器是可扩展的。Google 的云端文本识别模型也能够解码多种语言。
要开始,你需要一个 Google Cloud 订阅。按照以下步骤操作:
- 
前往你的 Firebase 项目控制台。 
- 
在左侧菜单中,你会看到你目前处于 Spark 计划(免费层)。 
- 
点击“升级”,并按照说明升级到 Blaze 计划,这是按需付费。 
- 
你需要提供信用卡或支付详情以供验证——这些将不会自动收费。 
- 
一旦你订阅,你将每月免费获得 1,000 次 Cloud Vision API 请求 
只有当你拥有升级的 Blaze 计划而不是免费层账户时,才能尝试此程序。以下是创建升级账户的步骤,请按照步骤操作以尝试提供的程序。
默认情况下,Cloud Vision 未为您的项目启用。要启用它,您需要访问以下链接:console.cloud.google.com/apis/library/vision.googleapis.com/?authuser=0。在顶部菜单下拉菜单中,选择包含您在上一节中添加的 Android 应用的 Firebase 项目。
点击启用以启用此功能。页面将看起来像以下截图:

现在回到您的代码,并做出以下更改。
您可以在我们的 Packt Github 仓库中找到应用程序代码:github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/Testrecognizationoncloud。
除了主活动之外的所有其他文件都没有变化。
变更如下:
import com.google.firebase.FirebaseApp;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.document.FirebaseVisionDocumentText;
import com.google.firebase.ml.vision.document.FirebaseVisionDocumentTextRecognizer; 
现在,我们需要将前面的包作为依赖项导入。
 private FirebaseVisionDocumentTextRecognizer textRecognizer;
上一段代码将声明文档文本识别器。
textRecognizer = FirebaseVision.getInstance().getCloudDocumentTextRecognizer();
上一段代码实例化并分配了云文本识别器。
       takePictureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture();
                //In this function we are having the code to decode the characters in the picture
            }
        });
    }
上一段代码为拍照按钮注册了 on-click-event 监听器。
Bitmap bmp = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
上一行从字节数组创建了一个位图。
FirebaseVisionImage firebase_image = FirebaseVisionImage.fromBitmap(bmp);
上一行创建了一个 firebase 图像对象以传递给识别器。
 textRecognizer.processImage(firebase_image)
上一行将创建的图像对象传递给识别器进行处理。
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText<() {
                                    @Override
                                    public void onSuccess(FirebaseVisionDocumentText result) {
                                        Toast.makeText(getApplicationContext(),result.getText(),Toast.LENGTH_LONG).show();
                                    }
                                })
上一段代码块将添加 on-success 监听器。它将接收一个 FirebaseVision 文档文本对象,该对象随后以Toast消息的形式显示给用户。
.addOnFailureListener(
            new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) 
                    {
                        Toast.makeText(getApplicationContext(),"Unable to read the text",Toast.LENGTH_LONG).show();
                    }
                  });
上一段代码块将添加 on-failure 监听器。它将接收一个异常对象,随后以Toast消息的形式向用户显示错误信息。
Once you run the code with the internet-connected device , you will get the same output as before, but from the cloud.
使用 ML Kit 进行人脸检测
现在,我们将尝试了解如何使用 ML Kit 进行人脸检测。之前作为 Mobile Vision API 一部分的人脸检测现在已移动到 ML Kit。
人脸检测概念
Google 开发者页面将人脸检测定义为在视觉媒体(数字图像或视频)中自动定位和检测人类面部的过程。检测到的面部以关联的位置、大小和方向报告。面部被检测到后,我们可以搜索面部中存在的地标,如眼睛和鼻子。
在我们继续使用 ML Kit 进行编程人脸检测之前,以下是一些重要术语,我们需要理解:
- 
人脸朝向:检测不同角度的人脸。 
- 
人脸识别:确定两个面部是否属于同一个人。 
- 
人脸追踪:指在视频中检测人脸。 
- 
地标:指人脸内的一个兴趣点。这对应于人脸上的显著特征,如右眼、左眼和鼻基底。 
- 
分类:确定面部特征的存在,例如眼睛是睁开还是闭合,或者面部是微笑还是严肃。 
使用 ML Kit 进行面部检测的示例解决方案
现在打开 Android Studio,创建一个带有空活动的项目。记下您在创建项目时给出的应用程序包名——例如,com.packt.mlkit.facerecognization。
在这里,我们将修改文本识别代码以预测面部信息。因此,我们不会更改包名和其他内容。只是代码更改。项目结构与之前显示的相同:

是时候编写我们应用程序的主活动类了。首先,我们需要从 Packt GitHub 仓库下载应用程序代码,网址为github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/facerecognization,然后在 Android Studio 中打开项目。
然后,我们将添加以下代码行到 Gradle 依赖项中。打开模块 app 的build.gradle文件,并添加以下依赖项:
implementation 'com.google.android.gms:play-services-vision:11.4.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
现在,我们将添加导入语句以使用面部检测:
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;
以下语句将声明FaceDetector对象:
private FaceDetector detector;
现在,我们将创建一个对象并将其分配给声明的检测器:
detector = new FaceDetector.Builder(getApplicationContext())
 .setTrackingEnabled(false)
 .setLandmarkType(FaceDetector.ALL_LANDMARKS)
 .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
 .build();
我们声明了一个字符串对象,用于将预测消息保存给用户:
String scanResults = "";
在这里,我们将检查检测器是否可操作;我们还有一个从相机获取的 bitmap 对象:
if (detector.isOperational() && bmp != null) {
然后,我们创建一个 frame 对象,这是FaceDetector类检测方法需要预测面部信息:
Frame frame = new Frame.Builder().setBitmap(bmp).build();SparseArray<Face> faces = detector.detect(frame);
一旦成功检测到,它将返回面部对象数组。以下代码将每个nface对象的信息附加到我们的结果字符串中:
for (int index = 0; index < faces.size(); ++index) {
    Face face = faces.valueAt(index);
    scanResults += "Face " + (index + 1) + "\n";
    scanResults += "Smile probability:" + "\n" ;
    scanResults += String.valueOf(face.getIsSmilingProbability()) + "\n";          scanResults += "Left Eye Open Probability: " + "\n";
    scanResults += String.valueOf(face.getIsLeftEyeOpenProbability()) + "\n";
    scanResults += "Right Eye Open Probability: " + "\n";
    scanResults += String.valueOf(face.getIsRightEyeOpenProbability()) + "\n";
}
如果没有返回面部,则将显示以下错误信息:
if (faces.size() == 0) {
    scanResults += "Scan Failed: Found nothing to scan";
 } 
如果面部大小不是0,这意味着它已经通过了for循环,将面部信息附加到我们的结果文本中。现在我们将添加面部总数并结束结果字符串:
else {
    scanResults += "No of Faces Detected: " + "\n";
    scanResults += String.valueOf(faces.size()) + 
   \n";
    scanResults += "---------" + "\n";
}
如果检测器不可操作,则错误信息将以以下方式显示给用户:
else {
    scanResults += "Could not set up the detector!";
}
最后,以下代码将向读者展示结果:
Toast.makeText(getApplicationContext(),scanResults,Toast.LENGTH_LONG).show();
运行应用程序
现在是时候运行应用程序了。为此,您需要通过手机中的 USB 调试选项将您的手机连接到桌面,并安装应用程序:

运行应用程序后,您将得到以下输出:

摘要
在本章中,我们讨论了 Firebase 在 Google I/O 2018 上宣布的 ML Kit SDK。我们涵盖了 ML Kit 提供的不同 API,例如图像标签、文本识别、地标检测等。然后我们使用设备端 API 创建了一个文本识别应用,接着又使用云端 API。我们还通过对文本识别应用进行微小修改创建了一个面部检测应用。在下一章中,我们将学习垃圾邮件分类器,并构建一个 iOS 上的此类分类器的示例实现。
第七章:垃圾邮件检测
本章将为您提供一个关于自然语言处理(NLP)的概述,并讨论如何将 NLP 与机器学习相结合,以提供解决方案。然后,本章将探讨一个利用 NLP 和线性 SVM 分类模型进行垃圾邮件检测的真实世界用例。程序将作为 iOS 的 Core ML 移动应用程序实现。
为了在机器学习算法中处理文本,我们将探讨将在文本数据上使用的各种 NLP 技术,以便使其准备好用于学习算法。一旦文本准备好,我们将看到如何使用线性 SVM 模型对其进行分类。
问题定义:提供了大量短信消息数据,这些消息需要被分类为垃圾邮件或非垃圾邮件。
在本章中,我们将涵盖以下主题:
- 
理解自然语言处理(NLP) 
- 
理解线性 SVM 算法 
- 
使用 Core ML 中的线性 SVM 解决该问题: - 
技术要求 
- 
如何使用 scikit-learn 创建模型文件 
- 
测试模型 
- 
将 scikit-learn 模型导入 Core ML 项目 
- 
使用 scikit-learn 模型编写 iOS 移动应用程序,并对其进行垃圾邮件检测 
 
- 
理解自然语言处理(NLP)
自然语言处理(NLP)是一个庞大的主题,本书的范围并不包括对这个主题的详细探讨。然而,在本节中,我们将探讨 NLP 的高级细节,并尝试理解使用 NLP 准备和处理文本数据所需的关键概念,以便使其准备好由机器学习算法进行预测。
介绍自然语言处理(NLP)
每天都会产生大量非结构化文本数据。社交媒体、如 Twitter 和 Facebook 的网站,以及如 WhatsApp 的通讯应用,每天都会产生大量的这种非结构化数据——更不用说博客、新闻文章、产品评论、服务评论、广告、电子邮件和短信产生的数据量了。所以,总结来说,存在大量的数据(以 TB 为单位)。
然而,由于以下原因,计算机无法从这些数据中获得任何洞察力,并直接根据这些洞察力执行特定操作,因为这些数据量巨大:
- 
数据是非结构化的 
- 
没有预处理,数据无法直接理解 
- 
这些数据不能以未经处理的形式直接输入到任何机器学习算法中 
为了使这些数据更有意义并从中提取信息,我们使用自然语言处理(NLP)。专注于人类语言与计算机之间交互的研究领域被称为自然语言处理(NLP)。NLP 是数据科学的一个分支,与计算语言学密切相关。它涉及计算机科学——分析、理解和从基于人类自然语言的数据(通常是文本、语音等非结构化数据)中提取信息。
通过 NLP,计算机可以分析和从人类语言中提取意义,并执行许多有用的事情。通过利用 NLP,可以完成许多复杂任务,例如自动总结大量文档、翻译、不同大量非结构化数据之间的关系提取、情感分析和语音识别。
为了让计算机理解和分析人类语言,我们需要以更结构化的方式分析句子并理解其核心。在任何句子中,我们需要理解三个核心内容:
- 
语义信息:这关系到句子的含义。这是句子中单词的具体含义,例如,风筝飞翔。在这里,我们不知道风筝是人造的还是鸟类的。 
- 
句法信息:这关系到句子的结构。这是句子中单词的具体句法含义。Sreeja 用糖果看到了 Geetha。在这里,我们不确定谁有糖果:Sreeja 还是 Geetha? 
- 
语用信息(上下文):这关系到句子的上下文(语言或非语言)。这是句子中单词使用的具体上下文。例如,他在外面在棒球和医疗保健的上下文中是不同的。 
然而,计算机不能像人类那样分析和识别句子。因此,有一个明确的方法可以使计算机执行文本处理。以下是该练习涉及的主要步骤:
- 
预处理:这一步涉及从句子中移除所有噪声,以便只保留对句子上下文至关重要的信息供下一步使用。例如,语言停用词(“噪声”),如是、这或一个,可以从句子中移除以进行进一步处理。在处理句子时,人脑不会考虑语言中存在的噪声。同样,计算机可以接收无噪声文本以进行进一步处理。 
- 
特征工程:为了计算机能够处理预处理后的文本,它需要了解句子的关键特征。这是通过特征工程步骤实现的。 
- 
NLP 处理:将人类语言转换为特征矩阵后,计算机可以执行 NLP 处理,这可能是分类、情感分析或文本匹配。 
现在,让我们尝试理解在每个步骤中将要执行的高级活动。
文本预处理技术
在我们处理文本之前,它需要先进行预处理。预处理将涉及以下内容:
- 
从考虑的文本中移除噪声 
- 
标准化句子 
- 
标准化句子 
根据需求,可能会有额外的步骤,例如语法检查或拼写检查。
移除噪声
句子中出现的任何可能不与数据上下文相关的文本都可以称为噪声。
例如,这可以包括语言停用词(在语言中常用词汇 – is、am、the、of和in)、URL 或链接、社交媒体实体(提及、标签)、以及标点符号。
为了从句子中去除噪声,一般的方法是维护一个噪声词字典,然后迭代考虑的句子中的标记与该字典进行对比,并移除匹配的停用词。噪声词字典会频繁更新以覆盖所有可能的噪声。
规范化
句子中单词的差异被转换为规范化的形式。句子中的单词可能有所不同,如sing、singer、sang或singing,但它们或多或少都能适应相同的上下文,并且可以被标准化。
有不同的方法来规范化句子:
- 
词干提取:从单词中去除后缀(如ing、ly、es、s)的基本基于规则的过程。 
- 
词形还原:识别单词词根的更复杂的过程。它涉及一个更复杂的过程来验证语义和句法。 
标准化
此步骤涉及标准化句子,以确保它只包含来自标准语言字典的标记,而不包含任何其他内容,如标签、俚语词汇等。所有这些都在此步骤中被移除。
特征工程
现在文本已经被处理,下一步是将文本中的特征排列好,以便它们可以被输入到任何机器学习算法中执行分类、聚类等操作。有各种方法将文本转换为特征矩阵,我们将在本节中介绍其中一些。
实体提取
在这里,从句子中提取出用于 NLP 处理的关键实体。命名实体识别(NER)是其中一种方法,其中的实体可以是地点、人物或纪念碑等命名实体。
主题建模
这是另一种方法,从文本语料库中识别主题。主题可以是单个单词、单词模式或共现单词序列。根据主题中的单词数量,这些可以被称为N-gram。因此,基于上下文和重复性,可以使用双词和三词作为特征。
词袋模型
词袋模型是对文本的表示,描述了文档中单词的出现情况。它涉及已知单词的表示和已知单词在文档中的出现度量的计算。该模型更侧重于文档中已知单词的出现,而不是单词的顺序或文档中单词的结构。
统计工程
文本数据也可以使用各种技术表示为数值。对于大量文本文档,词频-逆文档频率(TF-IDF)是此类中的重要技术。
TF–IDF
TF-IDF 是一种加权模型,它基于文档中单词的出现次数将文本文档转换为向量模型,而不考虑文档中文本的确切顺序。
让我们考虑一组 N 个文本文档和任意一个文档 D。然后,我们定义以下内容。
TF
这衡量了一个术语在文档中出现的频率。由于每个文档的长度不同,一个术语可能在长文档中比在短文档中出现得更频繁。因此,TF 通常会被除以文档长度以进行归一化:
TF(t) = (文档 D 中术语 t 出现的次数)/(文档中的总词数 N).
逆文档频率 (IDF)
这衡量了一个术语对于语料库的重要性。在计算 TF 时,所有术语都被视为同等重要。然而,通常认为停用词出现得更频繁,但就 NLP 而言,它们的重要性较低。因此,有必要降低常见术语的重要性,提高罕见术语的重要性,这就是 IDF,其计算如下:
IDF(t) = log_e(文档总数/包含术语 t 的文档数)
TF-IDF
TF-IDF 公式给出了一个术语在语料库(文档列表)中的相对重要性,其公式如下:

其中:
- 
tf[i,j] = i 在 j 中的出现次数 
- 
df[i] = 包含 i 的文档数 
- 
N = 文档总数 
考虑一个包含 1,000 个单词的文档,其中单词“rat”出现了 3 次。那么“rat”的词频(TF)就是 (3/1000=) 0.003。现在,在 10,000 个文档中,单词“cat”出现在其中的 1,000 个。因此,逆文档频率(IDF)计算为 log(10000/1000) = 1。因此,TF-IDF 权重是这些数量的乘积,即 0.003 * 1 = 0.12。
文本语料库中的单词或特征也可以组织成特征向量,以便于将其输入到 NLP 处理的下一步。
对文本进行分类/聚类
最后一步是实际使用特征工程矩阵或词向量进行分类或聚类。我们可以使用任何分类算法并将特征向量输入以执行分类或聚类。
与执行聚类类似,可以使用不同的相似度度量,例如余弦距离或 Levenshtein 距离。
理解线性 SVM 算法
在 第二章 “监督和非监督学习算法”中,我们介绍了 SVM 算法,现在我们已经了解了 SVM 模型的工作原理。线性支持向量机或线性 SVM 是一种线性分类器,它试图找到一个具有最大边缘的超平面,将输入空间分割成两个区域。
超平面是平面的推广。在一维中,超平面被称为点。在二维中,它是一条线。在三维中,它是一个平面。在更多维度中,你可以称之为超平面。
正如我们所见,SVM 的目标是识别一个试图找到最大间隔的超平面,将输入空间分成两个区域。如果输入空间是线性可分的,那么很容易将它们分开。然而,在现实生活中,我们发现输入空间非常非线性:

在前面的场景中,SVM 可以通过所谓的核技巧帮助我们分离红色和蓝色球,核技巧是使用线性分类器来解决非线性问题的方法。
核函数应用于每个数据实例,将原始的非线性观测映射到一个更高维的空间,在这个空间中它们变得可分离。
最受欢迎的核函数如下:
- 
线性核 
- 
多项式核 
- 
RBF(高斯)核 
- 
字符串核 
线性核通常被推荐用于文本分类,因为大多数文本分类问题都需要将文本分类为两类。在我们的例子中,我们还想将短信消息分类为垃圾邮件和非垃圾邮件。
在 Core ML 中使用线性 SVM 解决问题
在本节中,我们将探讨如何使用本章中介绍的所有概念来解决垃圾邮件检测问题。
我们将选取一些短信消息并尝试将它们分类为垃圾邮件或非垃圾邮件。这是一个分类问题,我们将使用线性 SVM 算法来完成这个任务,考虑到使用此算法进行文本分类的优势。
我们将使用 NLP 技术将数据-SMS 消息转换为特征向量,以输入到线性 SVM 算法中。我们将使用 scikit-learn 的 vectorizer 方法将短信消息转换为 TF-IDF 向量,该向量可以输入到线性 SVM 模型中,以执行短信垃圾邮件检测(将短信分类为垃圾邮件和非垃圾邮件)。
关于数据
我们用于创建检测垃圾邮件模型的数据来自www.dt.fee.unicamp.br/~tiago/smsspamcollection/,其中包含 747 个垃圾邮件样本,以及 4,827 条非垃圾邮件。
这些消息来自不同的来源,并标记为垃圾邮件和非垃圾邮件的类别。如果你在记事本或任何文本编辑器中打开下载的文件,它将具有以下格式:
ham   What you doing?how are you?
ham   Ok lar... Joking wif u oni...
 ham   dun say so early hor... U c already then say...
 ham   MY NO. IN LUTON 0125698789 RING ME IF UR AROUND! H*
 ham   Siva is in hostel aha:-.
 ham   Cos i was out shopping with darren jus now n i called him 2 ask wat present he wan lor. Then he started guessing who i was wif n he finally guessed darren lor.
 spam  FreeMsg: Txt: CALL to No: 86888 & claim your reward of 3 hours talk time to use from your phone now! ubscribe6GBP/ mnth inc 3hrs 16 stop?txtStop
 spam  Sunshine Quiz! Win a super Sony DVD recorder if you can name the capital of Australia? Text MQUIZ to 82277\. B
 spam  URGENT! Your Mobile No 07808726822 was awarded a L2,000 Bonus Caller Prize on 02/09/03! This is our 2nd attempt to contact YOU! Call 0871-872-9758 BOX95QU
在前面的示例中,我们可以看到每一行都以类别名称开头,后面跟着实际的消息。
技术要求
要创建一个将消息分类为垃圾邮件或非垃圾邮件的模型,我们需要一个能够做到这一点的库。在这里,我们选择了 scikit-Learn。
要编写这个应用,你需要在你的桌面电脑上安装 Python3+版本,并且必须在你的 Mac 机器上安装 Xcode 9+。如果你没有这些之一,请查阅本书的附录来学习如何获取它们。一旦你在你的机器上安装了 Python,执行以下命令以获取所需的包:
pip install scikit-learn pip install numpy pip install coremltools pip install pandas
使用前面的代码,我们安装了 scikit-learn 以获取访问算法的权限,以及 NumPy,因为 scikit-learn 需要它,还有 pandas(pandas是一个开源的 BSD 许可库,为 Python 编程提供高性能、易于使用的数据结构和数据分析工具)来从文件中读取模型和 core-ML 工具来生成 Core ML 模型文件。
现在,下载SMSSpamCollection.txt,一个从上一节中提到的模型链接的纯文本文件,并将其下载到你的磁盘上,然后放入你的project文件夹中。
使用 Scikit Learn 创建模型文件
在你的项目文件夹中,创建一个包含以下代码的 python 文件来创建一个模型文件:
# importing required packages
import numpy as np
import pandas as pd
# Reading in and parsing data
raw_data = open('SMSSpamCollection.txt', 'r')
sms_data = []
for line in raw_data:
    split_line = line.split("\t")
    sms_data.append(split_line)
#Splitting data into messages and labels and training and test in y we are having labels and x with the message text
sms_data = np.array(sms_data)
X = sms_data[:, 1]
y = sms_data[:, 0]
#Build a LinearSVC model
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
#Build tf-idf vector representation of data
vectorizer = TfidfVectorizer()
# converting the message text as vector
vectorized_text = vectorizer.fit_transform(X)
text_clf = LinearSVC()
# fitting the model
text_clf = text_clf.fit(vectorized_text, y)
测试拟合的模型,我们可以添加以下代码:
print text_clf.predict(vectorizer.transform(["""XXXMobileMovieClub: To use your credit, click the WAP link in the next txt message or click here>> http://wap. xxxmobilemovieclub.com?n=QJKGIGHJJGCBL"""]))
执行前面的程序后,它将显示给定的消息是垃圾邮件还是非垃圾邮件。
将 scikit-learn 模型转换为 Core ML 模型
在上一节中,我们创建了我们的模型来将消息分类为垃圾邮件和非垃圾邮件。现在,让我们将其转换为 Core ML 模型,以便我们可以在 iOS 应用中使用它。
要创建 Core ML 模型,将以下行添加到前面的代码中并运行它们。这将创建一个.mlmodel文件:
# importing the library
import coremltools
# convert to fitted model in to coreml model
coreml_model = coremltools.converters.sklearn.convert(text_clf, "message", "spam_or_not")
#set parameters of the model
coreml_model.short_description = "Classify whether message is spam or not"
coreml_model.input_description["message"] = "TFIDF of message to be classified"
coreml_model.output_description["spam_or_not"] = "Whether message is spam or not"
#save the model
coreml_model.save("SpamMessageClassifier.mlmodel")
现在,你可以获取生成的SpamMessageClassifier.mlmodel文件,并在你的 Xcode 中使用它。
编写 iOS 应用
你可以在我们的 GitHub 仓库中获取 iOS 项目的代码(github.com/PacktPublishing/Machine-Learning-for-Mobile)。一旦你下载了项目并在 Xcode 中打开它,你将找到以下目录结构:

在这里,我想向你解释一些重要的文件。Main. Storyboard 包含了应用的 UI 设计:

这里,我们有两个标签,一个按钮和一个文本框。两个标签是一个标题标签和一个结果标签。按钮用于提交输入并获取结果。我们还有一个文本框来输入消息。在这里,主要处理是在controller.swift视图中编写的:
//common imports
import UIKit
import CoreML
class ViewController: UIViewController {
    //binding to the UI elements
    @IBOutlet weak var messageTextField: UITextField!
    @IBOutlet weak var messageLabel: UILabel!
    @IBOutlet weak var spamLabel: UILabel!
// This function will take the text from the user input and convert it in to a vector format which our model requires using the wordslist.txt file and the SMSSpamCollection.txt file that we have downloaded.
    func tfidf(sms: String) -> MLMultiArray{
        //get path for files
        let wordsFile = Bundle.main.path(forResource: "wordlist", ofType: "txt")
        let smsFile = Bundle.main.path(forResource: "SMSSpamCollection", ofType: "txt")
        do {
            //read words file
            let wordsFileText = try String(contentsOfFile: wordsFile!, encoding: String.Encoding.utf8)
            var wordsData = wordsFileText.components(separatedBy: .newlines)
            wordsData.removeLast() // Trailing newline.
            //read spam collection file
            let smsFileText = try String(contentsOfFile: smsFile!, encoding: String.Encoding.utf8)
            var smsData = smsFileText.components(separatedBy: .newlines)
            smsData.removeLast() // Trailing newline.
            let wordsInMessage = sms.split(separator: " ")
            //create a multi-dimensional array
            let vectorized = try MLMultiArray(shape: [NSNumber(integerLiteral: wordsData.count)], dataType: MLMultiArrayDataType.double)
            for i in 0..<wordsData.count{
                let word = wordsData[i]
                if sms.contains(word){
                    var wordCount = 0
                    for substr in wordsInMessage{
                        if substr.elementsEqual(word){
                            wordCount += 1
                        }
                    }
                    let tf = Double(wordCount) / Double(wordsInMessage.count)
                    var docCount = 0
                    for sms in smsData{
                        if sms.contains(word) {
                            docCount += 1
                        }
                    }
                    let idf = log(Double(smsData.count) / Double(docCount))
                    vectorized[i] = NSNumber(value: tf * idf)
                } else {
                    vectorized[i] = 0.0
                }
            }
            return vectorized
        } catch {
            return MLMultiArray()
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
//This function will call when you click the predict button
    @IBAction func predictSpam(_ sender: UIButton) {
        let enteredMessage =  messageTextField.text!
// checking and handling empty message.
        if (enteredMessage != ""){
            spamLabel.text = ""
        }
// Calling the preceding function to convert the text to vector
        let vec = tfidf(sms: enteredMessage)
        do {
// Passing input to the our model to get the prediction results.
            let prediction = try SpamMessageClassifier().prediction(message: vec).spam_or_not
            print (prediction)
            if (prediction == "spam"){
                spamLabel.text = "SPAM!"
            }
// Our model is having ham as label for not spam messages so our model will send the label as ham. Hence we are converting to Not Spam for displaying purpose
           else if(prediction == "ham"){
                spamLabel.text = "NOT SPAM"
            }
        }
        catch{
                // catching the exception
            spamLabel.text = "No Prediction"
        }
    }
}
当你在 Xcode 的模拟器中运行应用时,它将生成以下结果:

摘要
在本章中,我们探讨了众多内容,例如,从高层次理解自然语言处理(NLP)。NLP 涉及多个步骤,例如文本预处理,以及执行这些步骤的技术,如特征工程和执行特征工程以及特征向量分类或聚类的方 法。我们还研究了线性 SVM 算法,其中我们详细介绍了 SVM 算法、核函数以及它如何更适用于文本分类。
我们使用线性 SVM 在 Core ML 中解决了我们的问题,并且我们还看到了一个使用我们在 scikit learn 中开发的线性 SVM 算法模型并转换为 Core ML 模型进行垃圾邮件检测的实际示例。我们使用转换后的 Core ML 模型编写了一个 iOS 应用程序。
在下一章中,我们将介绍另一个机器学习框架 Fritz,它试图解决我们在模型部署和升级中常见的各种问题,以及在不同移动操作系统平台间统一处理机器学习模型的方法。
第八章:Fritz
我们在前面章节中已经了解了由 Google 提供的移动机器学习 SDK——TensorFlow for mobile 和 Apple 的 Core ML,并对它们有了很好的理解。我们研究了这些产品的基本架构,它们提供的关键特性,并且尝试使用这些 SDK 进行了一些任务/程序的实践。基于我们对移动机器学习框架和工具的探索,我们将能够识别出一些导致移动机器学习部署及其后续维护和支持困难的差距。让我为您列举几个:
- 
一旦我们创建了机器学习模型并将其导入到 Android 或 iOS 应用程序中,如果需要对导入到移动应用程序中的模型进行任何更改,您认为这种更改将如何实施并升级到正在部署和使用的应用程序?如何在不需要在移动应用程序商店(App Store 或 Play Store)重新部署应用程序的情况下更新/升级模型? 
- 
一旦机器学习模型在野外投入使用,并且被用户在野外使用,我们如何监控模型在实时用户场景中的性能和用法? 
- 
此外,您可能已经体验过,在 iOS 和 Android 中使用机器学习模型的过程和机制并不相同。同样,将使用各种机器学习框架(如 TensorFlow 和 scikit-learn)创建的机器学习模型与 TensorFlow Lite 和 Core ML 兼容的机制也不同。没有共同的流程和用法模式供开发者遵循,以跨框架创建和使用这些模型。我们觉得,如果有一个通用的方法来使用来自不同供应商的机器学习模型,并且使用相同的过程和机制,那么事情将会简单得多。 
Fritz 平台已经尝试回答在机器学习模型使用和部署中观察到的所有之前提到的差距。作为机器学习平台,Fritz 试图提供解决方案,以简化移动应用程序中机器学习模型的使用和部署。它是一个带有现成机器学习功能的移动机器学习平台,并提供导入和使用自定义 ML 模型(TensorFlow for mobile 和 Core ML 模型)的选项。
因此,在本章中,我们将详细探讨以下内容:
- 
理解 Fritz 移动机器学习平台,其特性及其优势。 
- 
探索 Fritz 并使用我们已创建的 Core ML 回归模型来实现一个 iOS 移动应用程序。 
- 
探索 Fritz 并使用我们在第三章中创建的示例 Android 模型来实现一个 Android 移动应用程序,即使用 TensorFlow for mobile 实现的iOS 上的随机森林。 
Fritz 简介
Fritz 是一个免费的全端平台,使我们能够轻松创建机器学习驱动的移动应用程序。它是一个支持设备端机器学习的平台,即它有助于创建可以在移动设备上完全运行的移动机器学习应用程序。它支持 iOS 和 Android 平台。
预构建的 ML 模型
Fritz 提供了可以直接在移动应用程序中使用的内置 ML 模型。以下是 Fritz 支持的两种重要模型:
- 
目标检测:您可以在图像或实时视频的每一帧中识别感兴趣的对象。这有助于您了解图像中的对象以及它们在图像中的位置。目标检测功能完全在设备上做出预测,并且不需要互联网连接. 
- 
图像标注:您可以在图像或实时视频的每一帧中识别内容。这也完全离线工作,不需要互联网连接。 
使用自定义模型的能力
Fritz 为我们提供了将用于 Core ML、TensorFlow 移动和 TensorFlow Lite 的模型导入移动应用程序的能力,并提供可以直接与这些模型交互的 API。
模型管理
Fritz 的主要优势在于它能够实时进行 ML 模型管理和升级:
- 
它为我们提供了升级部署到现场机器学习模型的能力,即它允许开发者升级或更改 ML 模型,而无需进行应用程序升级和在移动应用程序商店中重新部署。 
- 
它为我们提供了监控部署到现场机器学习模型性能的设施。 
- 
它有助于部署、分析和机器学习模型管理。 
使用 Fritz 的动手示例
在本节中,我们将尝试使用 Fritz 以及我们使用 Core ML 和 TensorFlow 移动为 iOS 和 Android 创建的模型,并使用 Fritz 构建 iOS 和 Android 移动应用程序。此外,我们还将了解如何使用 Fritz 内置的模型,例如目标检测和图像标注。
在 Android 应用程序中使用 Fritz 的现有 TensorFlow 移动模型
在本节中,我们将了解如何使用 Fritz 工具包在 Android 移动应用程序中利用我们已创建的 TensorFlow 移动模型。我们将使用我们用 TensorFlow 移动创建的示例模型来进行求和操作 (a+b)。我们将详细介绍实现此目标所需的详细步骤。
在 Fritz 上注册
为了使用 Fritz,您必须在 Fritz 网络门户上注册账户:
- 
前往 fritz.ai/
- 
在顶部菜单中点击登录 
- 
点击创建账户 
- 
输入您的详细信息并提交 
- 
在 Fritz 中创建一个新的项目 
一旦您拥有账户,请使用您的凭证登录,然后执行以下步骤:
- 
点击“添加新项目”按钮 
- 
输入项目名称和组织 
- 
点击提交 
上传模型文件 (.pb 或 .tflite)
- 
点击左侧菜单中的自定义模型 
- 
给模型命名并添加描述 
- 
上传模型文件 
- 
点击创建模型文件按钮 
一旦上传,模型页面将看起来像这样:

这里,我们使用的是在第三章中创建的相同模型,iOS 上的随机森林:TensorFlow for Android。GitHub URL 是github.com/PacktPublishing/Machine-Learning-for-Mobile/blob/master/tensorflow%20simple/tensor/frozen_tfdroid.pb。
设置 Android 并注册应用
我们已经创建了一个项目并向其中添加了一个模型。让我们看看如何在 Android 项目中使用这个模型。现在,我将向您展示如何将我们在第三章中看到的 TensorFlow 简单示例,iOS 上的随机森林,转换为 fritz 格式。要继续,请在该示例中打开 Android studio。
如果您没有它,您可以从github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/tensorflow%20simple下载。在给定的路径中,TensorFlow 示例是 Android 项目,在 Android studio 中打开它。
添加 Fritz 的 TFMobile 库
在本节中,我们将把这个项目转换成一个由 Fritz 管理的项目。在模型页面,点击 SDK 说明按钮。它将打开一个对话框,显示集成信息,如下所示:

在这里,您将找到 API 密钥,它是项目唯一的,模型 ID,它对您上传的每个模型都不同,以及创建解释器的代码。
向项目中添加依赖项
为了访问 Fritz 解释器,您需要向项目中添加依赖项。为此,打开您的模块 app 的build.gradle文件。您需要添加一个指向 Fritz Maven 仓库的仓库条目。为此,添加以下行:
repositories {
    maven { url "https://raw.github.com/fritzlabs/fritz-repository/master" }
}
现在添加 Fritz 依赖项:
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'ai.fritz:core:1.0.0'
    implementation 'ai.fritz:custom-model-tfmobile:1.0.0'
    implementation 'com.stripe:stripe-android:6.1.2'
}
使用前面的代码,我们已经添加了 Fritz 核心库和tfmobile库。Fritz 核心库是必需的,用于与 fritz 云服务器通信以下载版本管理的模型文件。tfmobile库也是必需的,因为我们正在使用 TensorFlow 移动模型,并且我们需要 TensorFlow 库来进行推理。
在您的 AndroidManifest 中注册 FritzJob 服务
我已经提到,当您的应用在 fritz 云服务器上部署时,您的应用将下载模型文件。为此,Fritz 实现了一个名为FritzJob的服务,它将在后台运行。当它发现您的 Web 控制台中部署了新的模型时,当设备连接到 Wi-Fi 时,它将尝试下载。
要登录你的云账户,你的应用需要一些凭证。为此,fritz 提供了一个 API 密钥。为了启用此功能,我们需要在你的 Android 清单 XML 文件中添加一个元条目,如下所示:
<meta-data android:name="fritz_api_key" android:value="6265ed5e7e334a97bbc750a09305cb19" />
你需要替换的 fritz API 密钥值,应替换为你从浏览器中点击 SDK INSTRUCTIONS 时获取的你的 API 密钥。
我们还需要声明 Fritz 作业,如下所示:
<service
    android:name="ai.fritz.core.FritzJob"
    android:exported="true"
    android:permission="android.permission.BIND_JOB_SERVICE" />
由于我们的应用需要通过 Wi-Fi 连接到云服务器,我们需要提及该互联网访问权限:
<uses-permission android:name="android.permission.INTERNET"/>
现在,我的整个清单文件将看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.packt.fritz.samplefritzapp">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data android:name="fritz_api_key" android:value="6265ed5e7e334a97bbc750a09305cb19" />
        <service
            android:name="ai.fritz.core.FritzJob"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE" />
    </application>
</manifest>
将 TensorFlowInferenceInterface 类替换为 Fritz 解释器
打开你的应用的主活动并做出以下更改:
package org.packt.fritz.samplefritzapp;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import org.tensorflow.contrib.android.TensorFlowInferenceInterface;
import ai.fritz.core.*;
import ai.fritz.customtfmobile.*;
在前面的import语句中,我们已添加了对 Fritz 核心库和 Fritz 自定义模型库的导入,并且我们还在使用 Google 的TensorflowInfereceInterface:
public class MainActivity extends AppCompatActivity {
private TensorFlowInferenceInterface inferenceInterface;
 static {
System.loadLibrary("tensorflow_inference");
 }
在前面的行中,我们已声明了 TensorFlow 推理接口并加载了tensorflow_inference库,这是可选的。这可以通过 Fritz 本身隐式完成:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 Fritz.configure(this);
在前面的行中,我们已经配置了 fritz 服务并将其与你的应用链接。在这里,它将验证应用包名是否已添加到你的 Fritz 控制台。
要这样做,你需要在 Fritz 网络控制台中项目左侧菜单中点击项目设置。
然后,点击将 Android 应用添加到你的项目中,它将打开一个对话框,如下所示:

在这里,你需要给你的应用起一个名字,用于识别目的。然后你需要从你的 Android 清单文件中获取包名,并在Package ID文本字段中输入它。
这个特定的信息你可以从你的清单文件中的清单标签中获取,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.packt.fritz.samplefritzapp">
一旦注册,回到我们的代码:
 try {
FritzTFMobileInterpreter interpreter = FritzTFMobileInterpreter.create(this.getApplicationContext(),
 new ModelSettings.Builder()
.modelId("2a83207a32334fceaa29498f57cbd9ae")
.modelPath("ab2.pb")
.modelVersion(1)
.build());
这里,我们正在为我们的 Fritz 模型创建一个对象。第一个参数是应用程序上下文对象,第二个参数是模型信息对象。
在模型设置中,我们将提供模型 ID,这可以从你点击 Fritz 网络控制台中模型页面的 SDK 说明时显示的对话框中获取。
另一个重要的事情是模型路径。这是你的模型文件名,你将其放置在assets文件夹中:
 inferenceInterface = interpreter.getInferenceInterface();
在前面的行中,我们正在获取 TensorFlow 推理接口对象并将其分配给全局声明的变量:
 final Button button = (Button) findViewById(R.id.button);
 button.setOnClickListener(new View.OnClickListener() {
 public void onClick(View v) {
 final EditText editNum1 = (EditText) findViewById(R.id.editNum1);
 final EditText editNum2 = (EditText) findViewById(R.id.editNum2);
 float num1 = Float.parseFloat(editNum1.getText().toString());
 float num2 = Float.parseFloat(editNum2.getText().toString());
 long[] i = {1};
 int[] a = {Math.round(num1)};
 int[] b = {Math.round(num2)};
 inferenceInterface.feed("a", a, i);
 inferenceInterface.feed("b", b, i);
 inferenceInterface.run(new String[]{"c"});
 int[] c = {0};
 inferenceInterface.fetch("c", c);
 final TextView textViewR = (TextView) findViewById(R.id.txtViewResult);
 textViewR.setText(Integer.toString(c[0]));
 }
});
 }
 catch (Exception ex)
{
Toast.makeText(this.getApplicationContext(),ex.toString(),Toast.LENGTH_LONG).show();
 }
}
}
在前面的代码块中,我们已注册了一个事件监听器,它将在用户点击运行按钮时执行推理。
构建和运行应用
要查看结果,连接一个设备并运行项目。它将显示如下结果:

部署模型的新版本
Fritz 的真实力量在于自动下载修订后的模型文件。在这里,我们将演示这一点。
到目前为止,我们已经上传了我们的旧(a+b)(*2*)模型并执行了推理。现在,我们将将其更新到*(a+b)*(3)并检查我们的应用是否自动下载了修订后的模型。
为了做到这一点,我们需要创建(a+b)³模型。首先,我们需要回顾第四章下的创建和保存模型部分,即Android 中的 TensorFlow Mobile,在那里我们创建了(a+b)²模型。我们将进行一个小改动,将这个模型转换:
import tensorflow as tf
a = tf.placeholder(tf.int32, name='a')  # input
b = tf.placeholder(tf.int32, name='b')  # input
times = tf.Variable(name="times", dtype=tf.int32, initial_value=3)
c = tf.pow(tf.add(a, b), times, name="c")
saver = tf.train.Saver()
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init_op)
    tf.train.write_graph(sess.graph_def, '.', 'tfdroid.pbtxt')
    sess.run(tf.assign(name="times", value=3, ref=times))
    # save the graph
    # save a checkpoint file, which will store the above assignment
    saver.save(sess, './tfdroid.ckpt')
在前面的程序中,我们唯一做的改动是times变量的值,现在它是3。这将导致(a+b)乘以三,得到(a+b)³。请参阅第四章,Android 中的 TensorFlow Mobile,以获取有关如何运行和生成.pb扩展模型文件的说明。
一旦你得到frozen_tfdroid.pb文件,你可以从 Fritz 模型页面的 Web 控制台中上传此文件,如图所示:

展开添加更新模型面板并上传生成的模型。它将在右侧表格中添加为版本 2:

现在你已经上传了模型的修订版,但尚未发布。要这样做,你需要展开“发布新版本”面板并发布所需的版本。
一旦你这样做,所有安装了你的应用的移动设备在通过 WiFi 网络获取互联网连接时,都会下载已发布的模型。
这里是我连接到我的 WiFi 路由器并重新启动应用时得到的结果:

使用 fritz 预构建模型创建 android 应用
Fritz 为 iOS 和 Android 都提供了两个预构建模型:
- 
图像标记 
- 
目标检测 
在本节中,我们将了解如何在你的 Android 应用中使用图像标记模型。
要这样做,你需要在 Fritz 中创建一个项目;请参阅使用 Fritz 在 Android 应用程序中使用现有的 TensorFlow Mobile 模型部分中给出的步骤。
现在,打开 Android Studio 并创建一个带有空活动文件和布局文件的空项目。
向项目中添加依赖项
为了访问前面对话框中显示的 fritz 解释器,你需要向你的项目中添加依赖项。为此,打开你的模块应用的build.gradle文件。
你需要添加一个指向 fritz Maven 仓库的仓库条目。为此,添加以下行:
repositories {
    maven { url "https://raw.github.com/fritzlabs/fritz-repository/master" }
}
现在,添加 fritz 依赖项:
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'ai.fritz:core:1.0.1'
    implementation 'ai.fritz:vision-label-model:1.0.1'
}
在前面的行中,我们已经添加了 fritz 核心库和 fritz 视觉库用于标记。为了与 fritz 云服务器通信并下载版本管理所需模型文件,fritz 核心库是必需的。
Fritz 视觉库用于标记将下载所需的库,例如 TensorFlow Mobile 和视觉依赖项。
在你的 Android 清单中注册 Fritz JobService
我已经提到,当你的应用在 Fritz 云服务器上部署时,它将下载模型文件。为此,Fritz 实现了一个名为FritzJob的服务。此服务将在后台运行,当它在你网络控制台中找到新部署的模型时,当设备通过 WiFi 网络连接时,它将尝试下载。
为了登录你的云账户,你的应用需要一些凭证。为此,Fritz 提供了一个 API 密钥。为了启用此功能,我们需要在你的 Android 清单 XML 文件中添加一个元条目,如下所示:
<meta-data
    android:name="fritz_api_key"
    android:value="e35d2b5bbba84eca8969b7d6acac1fb7" />
你需要将 Fritz API 密钥的值替换为你从浏览器中点击SDK INSTRUCTIONS时的上一个对话框中获得的你的密钥。
我们需要声明 Fritz 作业,如下所示:
<service
    android:name="ai.fritz.core.FritzJob"
    android:exported="true"
    android:permission="android.permission.BIND_JOB_SERVICE" />
由于我们的应用需要通过 WiFi 连接到云服务器,因此我们需要提及该互联网访问权限:
<uses-permission android:name="android.permission.INTERNET"/>
我们还需要添加以下行:
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-permission android:name="android.permission.CAMERA" />
在 Android 中,相机处理机制已更改为camera2包,上一行指定了要使用哪个camera2功能。要了解更多信息,请查看developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL。因此,为了访问相机,我们还需要添加相机权限。
现在,我的整个清单文件将看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.avinaas.imagelabelling">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
    <uses-feature android:name="android.hardware.camera2.full" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="fritz_api_key"
            android:value="e35d2b5bbba84eca8969b7d6acac1fb7" />
        <service
            android:name="ai.fritz.core.FritzJob"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE" />
    </application>
</manifest>
创建应用布局和组件
在你的activity_main.xml文件中,该文件位于你的assets/layouts文件夹中,你需要输入以下代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.avinaas.imagelabelling.MainActivity">
<TextureView
    android:id="@+id/preview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@id/btn_takepic"
    android:layout_alignParentTop="true"/>
    <Button
        android:id="@+id/btn_takepic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:text="Start Labeling"
        />
</RelativeLayout>
在前面的 XML 工具中,上下文值需要根据你的主活动进行更改。
在前面的 XML 中,我们添加了一个按钮来接收事件,以及一个纹理视图,它作为相机流的占位符。
前面布局的设计视图将看起来像这样:

编写应用代码
此应用的代码可以在你的 GitHub 仓库中找到,地址为github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/Fritz/imagelabelling/imagelabelling。
下载代码后,在 Android Studio 中打开它,你可以在MainActivity.java中找到代码。
为了解释整个代码,可能更多地涉及 Android 代码。在这里,你可以找到对重要代码块的解释:
Fritz.configure(this.getApplicationContext());
在oncreate生命周期方法中的上一行将初始化 Fritz 框架:
options = new FritzVisionLabelPredictorOptions.Builder()
        .confidenceThreshold(0.3f)
        .build();
上一行将创建标签预测器的配置选项:
visionPredictor = FritzVisionLabelPredictor.getInstance(this.getApplicationContext(), options);
创建预测器的实例:
Bitmap bmp = BitmapFactory.decodeFile(file.getPath());
获取保存到文件中的图像并将其转换为位图:
FritzVisionImage img = FritzVisionImage.fromBitmap(bmp);
List<FritzVisionLabel> labels = visionPredictor.predict(img);
将位图图像转换为 Fritz 视觉图像,并将该图像对象提供给预测器的predict方法,该方法反过来返回预测标签列表:
String output="";
for(FritzVisionLabel lab: labels)
{
    output = output + lab.getText()+"\t Confidence: "+ lab.getConfidence();
}
if(output.trim().length()==0)
{
    output = "Unable to predict.";
}
Toast.makeText(MainActivity.this, output, Toast.LENGTH_LONG).show();
由于预测器返回了一个Fritzvisionlabel对象的列表,我们需要对其进行解码并展示给用户。前面的代码在“Toast”消息中向用户展示了内容和置信度百分比。
一旦运行应用程序,从摄像头捕获的图像帧将在我们布局中创建的纹理视图中显示。
一旦你点击“开始标注”按钮,它将保存图像到磁盘并将相同的图像输入到Fritzvisionlabel预测器。一旦你恢复预测结果,你将对其进行解释并以Toast消息的形式展示给用户。
要使前面的应用程序工作,我们需要将此应用程序添加到你的 Fritz 项目中。
要这样做,请点击 Fritz 网络控制台中左侧菜单中的“项目设置”。
然后,点击“将 Android 应用程序添加到项目”并会打开一个对话框,如下所示:

在这里,你需要给你的应用程序命名,以便于识别。然后你需要从你的 Android 清单文件中获取包名并将其输入到“包 ID”文本字段中。
这可以通过以下方式从你的清单文件中的 manifest 标签获得:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.avinaas.imagelabelling">
一旦注册了应用程序,你可以通过将 Android 设备连接到你的 PC 并启用 USB 调试选项来运行和查看结果。
确保你禁用了 Android Studio 中的“Instant run”选项。这可以通过文件菜单中的设置选项完成。
一旦应用程序成功运行,结果将如下所示:

使用 Fritz 在 iOS 应用程序中使用现有的 Core ML 模型
在本节中,我们将了解如何使用 Fritz 工具包在 iOS 移动应用程序中利用我们已创建的 Core ML 模型。我们将使用 Core ML 和Boston数据集创建的HousePricer.mlmodel,并使用线性回归算法进行房价预测。我们将详细说明实现此目标所需的步骤。
为了此目的,请从 Packt GitHub 上的线性回归示例源代码下载房价预测,链接为github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/housing%20price%20prediction/sample。
在 Fritz 中注册
为了使用 Fritz,你必须在 Fritz 网络门户中注册一个账户:
- 
前往 fritz.ai/。
- 
点击顶部菜单中的“登录” 
- 
点击“创建账户” 
- 
输入你的详细信息并提交 
在 Fritz 中创建新项目
一旦你有了账户,请使用你的凭证登录并执行以下步骤:
- 
点击“添加新项目”按钮 
- 
输入项目名称和组织 
- 
点击“提交” 
上传模型文件 (.pb 或 .tflite)
以下是将模型文件上传的步骤:
- 
在左侧菜单中点击“自定义模型” 
- 
输入模型名称和描述 
- 
上传在运行 Python 程序后生成的第一个线性回归章节中的模型文件 ( HousePricer.mlmodel)
您可以在下载目录中找到此文件:github.com/PacktPublishing/Machine-Learning-for-Mobile/tree/master/housing%20price%20prediction/sample/sample。
- 点击“创建模型文件”按钮
一旦上传,模型页面将看起来像这样:

创建 Xcode 项目
现在,打开您在 Xcode 中下载的项目。项目将看起来像这样。

安装 Fritz 依赖项
要安装 Fritz 依赖项,从 Fritz 下载您的模型 pod 文件。为此,您需要将您的 iOS 项目添加到您的 fritz 项目中。您可以从 fritz 控制台的项目设置页面这样做。
在项目设置页面中,点击“添加 iOS 项目”按钮。然后填写对话框,其中包含您在 Xcode 中打开应用程序时显示的应用程序名称。填写此信息时,请使用从构建设置中获取的捆绑 ID,如图所示:

然后,您将被允许下载 Fritz-info.plist 文件。将此文件添加到 Xcode 中的项目文件夹中,如图所示:

之后,您需要关闭 Xcode,从终端导航到您的项目文件夹,并依次执行以下命令:
$ pod init
$ pod 'Fritz'
$ pod install
这为您创建了一个 .xcworkspace 文件,用于您的应用程序。使用此文件进行所有未来的应用程序开发。
现在关闭您的 Xcode 应用程序,并使用此文件重新打开项目。
添加代码
在 fritz 控制台中打开您的模型控制台。它将有一个按钮 - SDK 指令,点击此按钮将打开如下截图所示的对话框。如图所示,创建一个具有所示文件名的新的文件,并将代码粘贴/写入其中:

现在,一旦添加了此文件,您需要打开 AppDelegate.swift 并进行以下修改:
- 
首先,添加一个新的导入语句 
- 
导入 Fritz
- 
现在在应用程序代理类中: 
      func application(_application : UIApplication, 
      didFinishLaunchingWithOptions launchOptions: 
      [UIApplication.LauncgOptionsKey: Any])
替换之前的方法定义,如图所示:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
-> Bool {
FritzCore.configure()
return true
}
构建、运行 iOS 移动应用程序
与我们构建 iOS 移动应用程序的方式类似,在模拟器中构建和运行项目,它将给出以下结果:

摘要
在本章中,我们学习了 Fritz,这是一个端到端平台,使我们能够创建机器学习应用。我们还探讨了预构建的 ML 模型以及如何在 Fritz 中使用自定义模型。接着,我们研究了如何在 iOS 和 Android 中实现 Fritz 到 Core ML 的迁移。最后,我们使用 Fritz 库创建了两个应用:一个使用预构建的 fritz 模型,另一个使用 iOS 的 Core ML 模型。在下一章中,我们将学习神经网络及其在移动应用和机器学习中的用途。
第九章:移动设备上的神经网络
在第二章“监督学习和无监督学习算法”中,当我们向您介绍 TensorFlow、其组件以及其工作原理时,我们简要地谈到了卷积神经网络(CNNs)以及它们是如何工作的。在本章中,我们将深入探讨神经网络的基本概念。我们将探讨机器学习和神经网络之间的相似性和差异。
我们还将讨论在移动设备上执行深度学习算法的一些挑战。我们将简要介绍适用于移动设备的各种深度学习和神经网络 SDK。在本章的末尾,我们将创建一个有趣的作业,该作业将利用 TensorFlow 和 Core ML。
在本章中,我们将介绍以下主题:
- 
创建 TensorFlow 图像识别模型 
- 
将 TensorFlow 模型转换为 Core ML 模型 
- 
创建一个利用 Core ML 模型的 iOS 移动应用程序 
- 
Keras 简介 
- 
创建一个手写数字识别解决方案 
在本章中,我们将实现本书中我们已经讨论过的所有主要主题。在继续之前,请确保你已经阅读了本书的所有前几章。
神经网络简介
神经网络是一个基于人类大脑神经元操作的硬件和/或软件系统。神经网络的设计灵感来源于人脑及其功能。让我们了解人脑的设计。神经元是大脑的基本工作单元。它是一种专门细胞,可以传递信息到其他神经细胞。大脑由大约 100,000,000,000 个神经元组成。神经元的主要功能是处理和传输信息。
神经元的通信步骤
神经元通信遵循四个步骤:
- 
神经元从外部环境或其他神经元接收信息。 
- 
神经元整合或处理来自所有输入的信息,并确定是否发送输出信号。这种整合在时间(输入的持续时间和输入之间的时间)和空间(神经元表面)上都会发生。 
- 
神经元以高速在其长度上传播信号。 
- 
神经元将这个电信号转换为化学信号,并将其传输到另一个神经元或到肌肉或腺体等效应器。 
为了更好地理解神经元——人类大脑的基本构建块——是如何工作的,请查看www.biologyreference.com/Mo-Nu/Neuron.html#ixzz5ZD78t97u。
现在,谈到人工神经网络中的神经元,这些神经元的职能是接收一些输入并产生输出。
激活函数
为了明确分类,神经元是一个占位符函数,它接收输入,通过在输入上应用函数来处理这些输入,并产生输出。任何简单的函数都可以放入定义的占位符中:

在神经元中使用的函数通常被称为激活函数。在人体中,有三种类型的神经元:感觉神经元、运动神经元和中间神经元。在人工世界中,激活函数可能会创建神经元的不同能力和功能。
这里有一些常用的激活函数:
- 
步进 
- 
Sigmoid 
- 
tanh 
- 
ReLU-Rectified 
- 
线性单元(主要用于深度学习) 
详细介绍每个函数的细节超出了本书的范围。然而,如果您想进一步研究神经网络,了解这些函数及其复杂性将是有益的。
神经元的排列
让我们看看人体中神经元的排列。一个典型的神经元有几个树突,通常以极其分支的方式排列,以便与其他许多神经元建立联系。人体中的神经元也按层排列。这些层的数量因身体和大脑的不同部位而异,但通常在三层到六层之间。
在人工世界中,这些神经元也按层排列。以下图表将帮助您了解神经元的组织结构:

网络最左侧的层被称为输入层,最右侧的层被称为输出层。神经元的中层被称为隐藏层,因为其值在训练集中未被观察到。
在这个示例神经网络中,有三个输入、三个隐藏单元和一个输出单元。任何神经网络都将至少有一个输入层和一个输出层。隐藏层的数量可以变化。
每个隐藏层中使用的激活函数可以相同网络中的不同。这意味着同一网络中隐藏层 1 的激活函数和隐藏层 2 的 b 激活函数可以不同。
神经网络类型
神经网络根据隐藏层的数量和每层使用的激活函数而有所不同。以下是一些常见的神经网络类型:
- 
深度神经网络:具有多个隐藏层的网络。 
- 
CNN:常用于与计算机视觉相关的学习问题。CNN 隐藏层使用卷积函数作为激活函数。 
- 
循环神经网络:常用于与自然语言处理相关的问题。 
当前在移动设备神经网络改进领域的研究/项目包括以下内容:
- 
MobileNet 
- 
MobileNet V2 
- 
MNasNet—在移动设备上实现强化学习 
图像识别解决方案
想象你和朋友们去了一家餐厅。假设你是一个健身狂热者,尽管你来到派对是为了享受自助餐,但作为一个健身狂热者,你很注意卡路里,不想过量。
现在想象一下,你有一个移动应用程序可以救你于水火之中:它拍摄食物的照片,识别其成分,并计算食物的卡路里值!你可以拍摄每一道菜并计算其卡路里值,然后决定是否将其放在你的盘子里。此外,这个应用程序会不断学习你拍摄的不同菜肴,并在这个领域继续学习和精通,以便它能很好地照顾你的健康。
我能看到你眼中的光芒。是的,这是我们本章想要尝试的移动应用程序。我们还想利用 TensorFlow 和 Core ML 来完成这项活动。我们将执行以下步骤来创建我们刚才讨论的应用程序:
- 
创建 TensorFlow 图像识别模型 
- 
将其转换为 .ml模型文件
- 
创建一个 iOS/SWIFT 应用程序来使用该模型 
我们将在接下来的章节中详细讲解这些步骤。
创建 TensorFlow 图像识别模型
TensorFlow 是一个开源软件库,用于在一系列任务中进行数据流编程。它是一个符号数学库,也用于机器学习应用,如神经网络。它被用于谷歌的研究和生产,经常取代其封闭源代码的前身 DistBelief。TensorFlow 是由谷歌大脑团队为谷歌内部使用而开发的。它于 2015 年 11 月 9 日以 Apache 2.0 开源许可证发布。
TensorFlow 是跨平台的。它几乎在所有设备上运行:GPU 和 CPU,包括移动和嵌入式平台,甚至张量处理单元(TPUs),这是专门用于执行张量数学的硬件。
TensorFlow 做什么?
为了简化,让我们假设你想要两个数字。现在,如果你想在常规编程语言中编写程序,比如 Python,你会使用以下代码:
a = 1
b = 2
print(a+b)
如果你运行程序,你将看到输出为3,然后你将在tensorflow上看到相同的实现:
import tensorflow as tf
x = tf.constant(35, name='x')
y = tf.Variable(x + 5, name='y')
model = tf.global_variables_initializer()
with tf.Session() as session:
    session.run(model)
    print(session.run(y))
让我解释一下前面的代码。首先,我们创建了一个名为x的常量,将其加 5,并将其存储在另一个变量/节点y中。如果你现在能看到y的输出控制台,你会找到节点的定义,但不是 40 的值。
在这里,你正在定义图的节点及其相应的操作。一旦初始化变量并创建和获取图的会话/实例,你就可以使用图。
以下图表将帮助你理解这个概念:

在 TensorFlow 中,我们将使用所有常量、占位符和变量来创建节点定义和链接,这将创建一个图,这与面向对象编程中的类概念类似。将图视为一个类,节点视为数据成员,tf.globalvariableinitilizer() 视为调用静态方法来初始化常量和变量,而 session.run() 视为调用类的构造函数。
重新训练模型
要创建一个图像分类器,我们需要经历很多事情,编写很多代码。为了保持简单,我们将向您展示如何使用 Google Code Lab 提供的代码来创建它。以下内容摘自 Google 的 Code Lab 教程。
这是通过卷积神经网络(CNNs)实现的。解释所有这些内容超出了本书的范围。我们在本章的引言中简要探讨了 CNN。然而,与海洋相比,这非常少。更多信息,感兴趣的读者可以查看 colah.github.io/posts/2014-07-Conv-Nets-Modular/。
让我们看看我们有多容易在 tensorflow 中创建一个图像分类器。要开始,我们需要安装 anaconda,然后运行以下命令:
conda create -n tensorflow pip python=3.6
一旦运行前面的命令,你会得到以下提示:

输入 y 以继续。一旦命令成功执行,你会看到以下屏幕:

输入 activate 项目。一旦项目被激活,你会看到这样的提示:
(project) D:\Users\vavinas>
然后,输入以下命令:
pip install tensorflow
使用以下命令来验证已安装的包:
pip list
它必须产生以下结果。如果你在你的机器上看不到这些包中的某些,请重新安装它们:

现在,我们已经成功安装了 tensorflow 及其依赖项。让我们从 Google Code Labs 获取进行分类的代码。为此,请确保你的机器上已安装 Git。有多种安装方法,但最简单的方法是通过 npm。
要检查 Git 是否已正确安装,在打开的命令提示符中输入 git。你会看到该命令的所有可用选项。如果它提示为 invalid command,请尝试正确安装它。现在,让我们执行克隆存储库的命令:
 git clone https://github.com/googlecodelabs/tensorflow-for-poets-2
完成后,使用以下命令进入 tensorflow-for-poets-2:
cd tensorflow-for-poets-2
以下文件夹包含所有必需的脚本,用于训练图像识别模型。如果你检查 tf_file 文件夹,它将是空的。在这里,我们将使用这个文件夹来保存训练图像,并使用脚本文件夹中的脚本训练模型。
要输入图像,您首先需要下载图像。在我们的示例中,我们使用带有四个类别标签的食品图像。您可以从我们的 Git 仓库下载它,project/food_photos,然后将该文件夹粘贴到tf_files。如果您无法执行此命令,请使用 Internet Explorer 打开文件夹,然后从tensorflow-for-poets-2/tf_files文件中下载。
将文件提取为平面文件,如下所示:

现在,我们将使用以下脚本重新训练模型。执行以下命令:
python -m scripts.retrain \
  --bottleneck_dir=tf_files/bottlenecks \
  --how_many_training_steps=500 \
  --model_dir=tf_files/models/ \
  --summaries_dir=tf_files/training_summaries/ mobilenet_0.50_224  \
  --output_graph=tf_files/retrained_graph.pb \
  --output_labels=tf_files/retrained_labels.txt \
  --architecture=mobilenet_0.50_224  \
  --image_dir=tf_files/food_photos
之前的 Python 脚本用于重新训练一个具有许多参数的模型,但我们将只使用和讨论几个重要的参数,如下所示:
- 
bottleneck_dir:这些文件将被保存到 bottlenecks/目录下。
- 
how_many_training_steps:这将是一个低于 4,000 的数字。更高的数字将使您的模型具有更高的精度,但需要太长时间来构建,并且模型文件会变得太大。
- 
model_dir:这告诉我们模型应该保存的位置。
- 
summaries_dir:包含训练摘要。
- 
output_graph:输出图的保存位置。这是我们将在移动设备上使用的模型。
- 
output_labels:这是包含类别标签的文件。通常,图像的类别标签是文件夹名称。
- 
architecture:这告诉我们应该使用哪种架构。在这里,我们使用的是具有 0.50 相对模型大小和 244 图像大小的 mobilenet 模型。
- 
image_dir:输入图像目录,在这种情况下,food_photos。
执行前面的命令将给出以下输出:

关于瓶颈
在这里,我们将尝试理解重新训练过程是如何工作的。我们使用的 ImageNet 模型由许多堆叠在一起的层组成。这些层已经过预训练,并且已经拥有足够的信息,有助于图像分类。我们试图做的只是训练最后一层,final_training_ops,当所有之前的层重新训练它们已经训练的状态时。
以下截图来自 TensorBoard。您可以在浏览器中打开 TensorBoard 来更好地查看它。您可以在“Graphs”标签下找到它:

在前面的图中,左侧的 softmax 节点是原始模型的输出层。softmax 右侧的所有节点都是由重新训练脚本添加的。
注意,这只有在重新训练脚本完成生成瓶颈文件后才会生效。
瓶颈是指位于最终输出层之前,执行分类的层。瓶颈并不暗示其传统意义上的减缓整个过程的含义。我们使用瓶颈这个术语,因为接近输出时,表示比网络主体部分更加紧凑。
每个图像在训练过程中被多次使用。计算每个图像瓶颈后面的层需要花费大量的时间。由于这些网络的底层没有被修改,它们的输出可以被缓存并重用。现在,你手中有了 TensorFlow 重新训练的模型。让我们使用以下命令测试我们刚刚训练的模型:
python -m scripts.label_image \
    --graph=tf_files/retrained_graph.pb  \
    --image=tf_files\food_photos\pizza\1.jpg
执行前面的代码块将给出食物图像所属的类别。现在,让我们进行下一个任务:将tensorflow模型转换为 Core ML 格式。
将 TensorFlow 模型转换为 Core ML 模型
TensorFlow 团队开发了一个用于将 TensorFlow 中创建的模型转换为 Core ML 的包,这最终用于 iOS 应用。要使用此包,你必须有安装了 Python 3.6 和 TensorFlow 的 macOS。使用此包,我们可以将 TensorFlow 模型文件(.pb)转换为 Core ML 格式(.mlmodel)。首先,你需要执行以下命令:
Pip install tfcoreml
一旦安装,请在你的 Python 文件中写下以下代码,将其命名为inspect.py并保存:
import tensorflow as tf
from tensorflow.core.framework import graph_pb2
import time
import operator
import sys
def inspect(model_pb, output_txt_file):
    graph_def = graph_pb2.GraphDef()
    with open(model_pb, "rb") as f:
        graph_def.ParseFromString(f.read())
    tf.import_graph_def(graph_def)
    sess = tf.Session()
    OPS = sess.graph.get_operations()
    ops_dict = {}
    sys.stdout = open(output_txt_file, 'w')
    for i, op in enumerate(OPS):
        print('---------------------------------------------------------------------------------------------------------------------------------------------')
        print("{}: op name = {}, op type = ( {} ), inputs = {}, outputs = {}".format(i, op.name, op.type, ", ".join([x.name for x in op.inputs]), ", ".join([x.name for x in op.outputs])))
        print('@input shapes:')
        for x in op.inputs:
            print("name = {} : {}".format(x.name, x.get_shape()))
        print('@output shapes:')
        for x in op.outputs:
            print("name = {} : {}".format(x.name, x.get_shape()))
        if op.type in ops_dict:
            ops_dict[op.type] += 1
        else:
            ops_dict[op.type] = 1
    print('---------------------------------------------------------------------------------------------------------------------------------------------')
    sorted_ops_count = sorted(ops_dict.items(), key=operator.itemgetter(1))
    print('OPS counts:')
    for i in sorted_ops_count:
        print("{} : {}".format(i[0], i[1]))
if __name__ == "__main__":
    """
    Write a summary of the frozen TF graph to a text file.
    Summary includes op name, type, input and output names and shapes.
    Arguments
    ----------
    - path to the frozen .pb graph
    - path to the output .txt file where the summary is written
    Usage
    ----------
    python inspect_pb.py frozen.pb text_file.txt
    """
    if len(sys.argv) != 3:
        raise ValueError("Script expects two arguments. " +
              "Usage: python inspect_pb.py /path/to/the/frozen.pb /path/to/the/output/text/file.txt")
    inspect(sys.argv[1], sys.argv[2])
前面的代码将模型文件作为输入参数,并将所有操作和输入/输出节点名称及其描述保存在我们提供的输入文本文件中。要运行此命令,请输入以下命令:
Python inspect.py retrained_graph.pb summeries.txt
在这个命令中,你正在执行之前保存的inspect.py代码。这也会输入从上一节获得的图文件以及你想要保存摘要的文本文件路径。
执行此命令后,summaries.txt将创建包含所有摘要的文件,如上图所示。这些将被添加到该文件中:

在这个文件中,你可以看到所有操作、输入和输出名称及其形状;你还可以看到整体操作符:

文件末尾,你会找到结束节点的定义;在我们的例子中,如下所示:

在这里,你可以看到结束节点操作类型是Softmax,它将产生的输出将存储在final_result:0名称中。现在,查看以下用于生成相应 Core ML 模型的代码块:

让我们详细理解前面的代码块。你必须已经注意到我们在第一行导入了tfcoreml包,然后使用了它的convert函数。以下是其参数:
- 
Tf_model_path:你在上一节中生成的(.pb)文件路径,将 TensorFlow 模型转换为 Core ML 模型。
- 
Mlmodel_path:你想要生成模型的输出模型文件路径。
- 
Output_feature_names:在这里,我们将获得从之前由我们的模型检查代码生成的文本文件中获得的输出变量名称。
- 
Image_input_names:您想要为图像输入指定的名称。在 Core ML/iOS 中,这将是一个图像缓冲区。
- 
Class_labels:这是在训练步骤中您将获得的文件。
一旦运行前面的代码,您将在您的目录中看到生成的converted``.mlmodel文件。您可以将它导入到 Xcode 项目中并使用它。
编写 iOS 移动应用程序
在本节中,我们将创建一个应用程序,利用我们创建的图像识别模型,通过您的 iOS 移动摄像头预测图像。
首先,您需要一个运行 Xcode 版本 9+的 Mac PC。从 Git 仓库下载源代码(Xcode 项目),然后导航到项目文件夹。在 Xcode 中打开recognition.xcodeproj图像。以下截图显示了项目的文件夹结构:

我们将要查看的主要文件是con``troller.swift。它包含以下代码:
import UIKit class ViewController: UIViewController {
 @IBOutlet weak var pictureImageView :UIImageView! @IBOutlet weak var titleLabel :UILabel!
这些是主 Storyboard 中图像视图控件和标题标签控件的输出:
private var model : converted = converted()
这是当我们添加上一节中创建的core-ml文件时生成的模型实例:
 var content : [ String : String ] = [ "cheeseburger" : "A cheeseburger is a hamburger topped with cheese. Traditionally, the slice of cheese is placed on top of the meat patty, but the burger can include many variations in structure, ingredients, and composition.\nIt has 303 calories per 100 grams.", "carbonara" : "Carbonara is an Italian pasta dish from Rome made with egg, hard cheese, guanciale, and pepper. The recipe is not fixed by a specific type of hard cheese or pasta. The cheese is usually Pecorino Romano.", "meat loaf" : "Meatloaf is a dish of ground meat mixed with other ingredients and formed into a loaf shape, then baked or smoked. The shape is created by either cooking it in a loaf pan, or forming it by hand on a flat pan.\nIt has 149 calories / 100 grams", "pizza" : "Pizza is a traditional Italian dish consisting of a yeasted flatbread typically topped with tomato sauce and cheese and baked in an oven. It can also be topped with additional vegetables, meats, and condiments, and can be made without cheese.\nIt has 285 calories / 100 grams" *]*
我们硬编码了要显示在标题标签中的内容,以对应于我们训练的相应类标签:
 let images = ["burger.jpg","pizza.png", "pasta.jpg","meatloaf.png"]
这些是我们添加到项目中的图像;它们将作为我们的预测应用程序的输入:
 var index = 0 override func viewDidLoad() {
 super.viewDidLoad() nextImage() } @IBAction func nextButtonPressed() { nextImage() } func nextImage() { defer { index = index < images.count - 1 ? index + 1 : 0 }        let filename = images[index]
 guard let img = UIImage(named: filename) else { self.titleLabel.text = "Failed to load image \(filename)" return } self.pictureImageView.image = img let resizedImage = img.resizeTo(size: CGSize(width: 224, height: 224)) guard let buffer = resizedImage.toBuffer() else { self.titleLabel.text = "Failed to make buffer from image \(filename)" return }
由于我们使用 224 像素的图像训练了我们的模型,因此我们也在调整输入图像的大小,并将其转换为图像缓冲区,这是我们想要提供给预测方法的:
 do { let prediction = try self.model.prediction(input: MymodelInput(input__0: buffer))
在这里,我们输入图像并获取预测结果:
 if content.keys.contains(prediction.classLabel) { self.titleLabel.text = content[prediction.classLabel] } else { self.titleLabel.text = prediction.classLabel; }
在前面的代码中,根据类标签,我们向用户显示内容:
 } catch let error { self.titleLabel.text = error.localizedDescription } } }
这完成了应用程序的创建。现在,我们将执行应用程序以找到以下图像作为输出:

点击“下一步”以找到我们的下一张图像:

手写数字识别解决方案
之前,我们创建了一个应用程序,帮助我们了解使用移动设备上的 TensorFlow 模型实现的神经网络图像识别程序的实现。现在,我们将创建另一个应用程序,使用神经网络和 Keras 的概念来实现手写数字的图像识别程序。在本节中,我们将创建一个用于移动设备上的手写数字识别解决方案的应用程序。然后,我们将此 Keras 模型转换为 Core ML 模型,并使用它来构建 iOS 移动应用程序。让我们先向您介绍 Keras。
Keras 简介
Keras 是一个高级神经网络 API,用 Python 编写,能够在 TensorFlow、CNTK 或 Theano 之上运行。它旨在使快速实验成为可能。
这里是一些 Keras 的关键用途:
- 
允许轻松快速地进行原型设计(通过用户友好性、模块化和可扩展性) 
- 
支持卷积网络和循环网络,以及两者的组合 
- 
在 CPU 和 GPU 上无缝运行 
Keras 的设计基于以下原则:
- 
用户友好性 
- 
模块化 
- 
易于扩展 
- 
兼容 Python 
要了解更多关于 Keras 的信息,请查看keras.io/。
安装 Keras
正如我们已经讨论过的,Keras 没有自己的后端系统。因为它运行在 TensorFlow、CNTK 或 Theano 之上,我们需要安装其中之一——个人推荐 TensorFlow。
我们需要使用pip包管理器安装h5py库,以便将 Keras 模型保存到磁盘上:
pip install tensorflow
pip install keras
pip install h5py
之前的命令将安装创建模型所需的基本库。
解决问题
在本节中,我们将看到神经网络的实际实现。我们将定义问题陈述,然后理解我们将用于解决问题的数据集,接着在 Keras 中创建模型以解决问题。一旦在 Keras 中创建了模型,我们将将其转换为与 Core ML 兼容的模型。这个 Core ML 模型将被导入 iOS 应用程序中,并编写一个程序来使用这个模型并解释手写数字。
定义问题陈述
我们将通过在 iOS 移动应用程序中实现的机器学习模型来解决识别手写数字的问题。第一步是拥有用于模型训练和测试的手写数字数据库。
MNIST 数字数据集(yann.lecun.com/exdb/mnist/)提供了一个手写数字数据库,包含 60,000 个训练示例和 10,000 个测试示例。它是 MNIST 中更大集合的一个子集。这些数字已经被尺寸归一化,并放置在固定大小的图像中。这是一个很好的数据库,对于想要在真实世界数据上学习技术和模式识别方法,同时尽量减少预处理和格式化工作的人来说非常有用。
在解决这个问题之前,我们将花一些时间来理解问题,看看神经网络可以在哪里提供帮助。我们可以将识别手写数字的问题分解成两个子问题。假设我们被给了一个手写的数字,如下所示:

首先,我们需要将包含许多数字的图像分解成一系列单独的图像,每个图像包含一个单独的数字。例如,我们希望将这个图像分解成七个单独的图像,如下所示:

对于人类来说,数字可以很容易地分开,但对于机器来说,完成这个简单的任务却非常具有挑战性。一旦数字被分开,程序需要分类每个单独的数字。例如,我们希望我们的程序能够识别第一个数字是5。
我们现在试图专注于问题的第二部分:识别单个数字并对它们进行分类。我们将使用神经网络来解决识别单个手写数字的问题。
我们可以使用一个具有 10 个神经元的输出层的 3 层神经网络来解决此问题。输入层和隐藏层是处理发生的地方。在输出层,根据激活的神经元,我们可以轻松推断出识别的数字。神经元 0 到 9 分别识别一个数字。
问题解决方案
问题解决方案包括以下关键步骤:
- 
准备数据 
- 
定义模型 
- 
训练和拟合模型 
- 
将训练好的 Keras 模型转换为 Core ML 模型 
- 
编写 iOS 移动应用程序 
现在,让我们逐个步骤进行,看看在每个步骤中我们需要做什么。
准备数据
第一个活动是数据准备。首先,让我们导入所有必需的库。如我们之前讨论的,我们将使用 MNIST 数据库作为手写数字数据集:
from __future__ import print_function
from matplotlib import pyplot as plt
import keras
from keras.datasets import mnist
mnist 是包含手写数字数据库的数据集,因此我们需要按照以下方式导入它:
from keras.models import Sequential
上述代码从 Keras 导入了 Sequential 模型类型。这只是一个神经网络层的线性堆叠:
from keras.layers import Dense, Dropout, Flatten
现在,我们需要从 Keras 导入核心层。这些是在几乎任何神经网络中使用的层:
from keras.layers import Conv2D, MaxPooling2D
从 Keras 导入 CNN 层。这些是卷积层,将帮助我们有效地在图像数据上训练:
from keras.utils import np_utils
导入 Utils。这将帮助我们稍后进行数据转换:
from keras import backend as K 
import coremltools
coremltools 将帮助我们将 Keras 模型转换为 Core ML 模型:
(x_train, y_train), (x_val, y_val) = mnist.load_data()
将预洗牌的 MNIST 数据加载到训练集和测试集中:
# Inspect x data
print('x_train shape: ', x_train.shape)
print(x_train.shape[0], 'training samples')
print('x_val shape: ', x_val.shape)
print(x_val.shape[0], 'validation samples')
print('First x sample\n', x_train[0])
如果运行上述代码,它将显示 X、Y 的形状,以及 X 的第一条记录。
因此,我们的训练集中有 60,000 个样本,每个图像都是 28 x 28 像素。我们可以通过在 matplotlib 中绘制第一个样本来确认这一点:

plt.imshow(x_train[0])
此语句将使用 matplotlib 库绘制 x_train 的第一条记录,将给出以下输出:

以下行将打印 y_train 的形状和 y_train 中的前 10 个元素:
print('y_train shape: ', y_train.shape)
print('First 10 y_train elements:', y_train[:10])
以下代码将找到图像的输入形状。MNIST 图像数据值是 uint8 类型,范围在 [0, 255],但 Keras 需要范围在 [0, 1] 的 float32 类型的值:
img_rows, img_cols = x_train.shape[1], x_train.shape[2]
num_classes = 10
# Set input_shape for channels_first or channels_last
if K.image_data_format() == 'channels_first': 
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_val = x_val.reshape(x_val.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else: 
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_val = x_val.reshape(x_val.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)                     
print('x_train shape:', x_train.shape)
# x_train shape: (60000, 28, 28, 1)
print('x_val shape:', x_val.shape)
# x_val shape: (10000, 28, 28, 1)
print('input_shape:', input_shape)
使用以下代码,我们将数据类型转换为与 Keras 中定义的数据类型兼容:
x_train = x_train.astype('float32')
x_val = x_val.astype('float32')
x_train /= 255
x_val /= 255
现在,y 中有一个包含 60,000 个元素的向量。让我们将其转换为 60,000 x 10 的数组,如下所示:
y_train = np_utils.to_categorical(y_train, num_classes)
y_val = np_utils.to_categorical(y_val, num_classes)
print('New y_train shape: ', y_train.shape)
# (60000, 10)
print('New y_train shape: ', y_train.shape)
# (60000, 10)
print('First 10 y_train elements, reshaped:\n', y_train[:10])
现在,y_train 将看起来像这样:

在前面的数组中,我们可以发现对于数字的存在,相应的位置将被填充为 1——所有其他位置都将填充为 0。对于第一条记录,我们可以理解预测的数字是 5,因为从 0 开始的第 6 个位置被填充了 1。
现在数据准备已完成,我们需要定义模型的架构。
定义模型的架构
数据准备完成后,下一步是定义模型并创建它,所以让我们创建模型:
model_m = Sequential()
前一行将创建一个顺序模型,该模型将以它们排列的顺序处理层。有两种方法可以构建 Keras 模型,顺序和功能:
- 
顺序 API:这允许我们逐层创建模型。通过这种方式,我们无法创建共享层的模型或具有多个输入或输出的模型。 
- 
功能 API:这允许我们创建比顺序模型更复杂、可以具有复杂连接层的模型——你可以从任何层连接到任何其他层: 
model_m.add(Conv2D(32, (5, 5), input_shape=(1,28,28), activation='relu'))
输入形状参数应该是 1 个样本的形状。在这种情况下,它与每个数字图像的 (深度,宽度,高度) 相同,即 (1, 28, 28)。
但其他参数代表什么?它们分别对应要使用的卷积滤波器的数量、每个卷积核的行数和每个卷积核的列数:
model_m.add(MaxPooling2D(pool_size=(2, 2)))
MaxPooling2D 是通过在上一层滑动一个 2 x 2 的池化滤波器并取 2 x 2 滤波器中 4 个值的最大值来减少我们模型中参数数量的方法:
model_m.add(Dropout(0.5))
这是一个用于正则化我们的模型以防止过拟合的方法:
model_m.add(Conv2D(64, (3, 3), activation='relu'))
model_m.add(MaxPooling2D(pool_size=(2, 2)))
model_m.add(Dropout(0.2))
model_m.add(Conv2D(128, (1, 1), activation='relu'))
model_m.add(MaxPooling2D(pool_size=(2, 2)))
model_m.add(Dropout(0.2))
model_m.add(Flatten())
model_m.add(Dense(128, activation='relu'))
model_m.add(Dense(num_classes, activation='softmax'))
print(model_m.summary())
一旦运行前面的代码行,模型架构的层的名称将在控制台中打印出来:

编译和调整模型
下一步是编译和训练模型。我们通过一系列迭代将模型放入训练阶段。Epochs 决定了训练阶段中模型要进行的迭代次数。权重将被传递到模型中定义的层。足够的 Epochs 将提供更高的准确率和最小的损失。在这里,我们使用 10 个 Epochs。
Keras 具有回调机制,该机制将在模型的每次训练迭代期间被调用,即在每个 Epoch 结束时。在回调方法中,我们保存该 Epoch 计算出的权重:
callbacks_list = [
    keras.callbacks.ModelCheckpoint(
        filepath='best_model.{epoch:02d}-{val_loss:.2f}.h5',
        monitor='val_loss', save_best_only=True),
    keras.callbacks.EarlyStopping(monitor='acc', patience=1)]
现在,使用以下代码编译模型:
model_m.compile(loss='categorical_crossentropy',optimizer='adam', metrics=['accuracy'])
categorical_crossentropy 损失函数衡量 CNN 计算出的概率分布与标签的真实分布之间的距离。
一个 optimizer 是一种随机梯度下降算法,它试图通过跟随正确的速度的梯度来最小化损失函数。accuracy 是正确分类的图像的比例——这是训练和测试期间最常监控的指标:
# Hyper-parameters
batch_size = 200
epochs = 10
现在,使用以下代码拟合模型:
# Enable validation to use ModelCheckpoint and EarlyStopping callbacks.model_m.fit(
    x_train, y_train, batch_size=batch_size, epochs=epochs,    callbacks=callbacks_list, validation_data=(x_val, y_val), verbose=1)
一旦程序执行完成,你将在运行目录中找到名为best_model.01-0.15.h5的文件。这表示best_model.{epoch number}-{loss value}.h5。
这是为给定数据集创建和训练的 Keras 模型。
将 Keras 模型转换为 Core ML 模型
现在 Keras 模型已经创建,下一步是将 Keras 模型转换为 Core ML 模型。对于第一个参数,使用笔记本文件夹中最新的.h5文件的文件名:
output_labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
coreml_mnist = coremltools.converters.keras.convert(
    'best_model.10-0.04.h5', input_names=['image'], output_names=['output'],    class_labels=output_labels, image_input_names='image')
coreml_mnist.save("minsit_classifier.mlmodel")
一旦成功运行代码,你将在你的目录中找到创建的minsit_classifer.mlmodel文件。我们将使用这个文件来创建一个 iOS 移动应用程序以检测数字。
创建 iOS 移动应用程序
现在,我们将创建 iOS 应用程序。你可以从我们的 Packt GitHub 仓库的ImageClassificationwithVisionandCoreML文件夹中下载代码。
在 Xcode9+中打开项目;项目结构将如下所示:

如果你打开设计师中的main.storyboard,你会看到以下 UI:

大多数代码是常见的 iOS 代码。查看以下代码片段,它对我们特别感兴趣,并包括手写数字预测代码:
lazy var classificationRequest: VNCoreMLRequest = {
        // Load the ML model through its generated class and create a Vision request for it.
        do {
            let model = try VNCoreMLModel(for: MNISTClassifier().model)
            return VNCoreMLRequest(model: model, completionHandler: self.handleClassification)
        } catch {
            fatalError("can't load Vision ML model: \(error)")
        }
    }()
    func handleClassification(request: VNRequest, error: Error?) {
        guard let observations = request.results as? [VNClassificationObservation]
            else { fatalError("unexpected result type from VNCoreMLRequest") }
        guard let best = observations.first
            else { fatalError("can't get best result") }        DispatchQueue.main.async {
            self.classificationLabel.text = "Classification: \"\(best.identifier)\" Confidence: \(best.confidence)"
        }
    }
它在底部包含两个按钮:一个用于从手机中选择图像,另一个选项用于拍照。请注意,如果你在模拟器中运行此应用程序,相机将无法工作。
你可以在模拟器中构建和运行应用程序。一旦应用程序在模拟器中成功打开,将手写数字 6 的图像拖拽到模拟器中的 example image 文件夹中–这将保存文件到模拟器的内存中。
返回应用程序并选择保存在设备内存中的拖拽图像。它将显示以下输出:

摘要
在本章中,我们介绍了神经网络的概念及其在移动机器学习领域的应用。我们创建了一个应用程序,使用 TensorFlow 和 Core ML 在 iOS 和 Xcode 中识别图像。我们还探讨了 Keras 深度学习框架。我们尝试使用 Keras 中的神经网络解决手写数字识别问题。我们构建了 Keras 机器学习模型来解决这个问题。然后,我们使用 Core ML 转换工具将此模型转换为 Core ML 模型。我们使用这个 Core ML 模型在 iOS 移动应用程序中执行手写数字识别。
在下一章中,我们将学习如何在 Android 中使用 Google Cloud Vision 标签检测技术。
第十章:使用 Google Vision 的移动应用程序
正如我们在第一章,“移动机器学习简介”中看到的,我们知道移动应用程序中的机器学习可以是在设备上实现,也可以使用机器学习云提供商服务实现。有各种机器学习云提供商:
- 
Clarifai 
- 
Google Cloud Vision 
- 
Microsoft Azure 认知服务 
- 
IBM Watson 
- 
Amazon Machine Learning 
在本章中,我们将深入探讨 Google Cloud Vision,以了解以下内容:
- 
Google Cloud Vision 的功能 
- 
如何在 Android 移动应用程序中使用 Google Cloud Vision 标签检测技术来确定相机拍摄的照片是什么。也就是说,我们基本上将图像输入到 Google Cloud Vision 中,看看它如何标记图像。Google Vision 将预测它从移动应用程序接收到的图像,并为图像提供标签。 
Google Cloud Vision 的功能
Google Cloud Vision API 包含各种复杂且强大的机器学习模型,有助于执行图像分析。它使用易于使用的 REST API 将图像分类到各种类别。Google Cloud Vision 提供的重要功能包括以下内容:
- 
标签检测:这使我们能够将图像分类到数千个类别。图像可以被分类到各种常见的类别标签,例如动物和水果。 
- 
图像属性检测:这使我们能够从图像中检测单个对象。它还可以检测诸如显著颜色等属性。 
- 
人脸检测:这使我们能够从图像中检测人脸。如果图像中有多个面孔,每个面孔都可以单独检测。它还可以检测与面孔相关的一些显著属性,例如戴头盔。 
- 
Logo 检测:这使我们能够从图像中检测印刷文字。训练了显著的品牌标志,可以检测到。 
- 
地标检测:它被训练来检测显著的地标——自然和人工的,因此这些地标是通过 Google Vision 进行检测的。 
- 
光学字符识别:即使图像不是英文的,它也能帮助检测图像中的文本。这支持广泛的多种语言。 
- 
显式内容检测:这有助于识别内容的类型或内容情感,例如暴力或幽默。它使我们能够通过利用可以构建的元数据信息来执行图像的情感分析。 
- 
搜索网页:这将在网络上搜索类似图像。 
所有这些由 Google Cloud Vision 提供的功能都可以通过调用 Google 提供的简单 RESTful API 来使用。然而,对于它们的使用,每个功能都有一定的费用。也可以使用功能组合。定价详情可以在 Google Cloud Vision 网站上找到:cloud.google.com/vision/。
使用 Google Cloud Vision 的示例移动应用程序
在本节中,我们将尝试使用 Google Cloud Vision 的 Android 移动应用程序示例。我们将从手机的相机捕获图像,将图像上传到 Google Cloud Vision,并查看它预测的图像是什么。这将使用 Google Cloud Vision 的标签检测功能,该功能确定上传图像的标签。
标签检测是如何工作的?
视觉 API 可以检测和提取图像中实体信息,涵盖广泛的类别。标签可以识别对象、位置、活动、动物种类、产品等。标签仅以英语返回。
需要确定标签的图像和我们要使用的 Google Vision 功能需要发送到请求 API。功能可以是Google Cloud Vision 功能部分中列出的任何功能,例如标签检测或标志检测。如果需要与图像一起发送任何额外的图像上下文,它可以作为附加参数发送。请求 API JSON 格式在此提供:
{
  "image": {
    object(Image)// Image which needs to be processed.
  },
  "features": [
    {
      object(Feature) //Google Vision Feature that needs to be invoked.
    }
  ],
  "imageContext": {
    object(ImageContext) //additional image context if required.
  },
}
图像对象可以是 base64 编码的字符串,也可以是需要分析的图像的 URL。该 URL 可以是 Google Cloud Storage 图像位置,或公开可访问的图像 URL。
请求的响应将是一个基于请求的功能的注释列表。在我们的案例中,它将是标签注释:
{
 "labelAnnotations": [
 {
 object(EntityAnnotation)
 }
 ],
 "error": {
 object(Status)
 },
}
返回的EntityAnnotation对象将包含图像的标签、预测分数和其他有用信息。所有与输入图像对象匹配的标签都作为包含预测分数的数组列表返回,基于此,我们可以在应用程序中执行所需的推理。
现在我们已经了解了标签检测的基本工作原理,让我们开始创建 Android 应用程序。
前提条件
为了开始探索 Google Vision 并编写使用 Google 视觉公开的服务编写的程序,以下是需要设置的内容,以便我们可以亲自动手:
- 
一个 Google Cloud Platform 账户 
- 
Google Cloud Console 上的一个项目 
- 
Android Studio 的最新版本 
- 
运行 Android 5.0 或更高版本的移动电话 
准备工作
本节提供了在使用我们的移动应用程序开始使用 Google Cloud Vision API 之前我们需要做的关键活动的详细信息:
- 
Google Cloud Vision API 应在 Google Cloud 控制台中启用,并创建一个将在移动应用程序代码中使用的 API 密钥。请执行以下步骤以获取 Cloud Vision API 密钥: 
- 
前往控制台。如果您没有试用账户,它将要求您创建一个并完成过程。 
- 
启用计费以获得 300 美元的免费信用额度。一旦我们有了账户,我们就可以进入控制台并完成创建密钥的过程。 
- 
从控制台创建一个项目。 
- 
打开该项目。前往 API 服务 | 搜索云视觉 API 库。 
- 
点击它并启用它。 
- 
前往 API 服务 | 凭据。 
- 
前往凭据 | API 密钥。 
- 
创建 API 密钥。 
- 
复制 API 密钥;这将在移动应用程序代码中使用。 
 
- 
在移动客户端应用程序中添加使用 Google Cloud Vision API 所需的依赖项。需要 Google API 客户端,因此需要将其添加到客户端项目中。这些需要在 Gradle 构建文件中指定。以下是一个包含关键依赖项的示例 Gradle 文件: 
dependencies {
 compile fileTree(include: ['*.jar'], dir: 'libs')
 testCompile 'junit:junit:4.12'
 compile 'com.android.support:appcompat-v7:27.0.2'
 compile 'com.android.support:design:27.0.2'
 compile 'com.google.api-client:google-api-client-android:1.23.0' exclude module: 'httpclient'
 compile 'com.google.http-client:google-http-client-gson:1.23.0' exclude module: 'httpclient'
 compile 'com.google.apis:google-api-services-vision:v1-rev369-1.23.0'
}
理解应用程序
在本节中,我们将查看源代码的关键流程,以了解从 Android 移动应用程序的角度如何使用 Google Vision API。
Vision 类代表 Google API 客户端的 Cloud Vision。第一步是初始化 Vision 类。我们通过 Builder 来完成,我们指定要使用的传输机制和 JSON 工厂:
Vision.Builder builder = new Vision.Builder(httpTransport, jsonFactory, null); 
下一步是将 API 密钥分配给 Vision Builder,以便它可以开始与云 API 交互。我们创建的密钥如下所示:
VisionRequestInitializer requestInitializer = new VisionRequestInitializer(CLOUD_VISION_API_KEY)
builder.setVisionRequestInitializer(requestInitializer);
最后一步是通过 Vision 实例来调用云 API:
Vision vision = builder.build();
现在我们将捕获一张图片并将其发送到云 API 以检测其标签。通过相机捕获图片的代码是常规的 Android 代码。以下代码提供了如何将图像转换为用于标签检测的 Vision 请求的详细信息:
BatchAnnotateImagesRequest batchAnnotateImagesRequest = new BatchAnnotateImagesRequest();
batchAnnotateImagesRequest.setRequests(new ArrayList<AnnotateImageRequest>() {{ AnnotateImageRequest annotateImageRequest = new AnnotateImageRequest();
 // Add the image
 Image base64EncodedImage = new Image();
 // Convert the bitmap to a JPEG
 // Just in case it's a format that Android understands but Cloud Vision
 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream);
byte[] imageBytes = byteArrayOutputStream.toByteArray();
// Base64 encode the JPEG
base64EncodedImage.encodeContent(imageBytes); annotateImageRequest.setImage(base64EncodedImage);
// add the features we want
annotateImageRequest.setFeatures(new ArrayList<Feature>() {{
Feature labelDetection = new Feature(); labelDetection.setType("LABEL_DETECTION"); labelDetection.setMaxResults(MAX_LABEL_RESULTS);
add(labelDetection);
}});
// Add the list of one thing to the request
add(annotateImageRequest);
}});
Vision.Images.Annotate annotateRequest =  vision.images().annotate(batchAnnotateImagesRequest);
Google Cloud Vision 将被作为一个异步任务来调用。从 API 收到的响应将被分析,以提供用户可读格式的数据。以下代码提供了从 Google Vision 收到的响应的详细信息:
 //Formatting the response as a string
 private static String convertResponseToString(BatchAnnotateImagesResponse response) {
 StringBuilder message = new StringBuilder("I found these things:\n\n"); List<EntityAnnotation> labels = response.getResponses().get(0).getLabelAnnotations();
 if (labels != null) {
 for (EntityAnnotation label : labels) {
 message.append(String.format(Locale.US, "%.3f: %s", label.getScore(), label.getDescription()));
 message.append("\n");
 }
 } else {
 message.append("nothing");
 }
 return message.toString();
 }
用户可以查看返回的图像标签。
输出
当一部手机被捕获并发送到视觉 API 时,此部分将显示 Android 应用程序屏幕。可能的标签列在输出屏幕上:

摘要
在本章中,我们探讨了 Google Cloud Vision 的工作原理,以及如何轻松地从移动应用程序中调用它。我们看到了如何轻松地进行复杂的机器学习预测,而无需选择和训练模型。在下一章中,我们将探索移动应用程序领域中机器学习的未来。
第十一章:移动应用程序上机器学习的未来
机器学习(ML)需要巨大的计算能力,因此需要专门的处理器。但如果机器学习的力量能够带到缺乏这种处理能力的移动设备上,并且也能在离线模式下工作,那么将会有巨大的机会,以及一个全新的商业类别,包含一系列难以想象的创新有用移动应用程序。客户和业务之间连接的整个方式都将被重塑。
移动设备已经成为人类身体的延伸器官。现在很难找到不带手机的人。如果手机要成为人类的一部分,那么就像眼睛、鼻子、腿等一样,知道我们每天做什么,并习惯了我们的生活方式,以类似的方式,手机也可以理解我们日常生活的方方面面,并揭示许多关键数据点,这些数据点我们可能没有时间自己分析。
此外,一个移动设备可以安装由不同组织提供的许多应用程序,这使得第三方很容易深入了解我们的生活方式、生活模式和深层次秘密,并根据收集到的关键指针采取许多不同的行动。可能会有这样的可能性,不仅会惠及第三方,也可能惠及我们。他们可以尝试让我们意识到我们对自己无知的事情,或者建议更好的方式来完成我们做的某些活动,从而改善我们的生活。可能性无限,留给我们的想象力去思考如何在移动设备上实现和实施机器学习。
我们还看到了物联网的爆炸式增长。这是另一个维度,其中移动设备中的机器学习变得至关重要。定时发送不同信息的传感器可以靠近传感器,而不是传输到服务器。可以使用不同的协议在传感器和移动设备之间进行此类数据交换,并迅速采取及时行动。在这里,同样,可能性无穷无尽,正在发生划时代的创新,而这只是冰山一角。
在本章中,我们将深入了解以下主题:
- 
关键机器学习移动应用程序 
- 
关键创新领域 
- 
利益相关者的机会——在移动机器学习生态系统中,关键的利益相关者正在做什么? 
关键机器学习移动应用程序
在本节中,我们将探讨一些最受欢迎的移动应用程序,并了解它们在移动机器学习领域的应用。
Facebook 开发了一个名为 Caffe2Go 的 AI 平台。通过这个工具集,Facebook 最初希望为用户提供丰富的 AI 和 AR 体验。他们允许用户通过设备上的机器学习处理视频和图像,并执行某些任务,而无需将这些视频和图像传输到后端进行复杂的图像和视频处理。他们的风格转换工具包允许用户将一种图像风格的美术品质应用到其他图像和视频中。
Google Maps
Google 推出了 TensorFlow Lite 以及 ML Kit,这些工具使用户能够在移动应用程序中执行移动机器学习。Google Maps 是 Google 的一个经典移动机器学习示例。
Snapchat
Snapchat 正在创新复杂的机器学习算法,这些算法能够感知由摄像头捕获的图像中的面部特征。这些算法试图学习面部特征,然后尝试创建一个带有关键面部特征点的面具。这个面具可以用来与有趣的图形并置,创造出留给用户想象和创造力的图像。
Tinder
Tinder,于 2012 年推出,是一款促进相互感兴趣用户之间沟通的社交应用程序。用户通过左滑或右滑来选择其他用户的照片,并可能与他们匹配。Tinder 引入了一个智能照片功能,利用机器学习算法提高了用户找到合适匹配的能力。这个功能允许用户首先看到最著名的照片,因为底层模型不断通过分析用户的滑动行为来学习和重新排序照片。
Netflix
Netflix 使用机器学习为用户提供高质量的流媒体体验。在移动设备上观看流媒体内容比在其他渠道上复杂得多。Netflix 正在实施复杂的机器学习算法,根据观看的内容来预测网络带宽、缓存需求以及设备的视频适应性需求,以改善和增强流媒体体验。
Oval Money
Oval Money 使用机器学习算法来学习用户的消费模式,以便为最终用户提供储蓄选项。它能够识别常规的重复模式并识别重复付款,以帮助用户节省金钱。
ImprompDo
ImprompDo 是一个时间管理应用程序,它学习用户行为并管理待办事项列表。它根据通过研究用户行为和他们的常规时间表、所在位置等信息,在最佳时间提醒用户处理待办事项列表中的项目。
Dango
Dango 是一个表情符号预测应用程序,它建议适合对话上下文的最合适的表情符号。它使用学习算法来理解不同的情绪和对话的上下文,从而提出及时的表情符号。
Carat
Carat 监控手机上发生的所有活动,并提供节省电池电量的建议。
Uber
Uber 利用机器学习技术帮助为乘客提供预计到达时间和费用。它还帮助为司机提供详细信息和地图,以满足这个预计到达时间。
GBoard
GBoard,谷歌为 iOS 和 Android 开发的移动键盘,使用机器学习来预测用户在真正输入之前将要输入的内容。
关键创新领域
以下部分详细介绍了利用机器学习力量的创新正在发生的某些商业领域。在这方面,已经有不少玩家正在引领潮流。
个性化应用
通过利用通过移动设备提供的各种参数来理解用户行为,并为了个性化目的理解他们的生活模式,这将对用户有价值。当同一个移动应用将要服务于广泛用户群体的用户档案时,如果它能提供最适合使用者的特定功能,这将具有重大价值。这种高级个性化可以通过利用机器学习来实现。
医疗保健
在这里,有各种用例可以帮助跟踪可以跟踪、学习和用于提供医疗保健创新的各种健康参数,例如可以根据移动应用中的图片和声音进行诊断的诊断应用。
通过移动应用跟踪个人定期健康和健身数据的健身跟踪和消费者医疗保健应用可以预防各种与生活方式相关的疾病。
这些移动应用实际上可以通过警报和通知来改变用户行为,并通过监控他们的生活方式来采取所需的任何行动。例如,它们可以建议散步、服药和眨眼。
目标化的促销和营销
移动应用可以用来研究用户行为并跟踪用户偏好,为用户提供目标化的促销。大多数收集的用户信息,如人口统计、使用统计和档案信息,可以使用机器学习算法进行分析,以对特定个人应推广的产品或服务做出可靠的预测。因此,与此一致,目标化的营销和广告可以针对用户。
视觉和音频识别
移动应用可以识别环境和用户环境,并修改设备的音频/视频控制,或根据用户偏好播放合适的音频和视频。
电子商务
具有机器学习智能的移动应用在电子商务领域可以有多种用途。一个这样的例子是零售店内的导航应用,它可以提高商业效益。
室内导航处理的是建筑内的导航。由于在建筑内通常无法接收到 GPS 信号,当需要自动定位时,会使用其他定位技术。在这种情况下,通常会使用 Wi-Fi 或信标(低功耗蓝牙(BLE))来创建所谓的室内 GPS。然而,与 GPS 不同的是,它们还允许你确定实际的楼层。大多数应用程序都需要室内路由功能,该功能通过室内导航应用程序精确地引导人们穿过建筑物,并以此自动确定他们的位置——这与我们在汽车中使用的导航系统非常相似。
在许多顶级电子商务网站上,当我们购买某个产品时,会提供产品推荐。这是基于浏览历史、购买历史、用户查询理解、排名和用户喜好确定,结合用户情况、位置、偏好和限制来实现的。
在电子商务中,趋势预测和根据观察到的趋势立即采取行动在销售中起着巨大作用。这两个方面之间的差距可以通过机器学习算法有效地填补。
财务管理
机器学习正在财务管理的每个阶段得到应用。用户投资组合管理、欺诈检测、交易、贷款管理和客户服务是结合用户数据和配置文件可以提供无数机会来以不同方式服务客户并利用机器学习算法的不同阶段。
游戏和娱乐
更真实、更具吸引力的增强虚拟现实,结合机器学习,可以为最终用户提供令人惊叹的个性化游戏和娱乐体验。
通过利用各种参数,例如设备能力、用户偏好和网络能力,通过应用机器学习,可以更高效、更有效地进行内容管理、视频流和内容渲染。
企业应用
那些拥有大量日常重复性活动的企业应用,现在通过提供给企业员工的新见解变得有趣,甚至更有生产力,这些见解实际上可以改善决策并使企业获得更大的价值,从而为企业节省大量资金。
招聘、时间管理、运营和资本支出、旅行以及销售流程可以根据特定用户、客户和地理区域进行定制,利用可用的庞大企业数据,并应用机器学习算法来提出有用的及时预测。
房地产
基于机器、神经网络和增强现实功能强大的可视化软件,当结合使用时,可以通过使客户能够可视化他们的梦想家园并在飞行中根据他们的偏好建模家园,从而显著帮助房地产领域。
宜家已经推出了一款名为宜家空间的应用程序(itunes.apple.com/us/app/ikea-place/id1279244498?mt=8),允许用户可视化他们选择的家具如何融入他们的家中。
同样,Azati 的图像建模应用程序允许用户用其他选择替换现有的墙面覆盖,从而使用户能够立即查看他们选择的覆盖物在计划购买或装饰的样板房上的效果。
农业
通过移动应用程序,可以为农民提供各种解决方案。通过智能手机捕获的土壤和植物图像可以进行分析,以提供有关土壤恢复技术、除草技巧、植物健康控制等方面的有用见解。这些图像可以在各种参数上进行分析,例如土壤缺陷、植物病虫害、缺陷以及土壤中的营养缺乏。可能性无穷无尽,可以扩展到农业的各个步骤,以帮助提高作物产量。
能源
能源行业是应用机器学习后可以带来大量能源节省的领域,从而保护环境并帮助我们走向绿色。
基于用户偏好和可用性,通过移动应用程序控制的机器学习智能家庭可以为每个家庭带来巨大的能源节省。
自动驾驶汽车可以通过优化路线和多人使用同一辆车旅行时的路线和利用,调节速度和能源消耗,从而节省能源。
机器学习还可以用于智能电网及其维护,它可以预测故障点以及故障发生的时间,从而可以采取必要的预防措施。
智能电网是一个包含各种操作和能源措施的电力系统,包括智能电表、智能家电、可再生能源资源和节能资源。电力生产和分配的电子功率调节和控制是智能电网的重要方面。它是一个使用数字通信技术检测和响应本地使用变化的电力供应网络。
移动安全
机器学习可用于面部识别工具,这些工具可能用于移动设备中应用程序的认证和授权。
微软、谷歌和其他公司正在大力开展这项工作,以保护他们的操作系统以及这些操作系统中的移动应用程序免受安全威胁。
谷歌也推出了一种名为群体分析的机器学习算法。该算法通过跟踪那些没有必要收集或发送数据的应用程序,帮助识别谷歌应用商店中的有害应用。
Zimperium 的 Z9 软件是利用机器学习实现移动安全性的移动设备恶意软件检测软件的例子。
利益相关者的机会
本节提供了关于该领域关键利益相关者的详细信息,他们贡献并决定了机器学习在移动设备上的成功和普及。它探讨了他们如何贡献于移动机器学习,以及他们各自正在进行的创新,以增加移动机器学习的接受度并使其广泛传播。
硬件制造商
硬件是执行机器学习移动应用程序的基础平台。机器学习在处理单元和内存方面有特定的要求,以便运行复杂的机器学习算法。直到最近,硬件限制是推动大多数机器学习处理在无处理单元或内存限制的后端服务器上进行的其中一个原因。但现在,大多数设备制造商都在进行突破性的创新,使硬件适合运行移动设备上的机器学习应用程序:
- 
苹果已经为其 iPhone X 的主芯片组设计了并构建了一个神经引擎,用于处理复杂的由机器学习驱动的图像处理。 
- 
在 Pixel 2 设备中,谷歌还构建了一套定制的芯片组,以满足机器学习(ML)的需求。 
- 
华为的 Mate 10 也内置了神经网络处理单元。 
- 
ARM 启动了一个项目,旨在创建一个由人工智能驱动的智能芯片,这将允许移动设备在离线时继续运行机器学习算法。这将减少数据流量,加快处理速度,同时节省电池消耗。 
- 
高通也在与 ARM 合作,生产下一代移动设备,使机器学习算法能够高效运行。 
移动操作系统供应商
移动操作系统,如 iOS 和 Android,以及微软的 Windows 移动操作系统,都在满足在移动设备上运行移动机器学习算法的需求。操作系统本身已经集成了各种功能来支持移动机器学习。
第三方移动机器学习 SDK 提供商
正如我们在本书中所见,有各种 SDK 可供程序员创建移动机器学习程序:
- 
TensorFlow Lite 
- 
Caffe2Go 
- 
Core ML 
- 
ML Kit 
- 
弗里茨 
我们已经探讨了这些 SDK 的高级架构,并在本书中使用了前面提到的每个 SDK 编写了示例移动机器学习应用程序。
在移动机器学习技术赋能的以下领域,所有人都有机会:
- 
就像混合移动应用程序开发一样,混合机器学习模型开发也可能存在一种方法,可以使用通用语言来开发这些机器学习模型 
- 
在模型部署和现场部署的机器学习模型的升级方面存在许多问题 
- 
在监控现场机器学习模型性能和使用的方面有许多需要改进的地方 
- 
在这些 SDK 中支持许多机器学习算法需要做大量的工作 
- 
现在,主要只从移动设备上进行模型的预测和使用;训练也可以在移动设备上通过设备端训练启用进行。 
机器学习移动应用程序开发者
作为移动应用程序开发者,你面前有一个巨大的机会,可以在这个领域创造突破性和创新性的解决方案。可能性无穷无尽,实施方法也如本章示例所示得到了简化。如果你在移动应用程序开发方面有很好的了解,并且能够对机器学习算法有一个基本的概念,你就可以将它们用于解决关键问题,并为最终用户提供价值驱动的创新。
摘要
在本章中,我们了解了移动领域机器学习的未来以及它对用户的有用之处。我们还讨论了使用机器学习的不同移动应用程序,包括 Facebook、Netflix 和 Google Maps。
我们还看到了各种商业领域如何使用机器学习应用程序,以及使用移动设备在机器学习领域中的利益相关者所存在的各种机会。
第十二章:问答
在本附录中,我们将探讨章节中未涵盖的概念和要点,但这些都是全面理解和欣赏移动机器学习所必需的。我们将关注可能出现在你心中的问题,并尝试回答与此领域相关的问题。
常见问题解答
我们将把常见问题解答组织成三个基本部分:
- 
第一部分将探讨更通用的、与数据科学、机器学习等相关的问题。 
- 
第二部分将探讨与不同移动机器学习框架相关的具体问题。 
- 
第三部分和最后一部分将探讨与移动机器学习项目实施相关的具体问题。 
数据科学
在本节中,我们将回答一些与数据科学及其应用相关的问题。
什么是数据科学?
数据科学是从数据中提取相关见解的过程。它是数学、机器学习、计算机编程、统计建模、数据工程和可视化、模式识别和学习、不确定性建模、数据仓库和云计算等多个领域的综合。追求这些领域所需的技能包括工程、数学、科学、统计学、编程、创造力和数据维护与维护。
数据科学在哪里使用?
数据科学用于人工智能(AI)和机器学习。它解决复杂的数据问题,揭示在应用之前未知的信息。它揭示了数据之间极端相关且对业务非常有用的未知相关性。
什么是大数据?
大数据通常包括超出常用软件工具捕获、管理和处理能力的数据集。
大数据的特点是 Gartner 在 2001 年提出的三个 V,即:
- 
容量:数据量巨大且在增加 
- 
速度:数据积累的速度快且在增加 
- 
多样性:被捕获的特征/特性的数量大且在增长 
Gartner 在 2012 年的定义是:大数据是高容量、高速度、高多样性信息资产,需要新的处理形式来实现增强决策、洞察发现和流程优化。
大数据可以包括大数据系统、大数据分析和大数据集。
什么是数据挖掘?
数据挖掘是检查大型现有数据集并从中提取有用见解的过程。
数据科学与大数据之间的关系
数据科学不一定涉及大数据,但数据规模的增长使得大数据成为数据科学的一个重要方面。
什么是人工神经网络?
人工神经网络(ANNs)是受构成动物大脑的生物神经网络启发的计算系统。这些系统不是通过特定的任务规则编程的,而是通过考虑例子来执行任务,例如图像识别。为了识别一朵玫瑰,它通过学习来学习玫瑰的特征,以定义一个样本为玫瑰,而不是通过编程。
什么是 AI?
AI 指的是通过机器模拟人类大脑功能。这是通过创建一个能够展示人类智能的 ANN 来实现的。AI 机器执行的主要人类功能包括逻辑推理、学习和自我纠正。这是一个非常复杂的领域,要使本质上不智能的机器思考和行动像人类一样,需要大量的计算能力和数据输入。
AI 分为两个部分:
- 
通用 AI:使机器在广泛领域变得智能,在思维和推理上类似于人类。这至今尚未实现,并且已经启动了许多正在进行的研究活动。 
- 
窄 AI:使机器在特定领域变得智能,如数字识别和国际象棋。这在今天是可能的。 
数据科学、AI 和机器学习是如何相互关联的?
了解数据科学、AI 和机器学习之间确切关系的信息是非常有趣且重要的:
- 
AI:这个领域试图通过人工方式模拟人类智能。正如人类能够看到、观察他们周围的数据并做出决策一样,同样的尝试正在通过机器进行。这是一个非常广泛的领域。这项技术仍在不断发展。为了通过 AI 完成人类非常容易完成的小任务,需要大量的数据。 
- 
机器学习:AI 的一个子集。专注于特定问题领域。这项技术有针对现实生活用例的实现。它是 AI 和数据科学之间的连接桥梁。 
- 
数据科学:这是一个数据研究领域,旨在从中提取信息。这可以使用机器学习来分析数据、大数据等: 

机器学习框架
在本节中,我们将探讨本书中已经讨论过的几个机器学习框架,以及我们没有讨论过的框架,并对它们提供一些简要的指导。
Caffe2
- 
来自 Facebook 的 Caffe2 是本书未讨论的关键移动机器学习框架之一。更多详情可以从 caffe2.ai/获取。
- 
Caffe2 是一个深度学习框架,它提供了一个简单直接的方式来实验深度学习,并利用社区对新型模型和算法的贡献。 
- 
原始的 Caffe 框架对于大规模产品用例非常有用,尤其是在其无与伦比的性能和经过良好测试的 C++代码库方面。 
- 
Caffe2 在许多方面是对原始 Caffe 框架的改进。 
- 
要理解和开始使用框架编写代码示例,它有一个陡峭的学习曲线。 
scikit-learn
- 
Scikit-learn 是众所周知的最著名的机器学习包之一,提供了大量常见机器学习算法的高效实现版本。 
- 
它不是一个移动机器学习包。然而,使用 scikit-learn 创建的模型可以通过转换工具转换为 Core ML 和 TensorFlow Lite 模型,并直接用于移动应用程序。 
- 
它在机器学习算法中具有类似和统一的 API 实现,并且提供了非常全面的辅助文档。 
- 
学习 scikit-learn 以及使用它实现和扩展模型非常容易。 
- 
Scikit-learn 最初由 David Cournapeau 在 2007 年的谷歌夏日代码项目中开发。后来,Matthieu Brucher 加入了项目,并将其作为他论文工作的一部分开始使用。2010 年,INRIA 参与其中,并于 2010 年 1 月底发布了第一个公开版本(v 0.1 beta)。现在,项目拥有超过 30 位活跃的贡献者,并得到了 INRIA、谷歌、Tinyclues 和 Python 软件基金会的赞助。 
- 
Scikit-learn 通过 Python 中的统一接口提供了一系列监督学习和无监督学习算法。 
- 
它遵循宽松的简化版 BSD 许可协议,并在许多 Linux 发行版中分发,鼓励学术和商业使用。 
- 
该库建立在 SciPy 之上,您必须先安装 SciPy 才能使用 scikit-learn。 
TensorFlow
- 
TensorFlow 是一个用于快速数值计算的开源库。它由谷歌创建并维护,并遵循 Apache 2.0 开源许可协议发布。API 使用 Python 编程语言编写,尽管也有访问底层 C++ API 的途径。 
- 
有一个针对移动设备的独立版本,我们已经在书中详细讨论过,并在我们的实际动手练习中使用过。 
- 
在 TensorFlow 中创建的模型可以用于转换为 TensorFlow 移动和 TensorFlow Lite 模型,并在移动应用程序中使用。 
- 
TensorFlow 旨在用于研究和开发以及生产系统。它可以在单 CPU 系统、GPU 上运行,以及移动设备和数百台机器的大型分布式系统中。 
- 
从数学上讲,张量是一个 n 维向量。它可以用来表示 n 维数据集。"Flow"指的是一个图;该图不能是循环的,图中的每个节点代表一个操作,如加法、减法等。每个操作的结果都会形成一个新的张量。 
- 
TensorFlow 能够并行评估每个节点,因此消除了在串行模式下等待节点评估的空闲浪费时间。 
- 
TensorFlow 允许用户利用并行计算设备来加速操作。 
Core ML
- 
苹果在 WWDC'17 上发布了 Core ML,今年更新到了 Core ML 2。提醒一下,Core ML 允许开发者将机器学习模型集成到 iOS 和 MacOS 应用中。这是该领域的第一次重大尝试,最初开发者们因为几个原因而非常喜欢它。 
- 
Core ML 支持多种机器学习模型,包括神经网络、树集成、支持向量机和广义线性模型。Core ML 需要 Core ML 模型格式(具有 .mlmodel文件扩展名的模型)。
- 
苹果还提供了转换器,可以将其他几个库中创建的模型转换为 Core ML 格式。由于我们在本书中使用了这些转换器,我们发现这些转换器极其简单易用,并且与大多数著名的现有机器学习库兼容。 
- 
苹果还提供了一些流行的开源模型,这些模型已经以 Core ML 模型格式存在,可以直接下载并用于构建我们的应用。 
- 
Core ML 针对设备性能进行了优化,这最小化了内存占用和功耗。严格在设备上运行也确保了用户数据的安全,即使在没有网络连接的情况下,应用也能运行。 
- 
Core ML 最大的优势是它极其简单易用。只需几行代码就可以帮助你集成一个完整的机器学习模型。自从 Core ML 发布以来,就有大量使用它的创新项目涌现。然而,Core ML 能做的事情也有局限性。 
- 
Core ML 只能帮助你将预训练的 ML 模型集成到你的应用中。这意味着你只能进行预测;无法进行模型训练。 
- 
到目前为止,Core ML 已被证明对开发者来说极其有用。今年在 WWDC 上宣布的 Core ML 2,应该通过称为量化和批量预测的技术将推理时间提高 30%。 
移动机器学习项目实施
在本节中,我们将探讨任何机器学习项目实施者在开始项目之前都会考虑的基本问题。
在开始项目之前,需要考虑哪些高级重要事项?
在开始项目之前,需要解决以下高级事项:
- 
根据我们看到的 ML 定义,对问题进行明确定义,为任务 T、性能度量 P 和经验 E 提供清晰的输入。 
- 
拥有所需数量的数据可用 
- 
设计移动端或基于云的移动机器学习框架的决策 
- 
正确选择适合我们需求的机器学习框架 
实施移动机器学习项目所需的角色和技能是什么?
可以为移动机器学习项目计划以下技能和角色:
- 
领域专家/专家:对问题、数据、数据中的特征、业务背景等进行输入 
- 
机器学习数据科学家:分析数据,进行特征工程和数据预处理,并构建机器学习模型 
- 
移动应用程序开发者:利用移动机器学习模型来构建移动应用程序 
- 
测试员:测试模型以及移动应用程序 
在这里,每个角色都可以通过这本书被其他人学习,并且可以由单个人或多个人执行,以确保移动机器学习项目的成功实施。
测试移动机器学习项目时应该关注什么?
项目中要测试的关键是移动机器学习模型。因此,独立于移动应用程序,模型需要彻底测试。
我们已经看到了在测试机器学习模型时应该关注什么。在测试模型时需要考虑训练数据、测试数据和交叉验证。需要测量所选模型的性能指标。对于每次运行,都需要进行清晰的记录,以便我们清楚地知道对于输入数据特征集的 delta 变化,输出会有什么样的 delta 变化。所有在第一章,《移动机器学习导论》中解释的概念,如准确性、精确度、召回率、错误等,都应该被测试机器学习模型的工程师清楚地理解。此外,对于每种类型的算法,错误和性能度量指标各不相同,在测试模型时应该充分考虑。测试机器学习模型本身就是一个值得写一本书的主题,而这本书中详细讨论的内容超出了范围。
领域专家将如何帮助机器学习项目?
领域专家/专家在任何一个机器学习项目的成功中扮演关键角色,他的具体价值将在以下领域体现:
- 
定义问题陈述并帮助正确理解解决方案的期望 
- 
数据准备: - 
在特征工程中,哪些是好的候选者被选中并保留为预测属性? 
- 
如何结合多个目标/属性以帮助解决问题陈述 
- 
如何采样以选择测试集和训练集 
- 
帮助进行数据清洗 
 
- 
- 
进度监控和结果解释: - 
定义所需的预测准确度 
- 
根据取得的进展,确定是否需要更多数据/附加数据 
- 
在中间设置一个检查点,并确定取得的进展是否与定义的问题陈述一致,追求的解决方案是否一致,是否可以继续在同一方向上推进,或者是否有必要采取不同的路径/重新校准方法。 
 
- 
- 
对进度进行持续更新和反馈 
机器学习项目中常见的陷阱有哪些?
以下是在任何机器学习项目中常见的一些陷阱:
- 
不切实际的目标,不明确的问题定义,没有适当的目标 
- 
数据问题: - 
建立预测模式的数据不足 
- 
预测属性选择不当 
- 
数据准备问题 
- 
数据归一化问题——未能跨数据集归一化数据 
- 
解决问题时数据使用的偏差 
 
- 
- 
机器学习方法选择不当: - 
选择的机器学习方法不适合定义的问题陈述 
- 
不尝试替代算法 
 
- 
- 
过早放弃。这种情况很常见。如果工程师看不到初始结果,无法进行各种依赖因素的排列组合,并且无法对结果进行系统记录,他们往往会失去兴趣。如果持续/有系统地记录并尝试各种可能性,机器学习问题可以轻松解决。 
安装
在本节中,我们将介绍设置本书中创建程序所需的不同工具和 SDK 安装程序。
Python
在本书中,我们使用 Python 创建了机器学习模型。因此,您必须知道如何在您的系统中安装 Python,以便通过实际示例进行学习。
它将显示最新的下载版本;下载安装程序并安装。
在 Windows 上安装时,它会询问是否要将 Python 添加到路径环境变量中。勾选复选框以自动为您完成。否则,您需要手动将其添加到路径变量中。
要检查您的机器上是否已安装 Python,请转到命令提示符或终端,并输入python。它应该显示 Python 提示符。否则,如果您已经将其安装到驱动器中,则需要设置路径变量。
Python 依赖项
Python 默认会附带pip包管理器。您可以使用pip进行安装。语法如下:
pip install package name
关于可用包的更多信息,您可以访问pypi.org/project/pip/。在本书中,我们已在各自的章节中给出了所有依赖项安装命令。
Xcode
首先,在 Apple 上创建一个开发者账户并登录到您的账户developer.apple.com/。点击下载并向下滚动/搜索最新版本的 Xcode,版本号高于 9.4,然后点击下载。它将下载 XZIP 文件。将其提取出来,并通过将其拖动到应用程序文件夹中在您的 Mac 机器上安装。
参考文献
以下是一些您可以参考的参考文献,以了解更多关于在移动设备上进行机器学习的知识:
- 
机器学习精通: machinelearningmastery.com/
- 
Analytics Vidhya: https://www.analyticsvidhya.com/ 
- 
弗里茨: fritz.ai/
- 
ML Kit: developers.google.com/ml-kit/
- 
TensorFlow Lite: www.tensorflow.org/lite/
- 
Core ML: developer.apple.com/documentation/coreml?changes=_8
- 
Caffe2: caffe2.ai/

 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号