【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件) を見る
【Python】 SimpleRNNで月平均気温を予測する
画像だけでなく時系列データにも手を出してみたい、ということで書籍「詳解ディープラーニング」を購入しました。書籍第5章から時系列データを扱っているのですが、そこで紹介されているSimpleRNNの例を写経します。書籍ではノイズの入ったサイン波の予測を行っているのですが、ここでは気象庁から取得した年別の月平均気温を使って予測を行います。
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 from keras.optimizers import Adam from keras.callbacks import EarlyStopping np.random.seed(0) def generate_temperatures(): # 月平均気温 temperatures = [[7.6, 6.0, 9.4, 14.5, 19.8, 22.5, 27.7, 28.3, 25.6, 18.8, 13.3, 8.8], #2000年 [4.9, 6.6, 9.8, 15.7, 19.5, 23.1, 28.5, 26.4, 23.2, 18.7, 13.1, 8.4], #2001年 [7.4, 7.9, 12.2, 16.1, 18.4, 21.6, 28.0, 28.0, 23.1, 19.0, 11.6, 7.2],#2002年 [5.5, 6.4, 8.7, 15.1, 18.8, 23.2, 22.8, 26.0, 24.2, 17.8, 14.4, 9.2], #2003年 [6.3, 8.5, 9.8, 16.4, 19.6, 23.7, 28.5, 27.2, 25.1, 17.5, 15.6, 9.9], #2004年 [6.1, 6.2, 9.0, 15.1, 17.7, 23.2, 25.6, 28.1, 24.7, 19.2, 13.3, 6.4], [5.1, 6.7, 9.8, 13.6, 19.0, 22.5, 25.6, 27.5, 23.5, 19.5, 14.4, 9.5], [7.6, 8.6, 10.8, 13.7, 19.8, 23.2, 24.4, 29.0, 25.2, 19.0, 13.3, 9.0], [5.9, 5.5, 10.7, 14.7, 18.5, 21.3, 27.0, 26.8, 24.4, 19.4, 13.1, 9.8], [6.8, 7.8, 10.0, 15.7, 20.1, 22.5, 26.3, 26.6, 23.0, 19.0, 13.5, 9.0], [7.0, 6.5, 9.1, 12.4, 19.0, 23.6, 28.0, 29.6, 25.1, 18.9, 13.5, 9.9], [5.1, 7.0, 8.1, 14.5, 18.5, 22.8, 27.3, 27.5, 25.1, 19.5, 14.9, 7.5], [4.8, 5.4, 8.8, 14.5, 19.6, 21.4, 26.4, 29.1, 26.2, 19.4, 12.7, 7.3], [5.5, 6.2, 12.1, 15.2, 19.8, 22.9, 27.3, 29.2, 25.2, 19.8, 13.5, 8.3], [6.3, 5.9, 10.4, 15.0, 20.3, 23.4, 26.8, 27.7, 23.2, 19.1, 14.2, 6.7], [5.8, 5.7, 10.3, 14.5, 21.1, 22.1, 26.2, 26.7, 22.6, 18.4, 13.9, 9.3], [6.1, 7.2, 10.1, 15.4, 20.2, 22.4, 25.4, 27.1, 24.4, 18.7, 11.4, 8.9]]#2016年 temperatures = np.array(temperatures) temperatures = np.reshape(temperatures, (temperatures.size)) return temperatures def generate_data(temperatures, length_per_unit, dimension): sequences = [] target = [] for i in range(0, temperatures.size - length_per_unit): sequences.append(temperatures[i:i + length_per_unit]) target.append(temperatures[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.9) 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(SimpleRNN(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 = 24 # 一次元データを扱う DIMENSION = 1 # 年別月平均気温の生成 temperatures = generate_temperatures() # トレーニング、バリデーション用データの生成 X_train, X_validation, Y_train, Y_validation = generate_data(temperatures, LENGTH_PER_UNIT, DIMENSION) # SimpleRNN隠れ層の数 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([temperatures[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(temperatures.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, 35.0]) plt.plot(temperatures, linestyle='dotted', color='#aaaaaa') plt.plot(part_of_sequence, linestyle='dashed', color='black') plt.plot(predicted, color='black') plt.show()
割と無難な結果を得ることが出来ました。
詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~
- 作者: 巣籠悠輔
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/05/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
【料理】 たらこパスタの実装
下記を参考に作りました。 cookpad.com
用意するもの(二名分)
- たらこ 2腹
- バター 30g
- 牛乳 大さじ4
- 醤油 大さじ1
- きざみのり 適量
- パスタ 180g
1 お湯を沸かす
2 ボールにたらこ、バター、牛乳、醤油を入れてソースを作る
3 パスタを茹でる
4 お湯を捨ててそこにソースを入れて良く混ぜる
5 容器に移してきざみのりをかける
【ディープラーニング】 不均衡データへの対処法
ディープラーニングというより、機械学習全般で起こりうる問題として不均衡データ問題があります。例えばラベル0のデータが99個あり、ラベル1のデータが1個しかない、といったように教師データのバランスが悪い場合、モデルは「とりあえず0と回答すれば99%の正解率が得られる」というようなずる賢い学習をしてしまいます。 この対処法の一つとしてこちらの論文(https://users.cs.fiu.edu/~chens/PDF/ISM15.pdf)ではデータの与え方を工夫しているのですが、自分のケースではかなり有効だったため、論文のpp.3に書いてある疑似コードをメモします。
!!!注意!!! 元の論文では"for N"の外側でCNNのトレーニングを行っていますが、kerasはデフォルトではトレーニングデータをシャッフルするので、内側でトレーニングした方が正例と負例の比率が意図した通りに保たれるので良いと考え意図的に変更しています
1. トレーニングデータを負例(大量)と正例(少量)に分割する 2. 負例をN個のバッチに分割する 3. for エポック 4. for N 5. ランダムにNp個の正例をピックアップする 6. 負例、正例を混ぜる 7. CNNのトレーニング
【WPF】 Contentに改行付きのテキストを書く
Contentに改行を付けたくて、その方法がここ(【WPF】コントロールのContentプロパティにテキストを改行して表示する - Microsoft.NET WPF - Project Group )で分かったのでメモします。
<!-- が改行を表しています--> <Button Content="Hello World \(^o^)/" IsHitTestVisible="False"/>
【OpenCV】 画像を合成する(アルファブレンディング)
// 画像を読み込む Mat lenna; imread("lenna.jpg").copyTo(lenna); if (lenna.empty()) { throw runtime_error("Failed to open image"); } // 画像を読み込む Mat clock; imread("clock.jpg").copyTo(clock); if (clock.empty()) { throw runtime_error("Failed to open image"); } // 画像を1:1の割合で合成する Mat destination; addWeighted(lenna, 0.5, clock, 0.5, 0.0, destination);
【Python】 ndarrayのインデキシング
書籍「科学技術計算のためのPYTHON入門」のメモです。ndarrayのインデキシングについて今まで何も意識せず使っていたのですが、書籍にまとめられていたのでメモします。
- 基本インデキシング(ビューが生成される)
# ndarray_viewの変更がndarrayにも影響を及ぼす ndarray_view = ndarray[1, :]
- 応用インデキシング(コピーが生成される)
- ブール値インデキシング
- 整数配列インデキシング
# ブール値インデキシングの例 # 0.5より大きい箇所のみ取り出す # maskedを変更してもndarrayに影響を及ぼさない mask = ndarray > 0.5 masked = ndarray[mask] # 整数配列インデキシングの例 # (0,2), (2,0), (1,3)の位置の要素を取り出す # extractedを変更してもndarrayに影響を及ぼさない extracted = ndarray[[0, 2, 1], [2, 0, 3]]
科学技術計算のためのPython入門 ――開発基礎、必須ライブラリ、高速化
- 作者: 中久喜健司
- 出版社/メーカー: 技術評論社
- 発売日: 2016/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る