1. 程式人生 > 其它 >有沒有必要把機器學習演算法自己實現一遍?

有沒有必要把機器學習演算法自己實現一遍?

哈哈哈哈,我覺得很多人都有這個疑問吧。機器學習好高大上,多麼牛逼的東西,光是看公式就已經眼花繚亂了,總覺得自己該全部去實現一遍,有的時候太懶,有的時候覺得能力不夠。道理雖然明白——任何事情自己親手做一做還是更好的,但機器學習已經有了大量的庫了,SVM-Light,R裡面的glm()方程,自己實現一遍,最後又不敢用(因為不知道演算法究竟是否正確),或者不能用(一是速度趕不上大神寫的庫那麼快,二是精度沒有專業庫那麼高),耗時耗力的寫了一堆後究竟有什麼用?

這裡很多答案都提供了一些解釋,但我想從另一個角度來聊聊這個問題。

我在1年半前(本科階段)就開始接觸計算心理學和機器學習方面的研究,在NAACL(自然語言處理排名第三的論壇)上發表了一篇文章,用的計算機教授寫的演算法庫,跑的是經過AdaGrad優化的向量支援機(SVM)演算法。在這種論壇發文章,你是必須去做海報展示的,站在自己的大幅海報面前傻傻的待4個小時,我的兩位教授(一位是認知語言學教授,一位是計算機教授)都在那裡。我的位置不太好,在最邊緣的角落裡,本來以為就可以贏得一份清淨,Philip Resnik走了過來。直到那一剎那之前,我一直不知道他是誰。但經過教授介紹後,他是馬里蘭大學的機器學習和自然語言處理教授,在這個領域混了多年,在Google Schoar上的論文引用數高達12,853。

他走過來的第一句話是:“假設我一點也不懂數學,告訴我你這篇論文做的是什麼。”我解釋後,看到我的計算機教授走了過來和Resnik聊天,Resnik問我的教授:“你用的是不是hinge loss(辛基損失函式)?”我的教授說:“是。但不是全域性優化,所以我沒有叫這玩意SVM……”(我憑回憶打出來的,可能不完全精確)。當時我站在一旁覺得這他們能這樣大聊特聊數學,甚至是向量支援機(我當時認為這是最厲害的演算法——除神經網路以外),簡直是太厲害了,我一點也聽不懂他們在講什麼。

直到現在,我才明白所謂的“辛基損失函式(Hinge loss)”其實就是Max(a,b)函式,就是比較 a 和 b 誰大誰小,然後選大的那個。這玩意究竟有什麼難理解的?為什麼要那麼高大上?你讓一個五歲的小孩,問他:“有一堆紅球,一堆綠球,哪一堆的球更多啊?”這個小孩都能告訴你正確答案。

當然這說的有點偏題了。後來我非常幸運的考上了研究生,才終於開始了對“高檔”演算法的學習。第一個學期被Christopher Manning(克里斯多夫·曼寧)的CS224N自然語言處理虐了一番,這個學期開始上Andrej Karpathy(安傑·卡帕西)的神經網路(CS231N),該君是李菲菲教授(音譯,Fei-Fei Li)的愛徒,在推特上有14.9K關注者,我越看他那張方塊臉,越覺得他長得像賈斯丁·汀布萊克(Justin Timberlake)。

我其實也是自控能力很差的人,在上安傑·卡帕西的課之前,也從沒有萌生過自己去寫機器學習演算法的想法。原因在文章開頭有提過:1. 我的程式碼執行速度肯定趕不上經過多次迭代的專業庫的執行速度;2. 我咋知道我的程式碼寫的就是對的呢?

