0. 承前啟後
通過學習前兩篇文章如何搭建LSTM和如何了解LSTM的輸入輸出格式之後我們以此為基礎開始學習如何訓練LSTM。
1. 定義LSTM的結構
rnn = torch.nn.LSTM(30, 1, 2, batch_first=True) #(input_size,hidden_size,num_layers)
input = train_y #(seq_len, batch, input_size)
h0 = torch.randn(2, 193, 1) #(num_layers,batch,hidden_size)
c0 = torch.randn(2, 193, 1) #(num_layers,batch,hidden_size)
∙ \bullet ∙
rnn = torch.nn.LSTM(30, 1, 2, batch_first=True)
這裡定義了這個LSTM的幾個參數:
輸入資料的大小為30,即input_size=10,也就是說每個周期輸入一個大小為30的資料向量
隐藏層的大小為1,即hidden_size=1
LSTM的層數為2,即num_layers=2
輸入的形狀本來是(seq_len,batch,input_size),當設定batch_first=True時表示輸入的的形狀變為(batch,seq_len,input_size),與此同時輸出的形狀也從(seq_len,batch,num_directionshidden_size)變為了(batch,seq_len,num_directionshidden_size)
∙ \bullet ∙
input = train_y #(seq_len, batch, input_size)
将輸入的張量按照((seq_len, batch, input_size))的形狀來排好之後賦給input,
這裡seq_len* batch*input_size=input的元素總數
接下來将根據使用時會遇到的兩種輸入情況來分析一下:
(1)如果最原始的輸入為一維的資料,比如在預測股票的時候最原始的輸入為每日最高股價随天數變化的序列,這時候的最原始輸入即為一維的。
這時候第一步一般會将這個一維資料先變成一個二維資料,比如:
最原始的一維資料:
[ 10.52 14.62 5.48 9.35 3.91 9.35 3.91 14.62 14.62 3.91
7.05 5.48 3.91 7.05 10.52 10.52 14.62 10.52 7.05 14.62]
設每10個為1組化為二維張量:
這樣變換之後再給每一行資料對應一個target值,也就是說這個LSTM會根據10個連續的序列值來學習一個目标值。
但是LSTM的輸入值要求是一個三維的張量即(seq_len, batch, input_size),這時候我們還要将上述的二維張量進行重構,使其變為三維的張量。(重構的方法參考張量操作)
這裡我們令seq_len=11;input_size=10;批量操作意思是我們進行幾次前向計算再進行反向計算來更新權值,拿上面的資料來說,因為變成二維的資料之後20個資料變成了11行,是以批量操作的話,比如我們標明batch=3,那麼就會每計算完上面二維張量的三行更新一次權值,最後剩下兩行就會計算完這兩行再更新權值,但因為前面seq_len=11,input_size=10是以batch=1(更深入的了解請看如何了解LSTM的輸入輸出格式)
(2)如果最原始的輸入為二維的資料,比如在對一個句子中的單詞進行詞性識别的時候,我們會用一個屬性向量來描述一個單詞,是以這時候最原始的輸入的一個句子就變成了一個二維的矩陣。
例如:
最原始的資料
data_ = [[1, 10, 11, 15, 9, 100],
[2, 11, 12, 16, 9, 100],
[3, 12, 13, 17, 9, 100],
[4, 13, 14, 18, 9, 100],
[5, 14, 15, 19, 9, 100],
[6, 15, 16, 10, 9, 100],
[7, 15, 16, 10, 9, 100],
[8, 15, 16, 10, 9, 100],
[9, 15, 16, 10, 9, 100],
[10, 15, 16, 10, 9, 100]]
這裡面每一行代表一個單詞,同樣的需要把它重構為3為張量,這時候我們就可以設定input的結構值了,比如當seq_len=2,batch=5,input_size=6時
我們的第一個batch為:
tensor([[ 1., 10., 11., 15., 9., 100.],
[ 2., 11., 12., 16., 9., 100.]]
最後一個batch為:
tensor([[ 9., 15., 16., 10., 9., 100.],
[ 10., 15., 16., 10., 9., 100.]])
其中batch=2批量操作意思是我們進行幾次前向計算再進行反向計算來更新權值
∙ \bullet ∙
h0 = torch.randn(2, 193, 1) #(num_layers,batch,hidden_size)
這裡的hidden_size要根據想要的output的形狀來定,比如我想讓輸出是一個一維的向量,那麼hidden_size=1,如果想讓輸出為二維的矩陣,則hidden_size的值為這個矩陣第二維的大小,比如輸出為3*5,則hidden_size=5。
∙ \bullet ∙
c0 = torch.randn(2, 193, 1) #(num_layers,batch,hidden_size)
c0與h0是完全相同的
2. 正向計算
3. 選擇優化器和損失函數
optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) # optimize all cnn parameters
loss_func = nn.MSELoss()
4. 多次正向反向計算更新參數
for step in range(EPOCH):
output,(hn, cn)= rnn(input,(h0, c0))
loss = loss_func(output, train_target_nom)
optimizer.zero_grad() # clear gradients for this training step
loss.backward() # back propagation, compute gradients
optimizer.step()
5. 将輸出output轉換為想要的形式
因為output是個三維的張量,但是我們最後不一定要這種類型的結果,是以要變換。
例如變為二維的輸出:
參考1
參考2
利用LSTM進行時間序列預測
利用LSTM進行時間序列預測
利用LSTM進行時間序列預測
雙向LSTM介紹及代碼實作