如何在iPhone上建立第一個(gè)機(jī)器學(xué)習(xí)模型
引言
作為一名數(shù)據(jù)科學(xué)家,我一直有一個(gè)夢(mèng)想——***科技公司在與我相關(guān)的領(lǐng)域不斷推出新產(chǎn)品。
如果你觀看了Apple公司***的iPhone X發(fā)布會(huì),你會(huì)發(fā)現(xiàn)iPhone X具有非??岬奶匦裕热鏔aceID、動(dòng)態(tài)表情、增強(qiáng)現(xiàn)實(shí),這些特性都使用了機(jī)器學(xué)習(xí)。作為一名駭客,我決定親自上手探索一下如何建立那樣的系統(tǒng)。
進(jìn)一步調(diào)查后我發(fā)現(xiàn)了一個(gè)很有趣的工具,那就是Apple官方面向開(kāi)發(fā)者推出的機(jī)器學(xué)習(xí)框架工具CoreML。它可以在iPhone、Macbook、Apple TV、Apple watch等任何一個(gè)蘋(píng)果設(shè)備上使用。
另一個(gè)有趣的發(fā)現(xiàn)是Apple在***的iPhone手機(jī)上設(shè)計(jì)了一個(gè)定制GPU,以及一個(gè)帶有神經(jīng)引擎的A11先進(jìn)仿生學(xué)處理芯片,以便用于優(yōu)化機(jī)器學(xué)習(xí)。
隨著核心組件計(jì)算引擎功能日益強(qiáng)大,iPhone將開(kāi)辟機(jī)器學(xué)習(xí)的新途徑,CoreML在未來(lái)的意義將越來(lái)越重要。
讀完這篇文章,大家將會(huì)了解Apple CoreML是什么以及為何它勢(shì)頭正猛。我們也將通過(guò)開(kāi)發(fā)一款iPhone上的垃圾短信分類(lèi)app來(lái)與大家一起一探CoreML的實(shí)現(xiàn)細(xì)節(jié)。
同時(shí),我們也會(huì)通過(guò)客觀評(píng)價(jià)CoreML的利弊來(lái)結(jié)束本篇文章。
文章目錄:
- CoreML是什么?
- 建立系統(tǒng)
- 案例學(xué)習(xí):實(shí)現(xiàn)一個(gè)iPhone上的垃圾短信分類(lèi)app
- 使用CoreML的利弊
01、CoreML是什么?
今年,Apple公司在每年一次的全球開(kāi)發(fā)者大會(huì)WWDC(類(lèi)似于谷歌的I/O會(huì)議)上大肆宣傳CoreML。為了更好地理解CoreML的作用,我們需要了解一些背景。
CoreML的背景
有趣的是,這并不是Apple公司***次發(fā)布移動(dòng)端機(jī)器學(xué)習(xí)框架。去年它就發(fā)布了一些同樣的框架庫(kù):
- Accelerate 框架和基本神經(jīng)網(wǎng)絡(luò)子程序(BNNS)——高效利用CPU并使用卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行預(yù)測(cè)。
- Metal Performance Shaders CNN(MPSCNN)——高效利用GPU并使用卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行預(yù)測(cè)。
這兩個(gè)框架庫(kù)的區(qū)別在于,一個(gè)針對(duì)CPU優(yōu)化而另一個(gè)針對(duì)GPU。這是因?yàn)橛袝r(shí)在inference(推斷)過(guò)程中CPU比GPU計(jì)算更快,而在training(訓(xùn)練)過(guò)程中幾乎每次都是GPU計(jì)算更快。
但為了提高性能,框架會(huì)非常接近底層硬件,使得這些混合框架對(duì)開(kāi)發(fā)者造成混亂,從而很難編程。
走進(jìn)CoreML
CoreML 會(huì)在之前提到的兩個(gè)庫(kù)上面提供一個(gè)抽象層,并且還會(huì)提供一個(gè)簡(jiǎn)單的接口,以達(dá)到同樣的效率。另一個(gè)好處是,在我們的app運(yùn)行時(shí),CoreML充分照顧到了CPU與GPU之間的上下文切換。
換句話(huà)說(shuō),假如我們有一個(gè)耗內(nèi)存的任務(wù),它涉及文本處理(自然語(yǔ)言處理),CoreML將自動(dòng)在CPU運(yùn)行;而如果我們有一個(gè)計(jì)算繁重的任務(wù),例如圖像識(shí)別,它將使用GPU;當(dāng)app包含這兩種功能的時(shí)候,它又會(huì)自動(dòng)切換從而使得兩者都得到***化的利用。
CoreML還將提供什么?
CoreML頂層還附帶了三個(gè)庫(kù):
- Vision:這個(gè)庫(kù)提供了高性能圖像分析與計(jì)算機(jī)視覺(jué)技術(shù),用于人臉識(shí)別、特征檢測(cè)以及圖像與視頻中的場(chǎng)景識(shí)別。
- Foundation(NLP):顧名思義,它提供了自然語(yǔ)言處理的一些功能
- Gameplay Kit:用于游戲開(kāi)發(fā)的庫(kù),此外它還提供了AI,并運(yùn)用決策樹(shù)。
以上提到的所有庫(kù)都可以用一些簡(jiǎn)單的接口輕松使用,可用于完成一系列任務(wù)。通過(guò)上述的庫(kù),CoreML最終框架圖如下:
注意,上述設(shè)計(jì)給iOS應(yīng)用程序提供了一個(gè)很好的模塊化結(jié)構(gòu)。你可以使用不同層進(jìn)行不同的任務(wù),也可以用多種方式使用它們(例如,在app中使用NLP進(jìn)行圖像分類(lèi))。了解更多:Vision、Foundation與GameplayKit。好了,現(xiàn)在我們有了足夠的理論知識(shí),是時(shí)候?qū)嵺`一下了!
“微信排版限制,需要代碼的同學(xué)請(qǐng)看文末的原文鏈接自行查找”
02、建立系統(tǒng)
為了充分使用CoreML,你需要遵循如下要求:
1.OS:MacOS(Sierra 10.12或以上)
2.Python 2.7和pip:點(diǎn)擊下載mac上的python。打開(kāi)終端,輸入如下代碼安裝pip:
- sudo easy_install pip
3.coremltools:這個(gè)包有助于將你的模型從python轉(zhuǎn)換成CoreML能理解的格式。在終端輸入如下代碼進(jìn)行安裝:
- sudo pip install -U coremltools
4.Xcode 9:這是用于構(gòu)建Apple設(shè)備上應(yīng)用程序的默認(rèn)軟件。點(diǎn)此下載。下載Xcode之前,你需要使用Apple ID進(jìn)行登陸。
登陸之后,你需要驗(yàn)證你的apple ID。你將會(huì)收到與注冊(cè)Apple ID的設(shè)備相同的通知。
點(diǎn)擊“允許”并輸入網(wǎng)站顯示的6位密碼。
當(dāng)你完成這一步,你將會(huì)看到一個(gè)下載選項(xiàng)。你可以在那兒下載Xcode?,F(xiàn)在,我們建立好了系統(tǒng),準(zhǔn)備好了的話(huà)就讓我們進(jìn)入實(shí)現(xiàn)部分!
03、案例學(xué)習(xí):實(shí)現(xiàn)一個(gè)iPhone上的垃圾短信分類(lèi)app
在本次開(kāi)發(fā)中,我們將著重于在兩個(gè)重要途徑上來(lái)使用CoreML的能力。讓我們開(kāi)始吧!
將你的機(jī)器學(xué)習(xí)模型轉(zhuǎn)換成CoreML格式
CoreML其中一個(gè)優(yōu)勢(shì),或者我應(yīng)該說(shuō)它的創(chuàng)造者作出的明智的決定是,支持在sklearn、caffe、xgboost等其他流行框架中訓(xùn)練好的機(jī)器學(xué)習(xí)模型的轉(zhuǎn)換。
數(shù)據(jù)科學(xué)社區(qū)并不會(huì)不嘗試CoreML試行,因?yàn)樗麄兛梢栽谒麄冏钕矚g的環(huán)境中進(jìn)行實(shí)驗(yàn)、訓(xùn)練他們的模型,然后輕松導(dǎo)入并在iOS/MacOS的app上使用。
下面是即時(shí)可用的CoreML支持的框架:
Mlmodel是什么?
為了使轉(zhuǎn)換過(guò)程簡(jiǎn)單,Apple設(shè)計(jì)了它自己的開(kāi)放格式來(lái)代表跨框架機(jī)器學(xué)習(xí)模型,即mlmodel。這個(gè)模型文件包含了模型各層的描述、輸入、輸出、類(lèi)標(biāo)簽、任何需要對(duì)數(shù)據(jù)進(jìn)行的預(yù)處理。它還包含了已學(xué)習(xí)的參數(shù)(權(quán)重及偏差)。
轉(zhuǎn)換流程如下:
- 在你最喜歡的框架中訓(xùn)練模型
- 使用python模塊coremltools將模型轉(zhuǎn)換為.mlmodel格式
- 在app中使用模型
在本次例子中,我們將在sklearn中訓(xùn)練一個(gè)垃圾短信分類(lèi)器,然后將該模型轉(zhuǎn)給CoreML。
關(guān)于垃圾短信數(shù)據(jù)集
SMS垃圾短信數(shù)據(jù)集 v.1是一個(gè)公開(kāi)的SMS標(biāo)注短信數(shù)據(jù)集,用于手機(jī)垃圾短信研究。它包含了5574份真實(shí)無(wú)編碼的英文短信,這些短信都標(biāo)注了合法(做作)或者垃圾短信。
你可以在此下載該數(shù)據(jù)集。
建立基礎(chǔ)模型
我們使用sklearn中的LinearSVC建立基礎(chǔ)模型。同時(shí),我們提取短信文本的TF-IDF值作為模型特征。TF-IDF是自然語(yǔ)言處理中的一種方法,它基于唯一標(biāo)識(shí)文檔的詞來(lái)分類(lèi)文檔。如果你想要學(xué)習(xí)更多NLP和tf-idf的知識(shí),你可以閱讀這篇文章。代碼如下:
- import numpy as npimport pandas as pd#Reading in and parsing dataraw_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 testsms_data = np.array(sms_data)X = sms_data[:, 1]y = sms_data[:, 0]
- #Build a LinearSVC modelfrom sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.svm import LinearSVC
- #Build tf-idf vector representation of datavectorizer = TfidfVectorizer()vectorized_text = vectorizer.fit_transform(X)text_clf = LinearSVC()text_clf = text_clf.fit(vectorized_text, y)
我們的模型建立好了,讓我們用一份垃圾短信測(cè)試一下:
- #Test the modelprint 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"""]))
有趣,我們的模型效果很好!讓我們添加交叉驗(yàn)證:
- #Cross - Validationfrom sklearn.model_selection import cross_val_scorecross_score = cross_val_score(text_clf, vectorized_text, y, cv=10)print cross_scoreprint "mean:",np.mean(cross_score)
- 現(xiàn)在已建好模型,為使它適用于CoreML,我們需要把它轉(zhuǎn)換成.mlmodel格式。用之前安裝的coremltools工具包來(lái)實(shí)現(xiàn)。以下代碼能將我們的模型轉(zhuǎn)換成.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")
這是如何運(yùn)作的呢?
首先我們運(yùn)用coremltools Python工具包。再選擇一個(gè)轉(zhuǎn)換器對(duì)模型進(jìn)行轉(zhuǎn)換,本例中用converters.sklearn,因?yàn)橐D(zhuǎn)換的模型是用sklearn工具建立的。然后在.convert()括號(hào)內(nèi)聲明模型對(duì)象、輸入變量名稱(chēng)、輸出變量名稱(chēng)。接下來(lái)設(shè)置模型參數(shù)來(lái)添加更多關(guān)于輸入、輸出的信息,***用.save()保存已轉(zhuǎn)換成CoreML格式的模型文件。
雙擊模型文件,會(huì)用Xcode打開(kāi)。
如你所見(jiàn),該模型文件顯示了很多信息,關(guān)于模型的類(lèi)型、它的輸入、輸出,輸入輸出的類(lèi)型等。我已在上圖中用紅色標(biāo)記。你可以將這些描述和轉(zhuǎn)換成.mlmodel時(shí)所提供的一一對(duì)比。
將自己的模型引入CoreML就是這么簡(jiǎn)單。現(xiàn)在你的模型已經(jīng)在蘋(píng)果生態(tài)系統(tǒng)里了,接下來(lái)真正好玩的開(kāi)始啦!
注意:這一步的完整代碼文件請(qǐng)看這里。進(jìn)一步了解coremltools請(qǐng)看這里,提供的不同種類(lèi)的轉(zhuǎn)換器請(qǐng)看這里。
將該模型用于我們的app
既然已經(jīng)訓(xùn)練好模型并引入CoreML中,讓我們用該模型開(kāi)發(fā)一個(gè)iPhone垃圾信息分類(lèi)app吧!
我們將在模擬器上運(yùn)行app。模擬器這一軟件能顯示app的界面及運(yùn)行情況,像在iPhone上真正運(yùn)行那樣。這樣節(jié)省了大量時(shí)間,因?yàn)橛胕Phone運(yùn)行app之前,我們就可以測(cè)試代碼、調(diào)試??匆幌伦罱K產(chǎn)品長(zhǎng)什么樣子吧:
下載工程
我已經(jīng)為我們的app制作了一個(gè)簡(jiǎn)單基礎(chǔ)的UI放在GitHub上。用以下命令加載并運(yùn)行:
- git clone https://github.com/mohdsanadzakirizvi/CoreML-on-iPhone.git
- cd CoreML-on-iPhone/Practice\ App/
- open coreml\ test.xcodeproj/
這會(huì)在Xcode打開(kāi)我們的項(xiàng)目。
在Xcode窗口中我用紅色標(biāo)示了三個(gè)重要區(qū)域:
- 左上角的播放按鈕用來(lái)啟動(dòng)app在模擬器運(yùn)行。
- 播放按鈕的正下方列出了與我們項(xiàng)目相關(guān)的文件和文件夾。這是項(xiàng)目導(dǎo)航欄,方便你找項(xiàng)目里的文件和文件夾。
- 播放按鈕旁邊寫(xiě)著iPhone 8,表示你想用模擬器仿真的目標(biāo)設(shè)備。你可以點(diǎn)擊它,在下拉列表里選擇iPhone 7。
讓我們開(kāi)始運(yùn)行app吧,看看會(huì)發(fā)生什么。點(diǎn)擊左上角的播放按鈕讓模擬器運(yùn)行app。在框中隨便鍵入些文字,點(diǎn)擊預(yù)測(cè)按鈕。發(fā)生了什么?
到現(xiàn)在,我們的app什么也沒(méi)做,只是原樣輸出框中鍵入的文字。
向你的app中添加一個(gè)訓(xùn)練好的模型
相當(dāng)簡(jiǎn)單:
- 將你的.mlmodel模型文件拖入到Xcode窗口工程導(dǎo)航欄中。
- 做好后,會(huì)彈出一個(gè)含有幾項(xiàng)選擇的窗口,默認(rèn)缺省,點(diǎn)擊“結(jié)束”。
- 當(dāng)你像這樣拖拽文件到Xcode時(shí),自動(dòng)在工程中生成該文件的參考路徑。這樣你能輕松地在代碼中獲取該文件。
編譯模型
在能夠用我們的模型進(jìn)行推測(cè)之前,需要讓Xcode在建立階段中編譯模型。以下是具體步驟:
在工程導(dǎo)航欄中選擇有藍(lán)色標(biāo)識(shí)的文件
會(huì)在右手邊打開(kāi)工程設(shè)置。點(diǎn)擊Compile Sources(編譯源)并選擇+標(biāo)識(shí)。
在新出現(xiàn)的窗口中選擇 SpamMessageClassifier.mlmodel文件,點(diǎn)擊新增。
現(xiàn)在每次運(yùn)行app,Xcode就會(huì)編譯我們的機(jī)器學(xué)習(xí)模型,使它能用來(lái)做預(yù)測(cè)。
在代碼中創(chuàng)建模型
任何為蘋(píng)果設(shè)備開(kāi)發(fā)的app都用swift編程。你不需要學(xué)swift但如果以后你有興趣深入,你可以跟著這個(gè)教程學(xué)。
在工程導(dǎo)航欄中選擇 ViewController.swift。這一文件包含大部分控制app功能的代碼。
第24行的 predictSpam() 函數(shù)會(huì)做最多的工作。刪除第25行,向函數(shù)中添加以下代碼:
- 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"
- }
以上代碼檢查用戶(hù)是否向框內(nèi)輸入了任何信息。如果有,調(diào)用tfidf()函數(shù)計(jì)算文本的tfidf值。然后生成一個(gè)SpamMessageClassifier 對(duì)象實(shí)例,再調(diào)用.prediction() 函數(shù)。這與sklearn中的 .predict() 函數(shù)相同。然后基于預(yù)測(cè)展示恰當(dāng)?shù)男畔ⅰ?/p>
但為什么需要tfidf()?
記住我們基于文本的tf-idf表征來(lái)訓(xùn)練模型,因此我們的模型需要相同形式的輸入。一旦獲得鍵入的文本框的信息,就調(diào)入tfidf()函數(shù)來(lái)做同樣的事。來(lái)寫(xiě)這一步的代碼吧,復(fù)制下列代碼放在predictSpam()函數(shù)后:
- //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()
- }
- }
以上代碼得到文本框內(nèi)輸入信息的tfidf表征,為此讀取SMSSpamCollection.txt原始數(shù)據(jù)庫(kù)并返回同樣信息。一旦你保存項(xiàng)目然后再次運(yùn)行模擬器,你的app就會(huì)運(yùn)行良好。
4、CoreML優(yōu)缺點(diǎn)
像每個(gè)發(fā)展中的庫(kù)一樣,CoreML有優(yōu)點(diǎn)也有缺點(diǎn)。讓我們說(shuō)清楚。
優(yōu)點(diǎn):
- 對(duì)在移動(dòng)設(shè)備上運(yùn)行性能進(jìn)行優(yōu)化,最小化內(nèi)存和能量消耗。
- 在移動(dòng)設(shè)備上運(yùn)行保證了用戶(hù)隱私,不再需要將數(shù)據(jù)發(fā)給服務(wù)器做預(yù)測(cè)。
- 在移動(dòng)設(shè)備上運(yùn)行意味著甚至在沒(méi)聯(lián)網(wǎng)的時(shí)候都可以做預(yù)測(cè),此外對(duì)用戶(hù)來(lái)說(shuō)反應(yīng)時(shí)間更短。
- 能自己決定在CPU還是GPU上運(yùn)行(或者都有)。
因?yàn)樗梢杂肅PU,所以你能在iOS模擬器上運(yùn)行它(iOS模擬器不支持GPU)。
提供了很多模型,因?yàn)樗軓钠渌髁鳈C(jī)器學(xué)習(xí)框架中引入模型:
- 支持向量機(jī)(SVM)
- 樹(shù)集成,如隨機(jī)森林、提升樹(shù)
- 線(xiàn)性回歸和邏輯回歸
- 神經(jīng)網(wǎng)絡(luò):前向反饋、卷積、循環(huán)
缺點(diǎn):
- 只支持有監(jiān)督模型,不支持無(wú)監(jiān)督模型和強(qiáng)化學(xué)習(xí)。
- 不支持模型在設(shè)備上再訓(xùn)練,只能做預(yù)測(cè)。
- 如果CoreML不支持某種層,你就不可以使用。目前還不能用自己的層擴(kuò)展CoreML。
- CoreML工具只支持少量訓(xùn)練工具的特定版本(竟然不支持tensorflow)。
- 不能看中間層的輸出,只能得到預(yù)測(cè)結(jié)果。
- 只支持回歸和分類(lèi)(不支持聚類(lèi)、排序、降維等)。
結(jié)語(yǔ)
本文中,我們學(xué)習(xí)了CoreML及應(yīng)用它開(kāi)發(fā)iPhone機(jī)器學(xué)習(xí)app。CoreML是一個(gè)較新的庫(kù),因此有自己的優(yōu)點(diǎn)和缺點(diǎn)。有一個(gè)非常有用的優(yōu)點(diǎn)是它在本地設(shè)備上運(yùn)行,因此速度更快,保證數(shù)據(jù)隱私。但同時(shí),它功能不全面,對(duì)數(shù)據(jù)科學(xué)家的需求考慮還不夠周全。期待后續(xù)版本會(huì)改進(jìn)。
如果你在某個(gè)步驟遇到困難,本文所有代碼都在GitHub上。