博客專欄

EEPW首頁 > 博客 > 特斯拉AI總監(jiān):我復(fù)現(xiàn)了LeCun 33年前的神經(jīng)網(wǎng)絡(luò),發(fā)現(xiàn)和現(xiàn)在區(qū)別不大

特斯拉AI總監(jiān):我復(fù)現(xiàn)了LeCun 33年前的神經(jīng)網(wǎng)絡(luò),發(fā)現(xiàn)和現(xiàn)在區(qū)別不大

發(fā)布人:機(jī)器之心 時(shí)間:2022-03-19 來源:工程師 發(fā)布文章

最近,特斯拉 AI 高級總監(jiān) Andrej Karpathy 做了一件很有趣的事情,他把 Yann LeCun 等人 1989 年的一篇論文復(fù)現(xiàn)了一遍。一是為了好玩,二是為了看看這 33 年間,深度學(xué)習(xí)領(lǐng)域到底發(fā)生了哪些有趣的變化,當(dāng)年的 LeCun 到底被什么卡了脖子。此外,他還展望了一下 2055 年的人將如何看待今天的深度學(xué)習(xí)研究。


圖片
1989 年,Yann Lecun 等人發(fā)表了一篇名為「Backpropagation Applied to Handwritten Zip Code Recognition」的論文。在我看來,這篇論文有一定的歷史意義,因?yàn)閾?jù)我所知,它是使用反向傳播訓(xùn)練的端到端神經(jīng)網(wǎng)絡(luò)在現(xiàn)實(shí)世界中最早的應(yīng)用。
圖片
論文鏈接:http://yann.lecun.com/exdb/publis/pdf/lecun-89e.pdf
盡管數(shù)據(jù)集和神經(jīng)網(wǎng)絡(luò)都比較小(7291 張 16x16 灰度數(shù)字圖像,1000 個神經(jīng)元),但這篇論文在 33 年后的今天讀起來依然沒感覺過時(shí):它展示了一個數(shù)據(jù)集,描述了神經(jīng)網(wǎng)絡(luò)的架構(gòu)、損失函數(shù)、優(yōu)化,還給出了訓(xùn)練集和測試集的實(shí)驗(yàn)分類錯誤率。它是那么得有辨識度,完全可以被歸類為現(xiàn)代深度學(xué)習(xí)論文,但它卻來自 33 年前。所以我開始復(fù)現(xiàn)這篇論文,一是為了好玩,二是為了將此練習(xí)作為一個案例研究,探討深度學(xué)習(xí)進(jìn)步的本質(zhì)。
圖片
實(shí)現(xiàn)
我試著盡可能地接近論文,并在 PyTorch 中復(fù)現(xiàn)了每個細(xì)節(jié),參見以下 GitHub 庫:
圖片
復(fù)現(xiàn)鏈接:https://github.com/karpathy/lecun1989-repro
最初的網(wǎng)絡(luò)是用 Lisp 實(shí)現(xiàn)的,使用了 Bottou 和 LeCun 1988 年提出的反向傳播模擬器 SN(后來被命名為 Lush)。這篇論文是法語的,所以我讀不懂。但從句法來看,你可以使用高級 API 指定神經(jīng)網(wǎng)絡(luò),類似于今天在 PyTorch 中做的事情。
在當(dāng)代軟件設(shè)計(jì)中,庫的設(shè)計(jì)分為以下 3 個部分:
1)一個快速 (C/CUDA) 通用 Tensor 庫,用來實(shí)現(xiàn)多維張量的基本數(shù)學(xué)運(yùn)算;2)一個 autograd 引擎,用來跟蹤前向計(jì)算圖并為 backward pass 生成運(yùn)算;3)一個可腳本化的(Python)深度學(xué)習(xí)、高級 API,包含常見的深度學(xué)習(xí)運(yùn)算、層、架構(gòu)、優(yōu)化器、損失函數(shù)等。
訓(xùn)練
在訓(xùn)練過程中,我們要對 7291 個樣本組成的訓(xùn)練集進(jìn)行 23 次 pass,總共有 167693 個樣本 / 標(biāo)簽展示給神經(jīng)網(wǎng)絡(luò)。最初的網(wǎng)絡(luò)在一個 SUN-4/260 工作站(發(fā)布于 1987 年)上訓(xùn)練了 3 天?,F(xiàn)如今,我用我的 MacBook Air (M1) CPU 就能運(yùn)行這個實(shí)現(xiàn),而且只用了 90 秒(實(shí)現(xiàn)了大約 3000 倍的加速)。我的 conda 被設(shè)置為使用本機(jī) amd64 構(gòu)建,而不是 Rosetta 模擬。如果 PyTorch 能夠支持 M1 的所有功能(包括 GPU 和 NPU),那么加速效果可能會更加明顯。
我還嘗試單純地在一個 A100 GPU 上運(yùn)行代碼,但訓(xùn)練卻更慢,原因很可能是網(wǎng)絡(luò)太?。? 層 convnet,最多 12 個通道,總共 9760 個參數(shù),64K MACs,1K 激活),并且 SGD 一次只使用一個示例。也就是說,如果一個人真的想用現(xiàn)代硬件(A100)和軟件基礎(chǔ)設(shè)施(CUDA,PyTorch)來解決這個問題,我們需要把 per-example SGD 換成 full-batch 訓(xùn)練,以最大限度地提高 GPU 利用率。這樣一來,我們很有可能額外實(shí)現(xiàn)約 100 倍的訓(xùn)練加速。
復(fù)現(xiàn) 1989 年的實(shí)驗(yàn)結(jié)果
原始論文給出了以下實(shí)驗(yàn)結(jié)果:



eval: split train. loss 2.5e-3. error 0.14%. misses: 10eval: split test . loss 1.8e-2. error 5.00%. misses: 102

但在第 23 輪 pass 之后,我的訓(xùn)練腳本 repro.py 打印出的結(jié)果卻是:


eval: split train. loss 4.073383e-03. error 0.62%. misses: 45eval: split test . loss 2.838382e-02. error 4.09%. misses: 82

所以,我只是粗略復(fù)現(xiàn)了論文的結(jié)果,數(shù)字并不精確。想要得到和原論文一模一樣的結(jié)果似乎是不可能的,因?yàn)樵紨?shù)據(jù)集已經(jīng)隨著時(shí)間的流逝而丟失了。所以,我必須使用更大的 MNIST 數(shù)據(jù)集來模擬它,取它的 28x28 digits,用雙線性插值將它們縮小到 16x16 像素,并隨機(jī)而不替換地從中抽取正確數(shù)量的訓(xùn)練和測試集示例。
但我確信還有其他影響精確復(fù)現(xiàn)的原因,如這篇論文對權(quán)重初始化方案的描述有點(diǎn)過于抽象;PDF 文件中可能存在一些格式錯誤(小數(shù)點(diǎn)、平方根符號被抹掉等等)。例如,論文告訴我們,權(quán)重初始化是從統(tǒng)一「2 4 / F」中提取的,其中 F 是 fan-in,但我猜這里實(shí)際是「2.4 / sqrt(F)」,其中的 sqrt 有助于保持輸出的標(biāo)準(zhǔn)差。H1 和 H2 層之間特定的稀疏連接結(jié)構(gòu)也有問題,論文只說它是「根據(jù)一個方案選擇的,這個方案先按下不表」,所以我不得不用重疊的塊稀疏結(jié)構(gòu)做一些合理的猜測。
該論文還聲稱使用了 tanh non-linearity,但是我擔(dān)心這可能實(shí)際上是映射 ntanh(1) = 1 的「normalized tanh」,并有可能添加了一個縮小的殘差連接,這在當(dāng)時(shí)非常流行,以確保 tanh 的平尾至少有一點(diǎn)梯度。最后,該論文使用了「牛頓法的特殊版本,該版本使用了 Hessian 的正對角近似」。但我只用了 SGD,因?yàn)樗黠@更簡單。而且,論文作者表示,「這種算法被認(rèn)為不會帶來學(xué)習(xí)速度的巨大提升」。
用新方法試試
這是我最喜歡的部分。我們生活在 33 年后的今天,深度學(xué)習(xí)已經(jīng)是一個非?;钴S的研究領(lǐng)域。利用我們現(xiàn)在對深度學(xué)習(xí)的理解以及這 33 年積累的研發(fā)經(jīng)驗(yàn),我們能在原結(jié)果的基礎(chǔ)上做出多少改進(jìn)呢?
我最初的結(jié)果是:


