在iPhone上创建你的第一个机器学习模型
2017年10月03日 由 xiaoshan.xiang 发表
211485
0
最近的苹果iPhone X发布会,你会看到iPhone X有一些很酷的功能,比如FaceID,Animoji和AR。我们需要弄明白建立这样一个系统需要什么。
当进一步研究时,得到的答案是苹果的官方机器学习工具CoreML。它适用于iPhone、Macbook、Apple TV、Apple watch,以及每一个苹果设备。
另一个有趣的功能是,苹果公司在最新的iphon上设计了一个定制的GPU和一个带有神经引擎(neural engine)深度加工的A11 Bionic(仿生)芯片(
https://www.extremetech.com/mobile/255780-apple-neural-engine-a11-bionic-soc),该芯片用于深度学习的优化。
“随着计算引擎的核心的日益强大,iPhone将会打开新的机器学习的途径,CoreML在未来的日子里的意义只会上升。”
在这篇文章的结尾,你将知道Apple CoreML是什么,以及它为什么会获得动力。我们还将通过构建iPhone的垃圾信息分类应用程序来研究CoreML的实现细节。
我们将客观地看待这篇文章的利弊。
1.什么是CoreML
苹果公司今年在他们的年度开发者大会WWDC(
https://developer.apple.com/wwdc/)(相当于谷歌I / O会议)上发布了CoreML(
https://developer.apple.com/documentation/coreml),并大肆宣传。为了更好地理解CoreML的作用,我们必须了解一些背景。
CoreML的背景
这并不是苹果第一次推出机器学习框架。去年,它还推出了一组同样的库:
- 加速和基本的神经网络子程序(BNNS)-高效利用CPU进行卷积神经网络的预测;
- Metal性能着色程序CNN(MPSCNN)-高效利用GPU进行卷积神经网络的预测。
不同的是,一个优化了CPU,而另一个优化了GPU。这样做是因为,在推理过程中,CPU有时可能比GPU快。而在训练过程中,几乎每次都是GPU更快。
多个框架在开发人员之间造成了很大的混乱,因为它们非常接近硬件(为了高性能),因此很难进行编程。
进入CoreML
CoreML为前两个库提供了另一个抽象化的层,并提供了一个简单的接口,以达到同样的效率水平。另一个好处是,在应用程序运行时,CoreML负责处理CPU和GPU本身之间的上下文转接。
“也就是说,例如,你有一个内存繁重的任务,该任务涉及文本处理(自然语言处理),CoreML将自动在CPU上运行它,如果计算像图像分类这样的繁重任务,它将使用GPU。如果应用程序中有两个功能,它也会自动处理这些功能,这样你就能在两个世界中获得最好的效果。”
CoreML提供了什么?
CoreML还附带了三个建立在其上的库:
- 视觉:提供高性能图像分析和计算机视觉技术的库,用于识别人脸,检测特征,并对图像和视频中的场景进行分类;
- Foundation(NLP):顾名思义,它是一个提供自然语言处理功能的库;
- 游戏工具包:一个用于游戏开发的库同样也提供人工智能提供,使用决策树。
以上所有的库,都很容易使用,并提供了一个简单的接口来完成一系列任务。使用上述库,CoreML的最终结构将如下所示:
注意,上面的设计为iOS应用程序提供了一个很好的模块结构。对于不同的任务对应不同的层,可以以多种方式使用它们(例如,在应用程序中使用带有图像分类的NLP)。可以在这里阅读更多关于这些库的内容:视觉(
https://developer.apple.com/documentation/vision)、Foundation(
https://developer.apple.com/documentation/foundation)和游戏工具包(
https://developer.apple.com/documentation/gameplaykit)。这已经足够了,现在开始进行下一项工作。
2.设置系统
要充分利用CoreML,需要遵循以下设置要求:
sudo easy_install pip
- coremltools:该程序包有助于将模型从python转换成CoreML能够理解的格式。要安装它,需要再次打开终端:
sudo pip install -U coremltools
登录后,需要验证Apple ID,你将收到与注册Apple ID的设备相同的通知。
选择“Allow”并在网站上输入给出的6位密码。
完成此步骤后,将显示一个下载选项,可以从那里下载Xcode。现在我们已经建立了自己的系统,并准备好继续执行实现部分。
3.案例研究:为iPhone实现垃圾信息分类器
我们将利用CoreML的力量来构建两种重要的方法。
开始:
将机器学习模型转换成CoreML格式
CoreML的优势之一是支持在其他流行的框架中建立训练机器学习模型的转换,比如sklearn,caffe,xgboost等。
“这并没有使数据科学社区疏远CoreML,因为他们可以在他们最喜欢的环境中进行实验,训练他们的模型,然后将其导入到他们的iOS / MacOS应用程序中。”
下面是CoreML支持的框架:
mlmodel是什么?
为了简化转换过程,苹果设计了自己的开放格式,用于表示跨框架机器学习模型,并命名为mlmodel。这个模型文件包含对模型各层的描述、输入和输出、类标签以及需要对数据进行的任何预处理。它还包含所有的学习参数(权重和偏差)。
转换流程是这样的:
- 在你喜欢的框架中进行培训;
- 使用coremltools python程序包将模型转换为.mlmodel;
- 在你的应用程序中使用这个模型。
在这个示例中,我们将在sklearn中构建一个垃圾信息分类器,然后将相同的模型转移到CoreML。
关于垃圾信息集合数据集
SMS垃圾信息集合v.1(
http://www.dt.fee.unicamp.br/~tiago/smsspamcollection/)是一组公开的SMS标签的信息,已被用于手机垃圾信息的研究。它有一个集合,由5574个英语,真实和非编码信息组成,被标记为合法(ham)或垃圾信息。
可以从这里下载数据集(
http://simplysanad.com/CoreML-on-iPhone/Complete%20App/coreml%20test/SMSSpamCollection.txt)。
构建基本模型
这就是它的代码:
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
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()
vectorized_text = vectorizer.fit_transform(X)
text_clf = LinearSVC()
text_clf = text_clf.fit(vectorized_text, y)
模型创建完成。用垃圾信息对它进行测试。
#Test the model
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"""]))
模型运行良好,添加一些交叉验证。
#Cross - Validation
from sklearn.model_selection import cross_val_score
cross_score = cross_val_score(text_clf, vectorized_text, y, cv=10)
print cross_score
print "mean:",np.mean(cross_score)
我们已经构建了模型,需要将其转换为 .mlmodel格式,以便与CoreML兼容。我们将使用前面安装的coremltools程序包(
https://pypi.python.org/pypi/coremltools)。下面的代码将把我们的模型转换为.mlmodel格式:
import coremltools
#convert 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")
发生了什么?
首先导入python中的coremltools程序包。然后使用转换器转换模型,在这种情况下,我们使用converters.sklearn,因为我们必须转换在sklearn中建立的模型。然后,传递模型对象、输入变量名和. convert()中的输出变量名。接着,设置模型的参数,以添加更多关于输入、输出的信息,最后调用. save()来保存模型文件。
当双击模型文件时,它应该在Xcode窗口中打开。
模型文件显示了模型的类型、输入、输出等的详细信息。上面的图像突出显示了这些信息。这些描述与我们在转换为.mlmodel时提供的描述相匹配。
将模型导入CoreML很容易。现在模型进入了苹果系统,这才是真正的开始。
注意:该步骤的完整的代码文件可以在这里找到(
https://github.com/mohdsanadzakirizvi/CoreML-on-iPhone/blob/master/Complete%20App/CoreML%20Conversion.ipynb)。阅读更多关于coremltools的信息(
https://apple.github.io/coremltools/),以及不同类型的转换器(
https://apple.github.io/coremltools/coremltools.converters.html)。
集成带有应用程序的模型
现在已经训练了我们的模型并将它转移到CoreML,接下来我们将使用这个模型,为iPhone构建一个垃圾信息分类器应用程序。
我们会在模拟器上运行我们的应用程序。模拟器是一个软件,它展示了应用程序的外观和工作方式,就好像它真的在手机上运行一样。这节省了很多时间,因为我们可以用我们的代码进行实验,并在实际手机上试验应用程序之前,修复所有的bug。看看最终的产品会是什么样子:
下载项目
我已经为我们的应用建立了一个基本的UI,它可以在GitHub上使用。使用以下命令来启动和运行:
git clone https://github.com/mohdsanadzakirizvi/CoreML-on-iPhone.git
cd CoreML-on-iPhone/Practice\ App/
open coreml\ test.xcodeproj/
使用Xcode打开我们的项目。
Xcode窗口突出了三个主要区域:
- 左上方的播放按钮用于在模拟器上启动应用程序。
- 在播放按钮下面是与该项目相关的文件和文件夹。被称为项目导航器,它在项目的文件和文件夹之间进行导航。
- 在播放按钮上,iPhone 8 Plus被写入,这表示你希望的测试模拟器的目标设备。你可以点击它,下拉选择iPhone 7
先运行我们的应用程序,看看会发生什么。点击左上方的播放按钮,在模拟器上运行我们的应用程序。试着在文本框里输入一些文本并点击“Predict”按钮。会发生什么呢?
目前,我们的应用程序并没有做很多事情,只是输出了在文本框里键入的东西。
在应用程序中添加预先训练的模型
这很简单:
- 将.mlmodel文件拖放到项目导航窗格中的Xcode窗口;
- 当你这样做的时候,窗口会弹出一些选项,选择默认选项,然后点击“Finish”;
- 当你将文件拖放到Xcode中时,它会自动为项目中的文件创建引用。通过这种方式,你可以轻松地在代码中访问该文件。
以下是整个过程:
编译模型
从模型开始进行推断之前,我们需要利用Xcode去创建阶段编译模型。步骤如下:
- 打开右侧的项目设置。单击编译源文件并选择+ 图标;
- 在窗口中选择mlmodel文件并单击Add。
每次运行应用程序时,Xcode都会编译我们的机器学习模型,以便它进行预测。
在代码中使用模型
- 在项目导航器面板中选择swift。该文件包含了许多控制我们应用程序功能的代码;
- 查看第24行中的函数predictSpam(),该函数完成了大部分的工作。删除第25行,并在函数中添加以下代码:
let enteredMessage = messageTextField.text!
if (enteredMessage != ""){
spamLabel.text = ""
}
//Fetch tfidf representation of text
let vec = tfidf(sms: enteredMessage)
do {
//Get prediction on the text
let prediction = try SpamMessageClassifier().prediction(message: vec).spam_or_not
print (prediction)
if (prediction == "spam"){
spamLabel.text = "SPAM!"
}
else if(prediction == "ham"){
spamLabel.text = "NOT SPAM"
}
}
catch{
spamLabel.text = "No Prediction"
}
上面的代码用来检查用户是否在文本框中输入任何信息。如果有,它将调用tfidf()函数来计算文本的tfidf。然后,创建SpamMessageClassifier的对象,并调用 .prediction() 函数。这相当于sklearn中的 .predict()函数。然后,根据预测显示适当的信息。
为什么需要tfidf()?
我们基于文本的tf - idf表示来训练我们的模型,所以我们模型期望输入的格式相同。一旦我们收到在文本框中的输入信息,我们就调用tfidf()函数来执行相同的操作。接下来编写代码,将下面的代码复制到predictSpam()函数下面:
//MARK: Functionality code
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..
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()
}
}
上面的代码找到了在文本框中输入信息的tfidf表示,它读取原始数据集文件SMSSpamCollection.txt和返回相同的操作。一旦你保存了程序并重新运行模拟器,应用程序就应该可以正常运行了。
4.CoreML的优点和缺点
就像所有发展中的库一样,它也有它的优点和缺点,让我们明确地说明它们。
优点:
- 对设备性能进行优化,最大限度地减少内存占用和功耗;
- On-device指用户数据的隐私,不再需要将数据发送到服务器进行预测;
- On-Device指在没有网络连接且对用户的响应时间减少的情况下的功能预测;
- 它决定是否在CPU或GPU上运行该模型(或两者兼而有之);
- 因为它可以使用CPU,你可以在iOS模拟器上运行它(iOS不支持GPU);
- 它支持许多模型,因为它可以从其他流行的机器学习框架中导入模型,如:
- 支持向量机(SVM);
- tree ensembles,如随机森林和提升数模型(boosted trees);
- 线性回归和逻辑回归;
- 神经网络:前馈,卷积,反复。
缺点
- 监督模型的本机支持,只支持无监督或增强学习;
- 没有对设备进行训练,只有推理(预测);
- 如果CoreML不支持某一层的类型,就不能使用它。目前不允许用自己的层类型扩展核心ML;
- 核心ML转换工具只支持有限数量的训练工具的特定版本(不包括tensorflow);
- 不能查看由中间层生成的输出,只能得到预测;
- 仅支持回归和分类(不支持集群、排名、维度减少等)。
总结
在这篇文章中,我们学习了更多关于CoreML的知识,以及它在构建iPhone机器学习应用程序方面的应用。CoreML是一个相对较新的库,因此有它自己的优点和缺点。其中一个非常有用的特性是它在本地设备上运行,从而提供了更快的速度和更多的数据隐私。与此同时,它还不能被认为是一个成熟的数据科学家友好的库。我们将拭目以待,看看它在即将发布的版本中会如何发展。
对于那些在某个步骤中被卡住的人,本文的所有代码都可以在GitHub上找到(
https://github.com/mohdsanadzakirizvi/CoreML-on-iPhone)。
另外,如果你想更深入地探索CoreML,这些是一些资源:
核心ML介绍:构建一个简单的图像识别应用(
https://www.appcoda.com/coreml-introduction/)。