This post have got access from the original author Avihay Assouline to translate into Chinese. If you are interest in this article and want to repost it, you should add the refer link to this article in your repost.
這篇文章已從英文原作者Avihay Assouline那里得到翻譯授權(quán),如果你對(duì)本文感興趣而且想轉(zhuǎn)發(fā),你應(yīng)該在轉(zhuǎn)發(fā)文章里加上本文的鏈接。
深度學(xué)習(xí)與App的魔幻結(jié)合
打造你自己的自動(dòng)駕駛汽車(chē)的第一步,是教會(huì)你的App從18000張圖片中識(shí)別交通燈

機(jī)器學(xué)習(xí)是發(fā)展最快和最令人興奮的領(lǐng)域之一,而其中最有代表性的是深度學(xué)習(xí)。自從我回到大學(xué),我一直專(zhuān)注于這個(gè)領(lǐng)域。然而,在2009年的時(shí)候,軟硬件和數(shù)據(jù)并不能達(dá)到實(shí)現(xiàn)深度學(xué)習(xí)的要求。但是,自從那以后,這些都不再是問(wèn)題。
在這個(gè)簡(jiǎn)短的入門(mén)指南中,我將會(huì)通過(guò)深度學(xué)習(xí)的一些基本步驟,示范一下如何自己入門(mén)深度學(xué)習(xí)。我們將開(kāi)發(fā)一款使用現(xiàn)場(chǎng)相機(jī)數(shù)據(jù)來(lái)識(shí)別交通燈的app。
在我們開(kāi)始學(xué)習(xí)之前,我想說(shuō)明一下一些事情。這個(gè)入門(mén)教程會(huì)跳過(guò)一些概念和難點(diǎn),以便于降低入門(mén)門(mén)檻和盡快實(shí)現(xiàn)真實(shí)測(cè)試。另外,我們將只使用深度學(xué)習(xí)中的圖片分類(lèi),以使整個(gè)入門(mén)過(guò)程變得更加直接和簡(jiǎn)單。
簡(jiǎn)介
在這里我假設(shè)你對(duì)深度學(xué)習(xí)有一定了解。你可能見(jiàn)過(guò)一些使用了深度學(xué)習(xí)的產(chǎn)品,比如Facebook的臉部識(shí)別,Apple的Siri,Mobileye的車(chē)輛碰撞識(shí)別等等。然而,隨著最近深度學(xué)習(xí)框架的開(kāi)源,不僅僅巨頭們可以開(kāi)發(fā)這些產(chǎn)品,創(chuàng)業(yè)公司現(xiàn)在也可以參與其中。例如, Clarifai 為你的應(yīng)用提供了視覺(jué)能力, AIDoc 對(duì)醫(yī)學(xué)放射工業(yè)發(fā)起了挑戰(zhàn)。這些可以看出使用場(chǎng)景正在改變。
深度學(xué)習(xí)
什么是深度學(xué)習(xí)?什么是神經(jīng)網(wǎng)絡(luò)?我可以在這里討論一下這些。但是,我更希望你看看這個(gè)由吳恩達(dá)講解的深度學(xué)習(xí)的視頻。雖然這段視頻有點(diǎn)長(zhǎng),但是吳恩達(dá)提供了一些很好的例子和講解。
如果你沒(méi)有時(shí)間去看完這段視頻,這里有一些里面說(shuō)的的重點(diǎn):在過(guò)去,為了讓我們的電腦能夠執(zhí)行不同的任務(wù),我們不得不為每個(gè)小問(wèn)題單獨(dú)編寫(xiě)算法。機(jī)器學(xué)習(xí)的強(qiáng)大之處在于,它能夠使用同一種算法進(jìn)行學(xué)習(xí)。它能夠自己發(fā)現(xiàn)問(wèn)題的關(guān)鍵和嘗試自己去解決問(wèn)題。在這個(gè)教程中你可以看到,除了提供數(shù)據(jù)給算法,我們幾乎沒(méi)有改變?nèi)魏螙|西,然而它卻能自己學(xué)習(xí)一個(gè)新的概念:交通燈。
訓(xùn)練過(guò)程
訓(xùn)練我們自己的深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò),是實(shí)踐學(xué)習(xí)算法的一步。我們提供一個(gè)圖片分類(lèi)的數(shù)據(jù)集給算法,希望它學(xué)習(xí)如何分類(lèi)不屬于訓(xùn)練數(shù)據(jù)集的新圖片。
假設(shè)我們能夠獲得所需要的數(shù)據(jù)(這里稱為“訓(xùn)練集”),用于訓(xùn)練我們的算法。然而,像人類(lèi)一樣,算法在訓(xùn)練期間是需要對(duì)其行為進(jìn)行反饋的。為了實(shí)現(xiàn)對(duì)算法的行為反饋進(jìn)行驗(yàn)證,我們需要為算法提供一個(gè)叫“驗(yàn)證集”的獨(dú)立數(shù)據(jù)集。
在完成訓(xùn)練以后,我們將使用“訓(xùn)練集”中沒(méi)有的數(shù)據(jù)作為輸入數(shù)據(jù),并看看它的表現(xiàn)如何。你猜對(duì)了,我們將需要第三個(gè)被稱為“測(cè)試集”的數(shù)據(jù)集,這個(gè)數(shù)據(jù)集將會(huì)幫我們測(cè)試出算法的識(shí)別精確度。
我們總共需要3個(gè)不同的數(shù)據(jù)集:訓(xùn)練,驗(yàn)證,測(cè)試。
遷移學(xué)習(xí)
在實(shí)踐中,我們不會(huì)經(jīng)常從零開(kāi)始訓(xùn)練我們的深度學(xué)習(xí)網(wǎng)絡(luò)。因?yàn)楝F(xiàn)實(shí)中,很難找到足夠大的數(shù)據(jù)集來(lái)做一些復(fù)雜任務(wù),例如圖片分類(lèi)。

