HInton第8課,之所以說之二三,是因為訓練RNN的四種方法之一:長短時記憶在lecture7中介紹過了,這里介紹的是第二和第三種方法:HF優化和Echo (這個字覺得翻譯成回聲是不是欠妥,所以保留着,不過個人覺得“回顯”不錯)狀態網絡。這課有兩個論文作為背景可以看《Generating Text with Recurrent Neural Networks》和《Echo state network - Scholarpedia》。
一、“Hessian-Free”優化的簡單的介紹
在這部分中,會簡短的介紹Hessian-free優化,這可以用在訓練RNN中,這也是一個非常復雜的優化,HInton並不期望從這部分中就能知道所有的細節(要記得這是給本科生上課的,所以不同級別的 不同對待),只希望能有個大致的感覺,他是如何工作的,在第二部分中才會舉個例子,它是如何完成一個很有趣的問題的。
當我們對NN訓練權重的時候,會讓誤差盡可能的在誤差表面上達到最低。所以問題來了,一個就是如果我們選擇了一個給定的方向,那么在正確的方向上(真正的方向)到底能下降多少,在誤差重新上漲之前那個方向上誤差到底下降了多少(也就是求局部最小值或者全局最小值),這里我們假設曲率是常數
,這里假設它就是個二次誤差表面(類似一個碗的縱切)。我們可以合理的假設當我們沿着梯度向下移動的時候,梯度的大小是減少的,這就是說我們認為誤差表面其實是個上凸形狀(就是碗型)。
我們通過某個具體的方向上的誤差中得到的減少的最大值是由梯度的曲率比決定的。所以其實我們希望在移動的方向上有個好的比率,就算是梯度已經相當小了,我們還是希望曲率變得更小。
上圖中就是個例子(圖中下面的小圖):垂直軸是表示誤差,水平軸表示移動方向上的權值,藍色箭頭對應關於從紅點開始的減少量。(上圖中的上面大圖):這里演示的是比上面那個更好的梯度曲率比,所以這次我們可以得到更大的誤差蝦醬值,所以更貼近最小值,問題在於如何找到第二個這種下降方向,即找到的方向上梯度是很小的,而且曲率甚至要更小。
這里以牛頓方法來開始吧,牛頓方法是為了處理在最速下降法上的基本問題的,也就是但梯度不在想要下降的方向上的問題。如果這個誤差表面有圓形橫截面,那么而且是二次的,那么梯度就是一個好的方向的選擇,它將會引導直至最小值,所以牛頓方法的想法是通過一個線性變換使得橢圓變成圓,如果將這個想法應用於梯度向量的轉換,那么就好像是在一個圓形誤差表面上下山(形象的稱呼)一樣。為了實現這一的效果,需要將dE關於dW的梯度乘以曲率矩陣的逆矩陣,所以H是曲率矩陣,有時候也被稱為Hessian,這就是我們擁有的權重的函數,而且我們需要對它取逆和與梯度相乘,然后我們就需要在那個方向上前進一段距離了。如果它真的是一個二次表面,而且我們選擇的epsilon是正確的,那么剩下的事情就好辦了,我們就可以在一個單步上達到表面的最小值,當然這里的單步是包含了很多復雜的東西的,也就是Hessian矩陣的逆矩陣。
這里伴隨的問題是即使我們只有1百萬個權重,這里的曲率矩陣,Hessian將會有1兆的項,這就是完全的不可能去求逆了。
所以曲率矩陣像上圖這樣,對於每個權重,Wi或者Wj,它們會告訴你在一個方向上和另一個方向上梯度的變化,換句話說,正如現在改變權重 i ,那么誤差關於權重 j 的梯度的變化是多少,也就是非對角線上的項所表示的;而在對角線上的項說明的是誤差梯度在這個權重方向上的這個權重的改變。所以曲率矩陣中非對角線項就是對應於誤差表面中的曲折(twists),這里的曲折意思是當你在一個方向上嘗試的時候,在另個方向上梯度會改變。如果我們有個很好的圓碗,所有的這些非對角線項就是0了,正如我們在一個方向上使用梯度,在其他方向上的梯度就不會受改變。
所以在最速下降法中的問題就是當你有個橢圓誤差表面,如上述一樣,在一個方向上的梯度改變會影響到其他方向上的梯度的改變,所以如果更新所有權重中的一個,那么在同一時刻就是也同時更新所有其他的權重,所有其他的權重上的更新又會導致第一個權重上梯度的改變,也就是說當更新的時候,有可能會讓事情變得更糟。梯度也許會因為其他權重上的改變而事實上會是個反正弦(這句話不知道什么意思)。所以當我們得到越來越多的權重的時候,我們就需要在每個權重上都要越來越注意,因為在所有權重上的同時的改變有可能會改變我們梯度的范圍。曲率矩陣決定着這些交互的尺寸(就是這個Hessian矩陣決定着所有權重的更新影響)。
所以我們不得不需要處理曲率,我們不可能忽略它。而且我們也希望處理的時候不需要進行對一個巨大的矩陣求逆,因為這個矩陣在一個大NN中將會有超多的項。我們所能做的就是通過觀察曲率矩陣的主對角線,然后以此得到步長尺寸,這個的確有所幫助,他會讓我們在不同的權重上擁有不同的步長尺寸,但是對角線也只是交互中的微小的一部分(這里是對於整個矩陣來說),所以我們這么干的時候其實是忽略了曲率矩陣的大部分信息的,事實上,我們差不多忽略了所有的信息;另一個我們所能做的就是將曲率矩陣用能抓住曲率矩陣主要方面的更低的矩陣秩來逼近(有點拗口,不過要是懂下面的幾個方法的原理,相信就應該知道說的是什么意思),方法有:Hessian-Free,LBFGS和許多其他方法,去試圖逼近最小化誤差的二階值。
在Hessian-Free方法中,我們通過對曲率矩陣進行逼近,然后假設逼近是正確的,所以我們假設知道曲率是多少,而且誤差表面也的確是二次的。然后現在,引入一個高效的方法來最小化誤差,叫做共軛梯度,一旦我們完成了,一旦我們逼近了曲率上的最小值,我們就隨后就對曲率矩陣進行另一次的逼近,然后使用共軛梯度來再次進行最小化。在RNN中加上一個關於其他隱藏激活值改變太多的懲罰項,這可以阻止我們過早的改變權值而導致在序列中后期的巨大影響。我們不想讓(RNN中的)影響很大,如果我們觀察隱藏激活值中的變化,那么就能通過懲罰這些變化來阻止事情的發生,如果我們在這些變化上使用的是二次懲罰項,那么就能將它們與Hessian-free方法中剩下的部分結合起來。
這里最后需要解釋的就是共軛梯度,這里將會簡短的說下。共軛梯度是個非常聰明的方法:不是和牛頓方法中直接試圖得到最小值,而是每次在一個方向上達到最小,所以它是以某個方向上的最速下降法然后在那個方向上達到最小值。這包含了對梯度的重新評估,和重新評估誤差去找到這個方向上的最小值。一旦這么做了,然后就可以找另一個方向,然后在這個方向上找最小值。這個方法聰明的地方在於它以這樣的方法選擇的第二個方向並不會影響在第一個方向上得到的最小值的結果,這也被稱之為共軛方向,共軛就是說在選擇新的方向上,不會改變之前方向上的梯度。這是個很有趣的想法,就像之前誤差表面上曲折(twists)的想法一樣,曲折就是說當你在一個方向上的時候,就會改變另一個方向上的梯度;而共軛方向是一旦到了一個方向上,那就不會有曲折發生,即一旦到了一個方向上,在第一個方向上的梯度就不會發生。
這里是個橢圓圖形,紅線是橢圓的主軸,我們通過采用沿着所有方向上執行一步最速下降法來作為開始(上圖中從橢圓外面進入的黑色箭頭),如果想想的話,就能發現其實最小值不是沿着紅線的,在紅線的正確角度上梯度是為0的,因為這是山谷的底部了,但是我們跟進的方向事實上不是這個點的正確角度。我們可以多做一些處理來使得在紅線上朝着正確角度前進一小步,然后沿着紅線前進一小步。因為紅線是朝着橢圓的中部坡度下降的,這也指導着我們一些處理上的想法,所以當在第一個方向上達到了最小值,我們將會筆直的橫跨橢圓的底部(第一個大黑箭頭),然后當我們達到了那個點,也就是那個方向上的最小值,對於沿着上圖中綠色線來說,黑色箭頭(第一個)的方向上的梯度都是0,所以我們可以沿着綠色線去任何地方而且不會破壞之前在黑色箭頭上得到最小值的事實。(個人:這大段意思就是開始的大黑色箭頭就是在第一個方向上得到的最小值,而且通過計算在綠色線上運動,第一個方向上的梯度都不會變化,那么就可以沿着這條線來計算第二個方向上的梯度並計算最小值了)
如果我們能在高維度誤差表面上徐哦多方向上這么干,我們最終就能得到在許多不同方向上的最小值,而且如果我們在我們空間上所有維度方向上都達到了局部最小值,那么也就會最后處在全局最小值的位置了。所以我們先執行第一步最速下降,然后找出綠色線方向,然后在這個方向上搜索我們可以走多遠以至於沿着這條線都能達到這個方向的誤差最小化;然后采取第二步,如圖中第二個黑色箭頭,在這個2D空間中,我們可以得到最小值(黑色箭頭頂端,也就是和綠線和紅線交叉的地方),是因為我們在第一步方向上得到的最小值而且現在第二個方向上也都達到了最小值,那么兩個方向上的最小值,就是全局最小了。
共軛梯度所能達到的它達到了在N-D二次表面上的全局最小,而這只需要N步,這非常的高效。它成功的在N個不同方向上使得梯度為0。它們雖然不是正交方向,但是他們都是各自獨立的,所以這是很有效率的達到全局最小的方法。更重要的是,在二次表面上跨出許多步后(就是只運行了小於N步的時候)將會讓誤差非常的接近最小值,而這就是為什么用它的理由,我們不需要完整的運行N步,因為當N很大的時候,計算代價比較大,有可能和將整個矩陣求逆一樣大,我們只需要執行小於N步,那么就能接近最小值。
可以直接將共軛梯度方法應用在非二次誤差表面上,比如來自多層非線性NN的誤差表面,而且通常效果還很不錯。它本質上也是批量的方法,但是也能將它應用在大mini批量上,當這么做了之后,在同一個大mini批量上執行了許多步共軛梯度,然后在下一個大mini批量上操作,這也叫做非線性共軛梯度。
Hessian-Free優化使用的是共軛梯度方法,在真正的二次表面上達到最小值,這也是共軛梯度最擅長的。在二次表面上的工作效果還是比非線性表面上的效果要好。這里HF方法是通過對真正的表面進行二次逼近得到的真正的二次表面。所以在得到逼近之后,使用共軛梯度在第一個逼近上接近最小值,然后在曲率上進行新的逼近,然后再次采用同樣的操作。
二、使用乘法連接來對字符串進行建模
這部分將介紹使用Hessian-Free優化去對字符串數據進行建模,這里的字符串都來自於維基。所以這里的想法就是從維基上閱讀大量的語句,然后讓模型試着去預測下一個單詞。在介紹模型學習之前,先說明下為什么我們需要乘法連接和我們怎樣在一個RNN中高效的執行這些乘法連接
這里先解釋下為什么使用字符串而不是單詞串(個人覺得翻譯成單詞流更好,想法來自c++語法)來進行模型的訓練,而單詞串是通常用來在對語言進行建模的時候使用的。
web網頁都是由字符串組成的;任何足夠強大的學習方法都能夠通過閱讀這些網頁理解知道到底發生了什么,這些方法都需要最基本的知道哪些字符組成單詞,正如我們肉眼看到的,這些都是正確的道理。所以在這里我們對接下來做的事情很有信心,我們希望某些模型能夠閱讀維基然后理解這個世界。
如果我們對維基文本預處理成單詞,那么這將會導致一個巨大的爭論,那么就充滿了問題了。比如第一個問題就是語素(相對於聲音也有音素),也就是語言學家認為的意思的最小單元。所以如果想要明智的去處理的話,我們就需要將每一個單詞拆成語素(如上圖中pre,es),但是問題就是還不清楚語素到底是什么。這些(上圖中的例子)都有點像語素,但是語言學家卻不會這么認為這些是語素。
所以在英語中,如果你以sn開頭的任何單詞,那么有可能有會存在嘴唇或鼻子所導致的意思的高度變化,特別是上嘴唇和鼻子,所以例如單詞snarl、sneeze、snot、snog、snort等。有着太多這樣的單詞是恰好一致的(個人:就是這里分出來的語素沒法用來表達單詞的意思,一個sn看起來像語素,但是同一個語素卻能存在多個單詞中,所以才覺得按照單詞訓練不太好,想按照字符訓練)。許多人也許會說是的,那么現在該干嘛呢?這完全不影響上嘴唇和鼻子啊,但是問問自己吧,為什么雪(snow,覺得是字幕錯誤,這里就當是某個單詞吧)是針對可卡因的一個好的單詞,然后這些單詞都來自於好幾個部分。所以正常的來說,我們想要將New York視為一個詞匯,但是如果我們想談論紐約的大教堂屋頂,那么我們就需要將new 和york視為兩個獨立的單詞(就是有些詞匯在某些情況是可以視為詞匯,但是某些情況卻需要分開看待)。
還有像Finnish(芬蘭語)這樣的語言,Finnish(芬蘭語)是一個膠合的語言,所以它是將許多語素放在一起來形成一個大單詞。所以這里就有個例子是將5個英語單詞組合成一個單詞的芬蘭語(上圖紅色最長的單詞),這時候就沒法知道單詞的意思了,但是不管是理解的缺失(就是水平不夠),這就是為了說明語素的划分其實很難。
上圖就是一個公認的RNN,可以用來對字符進行建模。本例子中,它有着一個隱狀態,然后Hinton使用了1500個隱藏單元,這里的隱狀態動態就是在時刻T 隱狀態提供的輸入去決定在時刻T+1時的隱狀態,同樣字符也提供着輸入,所以我們將當前字符和之前隱狀態的影響結合起來去得到一個新的隱狀態,然后當我們獲得了一個新的隱狀態,那么就試圖去預測下一個字符。所以我們這里有着在86個字符上(86這個數字目測應該就是ascii中可打印出的字符吧)的一個單一的softmax,然后通過得到的隱狀態去指定高度概率的下一個正確的字符(softmax就是選定輸出層上概率最大的那個作為結果的),然后將低概率的作為其他部分。然后從softmax開始使用BP來訓練整個系統的得到正確字符的低概率情況(就是使誤差最小化,讓整個系統能夠最大概率的識別正確的字符,當然是將正確字符的低概率事件作為誤差考慮了)。
(看上圖結構說明)我們用BP方法先穿過從隱藏到輸出之間的連接(就是輸出層與倒數第二層之間的權重)往回穿過隱藏到字符之間的連接,然后往回穿過隱藏到隱藏之間的連接等等,從所有的路徑返回到字符串的開始部分(也就是輸入層)。
預測86個字符比100,000個單詞簡單的多,所以在輸出層使用softmax也是很容易的,這里沒有前面課程說的那種大softmax的問題。
現在,來解釋為什么不使用那種RNN吧,而是使用另一種不同的網絡,而且工作的效率更好。在我們的例子中,你可能將所有的字符安排成一個有着86個分支率的樹。這里展示的,就是那個大樹的一個微型子樹,事實上,這個子樹將會出現很多次,但是每次代表着不同的事物(這里由fix前面的 三個點來表示)
,所以這里表示我們已經有了整個字符樹,然后我們就有了f,然后是i ,然后是 x。現在如果我們得到了一個 i ,我們就順着根到葉子節點部分往左下方走;如果我們得到了一個 e ,那么我們就往右下方走。所以每次我們得到了一個字符,我們往下移動一層去得到一個新的節點。在長度為n的所有字符串中有着指數級別的節點,所以我們會得到一個超大型樹以至於我們沒法將它們進行存儲起來,如果我們將它存儲起來了,我們所要做的就是在每個箭頭上加上概率了,這就是在給定節點的上下文的情況下得到字母的概率了。
在RNN中,我們試圖處理的事實是這整個樹是很巨大的,是通過一個隱狀態向量來表示每個節點的,所以現在下一個字符所要做的就是:考慮用來表示字符串而且后面跟着fix的一個隱狀態向量,然后在這個隱狀態向量上進行處理去生成一個合適的新隱狀態向量。如果下一個字符是 i 的話,那么就需要將這個隱狀態向量轉化成一個新的隱狀態向量。
關於處理這個(使用RNN的隱狀態)字符樹中的這些節點的一個很好的方法就是通過共享一些結構。例如,在我們到達那個節點的時候,也就是f,i,x ,我們就能決定他可能是個動詞,如果他是一個動詞,那么下一個就多半是 i 了,因為考慮可以用 i,n,g來后綴。而這時候就可以將那些沒有 f i x 的但是具有i,n,g 的子樹進行共享,而且可以在所有動詞之間共享。
注意到,是我們所處的當前狀態的連接和這個字符決定了我們所要走的路徑,我們不想 i 給我們一個狀態說下一個期望的字符是 n 而它卻不是一個動詞,所以我們不需要說i 可能會導致下一個是 n 了。我們想要說的就是,如果已經認為這是一個動詞了,那么當看見一個 i ,那么就期望下一個是 n 。這是實際生活中的聯系:我們認為他是一個動詞,然后我們看見個 i ,這使得我們進入這個狀態被標記為 f,i,x,i,那么就期望遇見下一個是 n。(這里說的比較羅嗦,其實就是這個樹結構可以有組織的搜索,而不是已經匹配了半個單詞的時候,下個字符還需要26個字母的去瞎匹配。就可以通過實際的單詞表等來很好的預測下個字符了)
所以我們通過乘法連接去試圖去實現上述的結果。不使用字符輸入到RNN中去得到額外的輸入,然后輸入給隱藏單元,Hinton這里使用這些字符去在一個完整的隱藏到隱藏的權重矩陣中進行交換,這里字符決定了轉換矩陣。現在,如果使用一個簡單的方法,那么就是讓這86個字符中的每個一都能找到一個1500×1500的矩陣,而這就是有着很多的參數需要處理了,如果我們有了這么多的參數,那么很有可能會過擬合,除非我們在一個超巨大數量的文本上運行,而這也沒那么多時間。
所以解決的方法就是如何達到使用乘法的相互作用的結果,就是在字符決定隱藏到隱藏權重的矩陣上使用更少的參數。通過考慮一個事實:字符在很多地方是通用的。例如,所有的數字在使得隱狀態進化的方式中都是相互之間相似的,所以我們希望對於86個字符中的每一個都得到一個不同的轉換矩陣,但是這86個字符具體權重矩陣能夠共享參數,這是合理的,因為我們知道字符8和9有着非常相似的轉換矩陣。
這里就是我們將要做的事情,這里先引入一個被稱為因子的東西,他們被上圖中有着F的一個三角形表示。因子的意思是組a 和組 b相互之間相乘去提供輸入給組 c。所以每個因子所作的就是首先計算它的兩個輸入組的權重化的和,所以這里先將組a的向量狀態稱之為 a,然后通過一個與因子連接的權重與之相乘,換句話說,就是基於向量a和權重向量u的標量積,就可以得到上圖中三角形左邊頂點的一個值,相似的,我們考慮組b就能得到因子的底部的頂點的值。現在我們將這兩個數字相乘,然后得到一個數字或者標量。然后我們使用這個標量與輸出到組c的權值v相乘去得到組c。就是如上圖中的公式。(中間省略一段廢話)然后,我們就得到了整群因子了。
這里是對因子的另一種理解方式,來說明具體的過程。每個因子實際上定義了一種非常簡單的轉換矩陣,這是一個有着的秩為1的轉換矩陣,所以之前得到的式子中(上圖中最上面那個式子)是將因子視為兩個標量的乘積乘以即將輸出的向量 v (也就是權值)。我們可以重新排列下這個式子(上圖中第二個式子),所以我們得到了一個標量乘積,然后重新安排最后一位,所以現在,我們考慮權重向量 u 和 v,然后得到一個外積,就得到了一個矩陣。這里的標量乘積是由b乘以w得到的,只是這個外積矩陣的系數而已,就是一個標量系數,然后乘以得到的外積矩陣得到一個標量矩陣,然后用當前隱狀態 a 乘以這個矩陣去決定因子 f 的輸入去得到下一個隱狀態。如果我們將所有的因子相加(上圖第三個式子),那么到組 c 的所有輸入就是一個標量的所有因子的和乘以一個秩為 1 的矩陣,這個和得到的是一個大矩陣,這就是所謂的轉換矩陣,然后將它乘以當前的 隱狀態 a 去得到一個新的隱狀態,所以我們能發現我們綜合了這個轉換矩陣,實際上,這個秩為1 的矩陣是由每個因子提供的,組 b 中當前字符所做的就是決定這些秩為 1 的矩陣的每個權值,b 乘以 w 就決定了每個矩陣的標量權值,標量系數。我們這里要做的就是將這個大字符指定正確的矩陣進行組合。
這里就是整個系統的示意圖了。這里有一群因子,實際上會有大約1500個因子,而且字符輸入在這里面是不相同的,只有他們中的一個是激活的(一次只輸入一個字符)所以每一次只有一個相關的權值,這個權值來自於當前的字符 k (上圖中舉的例子),也被稱為Wkf,是用在秩為1 的矩陣上的增益,這個矩陣是 由 u 和 v 的外積得到的。所以這個字符決定了一個增益 ,Wkf, 然后用u和v 得到的矩陣乘以這個增益,接着對所有不同的因子上加上所有的標量矩陣並得到一個轉換矩陣。
三、使用HF去學習並預測下一個字符
這部分將介紹在當Hessian-Free優化被用在包含乘法連接的RNN上和這個網絡在維基上訓練並預測下一個字符時到底發生了什么。這個網絡是在百萬級別的字符上訓練的,而且結果顯示它工作相當的出色。它學習了許多英語然后變得非常擅長以很有趣的方式來完成句子(就是補完句子)。
Ilya Sutskever使用了5百萬個字符串,每個字符串有100個字符,這些都是來自於英語版的維基。對於每個字符串來說,他就開始預測第11個字符后面的字符
,所以這個RNN是以一個默認的狀態開始的,它讀取前11個字符,然后每個時間步改變它的隱狀態,然后它就開始預測了,然后在基於預測上的誤差來使用BP去進行訓練。
他使用了Hessian-free優化,然后在一個非常快的GPU板上訓練了一個月並得到了一個很好的模型。
他的針對字符預測的最好的RNN有可能是當前用來預測字符的最好的單一模型。你可以通過結合不同的模型來比這個模型做的更好,比如決定使用哪個不同的NN,但是如果是單一的模型的話,他的模型也是差不多最好的了。
它與其他模型相比以非常不同的方式工作,所以Ilya的模型能夠平衡引號和括號很長的距離,而任何依賴於匹配指定的之前上下文的模型卻不能做到。例如,如果有一個括號,然后差不多想最多在35個字符后發現右括號,為了合理的完成這個任務,一個依賴於匹配以前上下文的模型就不得不匹配所有的介於括號中的35個字符,而且它也不像已經存儲了整個字符串。
一旦這個模型學習完成,那么就可以看到通過從模型中生成的字符串來觀察它到底知道了什么,當然也不需要過分解讀它所說的。生成字符串的方式是以隱狀態的默認狀態開始的;然后給它一個“燃燒中”的字符串流,所以我們是通過給他饋送字符,然后讓他在每個字符后進行更新它的隱狀態;然后我們讓它停止預測,觀察它預測下一個字符的概率分布;然后隨機從這個分布中挑選出一個字符,所以如果他預測Q的概率是1/1k,那么我們就每1k次挑選一個Q,然后我們告訴這個網絡我們挑選的字符是真實發生的字符,然后叫模型預測下一個字符,換句話說,我們告訴它它猜測的什么都是對的;然后讓它接着預測直到我們得到我們所要的的時候;然后觀察它輸出的字符來觀察他到底知道什么。
所以這里就有個由Ilya的網絡在被輸送一些“燃燒中”的字符串后預測的字符串。這“燃燒中”的字符串是從一個更大段的文本中選擇出來的,但是它也是一個連續的短文,結果顯示這個模型工作的很好。你有可能發現他有一些奇怪的語義聯想,例如“opus paul at rome”沒有人會這么說,但是我們可以理解opus和paul和rome是高度相互關聯的。你也可能注意到它不是真正的擁有很長范圍的主題結構,它在每個句號之后主題后就有了很大的改變。一個令人驚訝的事情是它幾乎不會生成奇怪的單詞(非單詞,就是它生成的都是我們可看過的單詞),意思就是即使他預測字符的概率,一旦你擁有了足夠的字符,那么讓它作為一個英語單詞來完成的唯一方法就是它會近乎完美的預測下一個字符,如果這不會發生的話,它就會生成一個非單詞。即使當它生成了一個非單詞,如上圖中紅色標注的,它們都是一個很好的非單詞。我們不會完全的肯定或者當看見它第一眼的時候,都不認為“ephemerable”不是個英語單詞;
你也許會發現它生成了一個右括號而沒有生成一個左括號,所以它沒有總是很好的平衡括號,它這樣的行為也是挺頻繁的,因為你有可能在文章的最后發現一個左括號然后在很久之后才有一個右括號。這在它的部分一致的行為(這里是解釋為什么上圖只有有括號,有可能在之前就有了左括號),它真的生成了這個右括號,是因為他在之前就有了一個左括號;
如果觀察這個文本,那么就能發現,里面還是有很多很好的局部語法的,所以三、四個單詞組成的單詞串看起來也很有合理性;同樣它有着許多的語義知識。
所以我們能做的一件事就是可以通過給它一些精心設計的字符串來測試這個模型去觀察它所知道的。所以Hinton試圖給它一些非單詞,“Thrunge”這不是一個英語單詞,但是大多數說英語的在但他們看到這個這個單詞的時候,都因為它的形式而猜測這是一個動詞(就是拿一個大多數人都會分錯的單詞給這個模型)。所以給它一個公開的上下文環境然后觀察下一個預測的將會是什么。
所以如果給它一個"Sheila thrunge"然后讓它預測下一個字符,最可能的字符就是 s ,這表明它認為(只是從維基上去讀起來)sheila是一個單數;如果給它“people thrunge”那么下一個最有可能的字符就是一個空格,而不是一個 s ,這表明它知道people是個復數;然后試圖給它一個名字列表,所以這里使用了名字首字母大寫,並在之間用了一個逗號,然后給“thrunge”的首字母大寫讓這個單詞看起來也像個名字,去觀察這個模型會用它們怎么做,然后事實上它真的把它當成個名字了,而且看起來還不是那么糟糕,這也表示它知道很多語言中的一大堆名字;同樣你也可以給他“the meaning of life is”然后看接下來是什么,如果結果是42,那么事情就不會那么有趣了,因為Hinton相當確信這是存在於維基的某個地方的語句,它隨機生成事物,但是在前10次的實驗中,它生成的都是“the meaning of ief is literally recognition”,這在句法上和語義上都是正確的;然后我們試了很多次,然后在上面的測試的10次之后它又得出了一個很有意思的語句,它生成的完整的“the meaning of life is”的語句,從在維基上讀取的結果看來它真的開始知道“the meaning of life”的真正意思了,盡管這可能看起來是奇異的過度解釋了。就是上圖最長的那句。
所以這個模型在讀完了這些維基上得到的字符之后知道的就是:當然它知道單詞,它幾乎總是生成英語單詞,它還知道在字符串的開頭通常都是大寫,它能生成數字和日期和類似的東西,不過它不是經常生成非單詞的,它幾乎很少會犯錯,而且當就算生成了非單詞,那也是具有可以理解的非單詞。它同樣知道很多名字,例如“Frangelini Del Key”,它知道日期和數字和上下文中發生的東西;
它也擅長平衡引號和括號,事實上它能對括號計數。如果你給它的不是一個左括號,它也不怎么生成一個右括號,如果你給它一個左括號,它差不多會在接下來的20或者更多的字符后面生成一個右括號。如果你給它兩個左括號,它會比較快速的生成一個右括號,但是如果給它三個的話不是意味着會更快;
它也清楚的知道一些有關語法的知識,因為它可以生成一些具有意義的簡短的英語單詞串,但是也很難一針見血的說形成這些知識的是什么,它不像三元組模型(之前課程說的)那樣是學習很短的單詞串,或者說他們有個包含簡短單詞串的表。它實際上是綜合了單詞串的,而且它通過有意義的語法來進行綜合的。也很難說是什么形成了語法知識,它也不是像一個語言學一樣有着一大堆的規則,它看起來更像是當一個人說一門語言的時候它腦袋中的語法一樣(傳說中的語感);
它也知道許多的弱語義聯想,所以例如:它甚至只生成一次“Wittgenstein”這個單詞,然后就很快的生成單詞“Plato”,所以它知道Plato和Wittgenstein都是有聯系的,這是一個很好的假設。它清楚的知道“cabbage”是與“vegetable”之間有着聯系。它不知道這些事物聯系的准確方式,同樣人也是這樣,如果你讓他們快速的反應:問你一個問題,然后想要你大聲的喊出答案。即你坐在這里看這個課程,實驗馬上就要開始了,最好如果你知道了這個答案,那么就需要快速大聲的喊出來,你就能很快的得到獎勵,對你說的什么內容不關心,關心的是你的快速反應。那么問題來了:奶牛喝什么?大多數人會立馬喊出來牛奶,但是大多數奶牛在大多數時間上都不喝牛奶。我們說牛奶是因為它有着喝和奶牛上的關系才直接脫口而出的,但是在邏輯上這不符合
最近,Thomas Mikolov和他的同僚已經訓練了一個相當大的RNN去預測在大量的數據集中的下一個單詞,他們使用和前饋NN一樣的技術,即首先將單詞轉換成一個實值特征向量,然后使用這些特征作為網絡剩余部分的輸入,他們做的比前饋NN好很多;他們同樣做的也比最好的其他模型要好;當你將它們與其他最好的模型平均后相比,他們仍然計勝一湊,所以這也是當前最好的語言模型了;
RNN的一個有趣的特性是它與其他達到通級別效果的模型相比需要更少的訓練數據;
更重要的是,正如這些數據集變得越來越大,RNN提升的比其他方法要快,所以其他方法例如三元組,在遇到更大的數據集的時候要想要得到更好的結果,但是卻是更慢的處理速度,你還需要將數據集的尺寸翻倍才能得到一個小的提升結果。而RNN,他們能使用這些數據做的更好,也就是說在隨着數據變得越來越大的情況下,打敗他們將會變得更加困難。Hinton認為這與使用大的,深的NN來做對象識別也是同樣的道理,但是一旦NN領先了,它們就能在更快的計算機和更大的數據集上做的更好,也會讓其他的方法更加的望塵莫及。
四、Echo狀態網絡(echo state network)
在這部分將會介紹echo狀態網絡。通過使用一個聰明的技巧去世的學習RNN變得更容易。他們在RNN中線通過一種方法進行初始化連接,即這種方法中有一個大的耦合振盪器的保留。所以如果你提供輸入給它,它就會將輸入轉換成這些振盪器的阻焊台,然后你就能從這些振盪器的狀態中預測你想要的輸出。唯一你所要學習的就是怎么耦合這些輸出到振盪器。這個方法是完全避免了關於學習隱藏到隱藏連接或者輸入到隱藏的連接的問題。然而,為了讓這些網絡在復雜的任務中表現良好,你就需要一個非常大的隱狀態,正如這部分將要介紹的,沒有原因不使用(就是應該用)給echo狀態網絡精心設計的初始化,然后使用帶有動量的BP through time去訓練這個網絡使它在當前執行的任務上完成的更好。
一個有趣和最近的想法去訓練RNN是完全不要訓練隱藏到隱藏的連接,而是隨機固定他們,並期望你能通過對輸出的影響進行訓練來學習序列。這與老想法的感知機強烈的相似。所以一個簡單的想法去訓練一個前饋NN的方法是去將網絡前面結構上特征檢測層的層隨機賦值固定,就是將這些權值以有意義的尺寸(個人:這里說的就是權重的大小的范圍)隨機賦值,然后所有你要學習的就是最后一層,也就是從最后一層隱藏單元上的激活值到輸出層上去學習一個線性模型。當然學習一個線性模型是可以更快的,這依賴於一個想法:一個輸入向量的大的隨機擴展可以通常使得線性模型能夠容易的擬合數據,當不能很好的擬合數據的時候,那么就觀察下原始的輸入。
雖然這里是個小型nn,這些紅色權值都是隨機固定的,它們會將輸入向量進行擴展,然后使用這些擴展的表征,然后試圖去擬合出一個線性模型。這和SVM很大的相似。所以這些相同的想法,在許多年之后,又重新循環到RNN上被RNN所用,想法就是將輸入到隱藏的連接和隱藏到隱藏的連接給精心選擇的值固定了,只是學習隱藏的最后一層到輸出的連接,然后當你使用的是線性輸出單元的時候,學習是相當簡單的,而且可以做的超級快。這個方法只在你精心安排隨機連接的時候才會工作,所以RNN不會沒有激活值的消失或者爆炸(之前課上講的兩個極端)。
所以在echo狀態網絡中設置隨機連接的方法就是設置隱藏到隱藏的權值使得激活向量的長度能夠保持在每個迭代之后還是相同的。如果使用線性系統和矩陣的話,就設置他們的譜半徑為 1 .,即隱藏到隱藏權值矩陣的最大特征值為 1 ,或者當他是線性系統的時候它就是 1 。如果你想在非線性系統中獲得同樣的特性,如果你設置這些權值都在正確的大小,那么一個輸入就能在遞歸狀態的周圍回顯很長一段時間(這里就是echo的來源)。
同樣的使用稀疏連接也很重要,所以不使用許多中等尺寸的權重,而是有一些相當大的權重,而且在隱藏到隱藏連接上靠近所有這些權重的權重都是為0,這也使得有了很多松散的耦合振盪,所以信息就能在網絡的一部分上掛起,而不會太快的傳遞給網絡的其他部分。
選擇輸入到隱藏連接的尺度同樣也是很重要的,這些連接需要去驅動這些松散的耦合振盪器,但是他們有不能抹去這些信息,也就是這些振盪器需要包括最近的歷史信息。
幸運的是在echo狀態網絡中這些學習是可以很快的,所以我們可以提供實驗去尋找合適的重要連接的尺寸,你可能認為那就是個小的學習循環而已,只是為了學習這些連接的尺寸,而它是通過這些實驗來進行反饋的排序。它同樣有助於學習在隱藏到隱藏連接上的稀疏,同樣的因為學習可以很快,所以可以提供實驗來找到好的解。這很重要是因為通常來說做實驗去使得系統很好的工作是很有必要的。
這里介紹的是一個簡單的例子,從一個echo狀態網絡的web上得到的。它有一個輸入序列,這個序列的實值是隨着時間變化的,並指定了一個echo狀態網絡輸出的sin波的頻率,所以你會希望這個模型能夠生成sin波,這里的輸入是指定這個頻率的。
目標輸出序列是同樣也是用輸出來指定同樣的頻率的波。
而且可以通過設置一個線性模型來簡單的進行學習,這個現象模型考慮隱藏單元的狀態然后用這些來預測正確的標量輸出值。
所以這里就是一張從echo狀態網絡的學術百科上下的圖,為了完成這個程序,輸入信號是sin波的期望頻率,在學習之后得到輸出信號(或者說是監督(teacher)信號),當學習的時候,輸出信號是一個被輸入指定頻率的sin波。在中部的填充是一個大的動態存儲器,所以從輸入信號得到的輸入可以驅動這些松散的耦合振盪器,並引發復雜的動態持續很長一段時間。這些輸出權值可以將這些復雜的動態映射到你想要的輸出的具體的動態。所有的其他圖片都是為了說明事實上包含在動態存儲器中的獨立單元的動態。所需要注意的一件事是從輸出回向到存儲器的連接,這部分不是總是需要的,但是他們有助於告訴存儲器到目前為止到底生成了什么。
這里就是一個在系統學習完之后實際生成的例子,你可以發現在開始部分,他生成一個sin波的相,在最后,他生成一個正確頻率的sin波,但是這個相卻是錯的,這是因為我們沒有告訴它里面應該是什么樣的相的sin波,所以他是滿足生成一個合適頻率要求的。
這里是echo狀態網絡許多好的方面。它們可以被很快的訓練是因為它們只是去擬合一個線性模型;他們同樣證明聰明的隱藏到隱藏權值初始化是很重要的;他們可以令人印象深刻的建立基於一維時間序列模型,這是它們優異的地方,它們可以通過觀察一段時間的時間序列,然后很好的預測未來很長一段時間上的結果,他們不擅長的地方是對高維數據進行建模,例如聲音系數幀,或者視頻幀;為了對像這樣的數據進行建模,它們需要在隱藏到隱藏連接上比RNN更多的隱藏單元;最近,Ilya Sutskever試圖去初始化一個RNN,並使用了所有人們在echo狀態網絡上提出的技巧,一旦你也這么做了,你會發現只是學習隱藏到輸出的連接就可以學習的相當好。但是假定你同樣學着去使隱藏到隱藏的權值更好(就是這里也考慮隱藏到隱藏的權值,Ilya是只對隱藏到輸出的權值進行學習了),那么模型就可以學的更好。所以Ilya試圖是echo狀態網絡初始化,但是隨后使用BP through time 來進行訓練。他使用帶有動量的rmsprop方法,然后發現,這實際上是一個非常高效的方法去訓練RNN。