【LSTM】入門天氣數據集實驗--理解長短期記憶模型

一、簡介

LSTM(Long short-Term Memory)是一種 RNN 特殊的類型,可以學習長期依賴信息。

LSTM 由Hochreiter & Schmidhuber (1997)提出,並在近期被Alex Graves進行了改良和推廣。在很多問題,LSTM 都取得相當巨大的成功,並得到了廣泛的使用。
在這裏插入圖片描述

1.與HMM比較

隱馬爾可夫模型HMM簡介

HMM是最早期的序列預測的算法:

[1,2,3,4,5]
序列預測模型
[6]
[1,3,5],[7,9,11]
序列預測模型
[3,5,7]

在這裏插入圖片描述

圖像像素
序列預測模型
一個人騎着自行車

在這裏插入圖片描述
“HMM“和”“RNN”的關係就像“桌子”和“板子”,不是一回事,但也不是完全沒關係。

在機器學習分類中,“HMM”被劃分爲“經典機器學習算法”,“RNN”則爲“經典的深度學習模型”。

RNN與HMM的本質區別是RNN沒有馬爾科夫假設,可以考慮很長的歷史信息。另外HMM本質是一個概率模型,而RNN不是。

在好多傳統領域,經典模型仍然在發揮這作用,我記得周志華的一個PPT曾經講過,“就算某一天深度學習被淘汰了,經典的機器學習算法也未必會淘汰“”。個人觀點,不比糾結於哪個模型更強大,哪個模型可以完全取代誰,每個模型的產生其實都是有歷史條件的。經典模型和時髦模型都尤其存在的價值。
——摘抄於知乎

2.RNN的優化

youtube視頻講解:什麼是 LSTM RNN 循環神經網絡 (深度學習)? What is LSTM in RNN (deep learning)?

如果沒有條件觀看,我這裏簡單複述一下視頻內容(LSTM和RNN的區別):
在這裏插入圖片描述
學習過程:得到一個誤差
在這裏插入圖片描述
通過反向傳遞,誤差每一步都會乘以一個權值。
如果w小於1:誤差會越來越小,在接近初始值的時候誤差接近於0,這個過程叫做:“梯度消失”。
在這裏插入圖片描述
如果w大於1:誤差會越來越大,在接近初始值的時候誤差超級大,這個過程叫做:“梯度爆炸”。這也是RNN無法解決的問題。
在這裏插入圖片描述
LSTM就是在RNN的基礎上增加了3個控制器:輸入、輸出、忘記
在這裏插入圖片描述 在這裏插入圖片描述
將LSTM內部分爲主線和分線部分,控制器輸入和忘記將分線有效的學習內容加入主線,最後輸出
在這裏插入圖片描述

3.LSTM的應用

1.自動圖片標題生成
《顯示並告知:一個神經網絡標題生成器》,2014
輸入一張圖片,預測圖片內容,再將單詞連接成一個完整的句子。
在這裏插入圖片描述
2.文本自動翻譯
3.自動手寫體生成
4.音樂的生成
5.字母的生成

更多瞭解參考:《機器學習博士手把手教你入門LSTM》

二、LSTM源碼實例

1.入門–天氣預測

博文參考:https://www.rs-online.com/designspark/lstm-1-cn
源碼:https://github.com/danrustia11/WeatherLSTM

臺灣宜蘭縣的每日環境溫度 進行lstm訓練:

  1. 讀取csv:(2000天+溫度記錄)
  2. 數據進行中值濾波和高斯濾波
  3. 構建LTSM神經網絡
  4. 劃分訓練集和測試集
  5. 訓練集訓練
  6. 測試集檢測
  7. 可視化查看結果

keras+sklearn學習參考源碼:

#
# 博文參考:https://www.rs-online.com/designspark/lstm-1-cn
# 源碼參考:https://github.com/danrustia11/WeatherLSTM
# LSTM weather prediction demo
# Written by: Dan R 2020
#


#
# Core Keras libraries
#
from numpy import array
from sklearn.metrics import r2_score # 擬合優度
from sklearn.metrics import mean_squared_error  # 均方差
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf  # 隨機數生成器,結果可重現
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM  # LSTM
from keras.layers import Bidirectional  # 雙向

#
# For data conditioning
#
from scipy.ndimage import gaussian_filter1d  # 數據調節
from scipy.signal import medfilt

#
# Make results reproducible
#
from numpy.random import seed
seed(1)

tf.random.set_seed(1)
#
# Other essential libraries
#

# Make our plot a bit formal
font = {'family': 'Arial',
        'weight': 'normal',
        'size': 10}
plt.rc('font', **font)


#
# Set input number of timestamps and training days
#
n_timestamp = 10  # 時間戳
train_days = 1500  # number of days to train from 開始的天數
testing_days = 500  # number of days to be predicted 可以預測的天數
n_epochs = 25  # 訓練輪數
filter_on = 1  # 激活數據過濾器


#
# Select model type 選擇型號類型
# 1: Single cell 單格
# 2: Stacked 堆疊
# 3: Bidirectional 雙向
#
model_type = 2

#-----------------------------------------
# 數據集
#-----------------------------------------
# 臺灣環境保護局提供的臺灣宜蘭縣的每日環境溫度
# url  =  'https://raw.githubusercontent.com/danrustia11/WeatherLSTM/master/data/weather_temperature_yilan.csv'
url = "D:/myworkspace/dataset/WeatherLSTM-master/data/weather_temperature_yilan.csv"
dataset = pd.read_csv(url)
if filter_on == 1:  # 數據集過濾
    dataset['Temperature'] = medfilt(dataset['Temperature'], 3)  # 中值過濾
    dataset['Temperature'] = gaussian_filter1d(
        dataset['Temperature'], 1.2)  # 高斯過濾


#
# Set number of training and testing data 設置訓練和測試數據集
#
train_set = dataset[0:train_days].reset_index(drop=True)
test_set = dataset[train_days: train_days+testing_days].reset_index(drop=True)
training_set = train_set.iloc[:, 1:2].values
testing_set = test_set.iloc[:, 1:2].values
#-----------------------------------------
# 數據集完
#-----------------------------------------


#
# Normalize data first
#
sc = MinMaxScaler(feature_range=(0, 1))  # 將數據標準化,範圍是0到1
training_set_scaled = sc.fit_transform(training_set)
testing_set_scaled = sc.fit_transform(testing_set)

#
# Split data into n_timestamp
#
def data_split(sequence, n_timestamp):
    X = []
    y = []
    for i in range(len(sequence)):
        end_ix = i + n_timestamp
        if end_ix > len(sequence)-1:
            break
        # i to end_ix as input
        # end_ix as target output
        seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
        X.append(seq_x)
        y.append(seq_y)
    return array(X), array(y)


X_train, y_train = data_split(training_set_scaled, n_timestamp)
X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
X_test, y_test = data_split(testing_set_scaled, n_timestamp)
X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)


# 使用Keras建構LSTM模型
if model_type == 1:
    # Single cell LSTM
    model = Sequential()
    model.add(LSTM(units=50, activation='relu',
                   input_shape=(X_train.shape[1], 1)))
    model.add(Dense(units=1))
if model_type == 2:
    # Stacked LSTM
    model = Sequential()
    model.add(LSTM(50, activation='relu', return_sequences=True,
                   input_shape=(X_train.shape[1], 1)))
    model.add(LSTM(50, activation='relu'))
    model.add(Dense(1))
if model_type == 3:
    # Bidirectional LSTM
    model = Sequential()
    model.add(Bidirectional(LSTM(50, activation='relu'),
                            input_shape=(X_train.shape[1], 1)))
    model.add(Dense(1))


#
# Start training 模型訓練,batch_size越大越精準,訓練消耗越大
#
model.compile(optimizer='adam', loss='mean_squared_error')
history = model.fit(X_train, y_train, epochs=n_epochs, batch_size=32)
loss = history.history['loss']
epochs = range(len(loss))


#
# Get predicted data 測試集預測
#
y_predicted = model.predict(X_test)

#
# 'De-normalize' the data 正規化將數據還原
#
y_predicted_descaled = sc.inverse_transform(y_predicted)
y_train_descaled = sc.inverse_transform(y_train)
y_test_descaled = sc.inverse_transform(y_test)
y_pred = y_predicted.ravel()
y_pred = [round(yx, 2) for yx in y_pred]
y_tested = y_test.ravel()


#
# Show results 顯示預測結果,包括原始數據、n個預測天數和前75天
#
plt.figure(figsize=(8, 7))

plt.subplot(3, 1, 1)
plt.plot(dataset['Temperature'], color='black',
         linewidth=1, label='True value')
plt.ylabel("Temperature")
plt.xlabel("Day")
plt.title("All data")


plt.subplot(3, 2, 3)
plt.plot(y_test_descaled, color='black', linewidth=1, label='True value')
plt.plot(y_predicted_descaled, color='red',  linewidth=1, label='Predicted')
plt.legend(frameon=False)
plt.ylabel("Temperature")
plt.xlabel("Day")
plt.title("Predicted data (n days)")

plt.subplot(3, 2, 4)
plt.plot(y_test_descaled[0:75], color='black', linewidth=1, label='True value')
plt.plot(y_predicted_descaled[0:75], color='red', label='Predicted')
plt.legend(frameon=False)
plt.ylabel("Temperature")
plt.xlabel("Day")
plt.title("Predicted data (first 75 days)")

plt.subplot(3, 3, 7)
plt.plot(epochs, loss, color='black')
plt.ylabel("Loss (MSE)")
plt.xlabel("Epoch")
plt.title("Training curve")

plt.subplot(3, 3, 8)
plt.plot(y_test_descaled-y_predicted_descaled, color='black')
plt.ylabel("Residual")
plt.xlabel("Day")
plt.title("Residual plot")

plt.subplot(3, 3, 9)
plt.scatter(y_predicted_descaled, y_test_descaled, s=2, color='black')
plt.ylabel("Y true")
plt.xlabel("Y predicted")
plt.title("Scatter plot")

plt.subplots_adjust(hspace=0.5, wspace=0.3)
plt.show()


mse = mean_squared_error(y_test_descaled, y_predicted_descaled) # 均方誤差
r2 = r2_score(y_test_descaled, y_predicted_descaled) # 決定係數(擬合優度)接近1越好
print("mse=" + str(round(mse, 2)))
print("r2=" + str(round(r2, 2)))

2.結果

在這裏插入圖片描述
圖一:全部數據(x軸:2000+天數,y軸:溫度)
圖二:n天溫度預測結果
圖三:前70天預測結果,可以看見LSTM在不斷學習優化
圖4,5,6:訓練評價因素可視化

3.評價標準

在這裏插入圖片描述

mse均方差(mean-squared-error)
在這裏插入圖片描述

R2 決定係數(擬合優度)
在這裏插入圖片描述
模型越好:r2→1

模型越差:r2→0

更多評價標準參考:學習筆記2:scikit-learn中使用r2_score評價迴歸模型

同理,在載入自己的數據集時,修改數據集讀取模塊即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章