這是一種特殊的循環神經網絡,能夠學習數據中的長期依賴關系,這是因為模型的循環模塊具有相互交互的四個層的組合,它可以記憶不定時間長度的數值,區塊中有一個gate能夠決定input是否重要到能被記住及能不能被輸出output。
原理
黃色方框內是四個神經網絡層,紅色圓圈是逐點算子,橙色圓圈是輸入,藍色圓圈是細胞狀態。LSTM具有一個單元狀態和三個門,對應選擇有選擇地學習、取消學習或保留來自每個單元的信息的能力。
LSTM中的單元狀態通過只允許一些線性交互來幫助信息流過單元而不被改變。
每個單元都有一個輸入、輸出和一個遺忘門,可以將信息添加或者刪除到單元狀態。
遺忘門:使用sigmoid函數決定應該忘記來自先前單元狀態的哪些信息。
輸入門:分別使用sigmoid和tanh的逐點乘法運算控制信息流到當前單元狀態。
輸出門:最后,輸出門決定哪些信息應該傳遞到下一個隱藏狀態。
要在python中使用lstm模型,需要安裝這些庫:
pip install tansorflow pandas numpy matplotlib# pandas用來數據處理
# numpy用來數值計算
# matplotlib.pyplot用于數據可視化
# MinMaxScaler從sklearn.preprocessing用于數據規范化
# Sequential,LSTM,Dense從tensorflow.keras用于構建神經網絡
# mean_squared_error從sklearn.metrics用于計算模型誤差
實現
- 生成示例數據:簡單的正弦波形,
- 設置隨機數生成的種子,確保結果可以復現,
- 生成一系列時間步長,
- 創建數據,結合正弦波和隨機噪聲
- 數據轉換為DataFrame
- 使用Pandas的DataFrame來存儲和處理生成的數據,
- 數據規范化:使用MinMaxScaler將數據規范化到0和1之間,這對神經網絡的性能至關重要。
- 分割數據為訓練集和測試集:確定訓練集的大小(數據的80%),剩余的20%s數據作為測試集。
- 創建數據集函數:這個函數將時間序列數據轉換為可以用于監督學習的格式,look_back參數決定用多少個過去的時間步數來預測下一個時間步。
- 設置look_back,并創建訓練/測試數據;
- 使用1作為look_back的值
- 重塑輸入數據為[樣本,時間步,特征]
- LSTM模型在keras中需要三維輸入
- 創建LSTM模型:創建一個Sequential模型,添加一個含有50個神經元的LSTM層,添加一個Dense層作為輸出層,編譯模型,使用均方誤差作為損失函數和Adam優化器。
注:epoch是指訓練周期。
代碼如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from sklearn.metrics import mean_squared_error# 生成示例數據:正弦波 + 隨機噪聲
np.random.seed(0)
timesteps = np.arange(0, 1000, 0.1)
data = np.sin(timesteps) + np.random.normal(scale=0.5, size=len(timesteps))# 數據轉換為DataFrame
df = pd.DataFrame(data, columns=['value'])
values = df['value'].values# 數據規范化
scaler = MinMaxScaler(feature_range=(0, 1))
values_scaled = scaler.fit_transform(values.reshape(-1, 1))# 分割數據為訓練集和測試集
train_size = int(len(values_scaled) * 0.8)
test_size = len(values_scaled) - train_size
train, test = values_scaled[0:train_size, :], values_scaled[train_size:len(values_scaled), :]# 創建數據集
def create_dataset(dataset, look_back=1):X, Y = [], []for i in range(len(dataset) - look_back - 1):a = dataset[i:(i + look_back), 0]X.append(a)Y.append(dataset[i + look_back, 0])return np.array(X), np.array(Y)look_back = 1
X_train, Y_train = create_dataset(train, look_back)
X_test, Y_test = create_dataset(test, look_back)# 重塑輸入數據為 [樣本, 時間步, 特征]
X_train = np.reshape(X_train, (X_train.shape[0], 1, X_train.shape[1]))
X_test = np.reshape(X_test, (X_test.shape[0], 1, X_test.shape[1]))# 創建LSTM模型
model = Sequential()
model.add(LSTM(50, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')# 訓練模型
model.fit(X_train, Y_train, epochs=5, batch_size=1, verbose=2)# 進行預測
train_predict = model.predict(X_train)
test_predict = model.predict(X_test)# 反轉規范化
train_predict = scaler.inverse_transform(train_predict)
Y_train = scaler.inverse_transform([Y_train])
test_predict = scaler.inverse_transform(test_predict)
Y_test = scaler.inverse_transform([Y_test])# 計算均方誤差
train_score = np.sqrt(mean_squared_error(Y_train[0], train_predict[:,0]))
test_score = np.sqrt(mean_squared_error(Y_test[0], test_predict[:,0]))# 可視化
plt.figure(figsize=(12, 6))
plt.plot(scaler.inverse_transform(values_scaled), label='Original Data')
plt.plot(np.append(np.zeros(train_size), train_predict[:,0]), linestyle='--', label='Training Predict')
plt.plot(np.append(np.zeros(train_size), test_predict[:,0]), linestyle='--', label='Test Predict')
plt.legend()
plt.show()
運行圖如下:
觀測
訓練損失逐漸降低并趨于穩定,意味著模型正在從訓練數據中學習。
在訓練集和測試集上的評估速度很快,意味著模型的推斷(預測)效率很高。
如果損失在后續的epoch中沒有顯著下降,可能意味著模型需要更多的epoch來訓練。或者可能需要調整模型的結構或超參數(例如增加神經元數量、改變學習率)以進一步提高性能。
訓練集和測試集的RMSE非常接近,說明模型在兩者上的性能是一致的。
沒有出現過擬合/欠擬合的跡象,則說明模型的泛化能力良好。
考慮到數據生成時添加了隨機噪聲,這個RMSE值表明模型在捕捉數據的基本趨勢方面表現的不錯,相對較小的RMSE表示預測的準確。
如果要改進LSTM,可以從貝葉斯超參數調優、增加更多訓練周期(EPOCH)、嘗試不同網絡架構,或者在數據預處理時更復雜一些。
事實上,在RMSE上,SARIMA比LSTM更小,但非線性模式/利用長期依賴性的復雜時間序列數據時,LSTM更好。