解讀|合成梯度,不需反向傳播的深度學習
TLDR:在這篇博文中,我們將從起點(從零開始)學習 DeepMind 最近提出的一篇論文 — 使用合成梯度的解耦神經介面。
他們在 iamtrask 完成後,我通常會發布新的博文。如果你有興趣閱讀更多,請隨時關注,歡迎指正!
合成梯度概述
通常,神經網路將其預測與數據集進行比較,以決定如何更新其權重。然後使用反向傳播來確定每個權重應該如何移動,以使預測更加準確。然而,對於合成梯度來說,數據的「最佳預測」由各層完成,然後基於這個預測更新權重。這個「最佳預測」被稱為合成梯度。數據僅用於幫助更新每個層的 「預測器」 或者合成梯度生成器。這使得(大部分情況下)單個層獨立學習,提升了訓練的速度。
上圖(論文中)對於所發生的事情(從左到右)給出了非常直觀的解釋。圓角的正方形是層,菱形物體是(我稱其為)合成梯度生成器。讓我們來看看一個常見的神經網路層是如何更新的。
使用合成梯度
我們不關注合成梯度(Synthetic Gradients)的創建方式,僅僅是關注其使用方法。最左邊的框顯示了如何更新神經網路的第一層。第一層前向傳播到合成梯度生成器(M i+1),然後返回梯度。使用此梯度而不是實際梯度(這將需要一個完整的正向傳播和反向傳播來計算)。然後,權重正常更新,並認為該合成梯度是真實的梯度值。如果你需要了解如何使用梯度更新權重,請查看 A Neural Network in 11 Lines of Python 或者也可以關注在 Gradient Descent 的後續帖子。
生成合成梯度
好的,這部分真的非常巧妙,坦白說,它的工作原理非常精妙。你如何為一個神經網路生成合成梯度?當然是使用另一個網路!合成梯度生成器不過是一個訓練良好的神經網路,在該網路中可以得到某一層的輸出並預測可能發生在該層的梯度。
旁註:Geoffrey Hinton 相關的工作
實際上,這讓我想起了幾年前 Geoffrey Hinton 做的一些工作。雖然我找不到參考文獻了,但是他的確做了一些工作,證明你可以通過隨機生成的矩陣反向傳播,並且仍然完成學習。此外,他表明其有一種正則化效應。這的確是一些有趣的工作。
好的,回到合成梯度。所以,現在我們知道合成梯度是由另一個神經網路訓練的,該神經網路基於某一層的輸出給出相應的梯度預測。論文還顯示,任何其他相關的信息均可以被用作合成梯度生成器網路的輸入,但在論文中,好像只有該層的輸出用於正常的前饋網路。此外,論文甚至指出可以使用單線性層作為合成梯度生成器。太厲害了,我們要嘗試一下。
我們如何學習生成合成梯度的網路?
那麼問題就來了,我們如何學習產生合成梯度的神經網路?事實證明,當我們進行全部的正反向傳播時,我們實際上得到了「正確的」梯度。我們可以用我們比較神經網路的輸出和數據集的方法,將其與我們的「合成」梯度進行比較。因此,我們可以通過假設「真實梯度」來自於虛擬數據集來訓練我們的合成神經網路。所以我們就可以像通常那樣訓練它們了。棒!
等等。。。如果我們的合成梯度網路需要反饋。。。有什麼意義?
問得好!這個技術的全部意義是允許單個神經網路訓練,而不用相互等待以完成前向與反向傳播。如果我們的合成梯度網路需要等待完整的前向/反向傳播過程的話,那麼我們又回到了原點並且還需要更大的計算量(這更糟了!)。為了找到答案,讓我們從論文中回顧一下。
請觀察左邊的第二部分。看看梯度(M i+2)是如何通過(f i+1)反向傳播到達M(i+1)的?正如你所看到的,每一個合成梯度生成器實際上只使用了來自下一層的合成梯度進行訓練。因此,只有最後一層實際上是在數據上訓練的。其他所有層,包括,合成梯度生成器網路,均基於合成梯度訓練。因此,網路只需等待來自下一層的合成梯度就可以訓練每個層。太棒了!
基線神經網路
編程時間到!為了開始(所以我們有一個更簡單的參考框架),我將使用一個用反向傳播訓練的 vanilla 神經網路,風格與 A Neural Network in 11 Lines of Python 相似。(所以如果你沒理解,去看那篇文章然後再回來)。然而,我要添加一個附加層,但是這不應該妨礙理解。我只是在想,既然我們在減少依賴關係,更多的層可能會說明的更好。
就我們所訓練的數據集而言,我將使用二進位加法來生成合成數據集。因此,神經網路將會採取兩個隨機二進位數並預測他們的和(也是二進位數)。好消息是,這使我們能夠靈活地根據需要增加任務的維度(難度)。以下是生成數據集的代碼。
(請於原文查看代碼:https://iamtrask.github.io/2017/03/21/synthetic-gradients/)
這裡是關於在該數據集的訓練 vanilla 神經網路的代碼
(請於原文查看代碼:https://iamtrask.github.io/2017/03/21/synthetic-gradients/)
現在,在這一點上,我覺得非常有必要做一些我在學習中幾乎從未做過的事情,增加一些面向對象的結構。通常,這會使網路模糊一點,並使其更難(從高級別)讀懂正在進行什麼(相對於只讀一個 python 腳本而言)。然而,因為本文是關於「解耦神經介面(Decoupled Neural Interfaces)」及其優點,實際上很難解釋這些介面是否合理解耦。所以,為了更易學習,我首先將上述網路轉化為完全相同的網路,但會使用一個在後文中會轉化為DNI的「Layer」類對象。 讓我們來看看這個 Layer 對象。
我們傳遞的第二個函數是 nonlin_deriv,一個特殊的導函數。該函數需要從非線性中輸出,並將其轉化為導數。對於 sigmoid 來說,這非常容易(out * (1 - out)),其中 「out」 是 sigmoid 的輸出值。這個特定的功能幾乎存在於所有常見的神經網路非線性中。
現在,我們來看看這個類中的各種方法。 forward 正如其名字所示。它通過層向前傳播,首先通過一個線性變換,然後通過非線性函數。 backward 接受了一個 output_delta 參數,它表示反向傳播期間從下一層返回的「真實梯度」(而非合成梯度),然後我們使用它來計算 self.weight_output_delta,它是我們權重輸出處的導數(僅在非線性內)。最後,它反向傳播錯誤並傳入至上一層,並將其返回。
update 可能是最簡單的方法。它只需要在權重的輸出中使用導數,並使用它來進行權重更新。如果你對這些步驟有任何疑問,再一次地,查看 A Neural Network in 11 Lines of Python 再回來。如果你能全部理解,那麼讓我們在訓練中看看我們的層對象。
給定一個數據集 x 和 y,這就是我們使用我們的新層對象的方式。如果你把它與之前的腳本進行比較,幾乎是一模一樣。我只是更換了調用的神經網路的版本。
所以,我們所做是將先前神經網路的腳本代碼在類中分成不同的函數。下面,我們在實際中看看這個層。
如果你將以前的網路和此網路同時插入 Jupyter notebooks,你將會看到隨機種子會使這些網路具有完全相同的值。看起來,Trinket.io 可能沒有完美的隨機選取種子點以使這些網路達到幾乎相同的值。然而,我向你保證,網路是相同的。如果你認為這個網路毫無意義,不要進行下一步的學習。在進行後面的學習前確保對這個抽象網路的工作方式熟稔於心,因為下面將會變得更加複雜。
整合合成梯度
好的,所以現在我們將使用一個與上述非常相似的介面,唯一不同在於我們將所學到的關於合成梯度的知識整合入 Layer 對象中(並重命名為 DNI)。首先,我們要向你展示類,然後我會對其進行解釋。一探究竟吧!
那麼,第一個大的變化。我們有了一些新的類變數。其中唯一真正重要的是,self.weights_synthetic_grads 變數,這就是我們的合成生成器神經網路(只是一個線性層,其實,,,就是一個矩陣)
前向和合成更新:前向方法已經變成 forward_and_synthetic_update。記得我們是如何不需要網路的任何其他的部分來更新我們的權重嗎?這就是神奇的地方了。首先,前向傳播像正常一樣發生(22行)。然後,我們通過非線性傳遞我們的輸出來生成我們的合成梯度。這部分可能是一個更複雜的網路,但是相反,我們決定保持簡單,並只是用一個簡單的線性層生成我們的合成梯度。在我們得到我們的梯度時,我們繼續執行並更新我們的普通權重(28 和 29 行)。最終,我們從權重的輸出反向傳播我們的合成梯度至其輸入,這樣我們可以將其傳入上一層。
更新合成梯度:好的,那麼我們在 「forward」 方法的結尾處返回了梯度。這就是我們從下一層接受進 update_synthetic_gradient 方法的東西。那麼,如果我們現在在第二層,那麼第三層從其 forward_and_synthetic_update 方法中返回了一個梯度,並將其輸入進第二層的 update_synthetic_weights。然後,我們只需要像更新普通的神經網路那樣更新我們的合成梯度就好。我們將輸入傳入合成梯度層(self.output),然後用 output delta 執行均值外積運算(矩陣轉置 → 矩陣乘法)。這與在一個普通的神經網路中學習沒什麼不同,我們只是在 leau of data 中得到一些特殊的輸入和輸出。
(請於原文查看代碼:https://iamtrask.github.io/2017/03/21/synthetic-gradients/)
讓我們在實踐中看一看它
(請於原文查看代碼:https://iamtrask.github.io/2017/03/21/synthetic-gradients/)
訓練有點不一樣。較大的數據批量規模和較小的 alpha 值似乎性能更好,但積極的一面是,在訓練中只迭代了一半次數!(這可能很容易調整,但是仍然。。不錯)。一些結論。訓練似乎有些混亂(不會下降)。我不知道在 hood 那發生了什麼事,但是當它收斂時,肯定很快。
希望你喜歡這個教程
我通常會在iamtrask上發布新完成的blogpost。 如果你有興趣閱讀,歡迎關注並給予反饋!
※深度學習和量子物理的共同點,或可用物理學打開深度學習黑箱
※將多代理路徑尋找推廣到真實世界應用:四大研究方向概覽
※解讀|藝術家如何藉助神經網路進行創作?
※機器學習和深度學習引用量最高的20篇論文:2014-2017
TAG:機器之心 |
※深度學習之DNN與反向傳播演算法
※大神Hinton:深度學習要另起爐灶,徹底拋棄反向傳播
※反向卷腹,經典動作的標準姿勢詳解
※反向平板支撐,加強你的核心和下半身
※「天生反骨」的反向傘好玩又好用,為啥成不了主流?
※科學家利用反向光合作用分解植物 或助解決污染問題
※練倒三角身材,反向划船最適合!
※人工智慧之父發話:拋棄反向傳播,人類需要重新開始!
※大爆炸會形成鏡像宇宙:時間是成反向
※反向聳肩,斜方肌下束最好的訓練方法
※改良版反向划船,不用啞鈴、杠鈴也能練出倒三角!
※獵天使魔女視角反向怎麼調節?視角反向調節方法詳解
※背肌鍛煉:反向划船常見錯誤!
※史密斯機反向提踵,極限刺激你的小腿肌
※它是代表輪迴的妖獸,有兩隻反向的頭顱,終生奔走,卻寸步難行
※斜方肌下束訓練動作:反向聳肩
※反向卷腹練腹肌,這些要點必須注意
※反向次數這是一個時常運用在力量舉訓練當中的技巧
※韋神看了要流淚,反向技能應該這麼用