深度學習筆記(一) tf.keras 構建lstm神經網絡進行時間序列預測


  簡介:長短期記憶人工神經網絡(Long-Short Term Memory, LSTM)是一種時間遞歸神經網絡(RNN),論文首次發表於1997年。由於獨特的設計結構,LSTM適合於處理和預測時間序列中間隔和延遲非常長的重要事件。

  目的:學會使用tf.keras構建lstm神經網絡進行一個基本的時間序列數據預測(入門版),基於官方案例-預測天氣數據進行學習。

  用戶:同通過學習庫的使用而進行應用的用戶,本節筆記不包含原理解讀。

參考鏈接:

  官方案例(具體代碼可從官方下載):https://keras.io/api/preprocessing/timeseries/#timeseries_dataset_from_array-function

  深度學習-理解keras中的loss和val_loss:https://blog.csdn.net/JaysonRen/article/details/103273519

  機器學習之優化器keras.optimizers.Adam()詳解:https://blog.csdn.net/i_canjnu/article/details/106035640

主要步驟分為:

  1、確定使用目的;2、讀取數據;3、數據預處理;4、構造樣本數據和測試數據;5、創建模型;6、訓練模型;7、展示訓練結果;8、進行預測;

下面開始上demo學習。

1、確定使用目的:

  馬克斯·普朗克生物地球化學研究所記錄了耶拿氣候數據,時間為2009年1月10日至2016年12月31日,每10分鍾記錄一次,具有14個特征,例如溫度,壓力,濕度等。

集構建一個天氣預測模型 。

  由於氣候的變化在一個小時內並不明顯,所以考慮使用這個數據建立一個溫度預測模型,使用前720分鍾(120個小時)數據72分鍾后(12個小時后)的溫度時點進行預測。

2、讀取數據

import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras
from zipfile import ZipFile
import os

uri = "https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip"
zip_path = keras.utils.get_file(origin=uri, fname="jena_climate_2009_2016.csv.zip")
zip_file = ZipFile(zip_path)
zip_file.extractall()
csv_path = "jena_climate_2009_2016.csv"

df = pd.read_csv(csv_path)
View Code

獲取原始數據后,對原始數據進行一個觀察,包括每個字段的趨勢。

# 繪制數據的情況

# 每個圖的標題
titles = ["Pressure","Temperature","Temperature in Kelvin","Temperature (dew point)","Relative Humidity","Saturation vapor pressure","Vapor pressure",
    "Vapor pressure deficit","Specific humidity","Water vapor concentration","Airtight","Wind speed","Maximum wind speed","Wind direction in degrees",]

# 原始數據的字段名
feature_keys = ["p (mbar)", "T (degC)","Tpot (K)","Tdew (degC)","rh (%)","VPmax (mbar)","VPact (mbar)","VPdef (mbar)","sh (g/kg)","H2OC (mmol/mol)",
    "rho (g/m**3)","wv (m/s)","max. wv (m/s)","wd (deg)",]

# 繪制的圖片顏色
colors = ["blue","orange","green","red","purple","brown","pink","gray","olive","cyan",]

date_time_key = "Date Time"