一般來(lái)說(shuō),我們會(huì)直接使用經(jīng)過(guò)大量數(shù)據(jù)訓(xùn)練的網(wǎng)絡(luò)作為初始的深度學(xué)習(xí)網(wǎng)絡(luò)。在我們這個(gè)例子中,我們使用了一個(gè)經(jīng)過(guò)一百萬(wàn)張圖片訓(xùn)練的預(yù)訓(xùn)練神經(jīng)網(wǎng)絡(luò),并用它來(lái)從20000張圖片中學(xué)習(xí)新的分類(lèi)。
這個(gè)小技巧確實(shí)有效,作為分類(lèi)問(wèn)題的一部分是共通的,例如識(shí)別邊緣,顏色,甚至形狀。
移動(dòng)設(shè)備的機(jī)遇
如果你對(duì)現(xiàn)今的世界足夠關(guān)注,你就能理解數(shù)據(jù)才是深度學(xué)習(xí)中最重要的東西。沒(méi)有足夠數(shù)量的數(shù)據(jù),我們的算法將不能根據(jù)問(wèn)題去學(xué)習(xí)并產(chǎn)生令人滿意的結(jié)果。
這里有一個(gè)對(duì)于移動(dòng)開(kāi)發(fā)者來(lái)說(shuō)非常巨大的機(jī)遇。全世界超過(guò)20億設(shè)備不斷提供各種不同類(lèi)型的數(shù)據(jù),這是非常有可能去開(kāi)發(fā)一款應(yīng)用去收集高質(zhì)量數(shù)據(jù),用于訓(xùn)練和學(xué)習(xí)。很多成功的創(chuàng)業(yè)公司都是圍繞這個(gè)想法而建立的。
使用Caffe進(jìn)行深度學(xué)習(xí)
Caffe
Caffe 是一個(gè)由Berkeley Visio和學(xué)習(xí)中心(BVLC)以及社區(qū)貢獻(xiàn)者一同開(kāi)發(fā)的深度學(xué)習(xí)框架。這個(gè)框架被世界范圍內(nèi)的計(jì)算機(jī)視覺(jué)研究者使用。盡管這是一個(gè)主要為計(jì)算機(jī)視覺(jué)開(kāi)發(fā)的框架,然而他可以做其他很多深度學(xué)習(xí)的工作。
DIGITS
英偉達(dá)的 DIGITS 使用了web交互界面簡(jiǎn)化了深度學(xué)習(xí)的一般步驟,例如:
- 數(shù)據(jù)集管理
- 在多GPU系統(tǒng)中設(shè)計(jì)和訓(xùn)練神經(jīng)網(wǎng)絡(luò)
- 通過(guò)先進(jìn)的虛擬化進(jìn)行實(shí)時(shí)性能管理
DIGITS 交互非常簡(jiǎn)單,開(kāi)發(fā)者只需要專(zhuān)注于神經(jīng)網(wǎng)絡(luò)的設(shè)計(jì)和訓(xùn)練,不需要投入太多精力到編程和調(diào)試。
硬件要求
訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)是一項(xiàng)計(jì)算密集型的工作。雖然你可以只通過(guò)只有CPU的機(jī)器來(lái)運(yùn)行,但是事實(shí)上你更需要一個(gè)擁有GPU(例如英偉達(dá)的GTX系列,$500 - $700)的性能強(qiáng)大的機(jī)器來(lái)運(yùn)行神經(jīng)網(wǎng)絡(luò)。
如果你沒(méi)有這樣一個(gè)性能強(qiáng)大的機(jī)器,你可以從亞馬遜那里租一個(gè)。例如你可以從spotinst這里獲取相關(guān)的服務(wù),而且只需要 0.2 美元/小時(shí)。如果你需要更多的幫助,可以聯(lián)系我。
開(kāi)發(fā)一個(gè)識(shí)別交通燈的App
這里我們開(kāi)始開(kāi)發(fā)一個(gè)你之前在視頻中看到的能識(shí)別交通燈的app。沒(méi)什么需要擔(dān)心的,所有的代碼都在Github上開(kāi)源。
為了繼續(xù)這個(gè)教程,你應(yīng)該先安裝Caffe和DIGITS。在這個(gè)教程中,我們將直接使用DIGITS的web交互界面,因此不需要在學(xué)習(xí)其他任何語(yǔ)言或框架。
通過(guò)使用Caffe & DIGITS,我們?cè)谝粋€(gè)預(yù)訓(xùn)練的網(wǎng)絡(luò)中實(shí)施遷移學(xué)習(xí),并教會(huì)它紅綠交通燈的新概念。然后,我們將把經(jīng)過(guò)訓(xùn)練的網(wǎng)絡(luò)應(yīng)用到我們一個(gè)簡(jiǎn)單的移動(dòng)應(yīng)用中。
交通燈數(shù)據(jù)
很多創(chuàng)業(yè)公司和有開(kāi)創(chuàng)精神的組織開(kāi)源了一些非常有用的訓(xùn)練集。其中有一些設(shè)立了一些能贏取獎(jiǎng)金的比賽,例如Udacity,Kaggle等。
為了讓這個(gè)簡(jiǎn)單應(yīng)用運(yùn)行起來(lái),我將會(huì)使用Nexar的 Challenge #1 數(shù)據(jù)集。這個(gè)數(shù)據(jù)集包括 18,659 個(gè)標(biāo)有交通燈的圖片。針對(duì)每張圖片,有人手動(dòng)標(biāo)記了包含的是紅燈還是綠燈或者沒(méi)燈。在這個(gè)簡(jiǎn)單應(yīng)用中,我們只關(guān)注圖片是否存在交通燈,不關(guān)心交通燈的位置或其他。

訓(xùn)練
為了這個(gè)應(yīng)用能正常使用,我們將從GoogLeNet做一次遷移學(xué)習(xí)。幸運(yùn)的是,DIGITS的標(biāo)準(zhǔn)網(wǎng)絡(luò)中已經(jīng)包含了這個(gè)。我們只需下載預(yù)訓(xùn)練caffmodel文件并用DIGITS打開(kāi)即可。
非常幸運(yùn),我有權(quán)限使用一個(gè)強(qiáng)大的機(jī)器,這個(gè)機(jī)器專(zhuān)門(mén)用來(lái)做VR體驗(yàn),而且擁有一個(gè)運(yùn)行在Ubuntu 14.04 平臺(tái)上的GTX 1070 GPU。對(duì)于一些人來(lái)說(shuō),看著訓(xùn)練過(guò)程一定是非常無(wú)聊的,特別當(dāng)你看到精度不斷提高時(shí)。

第一步,建立訓(xùn)練/驗(yàn)證/測(cè)試 數(shù)據(jù)集。DIGITS 提供一個(gè)便捷的方法。DIGITS根據(jù)它們的標(biāo)簽和你將要檢驗(yàn)和測(cè)試的數(shù)據(jù)劃分百分比,將所有樣本,劃分到不同的目錄。在我們的例子中,我們直接將DIGITS 一個(gè)目錄劃分為三個(gè)子目錄:紅,綠和背景。

第二步,建立模型。DIGITS 已經(jīng)包含了我們想要的GoogLeNet神經(jīng)網(wǎng)絡(luò)。GoogLeNet已經(jīng)通過(guò)訓(xùn)練能夠?qū)D片分成1000個(gè)不同的類(lèi)別。在我們的例子中,為了讓它能識(shí)別3種新的類(lèi)型,我們需要對(duì)它進(jìn)行一些改進(jìn)。不要擔(dān)心,這些只是一些簡(jiǎn)單的文本改動(dòng)。

我們要做的改動(dòng)是非常簡(jiǎn)單的: 查找/替換 所有出現(xiàn)loss1/classifier, loss2/classifier 和 loss3/classifier,并加上后綴‘/retrain’。例如 loss{x}/classifier 變成
loss{x}/classifier/retrain— 。 我們做這一步是為了讓我們的神經(jīng)網(wǎng)絡(luò)重新學(xué)習(xí),因?yàn)檫@新的部分與之前1000種分類(lèi)都不同。
為了能運(yùn)行遷移學(xué)習(xí),我們將使用預(yù)學(xué)習(xí)網(wǎng)絡(luò)信息(又稱權(quán)重),而這只需讓DIGITS 下載 bvlc_googlenet.caffemodel 這個(gè)預(yù)訓(xùn)練 caffe 模型即可。
值得慶賀,你現(xiàn)在已經(jīng)做好了訓(xùn)練網(wǎng)絡(luò)的準(zhǔn)備了。
根據(jù)默認(rèn)的訓(xùn)練設(shè)置, DIGITS 遷移學(xué)習(xí)能生成一個(gè)在驗(yàn)證集中精度達(dá)到 93.1% 的神經(jīng)網(wǎng)絡(luò)。難道這不令人興奮嗎?我們很難做到這一點(diǎn):)
訓(xùn)練完成之后,我們可以通過(guò)DIGITS下載我們的模型,然后獲取我們使用該模型開(kāi)發(fā)移動(dòng)應(yīng)用的必要數(shù)據(jù)。
開(kāi)發(fā)應(yīng)用
幸運(yùn)地,由于Aleph7和noradaiko做了一些基礎(chǔ)集成 ,我很容易的就可以將 Caffe 運(yùn)行在iOS上。除了使用這些基礎(chǔ)集成來(lái)作為我們的項(xiàng)目的開(kāi)始,我們還要改進(jìn)一下,以便它在相機(jī)的現(xiàn)場(chǎng)視頻流中能正常運(yùn)行。
這段代碼非常簡(jiǎn)單,讓我們來(lái)看一下 ViewController.mm 文件中最重要的部分:
NSString *netDefinition = [NSBundle.mainBundle pathForResource:@"deploy"
ofType:@"prototxt"
inDirectory:@"model"];
NSString *netWeights = [NSBundle.mainBundle pathForResource:@"model"
ofType:@"caffemodel"
inDirectory:@"model"];
NSString *datasetMean = [NSBundle.mainBundle pathForResource:@"mean"
ofType:@"binaryproto"
inDirectory:@"model"];
NSString *netLabels = [NSBundle.mainBundle pathForResource:@"labels"
ofType:@"txt"
inDirectory:@"model"];
string net_definition = string([netDefinition UTF8String]);
string net_weights = string([netWeights UTF8String]);
string dataset_mean = string([datasetMean UTF8String]);
string net_labels = string([netLabels UTF8String]);
classifier = new Classifier(net_definition,
net_weights,
dataset_mean,
net_labels);
我們通過(guò)DIGITS下載的文件model.caffemodel, mean.binaryproto, labels.txt 和 deploy.prototxt ,創(chuàng)建一個(gè)新的分類(lèi)器。
cv::Mat src_img, bgra_img;
UIImageToMat(image, src_img);
cv::resize(src_img, src_img, cv::Size(224, 224));
cv::cvtColor(src_img, bgra_img, CV_RGBA2BGR);
vector<Prediction> result = classifier->Classify(bgra_img, 3);
我們需要輸入各種尺寸的數(shù)據(jù)進(jìn)行分類(lèi)。為了做到這一點(diǎn),我們需要把我們的UIImage對(duì)象轉(zhuǎn)換為OpenCV的矩陣(第2行),改變其大小以適應(yīng)我們的網(wǎng)絡(luò),然后把顏色序列從 RGBA 轉(zhuǎn)換成 BGR。因?yàn)镃affe需要這樣的輸入格式,所以我們需要先做這個(gè)轉(zhuǎn)換。另外,你可能注意到,當(dāng)進(jìn)行分類(lèi)時(shí),這里有一個(gè)魔術(shù)數(shù)字‘3’。這表示的是你數(shù)據(jù)集分類(lèi)的數(shù)量 - 在我們這個(gè)例子中,表示:綠,紅,背景。
for (vector<Prediction>::iterator it = result.begin(); it != result.end(); ++it) {
NSString* mylabel = [NSString stringWithUTF8String:it->first.c_str()];
NSNumber* probability = [NSNumber numberWithFloat:it->second];
if (it == result.begin() && probability.floatValue > 0.6) {
_lightImage.image = [UIImage imageNamed:[labelToImage valueForKey:mylabel]];
}
}
接下來(lái),我們只需重復(fù)識(shí)別和捕獲最高確定性的識(shí)別。如果它通過(guò)了一些閥值(當(dāng)前設(shè)定為 60% 確定性)我們將用正確的交通燈圖片更新我們的UI。
準(zhǔn)備去讓你的數(shù)據(jù)跑起來(lái)嗎?非常好!
你必須做的的所有事情,只是改變了一開(kāi)始訓(xùn)練的樣本和改變分類(lèi)的數(shù)目。其他所有的東西都是不變的。
這是關(guān)于這個(gè)app的另外一段短視頻:
我能在我的線上App上用它嗎?
當(dāng)然,最好不。至少我現(xiàn)在不推薦。這個(gè)有點(diǎn)例子太過(guò)于笨拙以至于不適合直接使用。
你應(yīng)該在你桌面之外使用這個(gè)項(xiàng)目,去體驗(yàn)和測(cè)試你的算法,這是一種不需要編碼就能測(cè)試你的POC項(xiàng)目的好方法。你也可以用它來(lái)開(kāi)發(fā)快速應(yīng)用,去收集你在訓(xùn)練過(guò)程中輸入的新數(shù)據(jù)。
一旦你掌握了這個(gè)訓(xùn)練過(guò)程,你接下來(lái)將很容易的過(guò)渡到學(xué)習(xí)TensorFlow,或其他需要對(duì)深度學(xué)習(xí)有更深入理解的框架,例如 BrainCore。
如果你喜歡這篇文章,并且想繼續(xù)關(guān)注,請(qǐng)點(diǎn)擊 ? (喜歡) - 這將是我繼續(xù)下一篇的動(dòng)力!
你也可以在Twitter中關(guān)注英文原文作者。
如果你喜歡這篇譯文,記得在簡(jiǎn)書(shū)中給我點(diǎn)贊并關(guān)注我哦
本文Github地址