《神經網絡與深度學習》(六) 循環(遞歸)神經網絡RNN

《遞歸神經網絡難以想象的有效性》(原文"The Unreasonable Effectiveness of Recurrent Neural Networks")html

遞歸神經網絡(RNNs)有一些難以想象的地方。我仍然記得我訓練的第一個用於 圖片字幕的遞歸網絡。從花幾十分鐘訓練個人第一個嬰兒模型(至關隨意挑選的超參數)開始,到訓練出可以針對圖像給出有意義描述的模型。有些時候,模型對於輸出結果質量的簡單程度的比例,會與你的指望相差甚遠,而這還僅僅是其中一點。有如此使人震驚結果,許多人認爲是由於RNNs很是難訓練(事實上,經過屢次試驗,我得出了相反的結論)。一年前:我一直在訓練RNNs,我屢次見證了它們的強大的功能和魯棒性,並且它們的輸出結果一樣讓我感到有趣。這篇文章將會給你展示它難以想象的地方。linux

咱們將訓練一個RNNs讓它一個字符一個字符地生成文本,而後咱們思考「這怎麼可能?」git

順便說句,在講述這篇文章的同時,我一樣會將代碼上傳到 Github 上,這樣你就能夠基於多層LSTMs來訓練字符級語言模型。你向它輸入大量的文本,它會學習併產生相似的文本。你也能夠用它來從新運行我下面的代碼。可是咱們正在不斷超越本身;那麼RNNs到底是什麼呢?github

遞歸神經網絡

序列。你可能會問:是什麼讓遞歸神經網絡如此特殊?Vanilla神經網絡(卷積網絡也同樣)最大的侷限之處就是它們API的侷限性:它們將固定大小的向量做爲輸入(好比一張圖片),而後輸出一個固定大小的向量(好比不一樣分類的機率)。還不止這些:這些模型按照固定的計算步驟來(好比模型中層的數量)實現這樣的輸入輸出。遞歸網絡更使人興奮的主要緣由是,它容許咱們對向量序列進行操做:輸入序列、輸出序列、或大部分的輸入輸出序列。經過幾個例子能夠具體理解這點:web

 

每個矩形是一個向量,箭頭則表示函數(好比矩陣相乘)。輸入向量用紅色標出,輸出向量用藍色標出,綠色的矩形是RNN的狀態(下面會詳細介紹)。從作到右:(1)沒有使用RNN的Vanilla模型,從固定大小的輸入獲得固定大小輸出(好比圖像分類)。(2)序列輸出(好比圖片字幕,輸入一張圖片輸出一段文字序列)。(3)序列輸入(好比情感分析,輸入一段文字而後將它分類成積極或者消極情感)。(4)序列輸入和序列輸出(好比機器翻譯:一個RNN讀取一條英文語句而後將它以法語形式輸出)。(5)同步序列輸入輸出(好比視頻分類,對視頻中每一幀打標籤)。咱們注意到在每個案例中,都沒有對序列長度進行預先特定約束,由於遞歸變換(綠色部分)是固定的,並且咱們能夠屢次使用。redis

正如你預想的那樣,與使用固定計算步驟的註定要失敗的固定網絡相比,使用序列進行操做要更增強大,所以,這激起了咱們創建更智能系統更大的興趣。並且,咱們能夠從一小方面看出,RNNs將輸入向量與狀態向量用一個固定(但能夠學習)函數綁定起來,從而用來產生一個新的狀態向量。在編程層面,在運行一個程序時,能夠用特定的輸入和一些內部變量對其進行解釋。從這個角度來看,RNNs本質上能夠描述程序。事實上,衆所周知, RNNs是圖靈完備的 ,即它們能夠模擬任意程序(使用恰當的權值向量)。可是,相似於通用逼近定理神經網絡,你還不該該深刻閱讀。就當我沒說過這些吧。算法

若是訓練Vanilla神經網絡是優化功能,那麼訓練遞歸神經網絡則是優化程序。

序列缺失狀況下的序列處理。你可能會想,有序列做爲輸入或輸出多是相對少見的,但關鍵是,即便你的輸入/輸出是固定向量,仍然有可能使用這種強大的以序列的方式來處理它們。好比,下圖顯示了 DeepMind 中兩篇很是棒的論文的結果。在左邊,一個算法學習了一種遞歸網絡策略,能夠將它的注意力集中在圖像周圍;特別的,它學會了從左到右閱讀門牌號碼( Ba等人 )。在右邊,一個遞歸網絡經過學習在畫布上序列化地添加顏色而後生成一張數字圖像( Gregor等人 ):編程

  

左邊:RNN學習閱讀門牌號。右邊:RNN學習學習繪製門牌號。api

即便你的數據不是序列形式的,你仍然能夠制定並訓練出強大的模型來學習處理它。你能夠學習有狀態的程序來處理固定大小的數據。數組

RNN計算。那麼這些是如何工做的呢?主要是,RNNs有一個很是簡潔的API:它們將向量x做爲輸入,而後輸出結果向量y.然而,關鍵的是這個輸出向量的內容不只受到前一次輸入數據的影響,並且還會受整個歷史輸入數據的影響。這個API編寫成了一個類,它由一個step方法構成:

 

rnn = RNN()
y = rnn.step(x) # x is an input vector, y is the RNN's output vector

 

