2018年7月7日土曜日

Kerasでsin波を予測してみる

sin波の予測はサンプルとしてかなり使いやすいのでサンプルコードを置いておきます。 LSTMなどで作っているサンプルが多かったのですが、シンプルな全結合で書いてみました。 様々な検証がしやすいように書いたつもり。

基本的なコードはこことかここを参考にしている。 次稿で回帰の特性を確認する例として取り上げたかったので、Pandasの最新の仕様に合わせたり、説明がしやすくなるように微調整しています。
import keras
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.layers.normalization import BatchNormalization
from keras.callbacks import EarlyStopping
import math, random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def generate_data(period):
    random_factor = 0.5
    length = 500
    data = pd.DataFrame(np.arange(period * length + 1), columns=["t"])
    data["sine_wave"] = data.t.apply(lambda x: math.sin(
        x * (2 * math.pi / period)+ random.uniform(-1.0, +1.0) * random_factor))
    return data

def generate_dataset(dataframe, plen, inputs):
    x, y = [], []
    for i in range(len(dataframe)-inputs*2):
        x.append(dataframe[["sine_wave"]].iloc[i:i+inputs].values.flatten())
        y.append(dataframe[["sine_wave"]].iloc[i+inputs+plen].values.flatten())
    return np.array(x), np.array(y)

def load_data(data, test_size, inputs):
    n = int(round(len(data) * (1 - test_size)))
    x_train, y_train = generate_dataset(data.iloc[0:n], inputs, inputs)
    x_test, y_test = generate_dataset(data.iloc[n:], inputs, inputs)
    return (x_train, y_train), (x_test, y_test)

period = 100
data = generate_data(period)
# data[["sine_wave"]].head(period * 2).plot()
# plt.show()

inputs = 400
hiddens = 200
(x_train, y_train), (x_test, y_test) = load_data(data, 0.1, inputs)

model = Sequential()
model.add(Dense(hiddens, input_shape=(len(x_train[0]),)))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))
for i in range(1, 4):
    model.add(Dense(hiddens))
    model.add(Activation('relu'))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))
model.add(Dense(1))
model.compile(loss="mean_squared_error", optimizer="adam")

early_stopping = EarlyStopping(patience=0, verbose=1)
model.fit(x_train, y_train, batch_size=50, epochs=10, validation_data=(x_test, y_test), callbacks=[early_stopping])
score = model.evaluate(x_test, y_test)
print('Test score:', score)

predicts = model.predict(x_test)
positive = np.sum((predicts > 0) == (y_test > 0))
print('Test Accuracy:', positive / predicts.size)
上記のコードは過去のinputs = 400の動きを元にplen = 400後の数値を予測します。 これを実行すると多少のノイズがあるsin波でも正負の判定なら92%くらい、誤差なら0.04くらいの精度で予測できる事が確認できると思います。

0 件のコメント: