简体   繁体   English

神经网络:估计正弦波频率

[英]Neural network: estimating sine wave frequency

With an objective of learning Keras LSTM and RNNs, I thought to create a simple problem to work on: given a sine wave, can we predict its frequency? 为了学习Keras LSTM和RNN,我想创造一个简单的问题:给定一个正弦波,我们能预测它的频率吗?

I wouldn't expect a simple neural network to be able to predict the frequency, given that the notion of time is important here. 考虑到时间概念在这里很重要,我不希望简单的神经网络能够预测频率。 However, even with LSTMs, I am unable to learn the frequency; 然而,即使使用LSTM,我也无法了解频率; I'm able to learn a trivial zero as the estimated frequency (even for train samples). 我能够学习一个微不足道的零作为估计的频率(即使是火车样本)。

Here's the code to create the train set. 这是创建火车组的代码。

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))

Now, here's a simple neural network for this example. 现在,这个例子是一个简单的神经网络。

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)

As expected, this NN doesn't learn anything useful. 正如所料,这个NN没有学到任何有用的东西。 Next, I tried a simple LSTM example. 接下来,我尝试了一个简单的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)

However, this LSTM based model also doesn't learn anything useful. 但是,这个基于LSTM的模型也没有学到任何有用的东西。

Why doesn't it learn? 为什么不学习?

You think it's a simple problem to train an RNN on, but actually your setup isn't easy for the network at all: 您认为训练RNN是一个简单的问题,但实际上您的设置对于网络来说并不容易:

  • As already mentioned, there's lack of important samples . 如前所述, 缺乏重要的样本 You throw so much data into it (300 * 2000 points), but the actual target (frequency) is seen only once by the network. 你扔了太多的数据(300 * 2000点),但实际的目标(频率)只能由网络看到一次。 Even if the network does learn something, there's high chance it will overfit. 即使网络确实学到了东西,它也很有可能会过度适应。

  • Inconsistent data . 数据不一致 Remember that RNNs are good at capturing similar patterns in the series data. 请记住,RNN擅长捕获系列数据中的类似模式 For instance, in NLP all sentences in the corpus are governed by the same language rules and more sentences help RNN to understand these rules better, ie, more data helps. 例如,在NLP中,语料库中的所有句子都由相同的语言规则控制,并且更多句子有助于RNN更好地理解这些规则,即更多数据有帮助。

    In your case, the series with different frequencies aren't very much alike: compare the sine with frequency=1 and frequency=100 . 在您的情况下,具有不同频率的系列不是非常相似:将正弦与frequency=1frequency=100 This kind of diversity in the data makes it harder to learn, not easier. 数据的这种多样性使得学习变得更加困难,而不是更容易。 It doesn't mean that the frequency is impossible for an RNN to learn, it simply means that you shouldn't be surprised that a trivial RNN like yours has hard time. 这并不意味着RNN无法学习频率,这只意味着你不应该对像你这样的普通RNN有困难感到惊讶。

  • Data scale . 数据规模 Changing the frequency from 1 to 300, changes the scale of both x and y by two orders of magnitude, which may be problematic for any neural network. 将频率从1改为300,将xy的比例改变两个数量级,这对于任何神经网络都可能是有问题的。

Solution

Since your goal is rather educational, I solved the second and third items simply by limiting the target frequency to 10, so that scaling and distribution diversity isn't much of an issue (you are welcome to try different values here: you should see that increasing this one parameter to, say, 50 makes the task much more complex). 由于你的目标是相当有教育意义,我只是通过将目标频率限制为10来解决第二和第三项,因此缩放和分布多样性不是一个问题(欢迎你在这里尝试不同的值:你应该看到将这一个参数增加到50比较会使任务变得更加复杂。

