ニューラルネットワークを使って、正弦波のデータy=sin(fx)にノイズをのせた、y=sin(fx)+n (nがノイズ)からサンプルしたデータにフィッティングをして、y=sin(fx)を学習できるか試してみました。fは周波数の大小を表します。
モデルは、直線フィッティングのときと同じです。
学習データを[-10,10)の範囲で一様乱数で10000サンプルとって、100エポック学習しました。 学習できたモデルの出力はfの値ごとに下図のようになりました。横軸がx、縦軸がyです。 薄い水色の線は、ノイズを加える前の学習データの生成に使った正弦波です。紺色の線が、学習したニューラルネットワークが生成した曲線です。
f=0.5やf=1はともかく、それ以降はフィットできていません。特にf=4以降は完全に崩れています。f=16では、そもそも周波数が高すぎて、図では元の正弦波がつぶれてしまっています。きちんとフィットさせるためにはニューラルネットワークをもう少し工夫する必要があることが分かりました。
f=4のときの学習データに使ったデータの生成と同じ条件で、ただし乱数違いで生成したデータをプロットしたものが下図です。横軸の範囲が異なることに注意してください。
まだ正弦波を見て取れるのですが、今回使ったニューラルネットワークでは難しいようです。同様に、f=16のときの学習データに使ったデータの生成と同じ条件で、ただし乱数違いで生成したデータをプロットしたものが下図です。一応、正弦波の名残は残っていますが、元が正弦波とは言いがたいです。
今回の実験のモデルの学習時に使ったコードは以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # This script trains a neural network model using MNIST.
import keras, os, math
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation
TRAIN_EPOCH = 100
def approx_model():
model = Sequential()
model.add(Dense(32, input_shape=(1,)))
model.add(Activation('tanh'))
model.add(Dense(32))
model.add(Activation('tanh'))
model.add(Dense(1))
print(model.summary())
return model
def sine_dist(freq):
xd = np.random.rand(10000,)*20-10
yd = [math.sin(x*freq)+np.random.normal(0, 1) for x in xd]
return xd, yd
if __name__ == '__main__':
if not os.path.exists("models"):
os.mkdir("models")
# Make a model
model = approx_model()
opt = keras.optimizers.Adamax(lr=0.002, beta_1=0.9, beta_2=0.999,
epsilon=1e-08, decay=1e-4)
model.compile(optimizer=opt, loss='mean_squared_error')
model.save_weights("initial-weights.hdf5")
for freq in [0.5, 1, 2, 4, 8, 16]:
# Make data for training and validation
x_train, y_train = sine_dist(freq)
x_val, y_val = sine_dist(freq)
# Train and save a model
model.load_weights("initial-weights.hdf5")
model.fit(x_train, y_train, validation_data=(x_val, y_val),
epochs=TRAIN_EPOCH, batch_size=32)
model.save("models/sine-{0}.hdf5".format(freq))
|
グラフの描画に使ったコードは以下です(f=1の場合)。
1 2 3 4 5 6 7 8 9 10 11 12 | %matplotlib inline
import keras, math
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-30, 30, 0.001)
model = keras.models.load_model('models/sine-1.hdf5')
y = model.predict(x)
yc = np.array([math.sin(xi*1) for xi in x])
plt.grid()
plt.plot(x, yc, color='lightblue')
plt.plot(x, y, color='midnightblue')
plt.show()
|
0 件のコメント :
コメントを投稿