【Python】 LSTMによる時系列データの予測
前回SimpleRNNによる時系列データの予測を行いましたが、今回はLSTMを用いて時系列データの予測を行ってみます。
LSTMはSimpleRNNと比較すると長期依存性の高いデータに有効とのことなので、50回に一回パルスが発生する信号に対する予測をSimpleRNNとLSTMで行ってみました。
import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.layers.recurrent import SimpleRNN, LSTM from keras.optimizers import Adam from keras.callbacks import EarlyStopping np.random.seed(0) def generate_periodic_data(): pulse = [] for i in range(1000): if i%25 == 0: pulse.append(1.0) else: pulse.append(0.0) return np.array(pulse) def generate_data(pulse, length_per_unit, dimension): sequences = [] target = [] for i in range(0, pulse.size - length_per_unit): sequences.append(pulse[i:i + length_per_unit]) target.append(pulse[i + length_per_unit]) X = np.array(sequences).reshape(len(sequences), length_per_unit, dimension) Y = np.array(target).reshape(len(sequences), dimension) N_train = int(len(sequences)*0.8) X_train = X[:N_train] X_validation = X[N_train:] Y_train = Y[:N_train] Y_validation = Y[N_train:] return (X_train, X_validation, Y_train, Y_validation) def build_model(input_shape, hidden_layer_count): model = Sequential() model.add(LSTM(hidden_layer_count, input_shape=input_shape)) model.add(Dense(input_shape[1])) model.add(Activation('linear')) model.compile(loss='mse', optimizer=Adam()) return model # 一つの時系列データの長さ LENGTH_PER_UNIT = 201 # 一次元データを扱う DIMENSION = 1 # パルスの生成 pulse = generate_periodic_data() # トレーニング、バリデーション用データの生成 X_train, X_validation, Y_train, Y_validation = generate_data(pulse, LENGTH_PER_UNIT, DIMENSION) # LSTM隠れ層の数 HIDDEN_LAYER_COUNT = 25 # 入力の形状 input_shape=(LENGTH_PER_UNIT, DIMENSION) # モデルの生成 model = build_model(input_shape, HIDDEN_LAYER_COUNT) # モデルのトレーニング epochs = 500 batch_size = 10 early_stopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1) model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_validation, Y_validation), callbacks=[early_stopping]) # 予測を行う part_of_sequence = np.array([pulse[i] for i in range(LENGTH_PER_UNIT)]) predicted = [None for i in range(LENGTH_PER_UNIT)] Z = X_train[:1, :, :] for i in range(pulse.size - LENGTH_PER_UNIT + 1): y_ = model.predict(Z) # 予測結果を入力として利用するため、第0項を削除し予測結果をひっつける Z = np.concatenate( (Z.reshape(LENGTH_PER_UNIT, DIMENSION)[1:], y_), axis=0).reshape(1, LENGTH_PER_UNIT, DIMENSION) predicted.append(y_.reshape(-1)) predicted = np.array(predicted) # 予測結果の描画 plt.rc('font', family='serif') plt.figure() plt.ylim([0.0, 1.1]) plt.plot(pulse, linestyle='dotted', color='#aaaaaa') plt.plot(part_of_sequence, linestyle='dashed', color='black') plt.plot(predicted, color='black') plt.show()
SimpleRNNの予測結果がこちらで
LSTMの予測結果がこうなりました。
LSTMはもう少し綺麗に予測できることを期待していたのですが、パラメータチューニングを行っていないので上図のような結果になったのかなと思います。とはいえ閾値決めてあげることで後処理でどうにでもなりそうなのでSimpleRNNよりは良い結果なのではと思います。
詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~
- 作者: 巣籠悠輔
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/05/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る