RNN類有一些內部的狀態,會在每一次調用 step方法的時候進行更新。最簡單的狀況是,這個狀態由單個隱藏向量h構成。下面是Vanilla RNN中對step方法的一種實現:

 

class RNN:
  # ...
  def step(self, x):
    # update the hidden state
    self.h = np.tanh(np.dot(self.W_hh, self.h) + np.dot(self.W_xh, x))
    # compute the output vector
    y = np.dot(self.W_hy, self.h)
    return y

 

上面的代碼指明瞭vanilla RNN的前饋操做。這個RNN的參數是如下三個矩陣:w_hh,w_xh,w_hy。隱藏狀態self.h由兩個零向量初始化。np.tanh函數實現了非線性的方法,將活化結果壓縮到範圍[-1,1]以內。簡單介紹工做原理:tanh中有兩種形式:一種是基於前面的隱藏狀態,另外一種是基於當前的輸入。numpy中的np.dot是矩陣乘法。這兩種中間體相加,而後由tanh函數將它壓縮成一個新的狀態向量。若是你適合看數學公式的話,咱們一樣能夠將隱藏狀態寫成 ht+1 =tanh(Whh htWxhx t), tanh函數是元素智能的。

咱們用隨機數來初始化RNN矩陣,經過大量的訓練找到一個使人滿意的矩陣,而且用一些損失函數來度量,你能夠在輸入序列x上獲得你但願的輸出y。

更深層次說明。RNNs是一種神經網絡,並且若是你開始學習深度學習並開始像堆煎餅同樣積累模型,它們將會工做得更好(若是作得正確的話)。例如,咱們能夠經過如下方式創建一個2層的遞歸網絡:

 

y1 = rnn1.step(x)
y = rnn2.step(y1)

 

換句話說,咱們有兩個獨立的RNNs:一個RNN接收輸入向量,另外一個將前一個RNN的輸出做爲輸入。這兩個RNN沒有本質區別——這不外乎就是向量的輸入輸出而已,並且在反向傳播過程當中每一個模塊都伴隨着梯度操做。

來點更奇特的。我會簡要說明,實際上咱們大多數人使用一種與上面我所說起稍微不一樣的網絡,它叫作長短時間記憶(LSTM)網絡。LSTM是一種特殊類型的遞歸網絡,在實踐中工做效果更佳,這歸功於其強大的更新方程和一些吸引人的動態反向傳播功能。我不會詳細介紹,除了用於更新計算(self.h=···)的數學形式有點更復雜外,與其餘RNNs沒有多大區別。從如今開始,我將會交替使用術語「RNN/LSTM」,可是這篇文章中全部的實驗都是用LSTM完成的。

字符級語言模型

好,咱們如今已經初步瞭解了什麼是RNNs,爲何它們如此使人興奮,還有它們是如何工做的。咱們如今就用它來實現一個有趣的應用:咱們將要訓練字符級的語言RNN模型。具體來講就是,咱們將會向RNN輸入大量的文本數據,而後在一個序列中給定一個前面的字符,用它來創建計算這個序列下一個字符機率的模型。這將會讓咱們在同一時間產生新文本字符。

做爲一個案例,假設咱們只有四種字母的詞彙「helo」,而後咱們想要用訓練序列「hello」訓練一個RNN。這個訓練序列其實是來自於4個獨立的訓練案例:1.字母e應該在字母h出現的狀況下才可能出現,2.字母l應該出如今he出現的狀況下,3.字母l一樣能夠出如今hel出現的狀況下,最後4.字母o應該出如今hell出現的狀況下。

具體來講,咱們將用1-of-k編碼(全部都是0,除了詞彙中字符的索引)將每一個字符編碼成一個向量,而後用step函數每次向RNN中輸入一個字符。而後咱們會看到一個4維序列的輸出向量(每一個字符表明一個維度),咱們將此做爲RNN分配給序列下一個字符的置信度。下面是一張案例圖:

 

一個有四維輸入輸出層和一個有着3個單元(神經元)的隱藏層的實例。這張圖顯示了當將「helo」做爲RNN的輸入時前饋操做的活化結果。輸出層包含了RNN對下一個出現字符(這裏詞彙是「h,e,l,o」)的置信度。咱們但願使得綠色的數字儘量高而紅色數字儘量低。

好比,咱們能夠看出,在第一次執行step函數的時候,RNN讀取到字符「h」而後將它以後可能出現字符「h」的置信度設置爲1.0,可能出現字符「e」的置信度設置爲2.2,可能出現字符「l」的置信度設置爲-3.0,可能出現字符「o」的置信度設置爲4.1。由於在咱們的訓練數據中,下一個出現的字符是「e」,咱們將要提升這個字符的置信度(綠色數字)而且下降其餘字符的置信度(紅色數字)。一般的作法是使用一個交叉熵損失函數,這至關於在每一個輸出向量上使用Softmax分類器,將下一個出現的字符的索引做爲一個正確的分類。一旦損失進行了反向傳播而且RNN權值獲得更新,在輸入相同的狀況下,下一個正確的字符將會有更高的分數。技術解釋:該RNN是由小批量隨機梯度降低訓練的。我喜歡使用RMSProp (每一個參數的自適應學習率)來穩定更新。