# 展示原始數據可視化
def show_raw_visualization(data):
    time_data = data[date_time_key]
    # 7*2的總圖形結構
    fig, axes = plt.subplots(
        nrows=7, ncols=2, figsize=(15, 20), dpi=80, facecolor="w", edgecolor="k"
    )
    for i in range(len(feature_keys)):
        key = feature_keys[i]
        c = colors[i % (len(colors))] # 選擇一個顏色,循環選擇
        t_data = data[key] # 獲取對應字段數據
        t_data.index = time_data # 設置索引為時間
        t_data.head()
        ax = t_data.plot(
            ax=axes[i // 2, i % 2],
            color=c,
            title="{} - {}".format(titles[i], key),
            rot=25,
        )
        ax.legend([titles[i]])
    plt.tight_layout()  # 這個的作用是?自適應圖片大小


show_raw_visualization(df)
View Code

兩兩字段間的相關性:

def show_heatmap(data):
    plt.matshow(data.corr())
    plt.xticks(range(data.shape[1]), data.columns, fontsize=14, rotation=90)
    plt.gca().xaxis.tick_bottom()
    plt.yticks(range(data.shape[1]), data.columns, fontsize=14)

    cb = plt.colorbar()
    cb.ax.tick_params(labelsize=14)
    plt.title("Feature Correlation Heatmap", fontsize=14)
    plt.show()


show_heatmap(df)  # 展示字段兩兩相關性
View Code

3、數據預處理

由於原始數據不同字段的數據差異會比較多,所以需要進行無量綱處理,這里采用z-scroce。最后對數據進行拆分。

split_fraction = 0.715   # 訓練和測試數據集划分比例
train_split = int(split_fraction * int(df.shape[0]))  # 計算出划分的索引處
step = 6 # 數據的選取步頻

past = 720 # 使用前720個數據時間進行預測
future = 72 # 預測72個數據時點后的數據
learning_rate = 0.001 # 學習速率,用於建模的優化器參數
batch_size = 256 # 訓練的數據批此規模
epochs = 10 # 訓練次數

# 歸一化,z-score
def normalize(data, train_split):
    data_mean = data[:train_split].mean(axis=0)
    data_std = data[:train_split].std(axis=0)
    return (data - data_mean) / data_std
View Code
# 從相關熱圖中可以看到,相對濕度和比濕度等很少參數是多余的。因此,我們將使用選擇功能,而不是全部。
print(
    "The selected parameters are:",
    ", ".join([titles[i] for i in [0, 1, 5, 7, 8, 10, 11]]),
)
# 選擇更合適的字段進行建模
selected_features = [feature_keys[i] for i in [0, 1, 5, 7, 8, 10, 11]]
features = df[selected_features]
features.index = df[date_time_key]
features.head()

# 所有數據進行歸一化
features = normalize(features.values, train_split)
features = pd.DataFrame(features)
#print(features.head(2))

# 划分訓練數據和測試數據
train_data = features.loc[0 : train_split - 1] # 訓練數據
val_data = features.loc[train_split:]  # 測試數據,為什么val_data會被修改呢,哦,因為前面還沒有進行划分

print(train_data.head(2))
print(val_data.head(2))
View Code

4、構造樣本數據和測試數據

按前面所說,每10分鍾記錄一次觀察,即每小時6次。由於我們預計60分鍾之內不會發生重大變化,因此我們將每小時重新采樣一個點。函數timeseries_dataset_from_array中的sampling_rate參數可以達到此目的,可以快速的以一個滑動窗口獲取數據。

# 構造訓練數據
# 形成[[1,7,...720],[2,8,...,721]] 的x數據集,[[721],[722]...]的y數據集
# 類型於滑動窗口取數一樣
dataset_train = keras.preprocessing.timeseries_dataset_from_array(
    x_train,
    y_train,
    sequence_length=sequence_length, # 一批采集120次
    sampling_rate=step, # 6步采集一次,即 60分鍾采集一次
    batch_size=batch_size,
)
View Code
測試集
# 構造驗證數據
x_end = len(val_data) - past - future  # 因為是用720個監測數據去預測72個窗口數據后的值,所以要倒減一下

label_start = train_split + past + future # 同理Y值要延后一下

x_val = val_data.iloc[:x_end][[i for i in range(7)]].values
y_val = features.iloc[label_start:][[1]]

dataset_val = keras.preprocessing.timeseries_dataset_from_array(
    x_val,
    y_val,
    sequence_length=sequence_length,
    sampling_rate=step,
    batch_size=batch_size,
)


for batch in dataset_train.take(1):
    inputs, targets = batch

print("Input shape:", inputs.numpy().shape)
print("Target shape:", targets.numpy().shape)
View Code

5、創建模型

創建模型,創建一個(120,7)輸入,中間32個節點,輸入了1個節點的模型。還需要學習如何確定模型層數和中間層節點數。連續型數據,loss采用mse:均方損失函數。

# 創建模型
inputs = keras.layers.Input(shape=(inputs.shape[1], inputs.shape[2]))
lstm_out = keras.layers.LSTM(32)(inputs)
outputs = keras.layers.Dense(1)(lstm_out)

model = keras.Model(inputs=inputs, outputs=outputs)
# optimizer 優化器,加快學習速度,loss 損失計算
model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate), loss="mse")
# 展示模型
model.summary()
View Code

