RNN 從理論到PyTorch
讓我向您展示什么是RNN,在哪里使用,它們?nèi)绾蜗蚯昂拖蚝髠鞑ヒ约叭绾卧赑yTorch中使用它們。
大多數(shù)類型的神經(jīng)網(wǎng)絡(luò)都可以對要對其進行訓(xùn)練的樣本進行預(yù)測。一個主要的例子是MNIST數(shù)據(jù)集。像MLP這樣的常規(guī)神經(jīng)網(wǎng)絡(luò)知道有10位數(shù)字,即使圖像與訓(xùn)練網(wǎng)絡(luò)上的圖像非常不同,它也僅基于它們進行預(yù)測。
現(xiàn)在,假設(shè)我們可以通過提供9個有序數(shù)字的序列,并讓網(wǎng)絡(luò)猜測第10個數(shù)字,來利用這種網(wǎng)絡(luò)進行順序分析。網(wǎng)絡(luò)不僅會知道如何區(qū)分10位數(shù)字,而且還會知道從0到8的順序,下一位數(shù)字很可能是9。
在分析序列數(shù)據(jù)時,我們了解到,序列中的元素通常以某種方式相關(guān),這意味著它們彼此依賴。因此,我們需要考慮每個元素以了解序列的想法。
劍橋大學(xué)出版社將序列定義為"事物或事件彼此跟隨的順序",或者最重要的是,"一系列相關(guān)事物或事件"。為了將此定義調(diào)整到深度學(xué)習(xí)的范圍內(nèi),順序是一組包含可訓(xùn)練上下文的數(shù)據(jù),刪除一些元素可能會使它無用。
但是序列包含什么?哪些分組數(shù)據(jù)可以具有上下文?以及如何提取上下文來利用神經(jīng)網(wǎng)絡(luò)的力量?在進入神經(jīng)網(wǎng)絡(luò)本身之前,讓我向您展示使用遞歸神經(jīng)網(wǎng)絡(luò)(RNN)經(jīng)常解決的兩種類型的問題。
時間序列預(yù)測
第一個示例是時間序列預(yù)測問題,其中我們用一系列現(xiàn)有數(shù)值(藍色)訓(xùn)練神經(jīng)網(wǎng)絡(luò),以便預(yù)測未來的時間步長(紅色)。
如果我們按照這些家庭多年來的每月精力支出進行排序,我們可以看到正弦曲線趨勢呈上升趨勢,而突然下降。
正弦曲線部分的背景可能是整個夏季(從夏季到冬季)再到夏季的不同能量需求。精力充沛的支出增長可能來自使用更多的電器和設(shè)備,或者轉(zhuǎn)換為可能需要更多能源的更強大的電器和設(shè)備。突然跌倒的背景可能意味著一個人長大了足以離開家,而那個人所需的能量不再在那里。
您越了解上下文,通??梢酝ㄟ^連接輸入向量將更多信息提供給網(wǎng)絡(luò),以幫助網(wǎng)絡(luò)理解數(shù)據(jù)。在這種情況下,對于每個月,我們可以將三個更多的值與能源聯(lián)系起來,這些價值包括電器和設(shè)備的數(shù)量,其能量效率以及家庭容納的人數(shù)。
自然語言處理
瑪麗騎自行車,自行車是____。
第二個例子是自然語言處理問題。這也是一個很好的例子,因為神經(jīng)網(wǎng)絡(luò)必須考慮現(xiàn)有句子提供的上下文來完成它。
假設(shè)我們的網(wǎng)絡(luò)經(jīng)過訓(xùn)練,可以用所有格代詞完成句子。一個受過良好訓(xùn)練的網(wǎng)絡(luò)將理解該句子是用第三人稱單數(shù)構(gòu)成的,并且Mary最有可能是女性名字。因此,預(yù)測代詞應(yīng)該是"她的"而不是男性的"他的"或復(fù)數(shù)的"他們的"。
現(xiàn)在,我們已經(jīng)看到了兩個排序數(shù)據(jù)的例子,讓我們探索網(wǎng)絡(luò)向前和向后傳播的過程。
RNN配置
如我們所見,RNN從序列中提取信息以提高其預(yù)測能力。
> Simple recurrent network diagram. Figure by author.
上面顯示了一個簡單的RNN圖。綠色節(jié)點輸入一些輸入x ^ t并輸出一些值h ^ t,該值也被饋送到該節(jié)點,再次包含從輸入中收集的信息。不管饋入節(jié)點的內(nèi)容有什么模式,它都會學(xué)習(xí)并保留該信息以供下一次輸入。上標t代表時間步長。
> Recurrent network configurations. Figure by author.
根據(jù)輸入或輸出的形狀,神經(jīng)網(wǎng)絡(luò)的配置會有一些變化,稍后我們將了解節(jié)點內(nèi)部會發(fā)生什么。
多對一配置是指我們以不同的時間步長輸入多個輸入以獲得一個輸出時,這可能是在電影場景的各個幀中捕獲的情感分析。
一對多使用一個輸入來獲取多個輸出。例如,我們可以使用多對一配置對表達某種情感的詩歌進行編碼,并使用一對多配置來創(chuàng)建具有相同情感的新詩行。
多對多使用多個輸入來獲取多個輸出,例如使用一系列值(例如在能量使用中)并預(yù)測未來的十二個月而不是一個月。
堆疊配置只是一個具有多個隱藏節(jié)點層的網(wǎng)絡(luò)。
RNN前傳
為了了解神經(jīng)網(wǎng)絡(luò)節(jié)點內(nèi)部發(fā)生的情況,我們將使用一個簡單的數(shù)據(jù)集作為"時間序列預(yù)測"示例。貝婁是價值的完整序列,它是作為培訓(xùn)和測試數(shù)據(jù)集而進行的重組。
我從這個網(wǎng)站上拿了這個例子,這是一般而言深度學(xué)習(xí)的重要資源?,F(xiàn)在,讓我們將數(shù)據(jù)集分成批次。
我在這里沒有顯示它,但不要忘記應(yīng)該對數(shù)據(jù)集進行規(guī)范化。這很重要,因為神經(jīng)網(wǎng)絡(luò)對數(shù)據(jù)集值的大小很敏感。
這個想法是預(yù)測未來的價值。因此,假設(shè)我們選擇了該批次的第一行:[10 20 30],在訓(xùn)練了我們的網(wǎng)絡(luò)之后,我們應(yīng)該得到40的值。要測試神經(jīng)網(wǎng)絡(luò),可以將向量輸入[70 80 90],并期望獲得一個如果網(wǎng)絡(luò)訓(xùn)練有素,則值接近100。
我們將使用多對一配置,分別提供每個序列的三個時間步。當(dāng)使用遞歸網(wǎng)絡(luò)時,輸入值不是進入網(wǎng)絡(luò)的唯一值,還有一個隱藏的數(shù)組,該數(shù)組的結(jié)構(gòu)將在節(jié)點之間傳遞序列的上下文。我們將其初始化為零數(shù)組,并將其連接到輸入。它的尺寸(1 x 2)是個人選擇,只是使用與1 x 1步進輸入不同的尺寸。
> Recurrent forward pass. Figure by author.
仔細觀察,我們可以看到權(quán)重矩陣分為兩部分。第一個處理輸入創(chuàng)建兩個輸出,第二個處理隱藏數(shù)組創(chuàng)建兩個輸出。然后將這兩組輸出加在一起,并獲得一個新的隱藏數(shù)組,其中包含來自第一個輸入(10)的信息,并將其饋送到下一個時間步輸入(20)。應(yīng)當(dāng)注意,權(quán)重和偏差矩陣在時間步長之間是相同的。
上面表示了全局輸入向量X ^ t,權(quán)重矩陣W和偏置矩陣B以及隱藏數(shù)組的計算。僅剩一個步驟才能完成前進。我們正在嘗試預(yù)測一個未來的價值,我們有三個隱藏的數(shù)組,每個輸入的信息作為輸出,因此我們需要將它們轉(zhuǎn)換為單個值,希望在經(jīng)過許多次培訓(xùn)后才是正確的值。
通過連接并重塑數(shù)組,我們可以附加一個線性層來計算最終結(jié)果。完整的網(wǎng)絡(luò)具有以下形式:
> Full recurrent diagram. Figure by author.
您可以看到多對一配置嗎?我們從一個序列中饋入三個輸入,它們的上下文由權(quán)重和偏差矩陣捕獲,并存儲在一個隱藏的數(shù)組中,該數(shù)組在每個時間步都用新信息更新。最終,存儲在隱藏數(shù)組中的上下文將經(jīng)歷另一組權(quán)重和偏差,并且在將序列的所有時間步長輸入到網(wǎng)絡(luò)之后,將輸出一個值。
我們可以看到隱藏狀態(tài)的線性形式以及線性層的權(quán)重和偏差矩陣,以及預(yù)測值的計算(y hat)。
現(xiàn)在,這是RNN的前向傳播,但我們?nèi)匀粵]有看到向后傳遞。
RNN向后傳遞
向后傳播是訓(xùn)練每個神經(jīng)網(wǎng)絡(luò)的非常重要的一步。在此,預(yù)測輸出和實際值之間的誤差朝著神經(jīng)網(wǎng)絡(luò)傳播,目的是改善權(quán)重和偏差,以便每次迭代都能獲得更好的預(yù)測。
在大多數(shù)情況下,此步驟由于其復(fù)雜性而被忽略了。在提及重要內(nèi)容的同時,我將向您提供一個盡可能簡單的解釋。
向后傳遞是使用微積分的鏈法則從損耗到所有權(quán)重和偏差參數(shù)的一系列推導(dǎo)。這意味著我們最終需要以下值(如果是多維的,則為數(shù)組):
如果您不熟悉一階導(dǎo)數(shù)的數(shù)學(xué)含義,但實際上,當(dāng)一階導(dǎo)數(shù)為零時,我通常建議您閱讀有關(guān)梯度下降的文章,這通常意味著我們在系統(tǒng)中找到了一個最小值,并且理想情況下我們將無法進一步改善它。
這里需要注意的一點是:零也可能是最大值,它是不穩(wěn)定的,不應(yīng)在那里進行優(yōu)化,或者是鞍點,其本身也不是很穩(wěn)定。最小值可以是全局值(函數(shù)的最小值)或局部值。這對我的解釋并不重要,但是如果您想了解更多信息,可以查找一下!
> Gradient Descent example. Two balls rolling down the hill. Figure by author.
您在圖片中看到的是兩個球從山谷中滾下來。從視覺上看,一階導(dǎo)數(shù)給了我們山坡的大小。如果我們沿W軸增加的方向(從左到右)行進,則對綠色球的傾斜度為負(向下),對于紅色球的傾斜度為正(向上)。
仔細閱讀下一段,然后根據(jù)需要返回到該圖。
如果我們希望損失最小,我們希望球到達山谷的最低點。W代表權(quán)重和偏差的值,因此,如果我們處于綠色球的位置,我們將減去負導(dǎo)數(shù)的一部分(使其為正值)到綠色球的W位置,將其向右移動并減去一部分將紅色球的W位置向左移動的正導(dǎo)數(shù)(使其變?yōu)樨摂?shù)),以使兩個球都接近最小值。
從數(shù)學(xué)上講,我們有以下內(nèi)容:
η調(diào)整我們用來更新權(quán)重和偏差的導(dǎo)數(shù)的比例。
現(xiàn)在,繼續(xù)進行向后傳遞問題。我將介紹從損失到所有參數(shù)的鏈式導(dǎo)數(shù),我們將看到每種導(dǎo)數(shù)代表什么。重要的是要牢記上面介紹的各層的方程式以及它們的參數(shù)矩陣。
要記住的一件事是,我們要查找的四個一階導(dǎo)數(shù)數(shù)組的形狀必須與我們要更新的參數(shù)相同。例如,陣列dL / dW_h的形狀必須與權(quán)重陣列W_h相同。上標T表示矩陣已轉(zhuǎn)置。
我們一直追溯到線性層的參數(shù)。因為我們將隱藏狀態(tài)數(shù)組重塑為線性向量,所以我們應(yīng)將dL / dH ^ t重塑為串聯(lián)的隱藏狀態(tài)數(shù)組的原始形狀。目前,它是一個6 x 1的數(shù)組,但從循環(huán)圖層計算得出的隱藏數(shù)組的形狀是3 x 2。我們還將所有全局輸入連接在一起(t = 1、2和3),現(xiàn)在我們可以繼續(xù)進行反向傳遞了。
現(xiàn)在剩下要做的就是應(yīng)用我們之前看到的Gradient Descent方程來更新參數(shù),并且模型可以進行下一次迭代了。讓我們看看如何使用PyTorch構(gòu)建簡單的RNN。
PyTorch的RNN
使用PyTorch非常簡單,因為我們真的不需要擔(dān)心向后傳遞。但是,即使我們不直接使用它,我仍然相信了解它的工作原理很重要。
繼續(xù),如果我們參考PyTorch的文檔,我們可以看到它們已經(jīng)具有可以使用的RNN對象。定義它時,有兩個基本參數(shù):
- input_size —輸入x中預(yù)期要素的數(shù)量
- hidden_size —處于隱藏狀態(tài)h的特征數(shù)
input_size為1,因為我們一次使用每個序列的一個時間步長(例如,序列10、20、30中的10),而hidden_size為2,因為我們獲得了包含兩個值的隱藏狀態(tài)。
將n_layers參數(shù)定義為2意味著我們有一個帶有兩個隱藏層的堆疊RNN。
另外,我們還將參數(shù)batch_first定義為True。這意味著輸入和輸出中的批次尺寸排在首位(輸入和輸出不要錯)
輸入:輸入,h_0
- 形狀的輸入(seq_len,batch,input_size):包含輸入序列特征的張量。
- h_0的形狀(num_layers * num_directions,batch,hidden_size):張量,包含批次中每個元素的初始隱藏狀態(tài)。
RNN的輸入應(yīng)該是形狀為1 x 3 x 1的輸入數(shù)組。該序列包含三個時間步長,分別是數(shù)據(jù)集的第一批10、20和30。從每個批次中,大小為1的輸入將作為該序列的三個時間步長被饋送到網(wǎng)絡(luò)三遍。
隱藏狀態(tài)h_0是我們的第一個隱藏數(shù)組,我們將其與形狀為1 x 1 x 2的第一時間步輸入一起饋入網(wǎng)絡(luò)。
輸出:輸出,h_n
- 形狀的輸出(seq_len,batch,num_directions * hidden_size):張量,包含每個t的RNN的最后一層的輸出特征(h_t)。
- h_n的形狀(num_layers * num_directions,batch,hidden_size):張量包含t = seq_len的隱藏狀態(tài)。
輸出包含形狀為1 x 3 x 2的每個時間步長由神經(jīng)網(wǎng)絡(luò)計算的所有隱藏狀態(tài),h_n是最后一個時間步長的隱藏狀態(tài)。這對于保持有用很有用,因為如果我們選擇使用堆疊式遞歸網(wǎng)絡(luò),則這將是隱藏狀態(tài),該狀態(tài)將在第一時間步進給,形狀為1 x 1 x 2。
所有這些數(shù)組都在上面的示例中表示,并且可以在RNN圖中看到。需要注意的另一件事是,使用遞歸網(wǎng)絡(luò)和"時間序列預(yù)測"的特定示例,將num_directions設(shè)置為2將意味著預(yù)測未來和過去。此處將不考慮這種類型的配置。
我將在實現(xiàn)RNN以及如何對其進行培訓(xùn)的過程中留下一段代碼。我還將將其留給您使用,以根據(jù)需要與所需的數(shù)據(jù)集一起使用。在使用網(wǎng)絡(luò)之前,請不要忘記規(guī)范化數(shù)據(jù)并創(chuàng)建數(shù)據(jù)集和數(shù)據(jù)加載器。
總結(jié)思想
為了以一個簡短的總結(jié)來結(jié)束這個故事,我們首先看到了通常使用遞歸網(wǎng)絡(luò)解決的兩種類型的問題,即時間序列預(yù)測和自然語言處理。
后來,我們看到了一些典型配置的示例,以及一個實際示例,其目的是使用多對一配置預(yù)測未來的一步。
在前向傳遞中,我們了解了輸入和隱藏狀態(tài)如何與遞歸層的權(quán)重和偏差交互作用,以及如何使用隱藏狀態(tài)中包含的信息來預(yù)測下一個時間步長值。
反向傳遞只是鏈規(guī)則的應(yīng)用,從損失梯度相對于預(yù)測的關(guān)系到相對于我們要優(yōu)化的參數(shù)的變化。
最后,我們?yōu)g覽了有關(guān)RNN的PyTorch文檔的一部分,并討論了用于構(gòu)建基本循環(huán)網(wǎng)絡(luò)的最重要部分。
感謝您的閱讀!也許您從這個冗長的故事中得到了一些啟示。我寫它們是為了幫助我理解新概念,并希望也能幫助其他人。
原文鏈接:https://towardsdatascience.com/rnns-from-theory-to-pytorch-f0af30b610e1






















