一樣能夠注意到,字符「l」第一次輸入時,獲得的結果是「l」,可是第二獲得的結果是「o」。所以,這個RNN不能單獨依賴於輸入數據,必須使用它的遞歸鏈接來跟蹤內容以達到準確結果。

在測試的時候,咱們向RNN輸入一個字符,而後獲得了下一個可能出現字符的分佈。咱們從這個分佈中抽樣,而後又將這些樣本輸入到RNN中獲得下一個字符。重複這個過程,你就在作取樣的工做了!如今讓咱們在不一樣數據集上訓練RNN,看看會有什麼發生。

爲進一步說明,出於教育目的我還寫了一篇文章 minimal character-level RNN language model in Python/numpy 。只有大約100行代碼,若是你更擅長閱讀代碼而不是文字,你能夠從中獲得簡明的、具體的、有用的結論。如今咱們將深刻到實例結果,使用更高效的Lua/Torch代碼庫來編程。

開心使用RNNs

下面的5個字符模型案例都是使用我發佈在Github上的 代碼 進行訓練的。每一個實例的輸入都是單個文本文件,而後咱們訓練RNN預測序列中下一個可能出現的字符。

Paul Graham生成器

首先讓咱們嘗試用一個小英語數據集做一個全面檢查。我我的最喜歡的數據集是 Paul Graham散文串聯集。其基本思路是,散文中有不少智慧,不幸的是Paul Graham是一個相對緩慢的生成器。若是咱們可以按需生成智慧樣本,那不是很強大?RNNs在這裏就起到了做用。

鏈接過去5年全部的論文,咱們獲得了大約1MB的文本文件,或者說是大約100萬個字符(這是一個很是小的數據集)。技術方面:咱們用512個隱藏節點(大約350萬個參數)來訓練一個2層的LSTM,而後在每層以後設定參數爲0.5的dropout層。咱們將每批訓練100個實例,而後每超過100個字符則中止反向傳播。經過這些設置,每一批在TITAN Z GPU上處理完成大約須要0.46秒(這經過性能代價忽略不計的50個字符的BPTT算法將它分爲兩半)。事不宜遲,讓咱們看看RNN中的樣本:

"The surprised in investors weren't going to raise money. I'm not the company with the time there are all interesting quickly, don't have to get off the same programmers. There's a super-angel round fundraising, why do you can do. If you have a different physical investment are become in people who reduced in a startup with the way to argument the acquirer could see them just that you're also the founders will part of users' affords that and an alternation to the idea. [2] Don't work at first member to see the way kids will seem in advance of a bad successful startup. And if you have to act the big company too."

好了,很明顯上面的樣本不會很快隨時取代Paul Graham,但請記住, RNN不得不徹底從一個小的數據集(包括逗號,頓號和空格的位置)開始學習英語。我一樣喜歡讓它來學習支持本身的論證(好比上面的[2])。有時,它會提供一些可洞察的東西,好比「 a company is a meeting to think to investors」。若是你想了解更多,點擊這個 連接,它有5萬個字符樣本數據。

溫度。咱們一樣能夠在Softmax取樣的時候對溫度進行操做。將溫度從1降至更低的數字(好比0.5)可讓RNN有更高的置信度,可是樣本就會更保守。相反地,較高的溫度將會獲得更多元化的結果,可是失誤就更多(好比拼寫錯誤等)。特別地,將溫度設置成與0接近的數字就會獲得與Paul Graham類似的言論:

"is that they were all the same thing that was a startup is that they were all the same thing that was a startup is that they were all the same thing that was a startup is that they were all the same"

看起來咱們陷入了startups的死循環了。

Shakespeare

看樣子好像咱們的模型能夠學習拼寫英語單詞,可是數據更結構化更風格化又會怎樣呢?爲了檢測這一點,我下載了莎士比亞全部的做品並將它們串起來組成一個單一的(4.4MB)文件。如今咱們能夠訓練一個更大的網絡了,在這個例子中,咱們嘗試使用每層上都擁有512個隱藏節點的3層RNN網絡。在咱們訓練網絡幾小時後,咱們獲得了以下樣本:

 

PANDARUS:
Alas, I think he shall be come approached and the day
When little srain would be attain'd into being never fed,
And who is but a chain and subjects of his death,
I should not sleep.

Second Senator:
They are away this miseries, produced upon my soul,
Breaking and strongly should be buried, when I perish
The earth and thoughts of many states.

DUKE VINCENTIO:
Well, your wit is in the care of side and that.

Second Lord:
They would be ruled after this chamber, and
my fair nues begun out of the fact, to be conveyed,
Whose noble souls I'll have the heart of the wars.

Clown:
Come, sir, I will make did behold your worship.

VIOLA:
I'll drink it.

 

切記,RNN只認識字符,因此它將說話者的名字和內容一塊兒生成爲樣本。有時,咱們還能夠獲得相對延伸的獨白段落,好比:

 

VIOLA:
Why, Salisbury must find his flesh and thought
That which I am not aps, not a man and in fire,
To show the reining of the raven and the wars
To grace my hand reproach within, and not a fair are hand,
That Caesar and my goodly father's world;
When I was heaven of presence and our fleets,
We spare with hours, but cut thy council I am great,
Murdered and by thy master's ready there
My power to give thee but so much as hell:
Some service in the noble bondman here,
Would show him to her wine.