我直到現在都這樣認為:不考慮對方的環境和條件,知識與技能,就一味要求對方把機器學習演算法都實現一遍,估計是最無理取鬧的行為了吧。前天晚上,我跟另一個研究生Jason Freeman(傑森·弗里曼)聊天,他在微軟的西雅圖總部工作了4年,在目前越來越有名的TypeScript團隊工作了3年(TypeScript是靜態的JavaScript語言,正在國內和國外開始流行)——他告訴我他和安德斯·海爾斯伯格(Anders Hejlsberg)一起工作,他還經常頂撞安德斯。我的第一反應是:“他是誰……”(安德斯·海爾斯伯格是Delphi和C#之父,但我不熟悉這兩門語言,所以不會崇拜他——小廣告:Scala是我目前最喜歡的語言)。

我和傑森討論的是3月份開始究竟要不要選吳恩達(Andrew Ng)的機器學習課(CS229)。我持的立場是我可能不打算上那門課,因為我已經看過大部分他的視訊了,還讀了他講義的一部分(這裡是講義連結: CS 229: Machine Learning (Course handouts) http://t.cn/R009lCm)。因為我已經確定以後要做神經網路方面的研究,所以覺得他課上的一些其他內容比如特徵降維(PCA),對我而言用處不大,我只需要會用就行了。我不僅用過特徵降維,還用過更好的降維視覺化(tSNE演算法)。這玩意和我的領域不搭,為什麼我要浪費時間去學?

傑森的論點是,如果我學了它們的理論(甚至把它們實現一遍),就能更好的應用它們。我說:你把直覺(intuition)當什麼了?在我看來,對演算法進行“直觀”上的瞭解,就已經很足夠了。什麼是向量支援機?就是拿一個平面去分隔一堆點。更術語一點的解釋不外乎是拿一個超平面(Hyperplane)在高維空間裡去分割。什麼是特徵降維?就是看如何把高維度的點陣降到兩三個維度。什麼是alpha值?就是看這個演算法學得有多快。什麼是正則化(regularization)?就是別讓你的演算法過度擬合數據(當然L1,L2等等都有區別,但這些區別都很簡單,L1讓你關注某個值,L2讓你利用所有的值)。

為什麼我談這麼多關於理論的問題?在我看來,學習機器學習的演算法的進度是這樣的:應用 -》理論 -》實現。就跟教小孩折射一樣,你先讓他看看筷子在水中如何彎折(應用),再告訴他光的折射原因(理論),再讓他自己用其他物體來試試(實現)。實現,是這個漫長學習過程的最後一步。一開始就來談實現,實在是很神奇的事情。

讓我準確論述一下我的觀點:如果你是學界精英,那麼去學習那些你將要使用的演算法的理論,最後再自己嘗試著實現他們,是很有必要的,除非你是隻做應用(比如社會科學,心理學,商學等等)。如果是普通的程式設計師/工程師,不需要強迫自己去實現這些演算法。沒人會給你一個小獎章,大公司招這類員工的時候,也是更看重學歷,而不是看“哦,我把‘所有’的機器學習演算法都實現了一遍”。

最後送上一點我覺得實現機器學習演算法最好的路徑:

最好用Python和Numpy庫。這兩樣寶具會讓你非常輕鬆。安傑·卡帕西(Andrej)推薦用ipython notebook(現在改名叫Jupyter了),來視覺化資料,以及實驗演算法。昨天有一個下午茶會,我們系舉辦的,也邀請了安傑,我跑去湊熱鬧,跟安傑談到了這個問題,他說就算是大公司做研究,也是這種路徑,先從ipython notebook開始(這點讓我很驚訝)。

機器學習演算法最難的部分其實不是寫出來,而是高效率的實現,讓你的演算法跑快一點。其中一個技巧叫做“向量化”(Vectorization)。向量化就是說,能做矩陣操作就矩陣操作,最好連一個外迴圈都不寫。

這是我寫的Softmax演算法的測評:(在500個樣本上跑的)

naive loss: 2.384533e+00 computed in 0.255952s
vectorized loss: 2.384533e+00 computed in 0.004148s

第一個是用普通的Python和迴圈寫出來的,第二個是用向量化操作寫出來的,可以看到64倍速度的提升——側面也可以看到Python有多垃圾(慢)。

這個是SVM(支援向量機)演算法的測評:(同樣500個樣本)

Naive loss: 9.102322e+00 computed in 0.136226s
Vectorized loss: 9.102322e+00 computed in 0.005909s

這次的速度提升沒有那麼明顯,但也是26倍的提速。

但我只想說:向量化真是很難的事情。數學家隨便就寫公式,也不考慮考慮可憐的電腦科學孩子們。原初的公式幾十分鐘就搞定,向量化要一兩個小時的冥思苦想。

最後,對於那些讀懂了理論,實在是閒得無聊,或者想要進軍更高階的學術界的同志們,這裡是安傑·卡帕西課程式碼的連結:CS231n Convolutional Neural Networks for Visual Recognition(http://t.cn/RZ0FlxD)。如果你不屬於這個類別,就不要瞎摻合啦,用用別人的庫又怎麼了?駭客精神(Hacker Code)中一條就是:“不要重複勞動,有庫就要用庫,不然就是對庫寫作者的不尊重。”

(如果你還是不知道究竟該不該實現,歡迎閱讀下面我增加的內容) ------------------

最近這篇文章被學姐前輩Danqi Chen看到了。。所以我稍微補充幾句,免得被大牛們看到後笑話。。- ___ - || Danqi前輩是清華姚班的高材生,Chris Manning的博士,在224N課上是首席助教,然後被我纏著問了好多次問題……

這篇文章有點接近“反智”文章的邊緣,大意是實用主義至上,自己實現的必要性不大。這個觀點還是有很多爭議的,比如目前有一個答案就“實名”反對這個答案。機器學習是一個交叉學科,作為學生而言,從不同的部門學到的機器學習,必然是不一樣的。在統計學部門學到的機器學習,和在計算機部門學的機器學習,肯定是兩個樣。我秋天的時候跟一位概率教授上了一節課,當我告訴他斯坦福計算機入門概率課要介紹MLE(最大擬然估值)和蒙特拉羅模擬(Monte Carlo Simulation)的時候,他沉重的搖搖頭,說這麼早就介紹這樣深刻的概念,是很不應該的,在他的部門,要第三年的學生才接觸這樣的知識,因為直到那時,學生才有足夠的知識框架去理解這些知識。

我寫這篇文章是有一定的原因的。我認識一些國內的大學同學,都異常優秀,他們努力的程度是我一輩子都比不上的,他們中一部分人因為運氣不好(高考),不幸去了一些相對不是那麼優異的大學,但是他們用努力彌補這個缺陷,對數學和各種學科展開攻克,很多人的閱讀量和數學解題技巧也是我不能企及的。還有一部分人,是處於業界轉型邊緣,本來已是成熟的程式設計師,或者資料分析師,但是想要進一步提升自己,亦或是轉型。我把這兩類人定做這篇回答的目標受眾。我希望為他們寫一篇回答,不讓他們走我走過的彎路,不受太多的誤導。

開復先生(李開復)最近說深度學習急缺人才。我非常的不贊同。深度學習領域是處於半飽和狀態的,實際上就業情況就是一堆熠熠生輝(Scintillating)的博士們在學術界待膩了,想要去賺點錢玩玩,就跑去業界晃一圈的狀況。這和大部分人的就業狀況根本是不搭邊的。深度學習,以及理論機器學習,除非是平臺很高,起點很高,是很難得到廣泛認可的。

我最近剛買了一本書:

這本書很詳細的在講Lasso Loss(L1),寫SVM的部分也非常不錯,很神奇的是,三位作者,兩位是斯坦福統計學系的,一位是伯克利的。如果我能讀完這本書,會上來改進一下這個答案的。

最近我想提一提答案末尾寫的,關於“實現”的問題。我過去幾週一直在寫我自己的Theano庫(是的,放著牛逼的Lasagne不用,非要自己手寫),終於把CNN寫完後,現在在寫RNN的部分。當我已經花費這麼多的時間,然後意識到,我的程式碼暫時還只能在CPU上跑,因為我暫時還沒有用Theano的CUDA庫,又意識到,僅僅幾周後,我的兩門春季課已經開始教TensorFlow了,於是覺得自己是個傻子。

所以我自己都陷入了我回答中所寫的那個陷阱:實現之後卻不能使用,但又不願意放棄自己的程式碼,於是只有投入更多的時間去改程式碼,而不是去理解數學。願與各位共勉。