程序猿 愉快地玩起Cozmo + 卷積神經網路
事情的開始是這樣的,今年年中左右,由於貪玩和手癢,一直想買些小玩具來消磨下時間(已經入手Nintendo Switch, 高達RG模型,紅環自動鉛筆等...),突然看到Cozmo的廣告,整個眼睛都亮了起來。因為大學時候有看過《機器人總動員》(英文名字《WALL·E》),對裡面的瓦力還有伊娃,還有執著清洗髒東西的小清潔機器人完全沒有抵抗能力,電子聲音,有限的動作和表情組合出來的情感表達,個性,實在是萌爆了。不巧,Anki 公司找來做這個動畫的人一起搗鼓了一個標榜有"個性"的機器人小玩具,我還能有什麼抵抗能力呢?這個不就是我兒時一直夢寐以求的玩具么!(1600 RMB,淘寶入手的,也是不便宜的說..)
玩具的具體外形評測還有好玩的功能科普這裡就不做贅述了。有興趣的朋友可以去Anki的官網看廣告視頻。拿到手後確實發現它像一個小寵物一樣撒歡玩耍。對於智能那塊,人臉識別,一些有趣地和周圍環境的反應確實也做得很贊,在它家公司上發現說有Python SDK 開放,而且臉部的攝像頭能拿到實時圖像,嘿嘿,感覺能搞點事情了。
時下比較熱門的一個互聯網領域的"風口" 是機器學習(machine learning),也有很高大上的別稱:人工智慧(AI)。對於這個大浪潮,我是持激動又敬畏的態度。在閱讀了不少文章和報道後,我個人以為:這貨還是叫回"機器學習"吧。畢竟和真正的"人工智慧",我感覺還有不少的距離。但是!確實從機器視覺領域還有自然語言領域等,憑藉機器硬體還有海量數據的時代到來,80年代提出的神經網路演算法,梯度反饋優化的方法終於重新綻放耀眼光彩。以前不那麼容易做的事情,比如說視頻實時手掌,人像追蹤(需要一些實驗後根據數學模型手動設置判別模型的參數,這裡由於不是太了解內部實現細節,如果有錯誤的地方,歡迎斧正),現在可以直接用大量數據(raw data)輸入後,結合人工神經網路里的反向梯度傳播方法修正每一層的誤差來直接訓練從而達到目的。這樣帶來的好處是:以前受限於需要大量對應專業知識(比如說識別人和識別金魚需要的是完全不一樣的領域專業知識來工程化,數學化模型建模)才能建模的門檻直接被這種"簡單","粗暴"的方式直接踏平。舉一個例子來說:火到瘋了的AlphaGo 的開發人員,據說沒有一個是圍棋高手,但是他們開發,"訓練"出來的AlphaGo,卻是直接打垮了地球最強人類棋手們。
有點扯遠了,咳咳,回到主題:玩Cozmo和卷積神經網路。為什麼突然會想著結合Cozmo 和神經網路來玩點東西?因為條件很成熟了:
- 發現了Cozmo的PythonSDK,由於用Python,所以比較容易上手,封裝得也不錯,所以手癢了。尤其是裡面附帶的一些app 里例子也很好玩,先自己搗鼓下。
- 計算機視覺(Computer Vision)這塊一直沒咋接觸,因為一直在做Linux 後台開發,但是看到機器學習這麼火,我忍不住了,究竟為啥這麼火呀?為啥這麼強大呀?我想自己也試著跟上一波潮流。實際做點東西,比一直觀望強多了。
- 在網上看到有教程用卷積神經網路(CNN)來做樹莓派車自動駕駛的教程,github上有開源代碼,tensorflow 的開源框架,python環境雖然安裝比較麻煩,但是也是免費的!(你還想咋樣?)看到別人都這麼牛,我更手癢了。
第一次實驗: Cozmo+CNN 跑道自動駕駛
咳咳,標題是很高大上,實際上掰開了,裡面不外乎就是Cozmo PythonSDK開發+ CNN 圖片識別的一次嘗試,讓我細細道來。
- 目標:讓Cozmo能自己通過攝像頭在我畫出來的簡易跑道上直行,轉彎。
- 軟體科技樹: Python ,Tensorflow, CNN , OpenCV
- 硬體科技樹: MacbookPro 一台(筆記本電腦就可以),iPhone一台, 數據線一條(用來連接手機和電腦, Cozmo和手機的連接是通過Cozmo自己的一個wifi 頻道,你沒看錯,這貨不是用藍牙,是wifi)
素材有了,github上找了半天也找到了用樹莓派的一個類似的實現,代碼也拿到了。Python SDK也有了,剩下的就是問題的核心:怎麼做到讓Cozmo通過攝像頭知道現在是得左(右)轉呢? 答案就是 一切都靠CNN 了!(說了等於沒說...)
第一次嘗試
首先, Cozmo的Python SDK 里有一個app, 通過Python flask 庫做到通過網站和鍵盤的方式可以實時地獲取Cozmo的攝像頭信息和操控Cozmo 前進後退,左右等SDK 開放的動作。具體github代碼鏈接在此。藉由這個代碼,我可以做到一件事情,在鍵盤按下(操控Cozmo 前進後退,左轉,右轉)的時候,把攝像頭獲取到的圖片和當時我的鍵盤按鍵保存下來,這樣,就給到神經網路訓練提供了raw data!是的,我們要訓練這個網路的就是讓它學會識別當時的圖像(攝像頭面對跑道的圖像)和按鍵的對應關係,到時候我們跑一個模型出來,餵給它實時的軌道圖像,那不就知道他應該是左轉,右轉還是直行了么?(對應jkil 幾個鍵)
藉由修改上面提到的remote_control_cozmo.py 的源碼,我保存下來當時Cozmo的攝像頭拍攝到的圖片如下:
還有對應的按鍵信息,大概5000多張圖片。來做為餵給神經網路的原始圖片集合。神經網路的結構也不複雜,
5個卷積層來過濾特徵,4個全連接層,沒有dropout,非常粗糙,但是,對於我們這個玩具模型,已經足夠work起來了!
代碼跑起來了,也不複雜,但是效果差得讓人髮指,雖然CNN 訓練出來第一次是有50%多的識別率我就興沖沖地想試一下,發現Cozmo 像瞎子+傻子一樣,直愣愣往前沖,根本停不下來,也不會轉彎。
試著優化一下
由於是第一次玩,對CNN 的了解說實話也就是看過幾篇文章還有書,知道用tensorflow 怎麼寫的程度。一開始覺著是不是網路深度不夠,參數不夠多導致?亂調了一通之後我覺越來越不靠譜,先拋開神經網路,就我熟悉的軟體開發,編程層面:是不是能先做一下調優?
契機在我重新閱讀 樹莓派自動駕駛代碼,發現之前我的解決方案里:學習鍵盤按鍵和圖片的對應關係,是由於我先看了一個教程,GTA自動駕駛 這個教程先入為主,把自動駕駛直接簡化成按鍵對應分類問題。人家能work 是因為他是在電腦上直接模擬駕駛,輸入就是鍵盤和對應圖片,但是現在我是在現實中,中間鍵盤轉車輪速度,方向這一層是否有損耗?而且人家樹莓派的車是學習圖片和當時車左右輪轉速的關係的!是不是這個導致我走了彎路?
深入去看,按鍵變換組合是讓車執行左轉右轉的關鍵!而我的修改代碼在操作Cozmo行事時候,代碼只記錄了一個按鍵而不是按鍵的操作組合!那按照樹莓派例子的方式,是不是就能愉快的玩起了?
改成上面這種模式,再重新簡單訓練一次CNN, model不變,在60%的acc 下,Cozmo已經能愉快地在"看到"彎道的時候,做出轉彎的反應了!
https://www.zhihu.com/video/912028453098905600雖然很粗糙,但是我第一次看到了cnn實際應用上的強大!試想下,幾年前,一個普通程序員能直接通過一些圖片和簡單數據,就寫出一個能轉彎的model?不可思議的說呢。
小小總結下
進過這個小demo的研究和實踐,我對CNN里的底層原理的探究慾望越發強烈,而且這個demo只是通過簡單的訓練,60%的acc(loss 有點記不清楚了),就能讓Cozmo學習到了在跑道上簡單轉彎的技能,看來人工神經網路真的不可小覷啊!同時這個小項目由於家裡事情,還有個人工作事情,暫時就停止了開發,源碼我簡單貼到了github上,現在暫時還沒法做到Cozmo自己完整走完一圈跑道的程度,純粹學習和瞎玩的一個小玩具。
- 代碼鏈接 github 地址,訓練圖片5000張我沒有上傳,依賴python sdk 環境來跑起來哈
- cnn 框架里,用了 卷積核3*3, 5*5,有些論文說是比較好的尺寸,還沒認真研究過,而且也沒有dropout層來做過擬合防止,反正我也是打算讓它在原有的跑道上跑,這個也還好。
- tensorflow 當時用的是1.0 版本(3個月前),現在都1.4了,還是原來的macbook pro,用更複雜的網路架構,是不是能獲得更好的識別率和效果?
第二次實驗:Cozmo和3DCNN來做簡單手勢識別
過了2個月差不多,我又重新回來搞Cozmo和機器學習的東西啦。但是由於某些原因,跑道不見了,而且重新搞一個也比較煩,所以我就想說能不能玩一點新的東西,恰好那天被我無聊看到了有個手勢識別挑戰的網站 鏈接在此 。網站里有 一個眾多網友錄製的手勢視頻的數據集合。20G左右,然後已經有分類成30多個手勢分類,每個視頻是30多張的圖片結合。非常贊。看到這些,我又想搗鼓一些小玩意了,嘿嘿。
- 目標:讓Cozmo 看到我做出某些手勢後,有對應的動作:比如說做一個向上抬的手勢後,Cozmo 就乖乖往前跑一點過來。
- 軟體科技樹: Python, Keras, TensorFlow, 3DCNN, OpenCV
- 硬體科技樹: Mackbook ,iPhone, 數據線 (成本不變)
這次的試驗,比較好的地方是:數據集合已經是有的了。然後github上一樣,還是已經有了做jester挑戰的代碼範例了。我要做的事情還是簡單的軟體層面的接入和調優就可以了。嘿嘿,這個知識爆炸共享的時代,就是爽啊!
這次和上次實驗最大的不同是: 不再是簡單的圖片分類對應問題,這次是視頻的分類問題,複雜度上了一個等級,這次有些人也有用CNN 來做視頻識別的,只是我想玩點變種的,3DCNN,所以理論基礎還是要有的。這篇論文 Learning Spatiotemporal Features with 3D Convolutional Networks, 裡面已經有不少詳實的論述。還有一些文章講到可以用光流的方式來做調優,但是這個已經是後面的事情了,軟體開發有句話「過早的優化是萬惡之源」,等能跑起來,有簡單的效果,我再來做調優吧!
還是來說不同的地方:由於用了3DCNN,是用圖片集合的訓練(視頻),所以Macbook的CPU訓練,內存都是瓶頸(是的,我沒有用GPU來訓練,窮!)好在公司里的開發機還有16G的內存,CPU也是足夠強大,所以訓練我基本用公司的機器來搞了。另外,成功率一直很低,30%左右徘徊,用的Optimizar是默認的Adam,代碼也很簡單,用了Keras 框架和Python後,只能說寫神經網路代碼實在太簡單了(要講究運行效率,Caffe是不是也可以考慮下?)
實際運行上,卡在了訓練acc
遇到這個問題後,我想出來幾種解決方案:
- 把圖片解析度調高,讓網路有更多的像素數據來訓練!不壓縮
- 修改網路的層級和卷積核數量,提升學習的能力
- 使用下不要用默認的Adam優化器,試下SGD,或者Adadelta在不改變數據和模型的方式下。然後加多一個dropout 層?
- 參考一些論文,新增一個光流層,兩個神經網路來訓練
思前想後,我試了改圖片解析度,發現由於是load 圖片到內存運算,而且這麼多數據,雖然用了python的yeild 生成器來讀圖片,但是我家的Macbook和公司的電腦還是扛不住。而且優化網路卷積核的尺寸成7*7*7效果也很差,也試過了直接用SGD,acc 並沒有飆升,我表示很憂桑,這個時候,我在瞎逛的時候發現了這張圖:
看這個圖片,黃色的那傢伙Adadelta 優化器是不是跑得最快啊!之前我用的是200個epoch,bachsize是1500個視頻集合,是不是用這個傢伙能在不改變網路複雜度,還有數據集合大小的情況下獲得好的結果,事實證明,這次我賭對了!
在第19次epoch時候,就突破了我之前一直徘徊的30%左右的acc !
第一個難題終於有了些眉目了,做到這裡,是不是可以愉快的和Cozmo 結合起來,看下到底是咋樣的情況了?搞起!
file_object = open("c3d_architecture.json") model_json = file_object.read( ) model = model_from_json(model_json) model.load_weights("c3d_weights.h5") index = 0 while True: screen = np.array(robot.world.latest_image.raw_image) name = str(index).zfill(5) file_name = name +".jpg" cv2.imwrite("./TestImg/"+file_name, screen) index += 1 print("get pic ",index) await asyncio.sleep(0.08) if index == 41 : action = check_value_pics( model) if action == 0 : action2 = robot.turn_in_place(degrees(-30), in_parallel=True) action2.wait_for_completed() elif action == 1 : action2 = robot.turn_in_place(degrees(30), in_parallel=True) action2.wait_for_completed() elif action == 2 : action2 = robot.turn_in_place(degrees(180), in_parallel=True) action2.wait_for_completed() else : action2 = robot.turn_in_place(degrees(360), in_parallel=True) action2.wait_for_completed() index = 0 input() shutil.rmtree("./TestImg") os.mkdir("./TestImg")
基礎的demo核心代碼如上,簡單來說就是用訓練到的模型,先讓Cozmo的攝像頭連續拍攝40張圖片(模型訓練集合用的就是這個數量),然後保存到本地,再用model讀取後做出判斷(先不考慮性能),第一版本的結果如我視頻所示,雖然慢得驚人,但是,也是一個可以run的demo了!
視頻用手機拍攝,請忽略其中雄性程序猿的存在,也附上鏈接 youtube上的鏈接
https://www.zhihu.com/video/912040016832778240簡單講解下這個demo:訓練的手勢只有4種,左右揮手,上下揮手,用的都是jester的視頻集合。
有個這個基礎版本後,如裡面所示,速度實在是太慢了,令人髮指,那簡單提升下識別的速度呢?還是優化方案列表:
- 每個圖片識別一次,不夠40張就重複填充第一張。不是讓Cozmo等40張拍完,再計算個幾秒再得出反應。
- 優化下執行速度,用的是Keras +Tensorflow, Tensorflow 既沒有用GPU版本,也沒有本地編譯,直接pip wheel 安裝,所以有些指令集優化並沒能生效
- 試著用Caffe來改寫下框架,畢竟C++效率上總是比Python來得要快一點吧?
- 試下能不能升級下Tensorflow,或者重新編譯,支持下一些機器上的指令集。
經過的的實驗,在沒有看完Caffe demo 還有源碼的情況下,還有實在太懶不想改代碼成C++版本的情況下,我直接試著升級了tensorflow 到了1.4版本,源碼編譯,model的識別速度居然從3s種提升到了 幾百ms,實在是感動啊。有了這個提升,還有新加入了一種「沒有手勢」的識別,下面請欣賞第n次優化有的版本:
https://www.zhihu.com/video/912041932543361024對應 youtube 鏈接在此 ,是不是感覺快了很多!Cozmo還會把你的手勢說出來!還能前進後退!雖然還有錯誤識別,但是已經很好玩了有木有?(請忽略我的浮誇)
代碼已經上傳到github,不複雜。有興趣的同學可以看下 代碼鏈接
最後階段性總結下
上面的兩個小玩意,純粹是我的一個學習的小demo,不具備任何實際應用價值~~。但是從這個過程中,我擺脫了光看書籍,光看文章聽別人喧囂「人工智慧」的有多火熱的階段。試著實際接觸了下機器學習,雖然是比較低的層次,也沒有做一些深入的數據分析,模型調優,核心演算法優化等。但是光憑一些後台開發積累下來的直覺性經驗,也能簡單完起一個粗糙的玩具demo,自己還是有不少的收穫。當然,還有很多的東西最近也在惡補,包括數學的東西,卷積的概念等等:
- 卷積同時也是一個數學上的操作,在數學和信號處理也有對應的理論依據,牽涉到離散傅里葉變換,快速傅里葉變換等,那這些知識是否和機器學習里的卷積核里的卷積有什麼共通之處?是不是可以作為卷積核能過濾到「特徵」的理論基礎?卷積核從閱讀到的文獻來看,感覺就是一個濾波器對信號的反應,那用DSG(Digital Signal Processing ) 的相關知識來做學習和調優靠譜嗎?(這裡多謝 @WWXX 和 @徐鵬 的提醒,之前簡單認為數學上的卷積,資訊理論里的卷積以及機器學習里的卷積核用到的理論基礎是共通的。雖然也一篇文章確實有從對應的數學邏輯,傅里葉變換,頻域等角度來解析機器學習里的卷積, 文章鏈接在此,也附上其中的一個翻譯版本的鏈接,中文版鏈接在此,但我也還沒徹底搞清楚是否可信及其中的核心機制,有必要後續深究下去!卷積核一定有其的數學理論基礎或者說資訊理論理論基礎依據,待後續深入看看,說不定可以是下篇文章的主題,嘿嘿 ,歡迎隨時斧正,多謝。 )
- Keras , Tensorflow 很爽,框架很好用,但是還是有必要看一下C++ 的Caffe是怎麼做卷積運算的,學習下優秀的框架源碼。
- BP的演算法最近大神已經有膠囊演算法來替代優化,是不是也可以看一下,說不定是機器學習的下一波浪潮,畢竟現在都是靠梯度,反饋這些80年年代就已經提出的觀點在玩。
- 還有好多相關論文,還有文章,書籍需要惡補,對於CNN的內部原理還是停留在知其然而不知其所以然的程度。後續再優化CNN 估計還是得靠計算機視覺,信號科學這些學科來做指引方向,否則那些光流優化演算法的論文是怎麼來的?
總得來說前路漫漫,還有很多東西要學,雖然是做Linux C++ 後台開發,但是最近也用上了Golang還有python。機器學習絕對是一個很有用的工具和學科,很多以前不敢想像的東西也在逐步實現,我們軟體開發從業人員如果可以都是要接觸和學習的,國家也指著這個做彎道超車,看下我們在這個領域的論文發表率,能夠存在這個時代實在太好了!說不定能見證到世界的大革命!(哈哈哈,有點說激動了,也請華麗忽略),一起好好地玩起機器學習和Cozmo吧!
本文用到Cozmo兩張圖片還有優化器的gif圖來自網路,侵權請告知,會立馬刪除。其它內容為原創,如需轉載,請私信告知,多謝多謝。
推薦閱讀:
※想學習「機器學習」,需要學習哪些先導課程?
※目標檢測(5)-Faster RCNN
※Udacity的納米學位 (Nano degree)怎麼樣?
※論文導讀 | TFX:基於TensorFlow可大規模擴展的機器學習平台