本文为365天深度学习训练营 中的学习记录博客
参考文章:第R2周:LSTM-火灾温度预测(训练营内部可读)
作者:K同学啊
在本期我们将使用LSTM来实现对火灾温度的预测任务,有人肯定会问这个LSTM是什么,它的全程叫做长短期记忆网络,它是RNN的进阶版,简单的介绍一下就是RNN最大限度是理解一句话,那么LSTM的最大限度就是能理解一段话,具体的介绍我们在下面来叙述,我们首先来打开一下我们的数据集看看:
其中数据集里面的每列的标签含义为:
后面有关火灾的数据都是随着时间而变化的,我们需要根据这些数据对未来某时刻的火灾温度进行预测,好啦,介绍完之后我们开始正题内容。
在前面的简单介绍中,我们说了LSTM是RNN的进阶版,那么我们就需要知道为什么要研究LSTM,RNN能够将以前的信息连接到当前的任务,这很好,有时候我们只需要查看最近的信息就行,例如,我们需要通过一个语言模型根据前面的单词预测下一个单词,例如我们尝试预测“这些云朵在天空中”这句话中的天空,我们就不需要参考更远的上下文,在这种情况下,相关信息和需要它的地方之间的差距很小,这个时候RNN就可以胜任,但是在某些情况下,我们需要更多的上下文,例如预测“我在中国湖北长大的…我会说中文”这句话的最后的说中文,如果使用RNN进行预测,RNN能预测出这词应该要填一个语言,但是不知道填哪种语言,这个时候我们就需要前面的信息来判断后面应该填什么语言,如果这两个信息之前差距变得很大很大,那么RNN就变得无法学习连接信息。
RNN在实际应用中无法解决这种长期依赖的问题,这个时候LSTM就派上用场了。
短期记忆网络——通常简称为“LSTM”——是一种特殊的 RNN,能够学习长期依赖关系。它在处理大量问题时表现出色,现在已被广泛使用。
所有循环神经网络都具有神经网络重复模块链的形式。在标准 RNN 中,这个重复模块将具有非常简单的结构,例如单个 tanh 层:
LSTM 也有这种链状结构,但重复模块有不同的结构。不是只有一个神经网络层,而是有四个,以一种非常特殊的方式进行交互,是通过门控状态来选择调整传输的信息,简单的来说就是记住需要长时间记忆的信息,忘记不重要的信息,其结构如下:
LSTM由三个部分组成,每个部分执行一个单独的功能,这些部分被称为门,第一部分称遗忘门,第二部分称输入门,第三部分称输出门。
具体的介绍大家可以去看一下这篇国外的文章:长短期记忆 (LSTM) 简介
和之前一样,如果你GPU很好就只使用GPU进行训练,如果GPU不行就推荐使用CPU训练加GPU加速。
只使用GPU:
import tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")
if gpus:
tf.config.experimental.set_memory_growth(gpus[0], True) #设置GPU显存用量按需使用
tf.config.set_visible_devices([gpus[0]],"GPU")
print(gpus)
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
使用CPU+GPU:
import tensorflow as tf
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
import pandas as pd
import numpy as np
df_1 = pd.read_csv("./data/woodpine2.csv")
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['savefig.dpi'] = 500 #图片像素
plt.rcParams['figure.dpi'] = 500 #分辨率
fig, ax =plt.subplots(1,3,constrained_layout=True, figsize=(14, 3))
sns.lineplot(data=df_1["Tem1"], ax=ax[0])
sns.lineplot(data=df_1["CO 1"], ax=ax[1])
sns.lineplot(data=df_1["Soot 1"], ax=ax[2])
plt.show()
dataFrame = df_1.iloc[:,1:]
dataFrame
我们取数据集的前8个时间段的Tem 1、CO 1和Soot 1设置为X,第9九个时间段的Tem 1设置为y。
width_X = 8
width_y = 2
X = []
y = []
in_start = 0
for _, _ in df_1.iterrows():
in_end = in_start + width_X
out_end = in_end + width_y
if out_end < len(dataFrame):
X_ = np.array(dataFrame.iloc[in_start:in_end , ])
X_ = X_.reshape((len(X_)*3))
y_ = np.array(dataFrame.iloc[in_end :out_end, 0])
X.append(X_)
y.append(y_)
in_start += 1
X = np.array(X)
y = np.array(y)
X.shape, y.shape
我们打印出X、y的数组维度:
((5938, 24), (5938, 2))
from sklearn.preprocessing import MinMaxScaler
#将数据归一化,范围是0到1
sc = MinMaxScaler(feature_range=(0, 1))
X_scaled = sc.fit_transform(X)
X_scaled = X_scaled.reshape(len(X_scaled),width_X,3)
X_scaled.shape
(5938, 8, 3)
我们取前五千的数据为训练集,五千之后的数据为验证集:、
X_train = np.array(X_scaled[:5000]).astype('float64')
y_train = np.array(y[:5000]).astype('float64')
X_test = np.array(X_scaled[5000:]).astype('float64')
y_test = np.array(y[5000:]).astype('float64')
X_train.shape
(5000, 8, 3)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,LSTM
# 多层 LSTM
model_lstm = Sequential()
model_lstm.add(LSTM(units=64, activation='relu', return_sequences=True,
input_shape=(X_train.shape[1], 3)))
model_lstm.add(LSTM(units=64, activation='relu'))
model_lstm.add(Dense(width_y))
这里我们构建了多层LSTM层,其函数模型为:
tf.keras.layers.LSTM(
units,
activation="tanh",
recurrent_activation="sigmoid",
use_bias=True,
kernel_initializer="glorot_uniform",
recurrent_initializer="orthogonal",
bias_initializer="zeros",
unit_forget_bias=True,
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
time_major=False,
unroll=False,
**kwargs
)
其中的参数介绍,我直接截图官网的详细介绍:
# 只观测loss数值,不观测准确率,所以删去metrics选项
model_lstm.compile(optimizer=tf.keras.optimizers.Adam(1e-3),
loss='mean_squared_error') # 损失函数用均方误差
history_lstm = model_lstm.fit(X_train, y_train,
batch_size=64,
epochs=50,
validation_data=(X_test, y_test),
validation_freq=1)
训练的结果是:
Epoch 1/50
79/79 [==============================] - 1s 10ms/step - loss: 11686.5967 - val_loss: 3691.0500
Epoch 2/50
79/79 [==============================] - 1s 7ms/step - loss: 151.2972 - val_loss: 317.7450
Epoch 3/50
79/79 [==============================] - 1s 7ms/step - loss: 37.6472 - val_loss: 106.3978
Epoch 4/50
79/79 [==============================] - 1s 7ms/step - loss: 10.1789 - val_loss: 99.7457
Epoch 5/50
79/79 [==============================] - 0s 6ms/step - loss: 8.7049 - val_loss: 115.6766
Epoch 6/50
79/79 [==============================] - 1s 7ms/step - loss: 9.2803 - val_loss: 115.1288
Epoch 7/50
79/79 [==============================] - 0s 6ms/step - loss: 8.1934 - val_loss: 107.6996
Epoch 8/50
79/79 [==============================] - 0s 6ms/step - loss: 7.6814 - val_loss: 73.8946
Epoch 9/50
79/79 [==============================] - 1s 6ms/step - loss: 7.4581 - val_loss: 115.7030
Epoch 10/50
79/79 [==============================] - 1s 7ms/step - loss: 7.7914 - val_loss: 81.8359
Epoch 11/50
79/79 [==============================] - 1s 7ms/step - loss: 9.2118 - val_loss: 86.4748
Epoch 12/50
79/79 [==============================] - 1s 7ms/step - loss: 6.9482 - val_loss: 82.4900
Epoch 13/50
79/79 [==============================] - 1s 7ms/step - loss: 6.7160 - val_loss: 86.3577
Epoch 14/50
79/79 [==============================] - 1s 7ms/step - loss: 7.5583 - val_loss: 82.8828
Epoch 15/50
79/79 [==============================] - 1s 6ms/step - loss: 8.2439 - val_loss: 71.2496
Epoch 16/50
79/79 [==============================] - 1s 7ms/step - loss: 6.9511 - val_loss: 87.5125
Epoch 17/50
79/79 [==============================] - 1s 7ms/step - loss: 6.5218 - val_loss: 95.1897
Epoch 18/50
79/79 [==============================] - 1s 7ms/step - loss: 7.2178 - val_loss: 156.5886
Epoch 19/50
79/79 [==============================] - 1s 7ms/step - loss: 7.7970 - val_loss: 67.9543
Epoch 20/50
79/79 [==============================] - 1s 6ms/step - loss: 6.5448 - val_loss: 80.9858
Epoch 21/50
79/79 [==============================] - 1s 7ms/step - loss: 6.6814 - val_loss: 87.8312
Epoch 22/50
79/79 [==============================] - 1s 6ms/step - loss: 6.7830 - val_loss: 93.9837
Epoch 23/50
79/79 [==============================] - 0s 6ms/step - loss: 6.4453 - val_loss: 89.2516
Epoch 24/50
79/79 [==============================] - 1s 7ms/step - loss: 6.8551 - val_loss: 54.0458
Epoch 25/50
79/79 [==============================] - 0s 6ms/step - loss: 7.1806 - val_loss: 54.7397
Epoch 26/50
79/79 [==============================] - 0s 6ms/step - loss: 7.5586 - val_loss: 54.8446
Epoch 27/50
79/79 [==============================] - 0s 6ms/step - loss: 6.6819 - val_loss: 52.9399
Epoch 28/50
79/79 [==============================] - 0s 6ms/step - loss: 7.6259 - val_loss: 54.6638
Epoch 29/50
79/79 [==============================] - 1s 6ms/step - loss: 8.7933 - val_loss: 55.4396
Epoch 30/50
79/79 [==============================] - 0s 6ms/step - loss: 7.1920 - val_loss: 61.9947
Epoch 31/50
79/79 [==============================] - 1s 6ms/step - loss: 6.7282 - val_loss: 52.4816
Epoch 32/50
79/79 [==============================] - 1s 7ms/step - loss: 7.7619 - val_loss: 52.3930
Epoch 33/50
79/79 [==============================] - 1s 8ms/step - loss: 6.2908 - val_loss: 90.4385
Epoch 34/50
79/79 [==============================] - 1s 7ms/step - loss: 7.8380 - val_loss: 52.6972
Epoch 35/50
79/79 [==============================] - 1s 7ms/step - loss: 7.5878 - val_loss: 52.7349
Epoch 36/50
79/79 [==============================] - 1s 7ms/step - loss: 9.9398 - val_loss: 52.8272
Epoch 37/50
79/79 [==============================] - 1s 8ms/step - loss: 6.9212 - val_loss: 95.1052
Epoch 38/50
79/79 [==============================] - 1s 7ms/step - loss: 7.6226 - val_loss: 72.0266
Epoch 39/50
79/79 [==============================] - 1s 7ms/step - loss: 8.0218 - val_loss: 58.9474
Epoch 40/50
79/79 [==============================] - 1s 7ms/step - loss: 6.2650 - val_loss: 49.7152
Epoch 41/50
79/79 [==============================] - 1s 7ms/step - loss: 7.1157 - val_loss: 51.9619
Epoch 42/50
79/79 [==============================] - 1s 7ms/step - loss: 7.1721 - val_loss: 47.5208
Epoch 43/50
79/79 [==============================] - 1s 7ms/step - loss: 6.2749 - val_loss: 61.2468
Epoch 44/50
79/79 [==============================] - 1s 7ms/step - loss: 9.0165 - val_loss: 68.4650
Epoch 45/50
79/79 [==============================] - 1s 7ms/step - loss: 7.3368 - val_loss: 50.3002
Epoch 46/50
79/79 [==============================] - 0s 6ms/step - loss: 6.1518 - val_loss: 70.3923
Epoch 47/50
79/79 [==============================] - 1s 6ms/step - loss: 7.5889 - val_loss: 62.4437
Epoch 48/50
79/79 [==============================] - 1s 6ms/step - loss: 7.4014 - val_loss: 61.4142
Epoch 49/50
79/79 [==============================] - 1s 7ms/step - loss: 6.2537 - val_loss: 47.6556
Epoch 50/50
79/79 [==============================] - 1s 7ms/step - loss: 7.3076 - val_loss: 58.5787
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.figure(figsize=(5, 3),dpi=120)
plt.plot(history_lstm.history['loss'] , label='LSTM Training Loss')
plt.plot(history_lstm.history['val_loss'], label='LSTM Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()
predicted_y_lstm = model_lstm.predict(X_test) # 测试集输入模型进行预测
y_test_one = [i[0] for i in y_test]
predicted_y_lstm_one = [i[0] for i in predicted_y_lstm]
plt.figure(figsize=(5, 3),dpi=120)
# 画出真实数据和预测数据的对比曲线
plt.plot(y_test_one[:1000], color='red', label='真实值')
plt.plot(predicted_y_lstm_one[:1000], color='blue', label='预测值')
plt.title('Title')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
from sklearn import metrics
"""
RMSE :均方根误差,对均方误差开方
R2 :决定系数,可以简单理解为反映模型拟合优度的重要的统计量
"""
RMSE_lstm = metrics.mean_squared_error(predicted_y_lstm, y_test)**0.5
R2_lstm = metrics.r2_score(predicted_y_lstm, y_test)
print('均方根误差: %.5f' % RMSE_lstm)
print('R2: %.5f' % R2_lstm)
打印的结果是:
均方根误差: 7.65367
R2: 0.83103
其中,RMSE是预测值与真实值的误差平方根的均值,它用来估计模型预测目标值的性能(准确度),值越小,模型的质量越好,R2是将预测值跟只使用均值的情况下相比,看能好多少。其区间通常在(0,1)之间。0表示还不如什么都不预测,直接取均值的情况,而1表示所有预测跟真实结果完美匹配的情况,值越接近1,模型的质量越好,可以看见我们这里两者的值都还算不错。
本期的博客就到这里结束了,在最后我们聊聊其他的,现在疫情防控放开了,大家身边肯定多了不少“小阳人”,大家一定要多注意身体,尽量避免去人多 的地方,保护好自己的同时也在保护好自己的家人朋友,已经感染的朋友们,也不要慌张,听取专家的建议,一般正常人七天左右就好了,最近博主我也是感冒了,还没有去做检查,应该只是小感冒,最近身体不太舒服,更新比较慢,见谅!
最后祝大家身体都健健康康,一起迎接新年的到来!