使用RNN从噪声信号中恢复正弦波

时间:2016-11-28 11:50:24

标签: signal-processing real-time keras recurrent-neural-network lstm

我参与了一个应用程序,它需要通过测量一组(非线性)相关参数来实时估计某个系统的状态。到目前为止,应用程序使用的是扩展卡尔曼滤波器,但在某些情况下发现它表现不佳,这可能是因为实际系统与滤波器中使用的模型之间的差异太大而无法建模像白噪声。出于许多不相关的原因,我们无法使用更精确的模型。

我们决定尝试循环神经网络来完成任务。由于我对神经网络的经验非常有限,在解决真正的任务本身之前,我决定先用手工制作的问题练习。那个问题,我无法解决,所以我在这里寻求帮助。

这就是我所做的:我生成了一些不同相位,频率,幅度和偏移的正弦波形。然后我用一些白噪声使波形失真,并且(未成功)尝试训练LSTM网络以从噪声信号中恢复我的波形。我预计网络最终会学会将正弦波形拟合到噪声数据集中。

这是来源(略有删节,但应该有效):

#!/usr/bin/env python3

import time
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras.layers.wrappers import TimeDistributed
from keras.objectives import mean_absolute_error, cosine_proximity

POINTS_PER_WF = int(1e4)
X_SPACE = np.linspace(0, 100, POINTS_PER_WF)

def make_waveform_with_noise():
    def add_noise(vec):
        stdev = float(np.random.uniform(0.01, 0.2))
        return vec + np.random.normal(0, stdev, size=len(vec))

    f = np.random.choice((np.sin, np.cos))
    wf = f(X_SPACE * np.random.normal(scale=5)) *\
         np.random.normal(scale=5) + np.random.normal(scale=50)
    return wf, add_noise(wf)

RESCALING = 1e-3
BATCH_SHAPE = (1, POINTS_PER_WF, 1)

model = Sequential([
    TimeDistributed(Dense(5, activation='tanh'), batch_input_shape=BATCH_SHAPE),
    LSTM(20, activation='tanh', inner_activation='sigmoid', return_sequences=True),
    LSTM(20, activation='tanh', inner_activation='sigmoid', return_sequences=True),
    TimeDistributed(Dense(1, activation='tanh'))
])

def compute_loss(y_true, y_pred):
    skip_first = POINTS_PER_WF // 2
    y_true = y_true[:, skip_first:, :] * RESCALING
    y_pred = y_pred[:, skip_first:, :] * RESCALING
    me = mean_absolute_error(y_true, y_pred)
    cp = cosine_proximity(y_true, y_pred)
    return me + cp

model.summary()
model.compile(optimizer='adam', loss=compute_loss,
              metrics=['mae', 'cosine_proximity'])

NUM_ITERATIONS = 30000

for iteration in range(NUM_ITERATIONS):
    wf, noisy_wf = make_waveform_with_noise()
    y = wf.reshape(BATCH_SHAPE) * RESCALING
    x = noisy_wf.reshape(BATCH_SHAPE) * RESCALING
    info = model.train_on_batch(x, y)

model.save_weights('final.hdf5')

第一个密集层实际上是无用的,我添加它的原因是因为我想确保我能够成功地组合LSTM和时间分布密集层,因为我的真实应用程序可能需要这样的设置。

错误功能被修改了很多次。最初我使用的是普通均方误差,但训练过程非常缓慢,并且主要是收敛到简单地将输入噪声信号复制到输出中。稍后添加的余弦邻近度量基本上定义了函数形状之间的相似度;它似乎加快了学习的速度。另请注意,我只将损失函数应用于数据集的后半部分;这样做的动机是我期望网络需要看到信号的几个周期,以便能够正确识别波形的参数。但是,我发现这种修改对网络性能没有明显影响。

该脚本的最新修改使用了Adam优化器,我还尝试了具有不同学习速率和衰减设置的RMSProp,但我发现网络行为没有明显差异。

我正在使用配置为使用64位浮点的Theano 0.9(dev)后端,以防止数值稳定性可能出现的问题。 epsilon值相应地设置为1e-14。

这是15k..30k训练步骤之后输出的样子(从大约15k步开始,性能停止改善)(第一个图是为了清晰起见而放大的):

enter image description here enter image description here

情节传奇:

  • 蓝色(0) - 噪声信号,RNN的输入
  • 绿色(1) - 恢复的信号,RNN的输出
  • red(2) - 地面真相

我的问题是:我做错了什么?

0 个答案:

没有答案