KING LEAR:
O, if you were a feeble sight, the courtesy of your law,
Your sight and several breath, will wear the gods
With his heads, and my hands are wonder'd at the deeds,
So drop upon your lordship's head, and your opinion
Shall be against your honour.

 

在這些樣本中,我幾乎認不出這是莎士比亞的做品:)若是你喜歡莎士比亞,你可能會重視這份100,000個字符的樣本。固然,你也能夠用我提供的代碼,在不一樣溫度下生成許多你本身的樣本。

Wikipedia

咱們看到,LSTM能夠學習拼寫單詞和複製通常的句法結構。讓我來加大難度,在結構化markdown語言上訓練網絡。特別的,讓咱們使用 Hutter Prize 的100MB的Wikipedia原始數據訓練一個LSTM。在Graves等人 以後,我使用前96MB數據來訓練,剩下的則花一個晚上用來驗證和運行幾個模型。如今咱們能夠取樣Wikipedia文章了!下面是幾個有趣的節選。首先,一些基本的markdown輸出:

 

Naturalism and decision for the majority of Arab countries' capitalide was grounded
by the Irish language by [[John Clair]], [[An Imperial Japanese Revolt]], associated 
with Guangzham's sovereignty. His generals were the powerful ruler of the Portugal 
in the [[Protestant Immineners]], which could be said to be directly in Cantonese 
Communication, which followed a ceremony and set inspired prison, training. The 
emperor travelled back to [[Antioch, Perth, October 25|21]] to note, the Kingdom 
of Costa Rica, unsuccessful fashioned the [[Thrales]], [[Cynth's Dajoard]], known 
in western [[Scotland]], near Italy to the conquest of India with the conflict. 
Copyright was the succession of independence in the slop of Syrian influence that 
was a famous German movement based on a more popular servicious, non-doctrinal 
and sexual power post. Many governments recognize the military housing of the 
[[Civil Liberalization and Infantry Resolution 265 National Party in Hungary]], 
that is sympathetic to be to the [[Punjab Resolution]]
(PJS)[http://www.humah.yahoo.com/guardian.
cfm/7754800786d17551963s89.htm Official economics Adjoint for the Nazism, Montgomery 
was swear to advance to the resources for those Socialism's rule, 
was starting to signing a major tripad of aid exile.]]

 

你可能會想,上面的雅虎url並不真實存在,該模型只是將它做爲假想事物。一樣,能夠注意到模型學會正確打開和關閉插入語。模型一樣學會了許多結構化markdown語言,好比,有時候它建立了頭部信息和列表等:

 

{ { cite journal | id=Cerling Nonforest Department|format=Newlymeslated|none } }
''www.e-complete''.

'''See also''': [[List of ethical consent processing]]

== See also ==
*[[Iender dome of the ED]]
*[[Anti-autism]]

===[[Religion|Religion]]===
*[[French Writings]]
*[[Maria]]
*[[Revelation]]
*[[Mount Agamul]]

== External links==
* [http://www.biblegateway.nih.gov/entrepre/ Website of the World Festival. The labour of India-county defeats at the Ripper of California Road.]

==External links==
* [http://www.romanology.com/ Constitution of the Netherlands and Hispanic Competition for Bilabial and Commonwealth Industry (Republican Constitution of the Extent of the Netherlands)]

 

有時模型會生成隨機可是有效的XML文件:

 

<page>
  <title>Antichrist</title>
  <id>865</id>
  <revision>
    <id>15900676</id>
    <timestamp>2002-08-03T18:14:12Z</timestamp>
    <contributor>
      <username>Paris</username>
      <id>23</id>
    </contributor>
    <minor />
    <comment>Automated conversion</comment>
    <text xml:space="preserve">#REDIRECT [[Christianity]]</text>
  </revision>
</page>

 

這個模型徹底拼湊出了timestamp,id等等。一樣,注意到它以正確的嵌套順序適當的閉合了正確的標籤。若是你有興趣瞭解更多,這裏有 100,000 characters of sampled wikipedia

代數幾何(Latex)

以上結果代表,該模型在學習複雜句法結構方面表現得至關不錯。這些結果使人印象深入,個人實驗夥伴( Justin Johnson )和我打算在結構上再深刻研究,咱們使用這本關於代數棧/幾何的 書 。咱們下載了Latex的源文件(16MB),而後訓練了一個多層的LSTM。使人驚訝的是,由Latex產生的樣本幾乎是已經彙總好了的。咱們不得不介入並手動修復了一些問題,這樣你就獲得了合理的數學推論,這是至關驚人的:

 

代數幾何樣本(假的), 真正的PDF文件在這 

這是另外一份樣本:

 

 

產生了更多假的代數幾何,嘗試處理圖像(右)

正如上面你所看到的那樣,有些時候這個模型試圖生成LaTeX圖像,但很明顯它並不明白圖像的具體意思。一樣我很喜歡模型選擇跳過證實過程的那部分(「Proof omitted」,左上角)。固然,Latex有相對困難的結構化句法格式,我本身都尚未徹底掌握。爲舉例說明,下面是模型中的一個原始樣本(未被編輯):

 

\begin{proof}
We may assume that $\mathcal{I}$ is an abelian sheaf on $\mathcal{C}$.
\item Given a morphism $\Delta : \mathcal{F} \to \mathcal{I}$
is an injective and let $\mathfrak q$ be an abelian sheaf on $X$.
Let $\mathcal{F}$ be a fibered complex. Let $\mathcal{F}$ be a category.
\begin{enumerate}
\item \hyperref[setain-construction-phantom]{Lemma}
\label{lemma-characterize-quasi-finite}
Let $\mathcal{F}$ be an abelian quasi-coherent sheaf on $\mathcal{C}$.
Let $\mathcal{F}$ be a coherent $\mathcal{O}_X$-module. Then
$\mathcal{F}$ is an abelian catenary over $\mathcal{C}$.
\item The following are equivalent
\begin{enumerate}
\item $\mathcal{F}$ is an $\mathcal{O}_X$-module.
\end{lemma}

 

這份樣原本自一個相對合適的模型,其中顯示出了一些常見錯誤。好比,模型打開了一個\begin{proof}環境,可是卻以\end{lemma}結束。這個問題咱們必須手動修復,這多是因爲依賴關係太長而致使的:當這個模型作完了 proof過程,它就忘記了它是在作proof仍是lemma了。一樣的,當模型打開了一個\begin{enumerate}環境,而後卻忘記關閉它了。咱們發現,當咱們使用更大/更好的模型的時候,這種狀況出現得就較少了,儘管如此,這些問題仍是會出現。

Linux源代碼

我想看看這個模型處理結構化數據的極限,因此爲了這一終極目標,我打算開始編寫一些代碼,特別的,我瀏覽了 Github上Linux repo 全部的原始資料和頭文件,把它們串在一塊兒造成一個單一的巨大文件(474MB大小的C代碼)(我原本打算只訓練內核,可是它只有16MB)。而後,我花了幾天時間訓練出了大小恰好適合我GPU的3層LSTM網絡。這些模型有大約1000萬個參數,然而這對於RNN網絡來講仍是微不足道的。結果很是有趣:

 

/*
 * Increment the size file of the new incorrect UI_FILTER group information
 * of the size generatively.
 */
static int indicate_policy(void)
{
  int error;
  if (fd == MARN_EPT) {
    /*
     * The kernel blank will coeld it to userspace.
     */
    if (ss->segment < mem_total)
      unblock_graph_and_set_blocked();
    else
      ret = 1;
    goto bail;
  }
  segaddr = in_SB(in.addr);
  selector = seg / 16;
  setup_works = true;
  for (i = 0; i < blocks; i++) {
    seq = buf[i++];
    bpf = bd->bd.next + i * search;
    if (fd) {
      current = blocked;
    }
  }
  rw->name = "Getjbbregs";
  bprm_self_clearl(&iv->version);
  regs->new = blocks[(BPF_STATS << info->historidac)] | PFMR_CLOBATHINC_SECONDS << 12;
  return segtable;
}

 

這代碼總體上看起來很是棒。我認爲它不會立刻就能編譯經過,可是當你滾動查看這些代碼的時候給你的感受是這是一個很是強大的C代碼庫。注意到,RNN處處隨機生成代碼片斷和註釋。它不多會犯語法錯誤。好比,它適當的使用了字符類型、指針概念等。一樣它正確打開和關閉了代碼塊{[,而且學習將代碼縮進。一處常見的錯誤就是它不能跟蹤變量名:它經常會使用未定義的變量(好比上面出現的rw),或者聲明它歷來不用的變量(好比上面的int error),或者返回一個不存在的變量。讓咱們來看看更多的案例。下面是另一個代碼片斷,顯示了RNN學習操做數組的狀況:

 

/*
 * If this error is set, we will need anything right after that BSD.
 */
static void action_new_function(struct s_stat_info *wb)
{
  unsigned long flags;
  int lel_idx_bit = e->edd, *sys & ~((unsigned long) *FIRST_COMPAT);
  buf[0] = 0xFFFFFFFF & (bit << 4);
  min(inc, slist->bytes);
  printk(KERN_WARNING "Memory allocated x/x, "
    "original MLL instead\n"),
    min(min(multi_run - s->len, max) * num_data_in),
    frame_pos, sz + first_seg);
  div_u64_w(val, inb_p);
  spin_unlock(&disk->queue_lock);
  mutex_unlock(&s->sock->mutex);
  mutex_unlock(&func->mutex);
  return disassemble(info->pending_bh);
}

static void num_serial_settings(struct tty_struct *tty)
{
  if (tty == tty)
    disable_single_st_p(dev);
  pci_disable_spool(port);
  return 0;
}

static void do_command(struct seq_file *m, void *v)
{
  int column = 32 << (cmd[2] & 0x80);
  if (state)
    cmd = (int)(int_state ^ (in_8(&ch->ch_flags) & Cmd) ? 2 : 1);
  else
    seq = 1;
  for (i = 0; i < 16; i++) {
    if (k & (1 << 1))
      pipe = (in_use & UMXTHREAD_UNCCA) +
        ((count & 0x00000000fffffff8) & 0x000000f) << 8;
    if (count == 0)
      sub(pid, ppc_md.kexec_handle, 0x20000000);
    pipe_set_bytes(i, 0);
  }
  /* Free our user pages pointer to place camera if all dash */
  subsystem_info = &of_changes[PAGE_SIZE];
  rek_controls(offset, idx, &soffset);
  /* Now we want to deliberately put it to device */
  control_check_polarity(&context, val, 0);
  for (i = 0; i < COUNTER; i++)
    seq_puts(s, "policy ");
}

 

注意到,在第二個函數中,模型進行了這樣的比較tty == tty,這是永遠成立的。可是,至少此次變量tty只在這個函數中起做用!最後一個函數,注意到代碼沒有返回任何值,可是這是正確的由於函數的返回值聲明成了void。可是,前兩個函數一樣聲明成了void返回類型,卻返回了數值。這又是一個因爲長期迭代致使的常見錯誤。

有些時候模型會決定如今是時候產生一個新的文件了。這一般是有趣的部分:首先模型一個一個字符記住GNU許可證,而後include幾個頭文件,聲明一些宏,而後就開始生成代碼部分:

 

/*
 *  Copyright (c) 2006-2010, Intel Mobile Communications.  All rights reserved.
 *
 *   This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 *        This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software Foundation,
 *  Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/kexec.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/multi.h>
#include <linux/ckevent.h>

#include <asm/io.h>
#include <asm/prom.h>
#include <asm/e820.h>
#include <asm/system_info.h>
#include <asm/setew.h>
#include <asm/pgproto.h>

#define REG_PG    vesa_slot_addr_pack
#define PFM_NOCOMP  AFSR(0, load)
#define STACK_DDR(type)     (func)

#define SWAP_ALLOCATE(nr)     (e)
#define emulate_sigs()  arch_get_unaligned_child()
#define access_rw(TST)  asm volatile("movd %%esp, %0, %3" : : "r" (0));   \
  if (__type & DO_READ)

static void stat_PC_SEC __read_mostly offsetof(struct seq_argsqueue, \
          pC>[1]);

static void
os_prefix(unsigned long sys)
{
#ifdef CONFIG_PREEMPT
  PUT_PARAM_RAID(2, sel) = get_state_state();
  set_pid_sum((unsigned long)state, current_state_str(),
           (unsigned long)-1->lr_full; low;
}

 

這裏有太多有趣的地方能夠講述了,關於這部分我可能能夠寫一篇完整的博客來說述。可是在這裏我就省略這部分了,若是你有興趣查看,請點擊 1MB of sampled Linux code

瞭解到底發生了什麼

咱們能夠看出,最終訓練出的結果是使人印象深入的,可是這一切都是如何工做的?讓咱們經過運行兩個快速的實驗來簡要探索下。

訓練中樣本的演變

首先,探索模型訓練過程當中樣本文本是如何演變的是件有趣的事,好比,我用列夫·托爾斯泰的《戰爭與和平》訓練了一個LSTM網絡,而後每100次迭代訓練就生成樣本。100次迭代後模型生成了隨機、混亂的樣本:

 

tyntd-iafhatawiaoihrdemot  lytdws  e ,tfti, astai f ogoh eoase rrranbyne 'nhthnee e 
plia tklrgd t o idoe ns,smtt   h ne etie h,hregtrs nigtike,aoaenns lng

 

可是,注意到模型最少知道了要在每一個「單詞」間加上空格。有些時候會加上兩個空格。一樣模型不知道逗號後面一般跟着空格。300次迭代後咱們能夠看到模型開始有了引號和句號的概念:

 

"Tmont thithey" fomesscerliund
Keushey. Thom here
sheulke, anmerenith ol sivh I lalterthend Bleipile shuwy fil on aseterlome
coaniogennc Phe lism thond hon at. MeiDimorotion in ther thize."

 

此次單詞之間一樣由空格隔開,並且模型開始知道在句子末尾加上句號。500次迭代:

 

we counter. He stutn co des. His stanted out one ofler that concossions and was 
to gearang reay Jotrets and with fre colt otf paitt thin wall. Which das stimn 

 

如今模型會拼寫最短、最多見單詞,好比「we」,「He」,「His」,「Which」,「and」等。700次迭代的時候,咱們獲得了更像英語的文本:

 

Aftair fall unsuch that the hall for Prince Velzonski's that me of
her hearly, and behs to so arwage fiving were to it beloge, pavu say falling misfort 
how, and Gogition is so overelical and ofter.

 

在通過1200次迭代後,咱們發現模型開始使用引號和問號/感嘆號了,與此同時也學會了更長的單詞:

 

"Kite vouch!" he repeated by her
door. "But I would be done and quarts, feeling, then, son is people...."

 

通過2000次迭代,模型可以正確拼寫的單詞,引號,名字等:

 

"Why do what that day," replied Natasha, and wishing to himself the fact the
princess, Princess Mary was easier, fed in had oftened him.
Pierre aking his soul came to the packs and drove up his father-in-law women.

 

大致上咱們能夠這麼認爲,首先模型發現了單詞-空格這樣廣泛的結構,而後迅速學會拼寫單詞;從學習拼寫簡單單詞開始到最後學習拼寫長單詞。在單詞中顯現出主題內容(通常依賴於長期性)在不少次迭代後纔出現。

RNN預測結果和神經元激活可視化

可視化有趣的另外一個方面是能夠按字符來觀察預測分佈。在下面的可視化圖中,咱們向Wikipedia RNN模型中輸入了校驗好的數據集(藍色/綠色的行)中的字符,而後在每一個字符下面,咱們列出了(紅色部分)模型預測會出現的前5個字符,顏色深淺根據它們機率大小決定(深紅:預測準確,白色:不許確)。好比,注意到有一連串字符是模型很是有信心可以預測準確的(對http://www.序列模型置信度很是高)。

輸入字符序列(藍色/綠色)的顏色取決於RNN隱藏層中隨機選擇的神經元的激活狀況。定義綠色=很是興奮,藍色=不是那麼興奮(對於那些熟悉LSTMs細節的人來講,這些就是隱藏向量中[-1,1]範圍內的值,也就是通過門限操做和tanh函數的LSTM單元狀態)。直觀的,下圖顯示了在RNN「大腦」讀取輸入序列時一些神經元的激活狀況。不一樣的神經元可能有不一樣的模式;下面咱們將會看到我找到的4個不一樣的神經元,我認爲這幾個是有趣的,而且是可解釋的(許多其餘的並不容易解釋):

 

此圖中高亮的神經元彷佛對URL極度興奮,URL之外的地方就不那麼興奮。LSTM彷佛會用這種神經元來記住它是否在URL之中。

 

在這張圖中,當RNN在[[]]標記之中時,高亮的神經元表現極度興奮,因此在這種標記以外就沒那麼興奮,在神經元碰到字符「[」的時候不會表現得興奮,它必定要等到出現第二個「[」纔會激活。計算模型是否碰到了一個仍是兩個「[」的任務彷佛能夠用一個不一樣的神經元完成。

 

在這裏,咱們能夠看出在[[]]環境中,神經元有着線性的變化。換句話說,它的激活函數給了RNN中[[]]範圍的一種基於時間的座標系統。RNN能夠經過這些信息或多或少的依賴於字符在[[]]中出現的早/晚來生成不一樣的字符(有多是這樣)。

 

這是另一個神經元,它有着更個性化的行爲:它總體上比較平淡無常,可是碰到「www」中第一個「w」的時候忽然就開始變得興奮。RNN可能可使用這種神經元來計算「www」序列的長度,這樣它就知道是否應該再添加一個「w」仍是開始添加URL。

固然,因爲RNN隱藏狀態的龐大性,高維度性和分佈式特性,不少這樣的結論都稍微要加上特別說明才能理解。

源代碼

我但願經過我上面的講述,你會以爲訓練一個字符級語言模型是一次有趣的練習。你可使用我在Github(擁有MIT許可)上發佈的 char-rnn code 來訓練你本身的模型。它將大量文本文件做爲輸入,訓練出一個字符級模型,而後你就能夠從中獲得樣本文件。同時,若是你有一個GPU的話會對你有所幫助,否在在CPU上訓練的話會花大約10多倍的時間。無論怎樣若是你完成了訓練而且獲得了有趣的結果,請告知我!若是你在使用Torch/Lua代碼庫的時候碰到困難,請記住,這只是 100-line gist 的一個版本。

一些題外話。代碼是由 Torch7 編寫的,它最近成了我最喜歡的深度學習框架。我是最近幾個月纔開始使用Torch/Lua的,它們並不簡單(我花了大量時間來閱讀Github上Torch源碼,向它的發佈者提問才掌握它),可是一旦你掌握了足夠的知識,它就會給你帶來很大的靈活性和速度提高。我之前一樣使用過Caffe和Theano,我認爲Torch並不完美,可是它的抽象層次和原理比其餘的要優秀。在我看來,一個有效框架應該具備如下功能:

 

  1. 有許多功能(slicing,array/matrix等操做)的CPU / GPU透明的Tensor庫。
  2. 一個徹底獨立的代碼庫,它基於腳本語言(最好是 Python),工做在Tensors上,實現了全部深度學習方面的東西(前饋/後饋,圖形計算等)。
  3. 它應該能夠輕鬆共享預訓練模型(Caffe在這方面作的很好,其餘幾個則存在不足),這也是相當重要的。
  4. 沒有編譯過程(或者說不要像Theano目前那樣作)。深度學習是朝着更大更復雜的網絡發展,因此在複雜圖算法中花費的時間會成倍增長。重要的是,長時間或者是在開發階段不進行編譯所帶來的影響是很是巨大的。並且,進行編譯的話就會丟失可解釋性和有效進行日誌記錄/調試的能力。若是爲提升效率在圖算法開發好後當即編譯,那麼這樣作是可取的。

 

延伸閱讀

在結束這篇文章以前,我還想再介紹更多關於RNNs的東西,並大體提供目前的研究方向。最近在深度學習領域,RNNs頗受歡迎。和卷積網絡同樣,它們已經存在了幾十年,但它們的潛力最近纔開始獲得普遍的承認,這在很大程度上是由於咱們不斷增加的計算資源。下面是一些最近事態發展的簡要介紹(這絕對不是完整的列表,不少這樣的工做讓研究界好像回到了上世紀90那種研究熱潮,來看看相關的工做部分):

在NLP/語音領域,RNNs將 語音轉錄成文本 ,使用 機器翻譯 , 生成手寫文本 ,固然,它們已經被用來當作強大的語言模型( Sutskever等人 )( Graves )( Mikolov等人 )(都是在字符和單詞層面)。目前看來,單詞級的模型比字符級的模型要更好,但這確定是暫時的。

計算機視覺。在計算機視覺方面,RNNs也很快成爲了無處不在的技術。好比,咱們會見到RNNs在幀層面 分類視頻 , 添加圖片字幕 (一樣包括我和其餘人的工做), 添加視頻字幕 ,最近又用來 視覺問答 。我我的最喜歡的RNNs計算機視覺方面的論文是 Recurrent Models of Visual Attention ,這是由於它有着高層次方向特性(glance順序處理圖像)和低層次建模(REINFORCE學習規定它是強化學習中一個特定的梯度方法,能夠訓練出進行不可微計算的模型(以圖像周邊glance處理爲例))。我相信,這種混合模型類型——由CNN造成的原始感知器再加上RNN glance策略,將會在感知器中廣泛存在,特別是對於比分類更復雜的任務。

概括推理,存儲和關注模塊。另外一個很是使人興奮的研究方向是面向解決Vanilla遞歸網絡的侷限性。它的一個問題是RNNs不是數學概括的:它們可以很是好的記住序列,可是並不必定總可以獲得正確的結果(我會舉幾個例子來具體說明)。第二個問題是,它們沒必要每步都將表明大小和計算數量結合起來。具體來講,若是你把隱藏狀態向量的大小增長一倍,因爲矩陣乘法,每步中FLOPS的數量會變成原來的四倍。理想狀況下,咱們想保持龐大的表明性/存儲(好比,包含維基百科全部的內容或者多箇中間狀態變量),而同時保持計算的每一個時間步長固定的能力。

在這些方向上,第一個有說服力的例子在DeepMind上的 Neural Turing Machines 這篇論文中講述了。這篇論文描述了在計算開始時,模型在大的、外部的存儲陣列和更小寄存器之間執行讀寫操做的方法(把它想象成是你本身的工做存儲器)。相當重要的是,這篇論文也一樣介紹了有趣的內存尋址機制,這是用一個(平緩的,徹底可微的)關注模塊實現的。平緩關注模塊的概念是一個強大的建模特徵,同時也是 Neural Machine Translation by Jointly Learning to Align and Translate 這篇文章再機器翻譯上的一大特點,網絡存儲則用來問答。事實上,我不得不說:

關注模塊的概念在最近的神經網絡架構創新中是最有趣的。

如今,我不想講太多的細節,可是內存尋址的平緩關注模塊機制是很是方便的,由於它讓模型徹底可微,但不幸的是,這會犧牲一些效率,由於全部能夠被關注的都被關注了(平緩的)。你能夠把它想象成C語言中的指針,它不指向具體的地址,而是定義了在整個內存中分佈的全部地址,並將指針返回的所指向內容的加權總和值非關聯化(這個操做代價會很大!)。這促使多位做者在給多塊內存進行關注操做的時候使用平緩關注方式而不是猛烈關注方式(好比,對某些內存單元進行讀取操做,而不是從內存單元中讀出/寫入到某些地方)。這種模型有着更顯著的哲學吸引力,可擴展性和高效率性,可是不幸的是,它是不可微的。這就要使用強化學習文獻(好比REINFORCE)中使用到的技術來解決,人們將它完美地用於不可微的模型之中。這是正在進行的工做,可是針對這些困難的關注模型進行了探討,你能夠在 Inferring Algorithmic Patterns with Stack-Augmented Recurrent Nets Reinforcement Learning Neural Turing Machines , Show Attend and Tell 這幾篇論文中瞭解到。

人物。若是你願意閱讀我推薦的 Alex Graves , Ilya Sutskever 和 Tomas Mikolov 所寫的文章。你能夠從 David Silver 或 Pieter Abbeel 的公開課中瞭解到更多的關於REINFORCE,強化學習和策略梯度方法的知識。

代碼。若是你想實踐實踐訓練RNNs,我推薦你使用Theano的 keras 和 passage ,也可使用連同這篇文章一同發佈的Torch 代碼 ,或者使用我先前寫好的numpy源代碼 要點 ,它實現了一個有效率的、批量處理的LSTM前饋和後饋處理。你也能夠看看我基於numpy的 NeuralTalk ,它用了RNN/LSTM來給圖片加字幕,或者你可使用Jeff Donahue寫的 Caffe 

總結

咱們已經學習了RNNs是如何工做的,它們爲何變得相當重要,咱們在幾個有趣的數據集上訓練了一個字符級的RNN模型,而且咱們看到了RNNs的執行狀況。你徹底能夠毫無顧忌的用RNNs進行大量創新,而且我相信它們會在智能系統中成爲一種廣泛存在而且相當重要的組成部分。

最後,在這篇文章中加上一些元數據,我用這篇文章的源文件訓練了一個RNN。不幸的是,我只有46K的字符,沒有足夠的字符給RNN,可是返回的樣本(使用低溫度以獲得更典型的樣本)以下所示:

 

I've the RNN with and works, but the computed with program of the 
RNN with and the computed of the RNN with with and the code

 

好了,這篇文章是講述關於RNN和它工做情況的,很明顯它工做良好 :)。咱們下回見!

原文連接: The Unreasonable Effectiveness of Recurrent Neural Networks(譯者/劉翔宇 審校/劉帝偉、朱正貴、李子健 責編/周建丁)

轉自 http://blog.csdn.net/memray/article/details/48652647

相關文章
相關標籤/搜索