傳奇工程師卡馬克入坑 AI:徒手一周實現反向傳播和 CNN
新智元推薦
策劃編輯|Natalie撰稿|Natalie、Vincent
【新智元導讀】有這麼一個大牛程序員,他在幾乎沒有接觸過神經網路的情況下,僅用了一周時間,在幾乎是最基礎且受限的編程環境下,從零開始徒手擼碼,實現了反向傳播和 CNN。今年,這位程序員已經 48 歲了,他叫:約翰 · 卡馬克。
約翰 · 卡馬克是何方神聖?
誰是約翰 · 卡馬克?
他是一位集傳奇工程師、大神、瘋狂程序員、黑客之神、第一人稱射擊遊戲之父、業界活化石、一代玄學碼神所有稱號為一身的老牌程序員,一舉一動都牽動人心。
約翰 ·D· 卡馬克二世(John D. Carmack II,出生於 1970 年 8 月 20 日),是美國的電玩遊戲程序員、id Software 的創始人之一,id 是一家專門開發電子遊戲、電視遊戲的公司,成立於 1991 年。
至於 id Software 這家公司都製作過什麼遊戲呢?說幾個你應該就知道了:《CS(反恐精英)》、《半條命》、《毀滅戰士》都出自這家公司。
怎麼樣,對這位卡馬克先生多少有些了解了吧?
當然,對技術大牛的一切不提技術水平的吹捧都是耍流氓!——沃茨 · 基碩德,那我們就來說一說這位卡馬克大神的技術水平。
卡馬克最讓人咋舌的冒險就是涉足了第一人稱射擊遊戲領域。他的編程能力得以毫無保留地展現,隨後的《德軍總部 3D》(Wolfenstein 3D)、《毀滅戰士》(Doom)和《雷神之錘》(Quake)就是最好的佐證。這些遊戲和它們的後續版本都獲取了巨大的成功。
卡馬克喜歡在電腦圖像領域嘗試新的技術,比如他在 Doom 上第一次使用了二叉樹分區技術,表面緩存技術則在 Quake 中第一次出現。還有就是後來在 Doom3 裡面使用的 「卡馬克反轉」(即 shadow volume 的 z-fail 方法。事實上並不是卡馬克首先創新了這個技術,他在後來獨立研究出來)。
卡馬克創造的遊戲引擎被用來製作其他的第一人稱射擊遊戲,比如《半條命》(Half-life)和《榮譽勳章》(Medal of Honor)。
2013 年的 QuakeCon,卡馬克表示對函數式編程很感興趣。他在 Twitter 上表示了 「已經學習 Haskell 一年」,「學習 SICP 和嘗試使用 Scheme 中」,並且表示正在用 Haskell 重寫德軍總部。與此同時,卡馬克建議其他遊戲開發者嘗試函數式編程。
除了遊戲領域,卡馬克還是個火箭愛好者,並成立了名為犰狳宇航(Armadillo Aerospace)的私人研發團隊。
總結起來,這位卡馬克大神就是:特別能創造、特別能折騰還特別聰明。在 AI 大火的今天,他又把自己的 「折騰精神」 發揮得淋漓盡致。
大神的一周編程實踐:徒手實現反向傳播與 CNN
幾天之前,卡馬克大神在 Facebook 上發表了一篇文章,總結了一下自己如何徒手實現反向傳播與 CNN 的事情。以下內容編譯自卡馬克的自述文章:
間隔了好幾年,我終於又可以進行我的一周編程實踐了,在編程的世界裡我可以在隱士模式下工作,遠離日常的工作壓力。過去幾年,我的妻子一直慷慨地為我打造這種環境,但我一般不善於在工作中休息。
隨著 Oculus(卡馬克目前所在公司)工作步伐的改變,我打算從頭開始編寫一些 C ++ 代碼來實現神經網路,而且我想用嚴格的 OpenBSD 系統來實現。有人可能會說這是一個非常隨意且不太靠譜的選擇,但事實證明這是行得通的。
儘管我沒有真正使用過它,但我一直很喜歡 OpenBSD——一個相對簡單且足夠自用的系統,它具有緊湊的圖形界面,並且重視質量和工藝。Linux 什麼都好,但圖形界面不夠緊湊。
我不是 Unix 極客。各種系統我都可以用,但我最喜歡在 Windows 上使用 Visual Studio 進行開發。我認為在老式的 Unix 風格下完成一周的沉浸式工作會很有趣,即使這意味著工作速度要慢一些。這是一次復古計算的冒險——使用 fvwm 和 vi。不是 vim,實際上是 BSD vi。
其實到最後,我也並沒有真正全面地探索這個系統,95%的時間都花在基本的 vi/make/gdb 操作中。我喜歡那些操作手冊頁面,因為我試圖在自帶的系統中做所有事情,而不訴諸於互聯網搜索。閱讀諸如 Tektronix 終端等已有 30 多年歷史的事物的參考手冊是一件很有意思的事情。
我有點意外,C++ 的支持做得不是很好。G++ 不支持 C++ 11,並且 LLVM C++ 不能很好地與 gdb 配合使用。Gdb 也讓我踩了不少坑,我同樣懷疑是由於 C++ 的問題。我知道你可以獲得更新的版本,但我堅持使用基礎系統。
事後看來,我還不如完全復古,乾脆在 ANSI C 中做所有事情。和許多老程序員一樣,有很長一段時間,我一直在琢磨 「也許 C++ 並不像我們想像的那麼好」。我仍然喜歡 C++ 的很多方面,但對於我來說用普通的 C 語言來構建小型項目並不困難。
也許下次我再進行一周編程實踐時,我會嘗試完整的 emacs,這是另一個我還沒怎麼接觸過的主流文化。
我對大多數機器學習演算法已經有比較基本的了解,並且我已經完成了一些線性分類器和決策樹的工作,但出於某種原因,我從未使用過神經網路。在某種程度上,我懷疑是深度學習太過流行導致那個不願意人云亦云的內在的我感到抵觸。我仍然持有一點反思性的偏見,反對 「把所有的東西都扔在 NN(神經網路)上,讓它自己整理出來!」
為了徹底貫徹我這次復古主題的精神,我列印了幾篇 Yann LeCun 的舊論文,並打算完全脫離互聯網去完成所有事情,這就好像我被困在了某個山間的小屋裡,但最後我還是在 YouTube 上看了很多斯坦福 CS231N 課程視頻,並發現它們非常有價值。我一般很少看課程視頻,因為這通常讓我覺得時間花的不值,但在我 「隱退編程」 的這段時間裡看這些視頻感覺還是很棒的!
我不認為我有什麼特別的洞察力來為神經網路添磚加瓦,但對我來說這是非常高效的一周,充分將 「書本知識」 轉化為真實體驗。
我採用了一種我經常使用的模式:先寫出一段粗糙且不怎麼優美的代碼,初步得到結果,然後用從視頻課程學到的東西再寫出一段全新且更優美的代碼,這樣一來兩份代碼可以並存和交叉檢查。
我一開始嘗試實現反向傳播,結果兩次都做錯了,數值微分比較至關重要!有趣的是,即使在各個部分都出現錯誤的情況下,訓練仍然能夠進行——只要大多數時候符號正確,通常就會取得進展。
我對我的多層神經網路代碼非常滿意,它已經可以在我未來的工作中直接使用。是的,對於很多重要的事情我一般都使用一個已有的庫,但是在很多時候,哪怕只有一個. cpp 和. h 文件是你自己寫出來的,還是會方便許多。
我的 CNN 代碼還很粗糙但已經湊合能用了,我可能還會再用一兩天的時間來完成一個更乾淨而靈活的實現。
有一件事我覺得很有趣,在加入任何卷積之前,用我的初始 NN 基於 MNIST 進行測試,我得到的結果明顯好於 LeCun 98 年的論文中報告的用於比較的非卷積 NN——我使用了包含 100 個節點的單個隱藏層,在測試集上的錯誤率大約為 2%,而 LeCun 論文中使用了包含更多節點和更深層的網路錯誤率卻是 3%。我將其歸因於現代最佳實踐——ReLU、Softmax 和更好的初始化過程。
我認為這是關於神經網路工作的最有趣的事情之一 :它非常簡單,突破性的進步通常只需要幾行代碼即可表達出來。這感覺和圖形世界中的光線跟蹤有一些相似之處,只要你擁有數據並且對運行時間有足夠的耐心,你就可以很快地實現基於物理的光傳輸光線跟蹤器,並生成最先進的圖像。
通過探索一系列訓練參數,我對過度訓練 / 泛化 / 正則化有了更好的理解。在我不得不回家的前一天晚上,我不再修改架構,只是玩超參數。「訓練!」簡直比 「編譯!」 更糟糕,更難讓人保持專註。
現在,我要開始睜大眼睛尋找新的工作機會了,我迫不及待地想把我學到的新技能用起來!
我有點擔心明天進入辦公室時,我的郵箱和工作區將會變成什麼樣子。
之後,大神 Yann LeCun 也回復了卡馬克:
歡迎入坑,約翰!在 OpenBSD 上用 vi 來完成這件事實屬英雄所為!每個人第一次嘗試的時候都會遇到梯度錯誤。
在過去的 35 年裡,我也做過很多次類似的事情。我的第一個反向傳播模擬器是在 PDP11 的 FORTRAN 中編寫的(大約在 1984 年)。第二個是在 Pascal 上的 Pr1me OS(大約在 1986 年,使用類似 Emacs 的編輯器)。第三個是由 Leon Bottou 和我在 C 中使用 emacs / gcc / make 在我們的 Amiga 1000s 上編寫的(1987 年),我們寫了一個 lisp 解釋器用作互動式前端語言。當我在 1987 年搬到多倫多時,我把這個東西移植到了 Sun OS(BSD Unix)上。直到 2011 年左右,我們一直使用這個系統及其後繼者(稱為 Lush),2011 年之後我們才切換到 Torch7。但在 2010 年,我開始編寫一個名為 EBLearn 的 C ++ 深度學習框架,由 Pierre Sermanet 和 Soumith Chintala 完成並維護。
在我們 1998 年的論文中,MNIST 上的全連接網路的錯誤率是次優的,因為我們使用了最小平方損失(對於標記雜訊往往更加魯棒),而不是交叉熵,利用交叉熵和更大的網路(>1000 個隱藏單元),錯誤率可以下降到 1.6%左右。
對於不太了解技術的讀者,大概會產生一種 「神仙聊天」 的感覺,每一個字你都認識,但是你就是看不懂,所以我們貼心地為大家解釋了一個簡約版:
首先,大神卡馬克牛逼在哪兒了呢?看下知乎網友 wsivoky 的總結:
48 歲仍然在學習新技術、編寫代碼
喜歡受限的開發環境(Twitter 上曾說過,受限環境有益)
vi&emacs 都用 (注意是 bsd vi, 不是 vim,前者是 bill joy 當初開發的第一版也是第一個 screen editor )
使用 OpenBSD,但喜歡 Windows Visual Studio
用 makefile&gdb
使用 C++,同時也吐槽 C++
不用 Google Search, 完全看 man(Tektronix terminal 是 bill joy 編寫 vi 時代的顯示器,更早時候是靠紙張輸出... )
對 Deep Learning 如此流行持保留態度
列印了 MNIST 早期論文並嘗試實現
最終忍不住看了 cs231n
使用自己喜歡的開發方式:先實現後優化
實現反向傳播容易出錯
對 CNN 的效果很滿意 (Tensor 操作也是"from-scratch-in-C++"CPU 實現的?)
對 NN 代碼之少卻強大感到興奮(看到純手工擼的 NN 運行結果之神奇,是很持久的快感)
編寫演算法實現對過擬合、正則化、調參有了更好的理解
再簡約一點兒,大概就是這樣:
卡神:反向傳播和 CNN 這東西之前沒搞過,那既然如此就自己動手試試吧。一個禮拜之後發現:哎呀~ 神經網路這玩意兒還挺有意思,感覺入坑了。(?? ω ??)
樂村兒:大兄弟你終於入坑了,來來來,我跟你說,用哥這方法你還有上升空間,以後咱們可以經常交流經驗。(*≧︶≦))( ̄ ̄*) ゞ
成為大神,從你做起!
卡馬克的一周編程實踐一出,迅速在國內外程序員圈子裡引發騷動。
國外程序員論壇 Reddit 的 MachineLearning 板塊下,卡馬克一周編程實踐的話題受關注度 364,共收穫 53 則留言
知乎上也很快有網友發布了相關問題,截止發稿時間,已有 685 人關注,瀏覽次數 25991
卡馬克 Facebook 下的留言大多是這樣的:
其實大家為之震動的並非卡馬克入坑 AI 這件事本身(當然大神神乎其技的編程水平也確實讓人頂禮膜拜),而是卡馬克作為一位諸多成就加身的老牌程序員兼 Oculus CTO,仍然狂熱地愛著編程這件事本身,並且保持著對一切新鮮事物感到好奇的赤子之心。
當卡馬克對 AI、神經網路、深度學習產生興趣,決定探索一下這些新技術時,他沒有直接安裝 TensorFlow 或 PyTorch, 而是花了一個星期的時間,通過逐一編寫各個功能模塊代碼,並進行了 MNIST 實驗,從頭開始實現 CNN 和反向傳播。他沒有去學習最新的術語,但卻從中獲得了最有價值的知識。這裡不爭論 scratching 到底好還是不好,但手擼新技術確實是學習的一種好途徑。面對新技術,不糾結要不要嘗試、不猶豫會不會太難,而是動手干,無怪乎知乎網友將卡馬克稱作 「老程序員的標杆」。
這是一個最好的時代,技術日新月異,熱點一年一個,對技術人才的需求越來越大。這是一個最壞的時代,深陷技術漩渦的程序員們成為了最容易焦慮的群體,今天是 AI 火了我要不要轉行,明天是新技術太多學不動了,後天是 35 歲程序員中年危機了。其實哪裡有那麼多可焦慮的,有時間焦慮不如多擼幾行代碼。互聯網技術更新確實快,這要求程序員必須終身學習,但這是選擇了這個職業的宿命。
卡馬克告訴你:忘記中年危機吧,想想我們應該做些什麼,才不辜負這美好的時代!
寫在最後
這裡引用知乎網友姚鋼強的回答作為結語。
讀過《DOOM 啟世錄》 兩遍,John Carmack 說過:
在信息時代,客觀障礙已不復存在,所謂障礙都是主觀上的。如果你想動手開發什麼全新的技術,你不需要幾百萬美元的資金,你只需要在冰箱里放滿比薩和可樂,再有一台便宜的計算機,和為之獻身的決心。我們在地板上睡過,我們從河水中趟過。
他切實做到了,與君共勉。
參考資料:
1.https://zh.wikipedia.org/wiki/%E7%B4%84%E7%BF%B0%C2%B7%E5%8D%A1%E9%A6%AC%E5%85%8B
2.https://www.reddit.com/r/MachineLearning/comments/82mqtw/d_john_carmacks_1week_experience_learning_neural/
3.https://www.zhihu.com/question/268230219
4.https://www.facebook.com/permalink.php?story_fbid=2110408722526967&id=100006735798590
※谷歌和Facebook在LeCun老家搶生意,誰能贏得法蘭西AI之戰?
※效果驚艷!FAIR提出人體姿勢估計新模型,升級版Mask-RCNN
TAG:新智元 |