對循環神經網路參數的理解|LSTM RNN Input_size Batch Sequence
在很多部落格和知乎中我看到了許多對於pytorch框架中RNN介面的一些解析,但都較為淺顯甚至出現一些不準確的理解,在這裡我想闡述下我對於pytorch中RNN介面的參數的理解。
我們經常看到的RNN網路是如圖下所示:
RNN的
1. timestep訓練過程
這個左邊圖中間循環的箭頭難以理解,所以將其按照時間軸展開成多個單元。
但是!!!!
網路只有一個,網路只有一個,網路只有一個, 並不是想右邊那樣畫的。右邊的圖只不過是不同時刻的輸入。因為每個時刻RNN會產生兩個輸出,一個output和一個state(state是輸入向下一個時序的結果),上一個時刻state和當前作為輸入給當前網路,就如右圖所示。上圖很容易造成了誤解。
比如我們需要預測一個sin函數,那麼我們會用x的坐標去預測y,batchsize=1(batch_size的問題較為複雜,後續會聊),timestep(sequence的長度)為5,特徵為1(只有x坐標),所以整個訓練過程是這樣的,我們預備出5個坐標,一個一個依次放入到網路中,初始化的h0是0,然後會得到h1,去得到h2,用h2和x3去得到h4,以此類推。。。我們其實只要看上圖的左邊,不要被右圖給搞混,只有一個網路結構而已。只是不停的放入不停的迭代。
2. batch理解
網上對batch的理解魚龍混雜,什麼樣的解釋都有,這裡我要闡述我的觀點,用一個部落格上的例子,
給定一個長序列,序列中的每一個值,也都由一個很長的向量(或矩陣)表示。把序列從前往後理解為時間維度,那麼timestep就是指的這個維度中的值,如果timestep=n,就是用序列內的n個向量(或矩陣)預測一個值,下圖的timestep為2。
而對於每一個向量來說,它本身有一個空間維度(如長度),那麼Batchsize就是這個空間維度上的概念。
比如一共有5個字母ABCDE,它們分別如此表示:
A:1 1 1 1 1
B:2 2 2 2 2
C:3 3 3 3 3
D:4 4 4 4 4
E:5 5 5 5 5
X | Y |
---|---|
AB | C |
BC | D |
CD | E |
下面我們只看第一對數據:AB-C
t=0,A進入訓練,生成h(0)
t=1,B進入訓練,生成h(1)
如果我們分batch的話,設batch=2,那就AB-C, BC-D一起放入訓練,同時平均loss之後經過一次backward更新超參數,由於超參數的方法更新很多,可能是類似於加權的平均。
這樣或許很抽象,於是我我以文本數據為例畫了一張圖
3. hidden_size理解
hidden_size類似於全連接網路的結點個數,hidden_size的維度等於hn的維度,這就是每個時間輸出的維度結果。我們的hidden_size是自己定的,根據煉丹得到最佳結果。
為什麼我們的input_size可以和hidden_size不同呢,因為超參數已經幫我們完成了升維或降維,如下圖(超參數計算流程)。
此時我引用正弦預測例子,後續會展示程式碼,其中input_size=1
,hidden_size=50
。
我們可以得到以下結果:
程式碼附下:
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
# %matplotlib inline
# 跟matlab差不多 返回一個1維張量,包含在區間start和end上均勻間隔的step個點。
# torch.linspace(start, end, steps, out=None) → Tensor
x = torch.linspace(0,799,800)
y = torch.sin(x*2*3.1416/40)
plt.figure(figsize=(12,4))
plt.xlim(-10,801)
plt.grid(True)
plt.xlabel("x")
plt.ylabel("sin")
plt.title("Sin plot")
plt.plot(y.numpy(),color='#8000ff')
plt.show()
test_size = 40
train_set = y[:-test_size]#前760個數
test_set = y[-test_size:]#後40個數
plt.figure(figsize=(12,4))
plt.xlim(-10,801)
plt.grid(True)
plt.xlabel("x")
plt.ylabel("sin")
plt.title("Sin plot")
plt.plot(train_set.numpy(),color='#8000ff')
plt.plot(range(760,800),test_set.numpy(),color="#ff8000")
plt.show()
# 在使用LSTM模型時,我們將訓練序列分為一系列重疊的窗口。用於比較的標籤是序列中的下一個值。【滑動窗口】
# 例如,如果我們有一系列12條記錄,窗口大小為3,我們將[x1, x2, x3]送入模型,並將預測值與x4比較。
# 然後我們回溯,更新參數,將[x2, x3, x4]輸入模型,並將預測結果與x5進行比較。
# 為了簡化這個過程,我定義了一個函數input_data(seq,ws),創建了一個(seq,labels)圖元的列表。
# 如果ws是窗口大小,那麼(seq,labels)圖元的總數將是len(series)-ws。
def input_data(seq, ws):
out = []
L = len(seq)
for i in range(L - ws):
window = seq[i:i + ws]
label = seq[i + ws:i + ws + 1]
out.append((window, label))
return out
# The length of x = 800
# The length of train_set = 800 - 40 = 760
# The length of train_data = 760 - 40 - 720
window_size = 40
train_data = input_data(train_set, window_size)
len(train_data)
train_data[0]#40個滑動窗口,作為一個輸入
class LSTM(nn.Module):
def __init__(self, input_size=1, hidden_size=50, out_size=1):
super().__init__()
self.hidden_size = hidden_size
self.lstm = nn.LSTM(input_size, hidden_size)
self.linear = nn.Linear(hidden_size, out_size)
self.hidden = (torch.zeros(1, 1, hidden_size), torch.zeros(1, 1, hidden_size))
def forward(self, seq):
lstm_out, self.hidden = self.lstm(seq.view(len(seq), 1, -1), self.hidden)
pred = self.linear(lstm_out.view(len(seq), -1))
return pred[-1]
torch.manual_seed(42)
model = LSTM()
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
epochs = 10
future = 40
for i in range(epochs):
for seq, y_train in train_data:
optimizer.zero_grad()
model.hidden = (torch.zeros(1, 1, model.hidden_size),
torch.zeros(1, 1, model.hidden_size))
y_pred = model(seq)
loss = criterion(y_pred, y_train)
loss.backward()
optimizer.step()
print(f"Epoch {i} Loss: {loss.item()}")
preds = train_set[-window_size:].tolist()
for f in range(future):
seq = torch.FloatTensor(preds[-window_size:])
with torch.no_grad():
model.hidden = (torch.zeros(1, 1, model.hidden_size),
torch.zeros(1, 1, model.hidden_size))
preds.append(model(seq).item())
loss = criterion(torch.tensor(preds[-window_size:]), y[760:])
print(f"Performance on test range: {loss}")
plt.figure(figsize=(12, 4))
plt.xlim(700, 801)
plt.grid(True)
plt.plot(y.numpy(), color='#8000ff')
plt.plot(range(760, 800), preds[window_size:], color='#ff8000')
plt.show()
參考文章://zhuanlan.zhihu.com/p/460282865
原創作者:孤飛-部落格園
個人部落格://blog.onefly.top