RNN的神奇之處(The Unreasonable Effectiveness of Recurrent Neural Networks)
RNN有很多神奇的地方。我仍然記得為Image Captioning訓練的第一個RNN。我隨便設定了超引數,在訓練了幾十分鐘後這個小模型開始產生看起來非常不錯、幾乎有意義的描述。有些時候,模型的簡單程度與結果超出預期的程度對比十分懸殊——我的第一個RNN就是這些時候之一。當時這個結果讓我大吃一驚的原因是一個共識,即RNN是很難訓練的(事實上相比於支援這一共識,我的經歷裡大多數都是反對這一共識的)。快進到一年後:我一直在訓練RNN,許多次都見證了這個模型的能力(power)和健壯(robustness),仍然會有些神奇的輸出讓我在某些方面感到好玩。這篇部落格就是為了與你分享那些神奇之處。
我們將會訓練一個逐字產生文字的RNN,同時思考這一問題“這怎麼可能發生呢?”
本文用一個多層LSTM訓練了一個character-level的語言模型,程式碼在Github上。你可以用這些程式碼來複現我的實驗。但是現在先讓我們來想想:究竟什麼是RNN?
1 RNN
序列(Sequence)。什麼使得RNN如此特殊?Vanilla RNN的一個明顯的侷限是它的API的侷限性太強:輸入必須是固定長度的向量(如影象),產生的輸出也是固定長度的向量(如不同類別的概率)。除此之外,模型是通過固定數量的計算步驟(如模型中的網路層數)來完成這一對映的。RNN如此神奇的一個核心原因就是它允許我們操作向量的序列。輸入可以是序列,輸出也可以是序列,或者在大多數情況下,輸入輸出都是序列。下面是一些更具體形象的例子:
上圖中矩形代表向量,箭頭代表函式。輸入向量是紅色,輸出向量是藍色,綠色向量是RNN的狀態。從左到右依次為:(1) Vanilla mode,從固定大小的輸入到固定大小的輸出,如影象分類問題。(2) 輸出是序列,如Image Captioning。(3) 輸入是序列,如情感分析,輸入是一個句子,輸出是對句子情感極性的判定(積極或消極)。(4)輸入是序列,輸出也是序列,如機器翻譯。(5) 輸入與輸出是序列且同步,如一種視訊分類任務:對視訊中的每一幀打標籤。注意,對於序列長度是沒有任何限制的,因為圖中的遞迴變換(綠色矩形)可以被應用任意次。
正如你所期待的那樣,這種序列化的操作機制相比於固定大小的網路更為強大,因為後者在最開始就確定要計算多少步註定了模型的厄運,而且前者對於追求更加智慧的系統的我們來說也更有吸引力。另外,在之後的部分中我們將會看到,RNN將輸入向量和狀態向量用一個固定的(但是是學習過的)函式結合起來產生了一個新的狀態向量。在程式語言中,這可以被寫成一個固定的程式,這段程式有固定的輸入和一些內部變數。從這個角度說,RNN本質上是在描述程式(program)。事實上,從RNN可以模擬任意程式的角度來說,RNN是圖靈完備的(Turing-complete)。但是與神經網路的通用逼近定理一樣,你不應理解太多。忘掉我剛剛說的吧。
如果說訓練一個Vanilla是在優化函式,那麼訓練RNN就是在優化程式。
沒有序列時的序列化處理。你可能認為輸入或輸出為序列的情況比較少見,但是你必須意識到的重要的一點是:即便你的輸入或輸出是固定的向量,你也可以用這種強大的機制序列化的處理它。例如,下面兩張圖展示了DeepMind的兩個很棒的工作。左圖展示的是一個遞迴網路策略的演算法,它引導注意力遍歷整幅圖片,學習從左到右讀出門牌號(Ba et al.)。右圖是一個通過學習按順序向canvas新增顏色來產生數字圖片的遞迴網路(Gregor et al.)。
這一段及例子想要告訴你的是:即便你的資料不是序列的形式,你也可以把它變成序列的形式,然後學習一個很強的模型序列化的處理它。學習的是一個有狀態的、能夠處理固定大小資料的程式。
RNN的計算。所以這些事情如何工作呢?核心部分,RNN有一個欺騙性的簡單的API,接受輸入向量x
和輸出向量y
。然而,關鍵是輸出向量的內容不僅受你給定的輸入的影響,也受到你在過去給定的全部歷史輸入的影響。如果寫成一個類,RNN的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函式被壓縮,結果成為新的狀態變數,數學形式是
我們對RNN中的矩陣進行隨機初始化,在訓練過程中的大部分都在尋找可以是目標行為上升的矩陣,通常用某種損失函式來度量。損失函式表達了在給定輸入序列x
下,你更像見到哪種y
作為響應。
變“深”。RNN是神經網路,如果你戴上深度學習的帽子,開始把模型像煎餅一樣堆起來,每部分也能工作的很好。例如,我們可以像下面這樣建立一個2層的遞迴網路:
y1 = rnn1.step(x)
y = rnn2.step(y1)
換句話說我們有兩個單獨的RNN:一個RNN接收輸入向量,第二個RNN接收第一個RNN的輸出作為輸入。除了其中的任一個RNN知道或在意——其實輸入和輸出的都只是向量,在反向傳播過程中梯度會在每個模組中傳遞。
加點想象力。我想簡單提一下,在實際應用中我們採用一種LSTM的網路結構,與我上面描述的有一點不同。LSTM是RNN的一種,在實際應用中效果更好,因為它的更新方程更有效以及一些更動人的反向傳播特性。我不會具體介紹,但是上面我說的關於RNN的描述都是一樣的,只有更新隱藏狀態的數學表示式(self.h=...
那一行)變得更復雜了一點。從這裡開始我將交替使用”RNN”和”LSTM”這兩個名詞,但是這篇博文裡的實驗都使用了LSTM。
2 Character-level的語言模型
好啦,現在我們對RNN是什麼,為什麼讓人激動,以及是如何工作的有了一些瞭解。現在我們來通過一個有趣的應用來落實它:我們將訓練一個RNN character-level language model。意思是,我們餵給RNN大量的文字然後讓它依據已有的字元序列來對下一個字元的概率分佈建模。這回讓我們每一次為新文字產生一個字元。
舉一個可以手工操作的例子,假設我們現在有一個詞典,只包含四個可能的字母,
“h,e,l,o”,想訓練一個RNN,訓練序列是”hello”。這個訓練序列事實上產生了四個訓練例項:1.給定上文”h”,”e”的概率應該比較大;2.給定上文”he”,”l”的概率應該比較大;3.給定上文”hel”,”l”的概率應該比較大;4.給定上文”hell”,”o”的概率應該比較大。
更具體地,我們使用1-k編碼(i.e.只有字元在詞典中對應的下標的位置為1,其餘位置都為0)將每個字元編碼成一個向量,然後將它喂進RNN,每次用step
函式喂進一個字元。我們將會觀察到一個4維輸出向量(一個字元一維),我們可以把這個向量理解成RNN當前分配給每個字元將要在序列中下一位置出現的“信心”。
上圖是一個4維輸入的及4維輸出的RNN,隱藏層有3個單元。圖中描述的是以”hell”為輸入時RNN的前向傳播過程。輸出層的向量是RNN分配給下一個字元的“信心”;我們希望綠色的數值高,紅色的數值低。
(跳過半段對上圖的具體描述)
由於RNN全部由可導計算組成,我們可以應用反向傳播來找出我們應該想哪一個方向來調整權重向量使得希望的字元的分數變高。引數更新就是將每一個權重向量向梯度方向移動一個極小的量。如果我們在引數更新後喂進同樣的輸入,我們會發現正確的字元的分數會略微變高,錯誤的字元的分數會略微降低。我們可以重複許多次直到網路收斂,即它的輸出最後和訓練資料一致——總是能正確的預測下一個字元。
一個更技術流的解釋是,我們可以對每個輸出向量同時用Softmax分類器(也經常被稱為交叉熵損失函式)。RNN採用mini-bach隨機梯度下降法訓練,我喜歡用RMSProp或Adam(每個引數的學習率自適應)的方法來穩定更新。
注意第一次字元”l”輸入時,期望目標是”l”;但第二次時期望目標是”o”。因此RNN不能只依賴於輸入,必須利用遞迴關係來跟蹤記憶上文來完成這個任務。
在測試時,我們給RNN一個字元,然後得到字元可能在下一個位置出現的概率分佈。我們從這個分佈取樣,將取樣得到的結果當做下一個字元喂進RNN。重複這個過程你就是在對文字取樣!下面讓我們在不同的資料集上訓練RNN然後看看發生了什麼。
3 RNN的有趣之處
譯者注:本部分是對在不同資料集上結果的描述,在翻譯過程中有所刪減,只保留以下內容:資料集簡介,模型結構,訓練方式,效果評估。
3.1 保羅·格雷厄姆發生器
我們先用一個小的英文資料集做一個檢查。我最喜歡的趣味資料集是(保羅·格雷厄姆Paul Graham的文章集錦](http://www.paulgraham.com/articles.html]。
資料集:將PG近五年的文章合成一個約1MB大的文字檔案,包含了大約100萬個字元。
模型:2層LSTM隱藏層,每層512個節點,大約350萬個引數,每層dropout設為0.5。
訓練:每個batch包含100條樣本,反向傳播進行100個timestep就截斷。在TITAN Z GPU上,每個batch號是0.46秒。如果將BPTT限制在50,效果差不多但是耗時可以減半。
效果評估:一段節選如下:
“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.”
不幸的是,這個RNN模型完全不能取代PG,但是記得這是RNN完全從0開始學英語得到的,而且是在一個比較小的資料集上(包含了逗號,省略號,空格)。而且看起來它學會了支撐自己的觀點(e.g.[2])。而且某些地方能提供一絲靈感,如”a company is a meeting to think to investors”。如果你感興趣,可以看看這個5萬字符的結果。
溫度引數。我們可以調整取樣過程中Softmax函式的temperature引數。把T從1降低會使RNN更加自信,這意味著結果會更加保守,更“像”訓練樣本。相反,更高的T會提高多樣性,作為代價錯誤會更多(如拼寫錯誤等)。特殊的,將T設為接近0的值會產生最像PG說的話,如
“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”
譯者注:溫度引數是Softmax函式中的一個引數,預設為1。當T很大時,即趨於正無窮時,所有的啟用值對應的啟用概率趨近於相同(啟用概率差異性較小);而當T很低時,即趨於0時,不同的啟用值對應的啟用概率差異也就越大。Hinton在2015年的一篇文章中闡釋了如何根據溫度引數來soften神經網路的輸出,提出了distillation的方法。
3.2 莎士比亞
看起來RNN能學會拼寫英語單詞。那麼當資料中有更多的結構(structure)和題材(style)時它能否學會呢?為了檢驗這一點我下載了莎士比亞的所有作品來實驗。
資料集:4.4MB的文字檔案
模型:3層的LSTM隱藏層,每層512個節點
訓練:幾小時
效果評估:
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.
3.3 維基百科
我們已經看到LSTM可以學會拼寫單詞以及特定的語法結構。下面讓我們來提高難度,在有結構的markdown文字上訓練。
資料集:Hutter Prize 100MB資料。其中96MB用來訓練,其他用來測試。
訓練:一夜(overnight)
效果評估:
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][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.]]
上面的雅虎網址並不存在。值得注意的是,模型學會了正確的使用括號。模型也學會了正確使用一些複雜的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>
在上面這段XML中,時間戳、id等標籤的內容都是合法的。標籤也按照正確的順序關閉了。
3.4 代數幾何(LaTeX)
前面三個例子的結果說明模型在學習複雜的語法結構上確實表現不錯,這給我和同事Justin Johnson留下了深刻印象,於是我們決定在結構化的領域進行更深入的嘗試並拿到了一本代數幾何方面的書。我們下載了LaTeX原始檔(大小為16MB的一個檔案)並訓練了一個多層LSTM。令人驚喜的是,sample生成的LaTeX原始碼幾乎可以編譯。我們手工調整了幾個問題然後你就可以看到下面這樣的“假數學”,太驚喜了!
在上面的圖中你可以看到,模型還試圖產生LaTeX示意圖,雖然並沒有真的解決它。我還喜歡它選擇跳過證明的那部分(第二張圖左上角)。當然,你要記得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}
來結尾。這個是我們需要手工調整的問題的一個例子,很有可能是由於依賴過於長期而導致的——當模型結束證明的時候它已經忘記了它是在做一個證明還是一個引理。相似地,它開始了一個\begin{enumerate}
但是忘了結束它。當我們使用更大或更好的模型時,這類問題會少一些,但是仍然存在。
3.5 Linux原始碼
我想探索一下結構化資料表現上的極限,因此最後的挑戰我決定使用程式碼。我把Github上的Linux程式碼庫中的全部程式碼和標頭檔案合成了一個巨大的檔案(474MB的C程式碼)。然後我花了幾天時間訓練了幾個達到了我的GPU計算極限的3層LSTM模型。這些模型大概有一千萬個引數,對於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時不時的在程式碼中加入一些註釋作調劑,而且很少有語法錯誤。比如,它正確使用了字串、指標等,也學會了匹配括號和縮排程式碼。一個比較普遍的問題是它失去了對變數名的追蹤,經常會使用未定義的變數,宣告從未使用的變數或者是返回一個不存在的變數。
還有很多有趣的地方,如果你感興趣可以看看這個1MB的Linux程式碼樣本。
3.6 生成嬰兒名字
讓我們試一個有意思的。給RNN一個包含8000嬰兒名的大檔案,每行是一個名字,然後它可以生成新名字!我挑選了一些在訓練資料中沒有出現過的新名字(90%沒有出現過)列在下面:
Rudi Levette Berice Lussa Hany Mareanne Chrestina Carissy Marylen
Hammine Janye Marlise Jacacrie Hendred Romand Charienna Nenotto Ette
Dorane Wallen Marly Darine Salina Elvyn Ersia Maralena Minoria Ellia
Charmin Antley Nerille Chelon Walmor Evena Jeryly Stachon Charisa
Allisa Anatha Cathanie Geetra Alexie Jerin Cassen Herbett Cossie Velen
Daurenge Robester Shermond Terisa Licia Roselen Ferine Jayn Lusine
Charyanne Sales Sanny Resa Wallon Martine Merus Jelen Candica Wallin
Tel Rachene Tarine Ozila Ketia Shanne Arnande Karella Roselina Alessia
Chasty Deland Berther Geamar Jackein Mellisand Sagdy Nenc Lessie
Rasemy Guen Gavi Milea Anneda Margoris Janin Rodelin Zeanna Elyne
Janah Ferzina Susta Pey Castina
更多名字可以去這裡看。我最喜歡的幾個是”Baby”, “Killie”, “Char”, “R”, “More”, “Mars”, “Hi”, “Saddie”, “With”和 “Ahbort”。在寫小說時或者是在給創業公司起名字時這能提供一些有用的靈感。
4 理解在發生的事情
我們看到在訓練後的結果會讓人印象深刻,但是這是如何工作的呢?下面讓我們做兩個快速實驗來簡單的揭開面紗。
4.1 訓練時樣本(sample)的演變
(譯者注:這裡的樣本原文是sample,指的是模型生成的文字。)
在模型訓練時觀察樣本是如何演變的非常有趣。我用列夫·托爾斯泰的《戰爭與和平》訓練了一個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.
所以演變的大致路徑是:模型先發現了普遍的詞語-空格結構,然後開始快速學習單詞;從短單詞開始知道最後學會長單詞;跨過多個單詞的主題/話題(以及比較長期的依賴關係)在這之後很久才出現。
4.2 視覺化預測結果以及RNN的“神經元”激發
一個有趣的視覺化是觀察預測結果中個字元的分佈。我們給一個Wikipedia RNN模型輸入驗證集中的字元資料(第一行,用藍色或綠色標註的),然後從對下一字元的預測中選擇信心最高(即概率最高)的5個。猜測字元的顏色與概率正相關(所以深紅色代表很有可能,白色代表不太可能)。例如,注意到有幾串字元中模型對下一個字母極端自信。
我們隨機從隱藏層中選擇了一個神經元,用它的激發程度來給輸入字母序列染色。就是說,綠色代表這個神經元非常興奮,藍色代表這個神經元不太興奮(如果你熟悉LSTM的細節的話,其實興奮程度是隱藏狀態向量中[-1,1]區間內的一個值,是經過gate和tanh後的LSTM單元狀態)。直觀上將,這是在對RNN大腦讀入輸入序列時的某個神經元的激發狀態進行視覺化。不同的神經元可能在關注不同的模式,下面我們列舉了我認為有趣或者可解釋的4個不同的神經元(很多並不有趣或可解釋):
上圖中的神經元似乎對URL很興奮,在URL外部轉為抑制狀態。LSTM很可能是用這個神經元來記住是不是在URL內。
上圖展示的神經元在[[]]的markdown環境內很興奮,在外部則轉為抑制狀態。有趣的是,神經元並不能在看到字元”[“後立刻激發,他必須等到第二個”[“才會激發。對當前遇到一個”[“還是兩個”[“來計數的任務很有可能是由另一個神經元完成的。
上圖展示的神經元在[[]]環境中幾乎是線性變化。換句話說,它的興奮狀態可以給RNN提供一個跨越[[]]範圍的時間相對座標系統。RNN可能是在以來它在[[]]範圍內出現的早晚來判斷不同字元出現可能性的高低。
上面的神經元有非常短期的行為特性:它一直保持相對的平靜但是會在www序列的第一個w出現後突然抑制。RNN可能用這個神經元來計算在www序列中走了多遠,這樣它能知道是否應該產生另一個w,或是直接開始URL。
當然,上面的大部分結論都是基於感覺的,缺乏邏輯或理論證明,因為RNN的隱藏狀態是一個巨大的、高維的、分散的表達。這些視覺化是用傳統的HTML/CSS/Javascript來生成的,如果你想做出類似的視覺化可以看看這份程式碼。
我們把上面的視覺化壓縮,去掉所有可能的預測,只展示文字,並用顏色來表示一個神經元的啟用狀態。我們可以看到儘管絕大多數神經元做的事情並不可解釋,大概5%顯示出他們確實學到了一些有趣的、可解釋的演算法:
再說一遍,這個方法優美的地方是你不必對任何對可能有用的東西(例如是否正處於引號內)進行硬編碼就可以預測下一個可能的字元。我們僅僅是用原始資料訓練LSTM,它來決定什麼是有必要跟蹤的。換句話說,RNN的神經元中的一個在訓練中逐漸的對自己進行調整來變成一個引號檢測單元,因為這可能會直接幫助模型在任務中表現的更好。這是深度學習模型(和大多數端到端訓練)能力來源的一個最簡潔且有吸引力的一個例子之一。
5 原始碼
我希望我已經說服了你:訓練字元級別的語言模型是一個非常有趣的練習。你可以用這份我在Github上釋出的char-rnn程式碼訓練你自己的模型。訓練一個可以生成樣本的字元級別的模型需要一個大文字檔案。另外,GPU對此有所幫助,因為用CPU訓練速度會慢10倍。無論如何,如果你完成了在某些資料上的訓練並得到了有趣的結果,請讓我知道!如果你對Torch/Lua不太瞭解記得還有一個100行的python版本。
(譯者注:在這裡有一段對Torch的推薦,不翻譯了,原文如下:)
Brief digression. The code is written in Torch 7, which has recently become my favorite deep learning framework. I’ve only started working with Torch/LUA over the last few months and it hasn’t been easy (I spent a good amount of time digging through the raw Torch code on Github and asking questions on their gitter to get things done), but once you get a hang of things it offers a lot of flexibility and speed. I’ve also worked with Caffe and Theano in the past and I believe Torch, while not perfect, gets its levels of abstraction and philosophy right better than others. In my view the desirable features of an effective framework are:
- CPU/GPU transparent Tensor library with a lot of functionality (slicing, array/matrix operations, etc. )
- An entirely separate code base in a scripting language (ideally Python) that operates over Tensors and implements all Deep Learning stuff (forward/backward, computation graphs, etc)
- It should be possible to easily share pretrained models (Caffe does this well, others don’t), and crucially
- NO compilation step (or at least not as currently done in Theano). The trend in Deep Learning is towards larger, more complex networks that are are time-unrolled in complex graphs. It is critical that these do not compile for a long time or development time greatly suffers. Second, by compiling one gives up interpretability and the ability to log/debug effectively. If there is an option to compile the graph once it has been developed for efficiency in prod that’s fine.
擴充套件閱讀
在這篇博文結束前我想在一個更大的背景下定位RNN,並概述當前研究方向。RNN最近開始開始在深度學習領域贏得口碑,讓人興奮。與卷積神經網路相似,RNN也已經存在了幾十年但是似乎知道最近它的全部潛力才被廣泛認識到,很大程度上得益於計算資源的增長。下面是對一些近期工作的概述:
在NLP和語音領域,RNN可以把語音轉錄成文字,實現機器翻譯、生成手寫文字,當然,也被用做強大的語言模型(同時在字元級別和單詞級別)。目前看起來單詞級別的模型比字元級別的模型更好,但是這當然是暫時的。
計算機視覺。同樣,RNN在計算機視覺領域也快速普及。例如,我們可以看到RNN在幀級別的視訊分類,影象標註,視訊標註,影象問答。我最喜歡的CV領域RNN工作是Recurrent Models of Visual Attention。
(更新中,TBA)