6、訓練模型

使用ModelCheckpoint回調EarlyStopping函數定期保存檢查點,並使用該回調函數在驗證損失不再改善時中斷訓練

# 設置損失函數和訓練
path_checkpoint = "model_checkpoint.h5"
es_callback = keras.callbacks.EarlyStopping(monitor="val_loss", min_delta=0, patience=5)

# 使用ModelCheckpoint回調EarlyStopping函數定期保存檢查點,並使用該回調函數在驗證損失不再改善時中斷訓練。
modelckpt_callback = keras.callbacks.ModelCheckpoint(
    monitor="val_loss",
    filepath=path_checkpoint,
    verbose=1,
    save_weights_only=True,
    save_best_only=True,
)

history = model.fit(
    dataset_train,
    epochs=epochs,
    validation_data=dataset_val,
    callbacks=[es_callback, modelckpt_callback],
)
View Code

7、展示訓練結果

從結果看,通過訓練loss和val_loss都往更好的方向發展。

loss下降,val_loss下降:訓練網絡正常,最好情況。

loss下降,val_loss穩定:網絡過擬合化,可以添加Dropout和Max pooling。

loss穩定,val_loss下降:數據集有嚴重問題,建議重新選擇。

loss穩定,val_loss穩定:學習過程遇到瓶頸,需要減小學習率(自適應網絡效果不大)或batch數量。

loss上升,val_loss上升:網絡結構設計問題,訓練超參數設置不當,數據集需要清洗等問題,最差情況。

 

 

# 顯示結果
# loss:訓練集的差距大小 和 val_loss 測試集的差距大小
def visualize_loss(history, title):
    loss = history.history["loss"]
    val_loss = history.history["val_loss"]
    epochs = range(len(loss))
    plt.figure()
    plt.plot(epochs, loss, "b", label="Training loss")
    plt.plot(epochs, val_loss, "r", label="Validation loss")
    plt.title(title)
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    plt.show()


visualize_loss(history, "Training and Validation Loss")
View Code

8、進行預測

從測試數據集中再選出5個節點進行預測查看。預測值和實際值存在有點誤差。

# 預測
def show_plot(plot_data, delta, title):
    labels = ["History", "True Future", "Model Prediction"]
    marker = [".-", "rx", "go"]
    time_steps = list(range(-(plot_data[0].shape[0]), 0))
    if delta:
        future = delta
    else:
        future = 0

    plt.title(title)
    for i, val in enumerate(plot_data):
        if i:
            # 繪制預測數據
            plt.plot(future, plot_data[i], marker[i], markersize=10, label=labels[i])
        else:
            # 繪制歷史數據
            plt.plot(time_steps, plot_data[i].flatten(), marker[i], label=labels[i])
    plt.legend()
    plt.xlim([time_steps[0], (future + 5) * 2])
    plt.xlabel("Time-Step")
    plt.show()
    return

# 輸入5個批此數據,歷史數據是120個小時,預測數據是12個小時以后,使用模型預測處結果
for x, y in dataset_val.take(5):
    show_plot(
        [x[0][:, 1].numpy(), y[0].numpy(), model.predict(x)[0]],
        12,
        "Single Step Prediction",
    )
View Code

 

 

 

總結:

對keras創建Lstm神經網絡的流程大致有了一個了解,下來需要進一步了解具體的原理進行深入的學習,這樣的模型參數設置,和結果的好壞才有更准確的把握。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM