Helve’s Python memo

Pythonを使った機械学習やデータ分析の備忘録

<Keras> ニューラルネットワークによる正弦波の回帰【入門】

以前、Chainerの入門記事を書いたが、実装が容易なKerasを試してみた。
ニューラルネットワーク (NN) による回帰の実装例として、正弦波を学習させる。

目次

環境

Anaconda3 5.2.0
Python 3.6.5
TensorFlow 1.12.0
Keras 2.2.4
NumPy 1.14.3
matplotlib 2.2.2

はじめに

KerasのバックエンドにはTensorFlowを使う。
Anaconda Promptにて以下の通りインストールする。

conda install tensorflow
conda install keras

次に、Pythonで以下の通りライブラリをインポートする。

import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense

学習データ

x=-5~5の範囲で正弦波を生成する。
データ数は10,000点である。
なお、学習を高速化するためには扱う変数を全て標準化する必要があるが、簡単のため今回はそのままの値を用いる。

x = np.arange(-5, 5, 0.001).astype(np.float32)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()


出力
f:id:Helve:20181118115109p:plain


Kerasによる学習

NNモデル

説明変数と目的変数の次元はともに1なので、入力層と出力層のノード数は1となる。
隠れ層の数は4、ノード数は全て20とした。
また、活性化関数はtanhとする。

actfunc = "tanh"

model = Sequential()
model.add(Dense(20, activation=actfunc, input_dim=1))
model.add(Dense(20, activation=actfunc))
model.add(Dense(20, activation=actfunc))
model.add(Dense(20, activation=actfunc))
model.add(Dense(1))

以上の様に、Sequentialインスタンスを作成し、addメソッドで層を追加していく。
なお、Denseは全結合層である。

学習の実行

modelcomplieメソッドで最適化手法と損失関数を指定する。
最適化手法にはSGD (Stochastic Gradient Descent, 確率的勾配降下法) を用い、
損失関数は予測値と真値の二乗平均誤差 (mean squared error) とする。

次に、fitメソッドで学習を実行する。
学習データx, yを与え、バッチサイズ、エポック数を指定する。
verbose引数は、下表の通り学習の進行状況の表示に関するオプション。

verbose ログの表示
0 出力しない
1 プログレスバーで出力
2 損失関数のみの簡易表示

また、historyには学習時のログが格納される。

model.compile(optimizer='sgd',
              loss='mean_squared_error')

history = model.fit(x, y,
                    batch_size=100,
                    epochs=50,
                    verbose=1)

出力

実行すると、以下の通り学習の進行状況が表示される。
PCの性能によるが、数秒程度で学習は終了する。

Epoch 1/50
10000/10000 [==============================] - 1s 109us/step - loss: 0.2431
Epoch 2/50
10000/10000 [==============================] - 0s 9us/step - loss: 0.0159
Epoch 3/50
10000/10000 [==============================] - 0s 8us/step - loss: 0.0104
Epoch 4/50
10000/10000 [==============================] - 0s 8us/step - loss: 0.0091
Epoch 5/50
10000/10000 [==============================] - 0s 8us/step - loss: 0.0087
(略)
Epoch 50/50
10000/10000 [==============================] - 0s 8us/step - loss: 0.0032

学習モデルの評価

evaluateメソッドで検証用データに対する損失関数の値を出力する。
本来は学習データと検証データを分ける必要があるが、簡単のため同じデータとしている。

score = model.evaluate(x, y)
print(score)

出力
学習データと検証データが同じため、学習の最終エポックの損失関数に近い値が表示されるはずである。

10000/10000 [==============================] - 0s 13us/step
0.0034303181435687293

また、predictメソッドで説明変数に対する予測値を出力する。

pred = model.predict(x)

fig, ax = plt.subplots()
ax.plot(x, y)
ax.plot(x, pred)
plt.show()

出力
青が学習データ、黄色がNNの出力である。
xが-5や5に近い領域でやや異なる値となっているが、概ね正弦波の形状を学習できている。

f:id:Helve:20181118115134p:plain



また、学習中の損失関数の推移は、以下のように取得できる。

loss = history.history["loss"]

fig, ax = plt.subplots()
ax.plot(loss)
plt.show()

出力
横軸がエポック数、縦軸が(学習データに対する)損失関数である。
最初の1~2エポックで急激に損失関数が減少し、その後は緩やかに単調減少していることが分かる。
f:id:Helve:20181118115149p:plain