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

.. 雷鋒網按:本文作者紫杉,本文由雷鋒網整理自作者在知乎《有沒有必要把機器學習算法自己實現一遍?》問題下的回答。雷鋒網已獲得轉載授權。

哈哈哈哈,我覺得很多人都有這個疑問吧。機器學習好高大上,多麼牛逼的東西,光是看公式就已經眼花繚亂了,總覺得自己該全部去實現一遍,有的時候太懶,有的時候覺得能力不夠。道理雖然明白——任何事情自己親手做一做還是更好的,但機器學習已經有了大量的庫了,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))。因為我已經確定以後要做神經網絡方面的研究,所以覺得他課上的一些其他內容比如特徵降維(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。如果你不屬於這個類別,就不要瞎摻合啦,用用別人的庫又怎麼了?駭客精神(Hacker Code)中一條就是:「不要重複勞動,有庫就要用庫,不然就是對庫寫作者的不尊重。」

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

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

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

我最近剛買了一本書:

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

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

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


想在手機閱讀更多程式設計資訊?下載【香港矽谷】Android應用
分享到Facebook
技術平台: Nasthon Systems