使用前馈网络学习任意函数

人工智能 前馈神经网络
2021-10-28 08:27:14

我想得到一个在 matlab 中运行的简单示例,它将使用神经网络从输入输出数据(基本上是模型识别)中学习任意函数,然后能够仅从输入数据中近似该函数。作为训练这个网络的手段,我在 matlab 中实现了一个简单的反向传播算法,但我无法获得接近令人满意的结果。我想知道我可能做错了什么以及我可以使用什么方法。

目标是让网络表示一个已识别的函数 f(x),该函数将一系列 x 作为输入,并输出从 x -> y 学习到的映射。

这是我到目前为止的 GNU 八度代码:

pkg load control signal

function r = sigmoid(z)
    r = 1 ./ (1 + exp(-z));
end

function r = linear(z)
    r = z;
end 

function r = grad_sigmoid(z)
    r = sigmoid(z) .* (1 - sigmoid(z));
end 

function r = grad_linear(z)
    r = 1;
end 

function r = grad_tanh(z)
    r = 1 - tanh(z) .^ 2;
end

function nn = nn_init(n_input, n_hidden1, n_hidden2, n_output)
    nn.W2 = (rand(n_input, n_hidden1) * 2 - 1)'
    nn.W3 = (rand(n_hidden1, n_hidden2) * 2 - 1)'
    nn.W4 = (rand(n_hidden2, n_output) * 2 - 1)'
    nn.lambda = 0.005;
end

function nn = nn_train(nn_in, state, action)
    nn = nn_in;

    [out, nn] = nn_eval(nn, state);

    d4 = (nn.a4 - action) .* grad_linear(nn.W4 * nn.a3); 
    d3 = (nn.W4' * d4) .* grad_tanh(nn.W3 * nn.a2);
    d2 = (nn.W3' * d3) .* grad_tanh(nn.W2 * nn.a1);

    nn.W4 -= nn.lambda * (d4 * nn.a3');
    nn.W3 -= nn.lambda * (d3 * nn.a2');
    nn.W2 -= nn.lambda * (d2 * nn.a1');
end

function [out,nn] = nn_eval(nn_in, state)
    nn = nn_in;

    nn.z1 = state;
    nn.a1 = nn.z1;

    nn.a2 = tanh(nn.W2 * nn.a1);
    nn.a3 = tanh(nn.W3 * nn.a2);
    nn.a4 = linear(nn.W4 * nn.a3);

    out = nn.a4;
end

nn = nn_init(1, 100, 100, 1);
t = 1:0.1:3.14*10;
input = t;
output = sin(input);
learned = zeros(1, length(output));

for j = 1:500
    for i = 1:length(input)
        nn = nn_train(nn, [input(i)], [output(i)]); 
    end
    j
end

for i = 1:length(input)
    learned(i) = nn_eval(nn, [input(i)]);    
end

plot(t, output, 'g', t, learned, 'b');

pause

结果如下: 在此处输入图像描述

结果甚至不接近我想要的位置。它与我的反向传播实现有关吗?

我需要对代码进行哪些更改才能获得更好的近似值?

1个回答

您需要缩放输入。神经网络在有限的输入域上工作得最好,当超过它时训练很差。

对于统计数据,您通常会将输入缩放为均值 0,标准差 1。

在这里,您最好将输入大致拟合为 -1 到 1。

取决于您在哪里缩放值,但通常这是在 NN 代码之外完成的。所以我会做类似的事情:

nn_input = (t - 15)/15

然后nn_input在训练和评估循环中使用。当您将这些直接放入排序数组中进行绘图时,您无需进行任何进一步的重新映射或维护转换功能。但是,在更常见的任意输入情况下,您需要将转换因子存储在某处(在这种情况下,可能只是硬编码为一个函数),以便使用经过训练的 NN。

另一件可能有帮助的事情是在训练期间打乱您的输入/输出数据对,以消除输入对序列之间的相关性。