14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Keras入門(5)】単純なRNNモデル定義

Last updated at Posted at 2019-07-28

入門者に向けてKerasを使ったRNN(Recurrentニューラルネットワーク)の初歩を解説します。RNNは時系列データの予測やNLP(自然言語処理)などに強く、使いどころが多い便利な手法です。
Google Colaboratoryを使っているのでローカルでの環境準備すらしていません。Google Colaboratoryについては「Google Colaboratory概要と使用手順(TensorFlowもGPUも使える)」の記事を参照ください。

以下のシリーズにしています。

- 【Keras入門(1)】単純なディープラーニングモデル定義

##使ったPythonパッケージ
Google Colaboratoryでインストール済の以下のパッケージとバージョンを使っています。KerasはTensorFlowに統合されているものを使っているので、ピュアなKerasは使っていません。Pythonは3.6です。

  • tensorflow: 1.14.0
  • Numpy: 1.16.4
  • matplotlib: 3.0.3

処理概要

時系列データ予測として、正弦関数(sine)の値を予測します。
正弦関数は、こんなウネウネした値が変わっていくやつです。
image.png

以下の2種類の配列を作って、Kerasを使ったディープラーニングで予測モデルを作ります。

種類 Shape データ
説明変数(配列x_train) 10 X 40 xが-4.9から4.9までの0.2間隔の正弦関数の値
目的変数(配列y_train) 10 X 40 説明変数の1ずれた値

言葉だとわかりにくいですが、表とグラフにするとこんな感じ。目的変数の次の値を予測しています(つまり時系列データ予測)。そして、2つ目のデータセットでは、1つ目のデータセットから1つずつずらしています。!
50.Keras_RNN_list01.JPG

そして、訓練時のRNNへのデータの渡し方は下記のような形です。
51.Keras_RNN_Overview01.JPG

でもって、予測時は下記のように予測結果を次の予測データ元へ渡します。モデルが予測した値を再度使うあたりが再帰(Recurrent)たる所以ですね。
image.png

処理プログラム

プログラム全体はGitHubを参照ください。

1. ライブラリインポート

今回はmatplotlibとnumpyとtensorflowに統合されているkerasを使います。ピュアなkerasでも問題なく、インポート元を変えるだけです。

import numpy as np
import matplotlib.pyplot as plt

# TensorFlowに統合されたKerasを使用
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, SimpleRNN

##2. 前処理
###2.1. 正弦関数配列作成
-4.9から4.9までの50要素の等差数列(0.2間隔)の配列(x_sin)を作成し、対応する正弦関数の値の配列(y_sin)も
作成します。

# -4.9から4.9までの50要素の等差数列(0.2間隔)
x_sin = np.linspace(-4.9, 4.9)
y_sin = np.sin(x_sin)
plt.plot(x_sin, y_sin)
plt.show()

matplotlibでグラフ出力するとこんなです。
image.png

###2.2. 説明変数(x_train)と目的変数(y_train)作成
RNNに流すための形に整形します。

NUM_RNN = 10  # 1時系列のデータ数
NUM_DATA = len(x_sin) - NUM_RNN # 今回は40(=50-10)
x = []
y = []

for i in range(NUM_DATA):
    x.append(y_sin[i:i+NUM_RNN])      # 説明変数
    y.append(y_sin[i+1:i+NUM_RNN+1])  # 正解データなので1ずらした値
    
else:
    x_train = np.array(x).reshape(NUM_DATA, NUM_RNN, 1) # 入力を(サンプル数、時系列の数、入力層のニューロン数)にする
    y_train = np.array(y).reshape(NUM_DATA, NUM_RNN, 1) # 説明変数(x_train)と同様のshape

3. モデル定義

記事「【Keras入門(1)】単純なディープラーニングモデル定義」のときと違い、simpleRNNを使っています。実際にはLSTMやGRUなどを使うことが多いかと思いますが、今回はsimpleRNNで十分な精度が出ます。また、LSTMやGRUを使う場合も呼び出し方はほとんど変わりません。

NUM_DIM = 8  # 中間層の次元数

model = Sequential()

# return_sequenceがTrueなので全RNN層が出力を返す(Falseだと最後のRNN層のみが出力を返す)
model.add(SimpleRNN(NUM_DIM, input_shape=(NUM_RNN, 1), return_sequences=True))
model.add(Dense(1, activation="linear"))  #全結合層
model.compile(loss="mean_squared_error", optimizer="sgd")
model.summary()

summary関数で以下のようなモデルサマリを出してくれます。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn (SimpleRNN)       (None, 10, 8)             80        
_________________________________________________________________
dense (Dense)                (None, 10, 1)             9         
=================================================================
Total params: 89
Trainable params: 89
Non-trainable params: 0
_________________________________________________________________

##4. 訓練実行
fit関数を使って訓練実行です。20epoch程度でそこそこいい精度が出ます。

history = model.fit(x_train, y_train, epochs=20, batch_size=8)

# Lossをグラフ表示
loss = history.history['loss']
plt.plot(np.arange(len(loss)), loss) # np.arangeはlossの連番数列を生成(今回はepoch数の0から19)
plt.show()

image.png

5. テスト

最後にテストです。

5.1. テストデータ作成

訓練データの最初の10件をテストデータとします。

# x[0]は最初の入力(時系列10個の数)。reshape(-1)で一次元のベクトルにする。
x_test = x_train[0].reshape(-1)  

##4.2. 訓練済モデルを使ったテストデータの答え合わせ
predict関数を使ってテストデータから予測値を出力し、さらに次の予測の元データとします。

# データ数(40回)ループ
for i in range(NUM_DATA):
    y_pred = model.predict(x_test[-NUM_RNN:].reshape(1, NUM_RNN, 1))  # 直近データ(最後から10要素)を使って予測
    x_test = np.append(x_test, y_pred[0][NUM_RNN-1][0])  # 出力結果をx_testに追加(n_rnn-1が10番目を意味している)

# 最初の10要素は完全に同じ
plt.plot(x_sin, y_sin, label="Training data")
plt.plot(x_sin, x_test, label="Predicted")
plt.legend()
plt.show()

予測値と訓練データを比較でグラフ表示してみます。-4.9から-2.9までの値は完全に同じです。それ以降は、微妙にずれてはいますが、それっぽい値が出ています。
image.png

簡単な変更でモデルを複雑に変更

simpleRNNではなく、実務上はLSTMを使うことが多いはずです。
その場合、モデルの層をこんな感じにするだけです。
GPU向けのCuDNNLSTMもあります(確かモデル間の互換性がなかったような気がします(未確認))。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM

model.add(LSTM(NUM_DIM, input_shape=(NUM_RNN, 1), return_sequences=True))

GRUだとこう。GPU向けのCuDNNGRUもあります(確かモデル間の互換性がなかったような気がします(未確認))。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, GRU

model.add(GRU(NUM_DIM, input_shape=(NUM_RNN, 1), return_sequences=True))

双方向にしたい場合はBidirectionalを使います。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, simpleRNN, Bidirectional

model.add(Bidirectional(SimpleRNN(NUM_DIM, return_sequences=True), input_shape=(NUM_RNN, 1)))

複数層に重ねることもできます。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, simpleRNN

model.add(SimpleRNN(NUM_DIM, input_shape=(NUM_RNN, 1), return_sequences=True))
model.add(SimpleRNN(NUM_DIM, input_shape=(NUM_RNN, 1), return_sequences=True))
14
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?