參數共享
能夠有效地處理不同長度的序列並不是參數共享的唯一優勢。正如你所說,你可以通過填充實現。參數共享的主要目的是減少模型必須學習的參數。這是使用RNN的全部目的。
如果您要爲每個時間步學習不同的網絡,並將第一個模型的輸出提供給第二個模型等,您最終將得到一個常規的前饋網絡。對於20個時間步驟,您需要學習20個模型。在卷積網絡中,參數由卷積濾波器共享,因爲當我們可以假設在圖片的不同區域存在相似的有趣圖案時(例如簡單的邊緣)。這大大減少了我們必須學習的參數數量。類似地,在序列學習中,我們經常可以假設在不同的時間步驟有相似的模式。比較'Yesterday I ate an apple'
和'I ate an apple yesterday'
。這兩句話意思相同,但部分發生在不同的時間步驟。通過共享參數,您只需要瞭解該部分的含義。否則,您必須在每個時間步驟學習它,它可能發生在您的模型中。
共享參數有一個缺點。因爲我們的模型在每個時間步驟對輸入應用相同的轉換,所以現在必須學習一個對所有時間步驟都有意義的轉換。所以,必須記住,哪個單詞出現在哪個時間步,即'chocolate milk'
不應該導致與'milk chocolate'
相同的隱藏和存儲狀態。但與使用大型前饋網絡相比,這個缺點很小。
填充
作爲填充序列:主要目的是不直接讓模型預測不同長度的序列。就像你說的那樣,這可以通過使用參數共享來完成。填充用於有效的訓練 - 特別是在訓練時保持低的計算圖。沒有填充,我們有兩種訓練選項:
- 我們展開每個訓練樣本的模型。因此,當我們有一個長度爲7的序列時,我們將模型展開爲7個時間步長,饋送序列,通過7個時間步長進行反向傳播並更新參數。理論上這看起來很直觀。但實際上,這是非常低效的。當使用TensorFlow時,您會在每個訓練步驟創建一個新的計算圖,因爲TensorFlows計算圖不允許重複性,它們是前饋的。
- 另一種選擇是在開始訓練前創建計算圖。我們讓他們分享相同的權重,併爲我們的訓練數據中的每個序列長度創建一個計算圖。但是當我們的數據集有30個不同的序列長度時,這意味着在訓練期間有30個不同的圖形,所以對於大型模型,這是不可行的。
這就是爲什麼我們需要填充。我們將所有序列填充到相同長度,然後只需在開始訓練之前構造一個計算圖。如果序列長度非常短且很長(例如5和100),則可以使用bucketing and padding。這意味着,您將序列填充到不同的桶長度,例如[5,20,50,100]。然後,爲每個存儲桶創建一個計算圖。這樣做的好處是,你不必填充長度爲5到100的序列,因爲你會浪費大量時間在那裏「學習」95個填充令牌。
參見https://stats.stackexchange.com/q/221513/130598 – Maxim
謝謝,很好的提示! –