用Keras訓練BP神經網絡,並將模型用於預測

本文記錄了筆者用Keras框架編寫BP神經網絡,訓練並預測秦皇島未來煤價數據,共分爲三部分:訓練、驗證和預測。本文編寫於2020年5月19日,文中代碼全爲Python 3代碼,並在Jupyter中測試通過。
點擊跳轉至本文數據集下載鏈接

獻給新手!大家有疑問可以在評論區留言,一起進步~

1、數據讀入

數據集下載鏈接:戳這裏
在這裏插入圖片描述
訓練集一共62條,每條包含了9個屬性(A~I)和目標值target,我們將用他們來訓練模型:根據A-I的值來預測target的值

以下是需要預測的數據,我們將它放置在數據集的64~94行:
(僅有A-I屬性的數據,無target值,我們將用訓練好的模型來預測其target)
在這裏插入圖片描述
首先用Pandas讀入全部數據——

import pandas as pd 
data = pd.read_csv("C:/Users/LRK/Desktop/0518.csv") 

注意,用Pandas讀取的數據會是一個Numpy數組,在這種數據集上非常好用!!

★ 手動劃分訓練集(train_data)、訓練目標(train_targets),他們都是Numpy數組。

train_data = data.loc[0:61, ['A','B','C','D','E','F','G','H','I']]
train_data.shape

# 讀取數據集的0~61行、A~I列的數據

Output:(62, 9)

train_targets = data.loc[0:61, ['target']]
train_targets.shape

# 讀取數據集的0~61行、target列的數據

Output:(62, 1)

用Pandas讀取train_data是這樣的,非常美觀:
在這裏插入圖片描述
★ 讀取需要預測的數據的A-I特徵:

test_data = data.loc[62:92, ['A','B','C','D','E','F','G','H','I']]

在這裏插入圖片描述

2、數據預處理

在這裏,我們採用“數據標準化處理”,即:每個數據減去該列平均值,再除以該列的標準差。這是機器學習中常見的數據處理方式,一定程度上縮小了A~I列不同屬性的數據大小範圍,方便神經網絡進行訓練。
(這裏不明白的可以參考Andrew Ng的視頻課程)

mean = train_data.mean(axis=0)
train_data -= mean
std = train_data.std(axis=0)
train_data /= std

test_data -= mean
test_data /= std

警告:test_data進行預處理的時候,減去的平均值和除以的標準差,都是在訓練集上得出的,而非測試集上!!否則會影響準確性。

3、編寫模型(類BP神經網絡)

實在不知道Dense層堆疊該叫啥模型,就先管他叫做類BP網絡吧~

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"   # GTX 1050 Ti

from keras import models
from keras import layers

def build_model():
    model = models.Sequential()
    model.add(layers.Dense(64, activation='relu',
                           input_shape=(train_data.shape[1],)))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(1))
    model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
    return model

用MAE(平均絕對誤差)來衡量訓練效果。MAE是指實際值與預測值的差值大小。

4、劃分驗證集

考慮到訓練數據很少,我們採用K折交叉驗證(k=4)

import numpy as np

k = 4
num_val_samples = len(train_data) // k
num_epochs = 100
all_scores = []
for i in range(k):
    print('processing fold #', i)
    # 準備驗證數據:第 k 個分區的數據
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

    # 準備訓練數據:其他所有分區的數據
    partial_train_data = np.concatenate(
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

    # 構建 Keras 模型(已編譯)
    model = build_model()
    model.fit(partial_train_data, partial_train_targets,
              epochs=num_epochs, batch_size=1, verbose=1)
    # 在驗證數據上評估模型
    val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)
    all_scores.append(val_mae)

查看MAE的平均值:

np.mean(all_scores)

輸出:60.37001419067383

5、訓練模型

先練500輪看看。

from keras import backend as K
K.clear_session()

num_epochs = 500
all_mae_histories = []
for i in range(k):
    print('processing fold #', i)
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

    partial_train_data = np.concatenate(
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

    model = build_model()

    history = model.fit(partial_train_data, partial_train_targets,
                        validation_data=(val_data, val_targets),
                        epochs=num_epochs, batch_size=1, verbose=1)
    mae_history = history.history['val_mean_absolute_error']
    all_mae_histories.append(mae_history)

查看500輪中,每一輪的各個分區上的MAE的平均值:

average_mae_history = [
    np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

最後幾輪的MAE平均值如下:
在這裏插入圖片描述
可以看出,經過訓練,誤差已經縮小了很多!

我們再畫圖來看看——

import matplotlib.pyplot as plt

plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()

在這裏插入圖片描述
刪除前40輪的數據,再重新畫圖,方便觀察:

def smooth_curve(points, factor=0.9):
  smoothed_points = []
  for point in points:
    if smoothed_points:
      previous = smoothed_points[-1]
      smoothed_points.append(previous * factor + point * (1 - factor))
    else:
      smoothed_points.append(point)
  return smoothed_points

smooth_mae_history = smooth_curve(average_mae_history[40:])

plt.plot(range(1, len(smooth_mae_history) + 1), smooth_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()

在這裏插入圖片描述
可以看出,模型並沒有過擬合。

現在,我們用全部的訓練數據,對模型從頭開始重新訓練!

model = build_model()
# Train it on the entirety of the data.
model.fit(train_data, train_targets,
          epochs=600, batch_size=16, verbose=1)

分享最後幾輪的訓練過程如下:
在這裏插入圖片描述
由於訓練集很小,效果可能沒有很好。大家可以分享自己的指標或建議在評論區裏~

6、用訓練好的模型來預測新數據

這一塊網上能搜到的代碼很少,作爲新手也是踩了不少坑~最後自己琢磨出來了怎麼用Keras的Predict。

★ 其實!就兩句話的事兒!用Keras真的非常方便了!!

predict = model.predict(test_data)

predict

接下來,就會打印出64—94行(即預測集)對應的target值,如下圖所示。
在這裏插入圖片描述
在這裏插入圖片描述
用Python可以寫代碼把預測數據寫入到指定csv文件的指定行列上,所以應用時不必一個一個複製粘貼!具體代碼自己網上一扒就有~

7、預測結果可視化

在數學建模中,經常會遇到需要以圖表呈現數據。即數據可視化。這裏我們順便也演示一下。

注意:我們剛剛預測的30個值是未來30天的煤炭價格。我們將其畫折線圖呈現出來。代碼如下。

from matplotlib import pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif'] = [u'SimHei']
plt.rcParams['axes.unicode_minus'] = False

x = np.arange(1,31) 
plt.title("未來30天煤價走勢預測") 
plt.xlabel("未來一個月") 
plt.ylabel("煤價") 
plt.plot(range(0, 31, 1),predict)
plt.show()

效果如下圖。 注意:筆者一開始橫縱軸寫反了所以大家看到的橫縱座標標識是反的,但圖是對的。懶得改啦~
在這裏插入圖片描述
★ 既然說到python的matplotlib,那順便解釋兩個新手常見的問題吧!

  1. Jupyter中畫圖,寫標註時無法正常顯示中文
    解決辦法:加上這三條語句!別問爲什麼,加上去就是了!!
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = [u'SimHei']
plt.rcParams['axes.unicode_minus'] = False
  1. 用matplotlib畫圖,顯示什麼<Figure …>,圖沒顯示出來。
    解決辦法:加上下面的第一條語句。如果不行,把第二條也加上(加畫布用的)。
%matplotlib inline

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