eval: split train. loss 4.073383e-03. error 0.62%. misses: 45eval: split test . loss 2.838382e-02. error 4.09%. misses: 82

首先需要明確,我們正在進(jìn)行 10 個類別的簡單分類。但當(dāng)時(shí),這被建模為 targets -1(針對負(fù)類)或 + 1(針對正類)的均方誤差(MSE)回歸,輸出神經(jīng)元也具有 tanh non-linearity。因此,我刪除了輸出層上的 tanh 以獲得 class logits,并在標(biāo)準(zhǔn)(多類)交叉熵?fù)p失函數(shù)中進(jìn)行交換。這一變化極大地提高了訓(xùn)練錯誤,使訓(xùn)練集完全過擬合:


eval: split train. loss 9.536698e-06. error 0.00%. misses: 0eval: split test . loss 9.536698e-06. error 4.38%. misses: 87

我懷疑,如果你的輸出層有(飽和的)tanh non-linearity 和 MSE 誤差,你必須更加小心權(quán)重初始化的細(xì)節(jié)。其次,根據(jù)我的經(jīng)驗(yàn),一個微調(diào)過的 SGD 可以運(yùn)行得很好,但是當(dāng)前 Adam 優(yōu)化器(3e-4 的學(xué)習(xí)率)幾乎總是一個很好的基線,幾乎不需要調(diào)整。
因此,為了讓我更加確信優(yōu)化不會影響性能,我切換到了 AdamW with,同時(shí)將學(xué)習(xí)率設(shè)置為 3e-4,并在訓(xùn)練過程中將學(xué)習(xí)率降至 1e-4。結(jié)果如下:


eval: split train. loss 0.000000e+00. error 0.00%. misses: 0eval: split test . loss 0.000000e+00. error 3.59%. misses: 72

這在 SGD 的基礎(chǔ)上給出了一個稍微改進(jìn)的結(jié)果。不過,我們還需要記住,通過默認(rèn)參數(shù)也有一點(diǎn)權(quán)重衰減,這有助于對抗過擬合的情況。由于過擬合仍然嚴(yán)重,接下來我引入了一個簡單的數(shù)據(jù)增強(qiáng)策略:將輸入圖像水平或垂直移動 1 個像素。但是,因?yàn)檫@模擬了數(shù)據(jù)集的增大,所以我還必須將通道數(shù)從 23 增加到 60(我驗(yàn)證了在原始設(shè)置中簡單地增加通道數(shù)并不能顯著改善結(jié)果):


eval: split train. loss 8.780676e-04. error 1.70%. misses: 123eval: split test . loss 8.780676e-04. error 2.19%. misses: 43

從測試錯誤中可以看出,上述方法很有幫助!在對抗過擬合方面,數(shù)據(jù)增強(qiáng)是一個相當(dāng)簡單、標(biāo)準(zhǔn)的概念,但我沒有在 1989 年的論文中看到它,也許這是一個出現(xiàn)略晚的創(chuàng)新?由于過擬合仍然存在,我從工具箱里拿出了另一個新工具——Dropout。我在參數(shù)數(shù)量最多的層(H3)前添加了一個 0.25 的弱 dropout。因?yàn)?dropout 將激活設(shè)置為零,所以它與活動范圍為 [-1,1] 的 tanh 一起使用沒有多大意義,所以我也將所有 non-linearities 替換為更簡單的 ReLU 激活函數(shù)。因?yàn)?dropout 會在訓(xùn)練中引入更多的噪聲,我們還必須訓(xùn)練更長的時(shí)間,pass 數(shù)達(dá)到 80。最后得到的結(jié)果如下:


eval: split train. loss 2.601336e-03. error 1.47%. misses: 106eval: split test . loss 2.601336e-03. error 1.59%. misses: 32

這使得我們在測試集上只有 32/2007 的錯誤!我驗(yàn)證過,僅僅在原始網(wǎng)絡(luò)中將 tanh 換成 relu 并沒有帶來實(shí)質(zhì)性的收益,所以這里的大部分改進(jìn)來自于 dropout??偟膩碚f,如果我回到 1989 年,我將把錯誤率降低 60%(把錯誤數(shù)從 80 降到 30 個),測試集的總錯誤率僅為 1.5%。但這一收益并不是「免費(fèi)的午餐」,因?yàn)槲覀儙缀踉黾恿?3 倍的訓(xùn)練時(shí)間(從 3 天增加到 12 天)。但是推理時(shí)間不會受到影響。剩下的錯誤如下:
圖片
再進(jìn)一步
然而,在完成 MSE → Softmax、SGD → AdamW 的轉(zhuǎn)變,增加數(shù)據(jù)增強(qiáng)、dropout,以及將 tanh 換成 relu 之后,我開始逐漸放棄那些容易實(shí)現(xiàn)的想法,轉(zhuǎn)而嘗試更多的東西(如權(quán)重歸一化),但沒有得到實(shí)質(zhì)上更好的結(jié)果。
我還試圖將一個 ViT 縮小為一個與參數(shù)和 flops 數(shù)量大致匹配的「微型 ViT」,但它無法與一個卷積網(wǎng)絡(luò)的性能相媲美。當(dāng)然,在過去的 33 年里,我們還看到了許多其他的創(chuàng)新,但是其中的許多(例如殘差連接、層 / 批歸一化)只能在大模型中發(fā)揮作用,而且主要用于穩(wěn)定大模型的優(yōu)化。在這一點(diǎn)上,進(jìn)一步的收益可能來自于網(wǎng)絡(luò)規(guī)模的擴(kuò)大,但是這會增加測試時(shí)推理的延遲。
在數(shù)據(jù)上動手腳
提高性能的另一種方法是擴(kuò)大數(shù)據(jù)集的規(guī)模,盡管這需要花費(fèi)一美元的標(biāo)簽成本。這里再貼一下我們的原始基線:


eval: split train. loss 4.073383e-03. error 0.62%. misses: 45eval: split test . loss 2.838382e-02. error 4.09%. misses: 82

由于現(xiàn)在可以使用整個 MNIST,我們可以將訓(xùn)練集規(guī)模擴(kuò)大到原來的 7 倍(從 7291 擴(kuò)大到 50000)。僅從增加的數(shù)據(jù)來看,讓基線訓(xùn)練跑 100 pass 已經(jīng)顯示出了一些改進(jìn):


eval: split train. loss 1.305315e-02. error 2.03%. misses: 60eval: split test . loss 1.943992e-02. error 2.74%. misses: 54

進(jìn)一步將其與現(xiàn)代知識的創(chuàng)新相結(jié)合(如前一節(jié)所述),將獲得最佳性能:


eval: split train. loss 3.238392e-04. error 1.07%. misses: 31eval: split test . loss 3.238392e-04. error 1.25%. misses: 24

總之,在 1989 年,簡單地?cái)U(kuò)展數(shù)據(jù)集將是提高系統(tǒng)性能的一種有效方法,而且不會影響推理延遲。
反思
讓我們總結(jié)一下,作為一個來自 2022 年的時(shí)間旅行者,我們從 1989 年的深度學(xué)習(xí) SOTA 技術(shù)中學(xué)到了什么:

  • 首先,33 年來的宏觀層面沒有太大變化。我們?nèi)匀辉诮⒂缮窠?jīng)元層構(gòu)成的可微神經(jīng)網(wǎng)絡(luò)體系架構(gòu),并使用反向傳播和隨機(jī)梯度下降對它們進(jìn)行端到端優(yōu)化。一切讀起來都非常熟悉,只是 1989 年的網(wǎng)絡(luò)更小。

  • 以今天的標(biāo)準(zhǔn)來看,1989 年的數(shù)據(jù)集還是個「嬰兒」: 訓(xùn)練集只有 7291 張 16x16 的灰度圖像。今天的視覺數(shù)據(jù)集通常包含來自網(wǎng)絡(luò)的幾億張高分辨率彩色圖像(谷歌有 JFT-300M,OpenAI CLIP 是在 400M 張圖上訓(xùn)練的),而且會增長到幾十億張的規(guī)模。每張圖像包含的像素信息增長了 1000 倍(384 * 384 * 3/(16 * 16)),圖像數(shù)量增長了 100,000 倍(1e9/1e4) ,粗略計(jì)算的話,像素?cái)?shù)據(jù)輸入增長了 100,000,000 倍以上。

  • 那時(shí)的神經(jīng)網(wǎng)絡(luò)也是一個「嬰兒」:它大約有 9760 個參數(shù)、64K MACs 和 1K activations。當(dāng)前(視覺)神經(jīng)網(wǎng)絡(luò)的規(guī)模達(dá)到了幾十億參數(shù),而自然語言模型可以達(dá)到數(shù)萬億參數(shù)。

  • 當(dāng)年,一個 SOTA 分類器在工作站上訓(xùn)練需要 3 天,現(xiàn)在如果是在無風(fēng)扇筆記本電腦上訓(xùn)練只需要 90 秒(3000 倍加速),如果切換到 full-batch 優(yōu)化并使用 GPU,速度還能提升百倍以上。

  • 事實(shí)上,我能夠通過微調(diào)模型、增強(qiáng)、損失函數(shù),以及基于現(xiàn)代創(chuàng)新的優(yōu)化,將錯誤率降低 60% ,同時(shí)保持?jǐn)?shù)據(jù)集和模型測試時(shí)間不變。

  • 僅僅通過擴(kuò)大數(shù)據(jù)集就可以獲得適度的收益。

  • 進(jìn)一步的重大收益可能必須來自一個更大的模型,這將需要更多的計(jì)算和額外的研究與開發(fā),以幫助穩(wěn)定規(guī)模不斷擴(kuò)大的訓(xùn)練。如果我被傳送到 1989 年,而且沒有一臺更大的計(jì)算機(jī),我將無法進(jìn)一步改進(jìn)系統(tǒng)。


假設(shè)這個練習(xí)課程時(shí)間上保持不變,這對 2022 年的深度學(xué)習(xí)意味著什么?一個來自 2055 年的時(shí)間旅行者會如何看待當(dāng)前網(wǎng)絡(luò)的表現(xiàn)?

  • 2055 年的神經(jīng)網(wǎng)絡(luò)在宏觀層面上基本上與 2022 年的神經(jīng)網(wǎng)絡(luò)相同,只是規(guī)模更大。

  • 我們今天的數(shù)據(jù)集和模型看起來像個笑話,2055 年的二者規(guī)模都大約有 10,000,000 倍。

  • 一個人可以在一分鐘內(nèi)訓(xùn)練 2022 個 SOTA 模型,而且是在他們的個人電腦上作為一個周末娛樂項(xiàng)目來訓(xùn)練。

  • 今天的模型并不是最優(yōu)化的,只是改變了模型的一些細(xì)節(jié)、損失函數(shù)、增強(qiáng)或者可以將誤差降低一半的優(yōu)化器。

  • 我們的數(shù)據(jù)集太小了,通過擴(kuò)大數(shù)據(jù)集可以獲得適度的收益。

  • 如果不擴(kuò)大計(jì)算機(jī)基礎(chǔ)設(shè)施和投資相應(yīng)規(guī)模的高效訓(xùn)練模式的研發(fā),就不可能取得進(jìn)一步的收益。


但我想要表達(dá)的最重要的趨勢是,隨著 GPT 這種基礎(chǔ)模型的出現(xiàn),根據(jù)某些目標(biāo)任務(wù)(比如數(shù)字識別)從零開始訓(xùn)練整個神經(jīng)網(wǎng)絡(luò)的設(shè)置,會由于「微調(diào)」而變得落伍。這些基礎(chǔ)模型由那些擁有大量計(jì)算資源的少數(shù)機(jī)構(gòu)進(jìn)行訓(xùn)練,大多數(shù)應(yīng)用是通過對網(wǎng)絡(luò)的一部分進(jìn)行輕量級微調(diào)、prompt engineering,或是通過數(shù)據(jù)和模型蒸餾到更小的專用推理網(wǎng)絡(luò)的 optional step 來實(shí)現(xiàn)的。
我認(rèn)為,這一趨勢在未來將十分活躍。大膽假設(shè)一下,你根本不會再想訓(xùn)練一個神經(jīng)網(wǎng)絡(luò)。在 2055 年,你可以用說話的方式去要求一個 10,000,000 倍大小的神經(jīng)網(wǎng)絡(luò)大腦去執(zhí)行一些任務(wù)。如果你的要求足夠明確,它就會答應(yīng)你。
當(dāng)然,你也可以自己訓(xùn)練一個神經(jīng)網(wǎng)絡(luò),但你為什么要這么做呢?
原文鏈接:https://karpathy.github.io/2022/03/14/lecun1989/


*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點(diǎn),如有侵權(quán)請聯(lián)系工作人員刪除。



關(guān)鍵詞: AI

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