Nip*_*tra 7 python neural-network lstm keras tensorflow
为了学习Keras LSTM和RNN,我想创造一个简单的问题:给定一个正弦波,我们能预测它的频率吗?
考虑到时间概念在这里很重要,我不希望简单的神经网络能够预测频率.然而,即使使用LSTM,我也无法了解频率; 我能够学习一个微不足道的零作为估计的频率(即使是火车样本).
这是创建火车组的代码.
import numpy as np
import matplotlib.pyplot as plt
def create_sine(frequency):
return np.sin(frequency*np.linspace(0, 2*np.pi, 2000))
train_x = np.array([create_sine(x) for x in range(1, 300)])
train_y = list(range(1, 300))
Run Code Online (Sandbox Code Playgroud)
现在,这个例子是一个简单的神经网络.
from keras.models import Model
from keras.layers import Dense, Input, LSTM
input_series = Input(shape=(2000,),name='Input')
dense_1 = Dense(100)(input_series)
pred = Dense(1, activation='relu')(dense_1)
model = Model(input_series, pred)
model.compile('adam','mean_absolute_error')
model.fit(train_x[:100], train_y[:100], epochs=100)
Run Code Online (Sandbox Code Playgroud)
正如所料,这个NN没有学到任何有用的东西.接下来,我尝试了一个简单的LSTM示例.
input_series = Input(shape=(2000,1),name='Input')
lstm = LSTM(100)(input_series)
pred = Dense(1, activation='relu')(lstm)
model = Model(input_series, pred)
model.compile('adam','mean_absolute_error')
model.fit(train_x[:100].reshape(100, 2000, 1), train_y[:100], epochs=100)
Run Code Online (Sandbox Code Playgroud)
但是,这个基于LSTM的模型也没有学到任何有用的东西.
你认为训练 RNN 是一个简单的问题,但实际上你的设置对网络来说根本不容易:
如前所述,缺少重要的样本。你往里面扔了这么多数据(300 * 2000点),但网络只看到一次实际目标(频率)。即使网络确实学到了一些东西,它也很有可能会过拟合。
不一致的数据。请记住,RNN 擅长捕捉系列数据中的相似模式。例如,在 NLP 中,语料库中的所有句子都受相同的语言规则支配,更多的句子有助于 RNN 更好地理解这些规则,即更多的数据有帮助。
在您的情况下,具有不同频率的系列不太相似:将正弦与frequency=1和进行比较frequency=100。数据的这种多样性使学习变得更加困难,而不是更容易。这并不意味着 RNN 不可能学习频率,这只是意味着您不应该对像您这样的普通 RNN 遇到困难而感到惊讶。
数据规模。将频率从 1 更改为 300,会同时改变两个数量级x和y两个数量级,这对于任何神经网络来说都是有问题的。
由于您的目标颇具教育意义,因此我仅通过将目标频率限制为 10 来解决第二和第三项,因此缩放和分布多样性不是什么大问题(欢迎您在这里尝试不同的值:您应该看到将此参数增加到 50 会使任务变得更加复杂)。
第一项是通过为 RNN 提供每个频率的 10 个示例来解决的,而不仅仅是一个。我还添加了一个隐藏层以增加网络灵活性,以及一个简单的正则化器(Dropout层)。
完整代码:
import numpy as np
from keras.models import Model
from keras.layers import Input, Dense, Dropout, LSTM
max_freq = 10
time_steps = 100
def create_sine(frequency, offset):
return np.sin(frequency * np.linspace(offset, 2 * np.pi + offset, time_steps))
train_y = list(range(1, max_freq)) * 10
train_x = np.array([create_sine(freq, np.random.uniform(0,1)) for freq in train_y])
train_y = np.array(train_y)
input_series = Input(shape=(time_steps, 1), name='Input')
lstm = LSTM(units=100)(input_series)
hidden = Dense(units=100, activation='relu')(lstm)
dropout = Dropout(rate=0.1)(hidden)
output = Dense(units=1, activation='relu')(dropout)
model = Model(input_series, output)
model.compile('adam', 'mean_squared_error')
model.fit(train_x.reshape(-1, time_steps, 1), train_y, epochs=200)
# Trying the network on the same data
test_x = train_x.reshape(-1, time_steps, 1)
test_y = train_y
predicted = model.predict(test_x).reshape([-1])
print()
print((predicted - train_y)[:12])
print(np.mean(np.abs(predicted - train_y)))
Run Code Online (Sandbox Code Playgroud)
输出:
最大频率=10
[-0.05612183 -0.01982236 -0.03744316 -0.02568841 -0.11959982 -0.0770483
0.04643679 0.12057972 -0.00625324 -0.00724655 -0.16919005 -0.04512954]
0.0503574344847
Run Code Online (Sandbox Code Playgroud)
max_freq=20(其他都一样)
[ 0.51365542 0.09269333 -0.009691 0.0619092 0.09852839 0.04378462
0.01430321 -0.01953268 0.00722599 0.02558327 -0.04520988 -0.0614748 ]
0.146024380232
Run Code Online (Sandbox Code Playgroud)
max_freq=30(其他都一样)
[-0.28205156 -0.28922796 -0.00569081 -0.21314907 0.1068716 0.23497915
0.23975039 0.25955486 0.26333141 0.24235058 0.08320332 -0.03686047]
0.406703719805
Run Code Online (Sandbox Code Playgroud)
请注意,结果是随机的,实际上增加了散度max_freq的变化。但是即使它收敛了,尽管有更多的数据,性能也没有提高,反而变得更糟,而且速度非常快。