时间: 2020-09-03 00:08:26 人气: 2283 评论: 0
由于没有一个成熟的理论来解释神经网络,所以配置神经网络通常是困难的,经常被同学们调侃为“炼丹”。
对于一个给定的预测建模问题,你必须系统地尝试不同的配置然后从客观和变化的视角来审视不同配置的结果,然后尝试理解在不同的配置下分别发生了什么,从而对模型进行合理的调优。
本教程将专注于时间预测问题并讨论如何对LSTM(long-short term memory,长短期记忆,最流行的RNN网络之一)网络进行配置。
认真完成本教程后,您将掌握以下技能:
事不宜迟,我们现在就开始吧。
本教程可以分为以下6个部分;:
本教程假设您已经安装了Python SciPy环境。Python 2或3皆可。
本教程假定您已经安装了Keras v2.0或更高版本(TensorFlow或Theano作为后端皆可)。
本教程还假设您已经安装了scikit-learn,pandas,NumPy和Matplotlib。
如果你不知道如何配置这些环境,可以参考下面的文章:
该数据集描述了3年期间每月洗发剂的销量。
这个数据集的基本单元是与时间对应的销量,一共有36个观测值。这个数据集是由Makridakis, Wheelwright, and Hyndman (1998)贡献。
下面的代码演示了如何导入数据集并据此绘制销量随时间的变化情况
# load and plot dataset from pandas import read_csv from pandas import datetime from matplotlib import pyplot # load dataset def parser(x): return datetime.strptime('190'+x, '%Y-%m') series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser) # summarize first few rows print(series.head()) # line plot series.plot() pyplot.show()
运行代码导入数据集,数据会被加载为Pandas Series类型并且控制台会输出前五行的数据。
Month 1901-01-01 266.0 1901-02-01 145.9 1901-03-01 183.1 1901-04-01 119.3 1901-05-01 180.3 Name: Sales, dtype: float64
绘制销量随时间变化的折线图,可以很清楚地看到销量的增长趋势。
接下来,我们来看一下实验中LSTM的配置和实验所需的测试套件。
本节将介绍本教程中使用的测试套件。
我们将销量数据集分为两部分:训练集和测试集。
前两年的数据作为训练集,剩余一年的数据作为测试集。
训练集将用于模型的训练,训练得到的模型将用于预测测试集中的销量。
如果以最后一个月的销量作为恒定的预测值,对测试集中的销量值预测误差为平均每月136.761的。这也是我们对模型在测试集上性能要求的下限。
我们将使用滚动预测方案,也称为前向模型验证。
测试数据集上的时间步长每次挪动一个单位.每次挪动后模型对下一个单位时长中的销量进行预测,然后取出真实的销量同时对下一个单位时长中的销量进行预测。
这种方案模拟了真实世界当中的场景,每个月都会有新的销量数据,我们会利用过去月份的销量数据对下个月的销量进行预测。
这个过程可以通过借助训练集和测试集中的时间标记来完成,在后面我们会一次性预测出测试集中所有的销量数据。
我们将会利用测试集中所有的数据对模型的预测性能进行训练并通过误差值来评判模型的性能。在这个例子里我们使用均方根误差(RMSE),因为相比于其他损失函数它可以提供较大的罚值,从而使模型的预测值更趋近于真实的销量值。
在我们在数据集上拟合LSTM模型之前,我们必须先对数据集格式进行转换。
下面就是我们在拟合模型进行预测前要先做的三个数据转换:
为了让模型仍旧可以输出我们需要的销量预测值,需要对变换后的输出进行逆变换从而输出模型的原始预测值。
每个实验场景需要重现10次以上。
这是因为即使给定了模型训练所需的超参数,LSTM模型的随机初始化也可能会引起模型训练结果间的巨大差异。
通过审视不同模型超参数下模型性能随迭代次数(epochs)的变化曲线,我们可以得到一些可能提升模型性能的超参数调整区间或方向。
在每个批次的数据集训练结束后,测试集和训练集上的得分(即均方根误差)会打印输出出来。
每个批次结束后打印输出性能评估指标可以帮助我们更好地了解到模型的现状,比如说是否发生了过拟合。
训练集和测试集上的RMSE损失值曲线在运行结束之后通过折线图展现,我们设定测试集曲线为蓝色,测试集为橙色。
下面让我们编写代码,然后对模型的结果进行分析。
我们调整的第一个模型超参数是epochs。
为了保持其他超参数的一致,我们固定神经元数量为1,Batch Size为4。下面我们通过调整epochs来观察模型性能参数的变化。
下面给出了我们实验使用的代码清单。
代码是最好的注释,同时代码也易于复用和变更,这份代码是我们下面所有的实验的基础代码,我们只需要在上面稍作变更就可以完成后续的所有实验。
from pandas import DataFrame from pandas import Series from pandas import concat from pandas import read_csv from pandas import datetime from sklearn.metrics import mean_squared_error from sklearn.preprocessing import MinMaxScaler from keras.models import Sequential from keras.layers import Dense from keras.layers import LSTM from math import sqrt import matplotlib # be able to save images on serve matplotlib.use('Agg') from matplotlib import pyplot import numpy # date-time parsing function for loading the dataset def parser(x): return datetime.strptime('190'+x, '%Y-%m') # frame a sequence as a supervised learning problem def timeseries_to_supervised(data, lag=1): df = DataFrame(data) columns = [df.shift(i) for i in range(1, lag+1)] columns.append(df) df = concat(columns, axis=1) df = df.drop(0) return df # create a differenced series 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) # scale train and test data to [-1, 1] def scale(train, test): # fit scale scaler = MinMaxScaler(feature_range=(-1, 1)) scaler = scaler.fit(train) # transform train train = train.reshape(train.shape[0], train.shape[1]) train_scaled = scaler.transform(train) # transform test test = test.reshape(test.shape[0], test.shape[1]) test_scaled = scaler.transform(test) return scaler, train_scaled, test_scaled # inverse scaling for a forecasted value def invert_scale(scaler, X, yhat): new_row = [x for x in X] + [yhat] array = numpy.array(new_row) array = array.reshape(1, len(array)) inverted = scaler.inverse_transform(array) return inverted[0, -1] # evaluate the model on a dataset, returns RMSE in transformed units def evaluate(model, raw_data, scaled_dataset, scaler, offset, batch_size): # separate X, y = scaled_dataset[:,0:-1], scaled_dataset[:,-1] # reshape reshaped = X.reshape(len(X), 1, 1) # forecast dataset output = model.predict(reshaped, batch_size=batch_size) # invert data transforms on forecast predictions = list() for i in range(len(output)): yhat = output[i,0] # invert scaling yhat = invert_scale(scaler, X[i], yhat) # invert differencing yhat = yhat + raw_data[i] # store forecast predictions.append(yhat) # report performance rmse = sqrt(mean_squared_error(raw_data[1:], predictions)) return rmse # fit an LSTM network to training data def fit_lstm(train, test, raw, scaler, batch_size, nb_epoch, neurons): X, y = train[:, 0:-1], train[:, -1] X = X.reshape(X.shape[0], 1, X.shape[1]) # prepare model model = Sequential() model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True)) model.add(Dense(1)) model.compile(loss='mean_squared_error', optimizer='adam') # fit model train_rmse, test_rmse = list(), list() for i in range(nb_epoch): model.fit(X, y, epochs=1, batch_size=batch_size, verbose=0, shuffle=False) model.reset_states() # evaluate model on train data raw_train = raw[-(len(train)+len(test)+1):-len(test)] train_rmse.append(evaluate(model, raw_train, train, scaler, 0, batch_size)) model.reset_states() # evaluate model on test data raw_test = raw[-(len(test)+1):] test_rmse.append(evaluate(model, raw_test, test, scaler, 0, batch_size)) model.reset_states() history = DataFrame() history['train'], history['test'] = train_rmse, test_rmse return history # run diagnostic experiments def run(): # load dataset series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0] 技术沙龙 教程文章 热点综合