从零开始应用LSTM网络

Posted 彭祥.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始应用LSTM网络相关的知识,希望对你有一定的参考价值。

数据预处理

该部分包含生成差分数据,归一化,数据缩放,生成监督数据集等。

将数据转换成有监督数据

# coding=utf-8
from pandas import read_csv
from datetime import datetime
from pandas import DataFrame
from pandas import concat


# load data
def parser(x):
    return datetime.strptime(x, '%Y/%m/%d')


series = read_csv("data_set\\shampoo-sales.csv", header=0, parse_dates=[0], index_col=0, squeeze=True,
                  date_parser=parser)

'''                     
将数据转换成有监督数据  
即包含input output      
训练的目的就是找到训练数据input和output的关系                                                                           
此处的input是t时间步的数据,output为t+1时间步的数据                                                                     
具体实现就是将整体的时间数据向后滑动一格,和原始数据拼接,就是有监督的数据                                              
'''
# 这个函数说了一大堆,简单说就是把data数组重新构造成两两一组的二维数组,每个数据对格式是[0,n],[n,n+1],[n+1,n+2],
# 第一组数据用0补全,即为[0,n],这就是所谓的监督学习数据
def timeseries_to_supervised(data, lag=1):  # lag表示的是当前的值只与历史lag个时间步长的值有关,也就是用lag个数据预测下一个
    df = DataFrame(data)
    colums = [df.shift(i) for i in range(1, lag + 1)]  # 原始数据时间窗向后移动lag步长
    colums.append(df)  # 拼接数据
    df = concat(colums, axis=1)  # 横向拼接重塑数据,格式:input putput
    df.fillna(0, inplace=True)  # 由于数据整体向后滑动lag后,前面的lag个数据是Na形式,用0来填充
    return df


X = series.values
supervised = timeseries_to_supervised(X, 1)
print(supervised.head())

原数据:

转换为监督数据后:

数据缩放

# coding=utf-8
from pandas import read_csv
from pandas import datetime
from pandas import Series
from sklearn.preprocessing import MinMaxScaler
# load data
def parser(x):
    return datetime.strptime(x, '%Y/%m/%d')

series = read_csv('data_set/shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True,
                  date_parser=parser)
print (series.head())
# 所谓缩放,就是把一组数组中的数字都变成[-1,1]范围的数字,取数组中最大的那个数组,令其为1,最小的数字,令其为-1,
# 剩下的数字根据比例关系,在[-1,1]中给其找一个对应值
# 缩放
X = series.values
X = X.reshape(len(X), 1)  # MinMaxScaler函数需要矩阵作为输入,所以reshape数据为矩阵,因为是一维数组,所以生成的是n行1列的一个矩阵
scaler = MinMaxScaler(feature_range=(-1, 1))  # 定义缩放范围,-1,1是数据缩放的范围
scaler = scaler.fit(X)  # 调用缩放数据的fun
scalered_X = scaler.transform(X)#转换成一个[-1,1]区间的矩阵
scalered_series = Series(scalered_X[:, 0])#把矩阵序列化成列表
print (scalered_series)

# 逆缩放,反着来一遍,转换回去
inverted_X = scaler.inverse_transform(scalered_X)#把数值为[-1,1]之间的矩阵转换成正常数据的矩阵
inverted_series = Series(inverted_X[:, 0])#把矩阵转换成列表
print (inverted_series.head())

搭建网络

从0开始实现深度学习网络

我们搭建网络并训练的流程为:

读取数据,如读取时间序列,图片等
数据预处理,如将其转换为监督数据,数据归一化,缩放等,划分数据集
搭建模型,设置网络层结构,设置参数,神经元个数等
编译模型,设置批次大小,损失函数,优化器等
训练模型,设置迭代次数,批次大小传入数据等
保存模型,如参数权值等
模型预测数据,使用已保存模型进行数据预测
模型评估,设置评估函数
结果分析,如通过图像。

数据读取,使用的是numpy的read_csv

# 读取时间数据的格式化
def parser(x):
    return datetime.strptime(x, '%Y/%m/%d')
# 加载数据
series = read_csv('data_set/shampoo-sales.csv', 
header=0, parse_dates=[0], index_col=0, squeeze=True,
                  date_parser=parser)

转换为差分数据,即将数据变为稳定的

# 转换成差分数据
def difference(dataset, interval=1):
    diff = list()
    for i in range(interval, len(dataset)):
        value = dataset[i] - dataset[i - interval]
        diff.append(value)
    return Series(diff)
diff_values = difference(raw_values, 1)#转换成差分数据

转换为有监督数据,即input,output形式

# 转换成有监督数据
def timeseries_to_supervised(data, lag=1):
    df = DataFrame(data)
    columns = [df.shift(i) for i in range(1, lag + 1)]  # 数据滑动一格,作为input,df原数据为output
    columns.append(df)
    df = concat(columns, axis=1)
    df.fillna(0, inplace=True)
    return df
# 让数据变成稳定的
# 把稳定的数据变成有监督数据
supervised = timeseries_to_supervised(diff_values, 1)

划分训练集测试集

# 数据拆分:训练数据、测试数据,前24行是训练集,后12行是测试集
train, test = supervised_values[0:-12], supervised_values[-12:]

数据缩放至-1到1之间

# 缩放
def scale(train, test):
    # 根据训练数据建立缩放器
    scaler = MinMaxScaler(feature_range=(-1, 1))
    scaler = scaler.fit(train)
    # 转换train data
    train = train.reshape(train.shape[0], train.shape[1])
    train_scaled = scaler.transform(train)
    # 转换test data
    test = test.reshape(test.shape[0], test.shape[1])
    test_scaled = scaler.transform(test)
    return scaler, train_scaled, test_scaled
scaler, train_scaled, test_scaled = scale(train, test)

模型训练,这里批次大小设置为1,即每次训练一个数据,使用手写循环调用fit,从而没训练一次数据便完成一次权值更新

def fit_lstm(train, batch_size, nb_epoch, neurons):
    X, y = train[:, 0:-1], train[:, -1]
    X = X.reshape(X.shape[0], 1, X.shape[1])
    model = Sequential()
    # 添加LSTM层
    model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
    model.add(Dense(1))  # 输出层1个node
    # 编译,损失函数mse+优化算法adam
    model.compile(loss='mean_squared_error', optimizer='adam')
    for i in range(nb_epoch):
        # 按照batch_size,一次读取batch_size个数据
        model.fit(X, y, epochs=1, batch_size=batch_size, verbose=0, shuffle=False)
        model.reset_states()  #更新权值
        print("当前计算次数:"+str(i))
    return model
lstm_model = fit_lstm(train_scaled, 1, 1500, 1)  # 训练数据,batch_size,epoche次数, 神经元个数

预测数据

# 预测
train_reshaped = train_scaled[:, 0].reshape(len(train_scaled), 1, 1)#训练数据集转换为可输入的矩阵
lstm_model.predict(train_reshaped, batch_size=1)#用模型对训练数据矩阵进行预测

预测数据并完成性能分析

predictions = list()
for i in range(len(test_scaled)):#根据测试数据进行预测,取测试数据的一个数值作为输入,计算出下一个预测值,以此类推
    # 1步长预测
    X, y = test_scaled[i, 0:-1], test_scaled[i, -1]
    yhat = forcast_lstm(lstm_model, 1, X)
    # 逆缩放
    yhat = invert_scale(scaler, X, yhat)
    # 逆差分
    yhat = inverse_difference(raw_values, yhat, len(test_scaled) + 1 - i)
    predictions.append(yhat)
    expected = raw_values[len(train) + i + 1]
    print('Moth=%d, Predicted=%f, Expected=%f' % (i + 1, yhat, expected))

print(predictions)
# 性能报告
rmse = sqrt(mean_squared_error(raw_values[-12:], predictions))
print('Test RMSE:%.3f' % rmse)
# 绘图
pyplot.plot(raw_values[-12:])
pyplot.plot(predictions)
pyplot.show()

以上是关于从零开始应用LSTM网络的主要内容,如果未能解决你的问题,请参考以下文章

LSTM -长短期记忆网络(RNN循环神经网络)

多图+公式全面解析RNN,LSTM,Seq2Seq,Attention注意力机制

从零开始实现循环神经网络(无框架)

不怕学不会 | 使用TensorFlow从零开始构建卷积神经网络

Keras深度学习实战(29)——长短时记忆网络详解与实现

Keras深度学习实战(29)——长短时记忆网络详解与实现