深度学习及AR在移动端打车场景下的应用
本文內(nèi)容根據(jù)作者在美團Hackathon 4.0中自研的項目實踐總結(jié)而成。作為美團技術(shù)團隊的傳統(tǒng)節(jié)目,每年兩次的Hackathon已經(jīng)舉辦多年,產(chǎn)出很多富于創(chuàng)意的產(chǎn)品和專利,成為工程師文化的重要組成部分。本文就是2017年冬季Hackathon 4.0一個獲獎項目的實踐總結(jié)。
前言
2017年在移動端直接應(yīng)用AI算法成為一種主流方向。Apple也在WWDC 2017上重磅推出Core ML框架。準備Hackathon的過程中,我們就想能否基于Core ML的深度學習能力,結(jié)合AR,做酷一點的產(chǎn)品。我們觀察到在晚上下班時間,是公司的打車高峰時段,這時候經(jīng)常會有一堆車在黑暗中打著雙閃,你很難通過辨認車牌去找到你叫的專車,所以我們把產(chǎn)品定向為一個打車時幫助用戶找到車的App。
很快我們就把上面的想法落地實現(xiàn)了,開發(fā)了一個叫做WhereAreYou的簡單App應(yīng)用,相當于AR版本的微信共享位置,只要打開攝像頭就可以看到小伙伴們的方位和遠近。當然了,應(yīng)用于打車場景下,就是讓用戶知道目標車輛從何駛來、距離多遠。程序大概結(jié)構(gòu)如圖1所示:
遠距離下使用AR幫助用戶找到目標方位
我們用Node.js寫了一個簡單的服務(wù),用戶可以創(chuàng)建一個共享位置的group,其他用戶拿到groupID后可以加入這個組,接著程序會通過服務(wù)來共享他們各自的GPS信息,同一個group內(nèi)的成員可以在地圖上看到其他成員的位置。值得一提的是,我們添加了一個AR模式,成員點擊AR按鈕后可以進入,此時攝像頭會被打開,如果同一個組的其他小伙伴方位距離此用戶很近,屏幕上就會出現(xiàn)一個3D模型,告訴用戶附近有某某小伙伴,距離此地的遠近等信息。主要過程和效果如圖2所示:
項目做到這里都很順利,接下來就遇到了一些難點,主要是利用ARKit渲染模型的部分。其中有一個問題是如何把兩個GPS空間上的方位反映到用戶屏幕上,經(jīng)過一些努力,我們終于攻克這個難關(guān),這里可以分享一點干貨:
那么問題來了,如何將一個3D模型顯示在屏幕正中央 \(\gamma\) 處呢?這里就用到了ARKit的ARSCNView中的模型渲染API,跟OpenGL類似,ARSCNView從創(chuàng)建之初會設(shè)置一個3D世界原點并啟動攝像頭,隨著手機的移動,攝像頭相當于3D世界中的一個眼睛,可以用一個觀察矩陣[camera]表示。這樣在屏幕正中央俯視偏角 \(\gamma\) 處渲染一個3D節(jié)點的問題,其實就是如何才能把觀測坐標轉(zhuǎn)換為世界坐標的問題。我們首先將物體放在手機前3米處,然后直接根據(jù)下圖所示公式就可求得最終坐標:
下面是在ARSCNView每次重新渲染回調(diào)中設(shè)置模型位置的邏輯:
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {guard let renderLocations = self.netGroupInfo?.locations?.filter({ (userLocation) -> Bool inreturn userLocation.userId != GroupMenberManager.sharedInstance.getCurrentUserID()}) else {return}DispatchQueue.main.async {guard let camera = self.sceneView.pointOfView else { return }//當前用戶定位let currentLocation = UserLocation() currentLocation.latitude = GroupMenberManager.sharedInstance.userLatitudecurrentLocation.longitude = GroupMenberManager.sharedInstance.userLongitute// 循環(huán)處理當前組內(nèi)其他成員for renderLocation in renderLocations {// 兩點間距離公式求得距離用來控制3D模型字體大小,直觀的反應(yīng)距離的遠近let distance = currentLocation.distanceFrom(renderLocation)// 求得兩個用戶間的坐標關(guān)系let angle = currentLocation.angleFrom(renderLocation)// 根據(jù)上述公式求得3D模型要渲染的最終位置 compassAngle為實時獲取的陀螺儀指南針方向var position = SCNVector3(x: 0, y: 0, z: -3).roateInHorizontalPlaneBy(angle: self.compassAngle - angle)position = camera.convertPosition(position, to: nil)//穩(wěn)定在水平上position.y = 0;//更新位置self.virtualObjectManager.findVirtualObject(renderLocation.userId ?? "")?.scnNode.position = position//根據(jù)距離更新模型文字和大小self.virtualObjectManager.findVirtualObject(renderLocation.userId ?? "")?.changeNodeTextAnSize(text: renderLocation.userTitle, distance: distance)}}}寫了一個周末差不多把上面功能完成,這個時候?qū)τ趨①惈@獎是沒有任何底氣的。因為其實這個點子并不十分新穎,技術(shù)難點也不夠。最主要的痛點是,我們真機聯(lián)調(diào)測試的時候發(fā)現(xiàn),在10m范圍內(nèi)GPS定位的精度完全不可靠,屏幕中渲染的點位置經(jīng)常錯亂。我們之前知道近距離GPS定位會不準,卻沒想到3D模型在屏幕上對誤差的反應(yīng)這么敏感,這樣的話比賽時現(xiàn)場演示是絕對不行的。
既然GPS近距離定位不準無法解決,我們決定在近距離時放棄GPS用另一種方式提醒用戶目標在哪里。
近距離下使用AI算法找到目標
我們做了一個設(shè)想,就是讓程序在10米范圍能夠智能地去主動尋找到目標,然后在手機屏幕上標注出來。
之后我們對視覺算法在移動端實現(xiàn)的現(xiàn)狀進行調(diào)研,發(fā)現(xiàn)隨著近幾年計算機視覺飛躍式發(fā)展,網(wǎng)上各種開源圖片分類識別算法有很多,加上2017 年年初Apple推出了非常靠譜的Core ML,所以在短時間內(nèi)實現(xiàn)一個移動端的“目標發(fā)現(xiàn)”算法是可行的。
在確定WhereAreYou需要添加的功能后,我們立足于打車找車這個問題進行調(diào)研開發(fā),最后終于實現(xiàn)了一個穩(wěn)定、高效、實時的基于多種CNN模型混合的車輛發(fā)現(xiàn)跟蹤算法,下面GIF可以看到效果。
在使用完Core ML之后,真心覺得它確實如Apple在WWDC 2017上所言,性能十分優(yōu)越。由此可以預見之后幾年,在移動端直接應(yīng)用AI算法的優(yōu)秀App會層出不窮。
扯遠了,上點干貨吧!
在說我們的《基于多種CNN模型混合的車輛發(fā)現(xiàn)跟蹤算法及其移動端實現(xiàn)》之前,先說一下Apple的Core ML能幫我們做到哪一步。
Core ML 是一個可以讓開發(fā)者很容易就能在應(yīng)用中集成機器學習模型(Machine Learning Models)的應(yīng)用框架,在 iOS、watchOS、macOS和tvOS上都可以使用它。Core ML使用一種新的文件格式(.mlmodel),可以支持多種類型的機器學習模型數(shù)據(jù),比如一些深度神經(jīng)網(wǎng)絡(luò)算法(CNN、RNN),決策樹算法(boosted trees、random forest、decision trees),還有一些廣義的線性模型(SVM、Kmeans)。Core ML models以.mlmodel文件的形式直接集成到開發(fā)應(yīng)用中,文件導入后自動生成對應(yīng)的工具類可直接用于分類識別等AI功能。
我們知道通過Keras、Caffe、libsvm 等開源學習框架可以生成相應(yīng)的模型文件,但這些模型文件的格式并不是.mlmodel。Core ML Tools可以對這些文件進行轉(zhuǎn)換,生成.mlmodel文件,將目前比較流行的開源學習框架訓練出的模型直接應(yīng)用在Core ML上,如圖8所示:
coremltools本身是一個Python工具包,它可以幫我們完成下面幾件事情:
- 第一點就是剛剛提到的將一些比較出名的開源機器學習工具(如Keras、Caffe、scikit-learn、libsvm、XGBoost)訓練出來的模型文件轉(zhuǎn)換為.mlmodel。
- 第二點是提供可以自定義轉(zhuǎn)換的API。打個比方,假設(shè)Caffe更新到了Caffe 3.0,本身模型的文件格式變了,但coremltools還沒來及更新,這時就可以利用這些API自己寫一個轉(zhuǎn)換器。
- coremltools工具本身可以使用上述所說的各種開源機器學習工具訓練好的模型進行決策。
看到這里是不是內(nèi)心很澎湃?是的,有了這個工具我們可以很方便地把訓練好的模型應(yīng)用到Apple設(shè)備上,所以趕緊安裝吧!步驟很簡單,機器上有Python(必須是Python 2.X)環(huán)境后執(zhí)行pip install -U coremltools就好了。
那如何進行轉(zhuǎn)換呢?舉一個例子:
我們可以到Caffe Model Zoo上下載一個公開的訓練模型。比如我們下載web_car,這個模型可以用于車型識別,能夠區(qū)分奔馳、寶馬等諸多品牌的各系車型約400余種。下載好web_car.caffemodel、deploy.prototxt、class_labels.txt這三個文件,寫一個簡單的Python腳本就可以進行轉(zhuǎn)換了。
import coremltools# 調(diào)用caffe轉(zhuǎn)換器的convert方法執(zhí)行轉(zhuǎn)換 coreml_model = coremltools.converters.caffe.convert(('web_car.caffemodel', 'deploy.prototxt'), image_input_names = 'data', class_labels = 'class_labels.txt')# 保存轉(zhuǎn)換生成的分類器模型文件 coreml_model.save('CarRecognition.mlmodel')coremltools同時還提供了設(shè)置元數(shù)據(jù)描述的方法,比如設(shè)置作者信息、模型輸入數(shù)據(jù)格式描述、預測輸出張量描述,較為完整的轉(zhuǎn)換腳本如下:
import coremltools# 調(diào)用caffe轉(zhuǎn)換器的convert方法執(zhí)行轉(zhuǎn)換 coreml_model = coremltools.converters.caffe.convert(('googlenet_finetune_web_car.caffemodel', 'deploy.prototxt'), image_input_names = 'data', class_labels = 'cars.txt')# 設(shè)置元數(shù)據(jù) coreml_model.author = 'Audebert, Nicolas and Le Saux, Bertrand and Lefevre Sebastien' coreml_model.license = 'MIT' coreml_model.short_description = 'Predict the brand & model of a car.' coreml_model.input_description['data'] = 'An image of a car.' coreml_model.output_description['prob'] = 'The probabilities that the input image is a car.' coreml_model.output_description['classLabel'] = 'The most likely type of car, for the given input.'# 保存轉(zhuǎn)換生成的分類器模型文件 coreml_model.save('CarRecognition.mlmodel')上面所說的“可以讓開發(fā)者很容易地在應(yīng)用中集成機器學習模型”是什么意思呢?是指如果你有一個CarRecognition.mlmodel 文件,你可以把它拖入到Xcode中:
Xcode會自動生成一個叫做CarRecognition的類,直接使用其預測方法就好了。比如對一個汽車圖片做識別,像這樣:
let carModel = CarRecognition() let output = try carModel.prediction(image: ref)基于上述Core ML提供的功能結(jié)合一些開源模型算法我們完成了《基于多種CNN模型混合的車輛發(fā)現(xiàn)跟蹤算法及其移動端實現(xiàn)》。
首先說一下大概的算法流程,還記得本文一開始在圖1中提到的WhereAreYou程序結(jié)構(gòu)圖嗎?現(xiàn)在我們在AR模塊中添加主動尋找目標的功能。當目標GPS距離小于50米時,算法被開啟。整個識別算法分為目標檢測、目標識別以及目標追蹤。當攝像頭獲取一幀圖片后會首先送入目標檢測模塊,這個模塊使用一個CNN模型進行類似SSD算法的操作,對輸入圖片進行物體檢測,可以區(qū)分出場景中的行人、車輛、輪船、狗等物體并輸出各個檢測物體在圖片中的區(qū)域信息。
我們篩選所有汽車目標,將對應(yīng)物體的圖片截取后送入目標識別模塊,對車型進行識別。之后拿到識別出的車型跟車主上傳的車型進行對比,如果車主的車型跟識別出的結(jié)果一致,就將當前幀和目標區(qū)域送入目標跟蹤模塊,并對當前車輛進行持續(xù)跟蹤。當然如果跟蹤失敗就從頭進行整個過程。具體如圖10所示:
下面說一下為什么要結(jié)合這三種算法進行“尋找車主汽車”這個任務(wù):
大家應(yīng)該還記得剛剛介紹coremltools的時候舉的一個例子,在例子中我們在Caffe Model Zoo下載了一個車型識別的算法模型。沒錯,我們這個結(jié)合算法其目標識別模塊中用的車型識別正是這個模型。最初調(diào)研時,在caffe上找到這個開源模型很開心,覺得把這個模型下載好后轉(zhuǎn)換一下應(yīng)用到工程中就完事了。結(jié)果發(fā)現(xiàn),實際上將拍攝到的整幅圖片送入這個模型得到的識別正確率幾乎為零。分析原因是因為這個模型的訓練數(shù)據(jù)是汽車的完整輪廓,而且訓練圖片并無其它多余背景部分。而現(xiàn)實中用戶不可能只拍汽車,場景中汽車只是很小的一個區(qū)域,大部分還是天空、馬路、綠化帶等部分,整幅圖片不做截取直接進行處理識別率當然不行。所以只有先找到場景中的車在哪,然后再識別這個是什么車。
在一副圖片中標定場景中出現(xiàn)的所有車輛的位置,其實就是SSD問題(Single Shot MultiBox Detector),進一步調(diào)研可以了解到近幾年基于CNN的SSD算法層出不窮,各種論文資料也很多。其中要數(shù)康奈爾大學的YOLO算法尤為出名。更重要的是原作者提供了一個他訓練好的模型,這個模型在GitHub上就可以下載,沒錯我們結(jié)合算法其目標檢測中的模型算法就是使用的這個→_→ 。
YOLO算法的一個特性就是其檢測識別速度十分快,這是由其網(wǎng)絡(luò)結(jié)構(gòu)和輸入結(jié)構(gòu)決定的。YOLO模型輸出張量結(jié)構(gòu)決定了在屏幕上如何截取對應(yīng)圖片區(qū)域,這里簡單介紹一下,概念不嚴謹之處還請各位不吝賜教。如圖11所示,YOLO算法將輸入圖片分為13 × 13個小塊,每張圖片的各個小塊對應(yīng)到其所屬物體的名稱和這個物體的范圍。打個比方圖11中狗尾巴處的一個小塊對應(yīng)的是狗和這個狗在圖片中的位置(dog、x、y、width、height),算法支持20種物體的區(qū)分。通過網(wǎng)絡(luò)預測得到的張量為13 × 13 × 125。
其具體意義是一張圖片中所有小塊(共13 × 13個)每次預測得到5組結(jié)果,每組結(jié)果對應(yīng)一個矩形區(qū)域信息(x、y、width、height)代表本小塊所屬的目標區(qū)域,同時給出這個區(qū)域確信是一個目標的概率(confidence,這里的“確信是一個目標”是指20種物體任意一個即可),還有 20種物體各自的確信概率。即125 = 5 × 25(x、y、width、height、confidence、Class1Confidence、Class2Cconfidence……)。了解這點后我們就不難截取最終識別結(jié)果所對應(yīng)的圖片區(qū)域了(當然只選取置信率比較高的前幾個)。
圖12展示了YOLO高效地執(zhí)行結(jié)果,圖13展示了YOLO目標檢測與車輛識別結(jié)合后的執(zhí)行效果。
算法到此時可以算是差不多了,但從圖13中還是可以看到一些問題:
識別的結(jié)果并不是每幀圖片都是對的,而且也并不是每幀圖片都能檢測出場景中的每一個車輛。這樣就會導致在屏幕上標注車輛位置提示用戶時會出現(xiàn)斷斷續(xù)續(xù)。經(jīng)過調(diào)研后我們又加入了目標跟蹤的模塊。目標跟蹤的任務(wù)比較好理解,輸入一幀圖片和這張圖片中的一個區(qū)域信息,要求得出下一幀中這個區(qū)域?qū)?yīng)圖像所在位置,然后迭代此過程。目標跟蹤算法在深度學習火起來之前就比較成熟了,文獻和開源實現(xiàn)都比較多,我們選用 CoreML官方提供的跟蹤模塊進行處理,實驗效果發(fā)現(xiàn)還不錯,最終結(jié)果如上(圖7)所示。
各個模塊執(zhí)行時間統(tǒng)計如下:
總結(jié)
《基于多種CNN模型混合的車輛發(fā)現(xiàn)跟蹤算法及其移動端實現(xiàn)》這個項目由于時間原因還有很多缺陷,誠如當時評委意見所說的那樣“核心算法都是使用網(wǎng)上現(xiàn)有模型,沒有自己進行訓練”,此算法可以提高優(yōu)化的地方有很多。比如添加車輛顏色、車牌等檢測提高確認精度,優(yōu)化算法在夜間、雨天等噪聲環(huán)境下的表現(xiàn)等。
最后,通過這個項目的開發(fā)實現(xiàn)讓我們知道在移動端應(yīng)用CNN這樣的學習算法已經(jīng)十分方便,如圖15這樣構(gòu)建的移動端AI程序的執(zhí)行速度和效果都很不錯。希望我們的WhereAreYou項目就像能夠幫助用戶更快找到車一樣,給前端工程師提供多一些靈感。相信未來前端工程師能做的可以做的需求會越來越有趣!
參考文獻
- [1] Yang L, Luo P, Change Loy C, et al. A large-scale car dataset for fine-grained categorization and verification[C]//Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015: 3973-3981.
- [2] Redmon J, Farhadi A. YOLO9000: better, faster, stronger[J]. arXiv preprint arXiv:1612.08242, 2016.
- [3] https://developer.apple.com/machine-learning/ .
- [4] https://pypi.python.org/pypi/coremltools .
- [5] https://github.com/caffe2/caffe2/wiki/Model-Zoo .
作者簡介
- 大衛(wèi),美團前端iOS開發(fā)工程師,2016年畢業(yè)于安徽大學,同年加入美團到店餐飲事業(yè)群,從事商家移動端應(yīng)用開發(fā)工作。
總結(jié)
以上是生活随笔為你收集整理的深度学习及AR在移动端打车场景下的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最新阿里内推高级Java面试题
- 下一篇: 深度学习在美团的应用