The first item is solved by giving the RNN 10 examples of each frequency, instead of just one. 第一项是通过给出每个频率的RNN 10个例子来解决的,而不仅仅是一个。 I've also added one more hidden layer to increase network flexibility, plus a simple regularizer ( Dropout layer). 我还添加了一个隐藏层以增加网络灵活性,以及​​一个简单的正则化器( Dropout层)。

The complete code: 完整的代码:

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)))

The output: 输出:

max_freq=10 max_freq = 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

max_freq=20 (everything else is the same) 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

max_freq=30 (everything else is the same) 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

Note that results are random and actually increasing the max_freq increases the changes of divergence . 请注意,结果是随机的,实际上增加max_freq增加发散的变化。 But even when it converges, the performance doesn't improve despite having more data, instead gets worse and pretty fast. 但即使它收敛,尽管拥有更多数据,但性能并没有提高,反而变得更糟,速度更快。

sample data item very low, one for each freq, 样本数据项非常低,每个频率一个,

add small noise and use more data, 添加小噪音并使用更多数据,

normalize output data -1 to 1 range then try again 将输出数据标准化为-1到1范围,然后再试一次

As you said, you want to predict the frequency. 如你所说,你想预测频率。 You also want to use LSTM. 您还想使用LSTM。 First we generate enough data to train, then we build the network. 首先,我们生成足够的数据进行训练,然后我们构建网络。 I'm sorry my example is not with keras , I'm using tflearn . 对不起,我的例子不是keras ,我正在使用tflearn

import numpy as np
import tflearn
from random import shuffle

# parameters
n_input=100
n_train=2000
n_test = 500
# generate data
xs=[]
ys=[]
frequencies = np.linspace(1,50,n_train+n_test)
shuffle(frequencies)

t=np.linspace(0,2*np.pi,n_input)
for freq in frequencies:
    xs.append(np.sin(t*freq))
    ys.append(freq)

xs_train=np.array(xs[:n_train]).reshape(n_train,n_input,1)
xs_test=np.array(xs[n_train:]).reshape(n_test,n_input,1)
ys_train = np.array(ys[:n_train]).reshape(-1,1)
ys_test = np.array(ys[n_train:]).reshape(-1,1)

# LSTM network prediction
net = tflearn.input_data(shape=[None, n_input, 1])
net = tflearn.lstm(net, 10)
net = tflearn.fully_connected(net, 100, activation="relu")
net = tflearn.fully_connected(net, 1)
net = tflearn.regression(net, optimizer='adam', loss='mean_square')
model = tflearn.DNN(net)
model.fit(xs_train, ys_train, n_epoch=100)

print(np.hstack((model.predict(xs_test),ys_test))[:10])
# [[ 13.08494568  12.76470588]
#  [ 22.23135376  21.98039216]
#  [ 39.0812912   37.58823529]
#  [ 15.77548409  15.66666667]
#  [ 26.57996941  25.58823529]
#  [ 26.57759476  25.11764706]
#  [ 16.42217445  15.8627451 ]
#  [ 32.55020905  30.80392157]
#  [ 44.16622925  43.01960784]
#  [ 26.18071365  25.45098039]]

If you have the data in that order, you don't actually need LSTM, you can easily replace the LSTM part with a Deep Neural Network: 如果您拥有该顺序的数据,则实际上并不需要LSTM,您可以使用深度神经网络轻松替换LSTM部件:

# Deep network instead of LSTM
net = tflearn.input_data(shape=[None, n_input])
net = tflearn.fully_connected(net, 100)
net = tflearn.fully_connected(net, 100)
net = tflearn.fully_connected(net, 1)
net = tflearn.regression(net, optimizer='adam',loss='mean_square')

model = tflearn.DNN(net)
model.fit(xs_train, ys_train)
print(np.hstack((model.predict(xs_test),ys_test))[:10])

Both codes are going to give you as result the predicted value of the frequency. 这两个代码都将为您提供频率的预测值。 I also created a gist with the program. 我还为该程序创建了一个要点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM