用神经网络逼近正弦函数

时间:2012-12-15 23:53:13

标签: machine-learning neural-network

出于学习目的,我实现了一个简单的神经网络框架,它只支持多层感知器和简单的反向传播。对于线性分类和通常的XOR问题,它可以正常工作,但对于正弦函数近似,结果并不令人满意。

我基本上试图用一个由6-10个神经元组成的隐藏层来近似正弦函数的一个周期。网络使用双曲正切作为隐藏层的激活函数和输出的线性函数。结果仍然是对正弦波的粗略估计,需要很长时间才能计算出来。

我查看了encog以供参考,但即便如此,我也无法通过简单的反向传播(通过切换到弹性传播,它开始变得更好但仍然比提供的超级光滑R脚本更糟糕) in this similar question)。我实际上是在尝试做一些不可能的事情吗?是否不可能通过简单的反向传播来近似正弦(没有动量,没有动态学习率)? R中神经网络库使用的实际方法是什么?

编辑:我知道即使使用简单的反向传播也很难找到一个足够好的近似值(如果你的初始权重非常幸运),但是我知道可能实际上更有兴趣知道这是否是可行的方法。与我的实现或甚至阻塞的弹性传播相比,我链接到的R脚本似乎只是非常快速和强大地收敛(在40个时代,只有很少的学习样本)。我只是想知道我是否可以做些什么来改进我的反向传播算法以获得相同的性能,或者我是否需要研究一些更高级的学习方法?

4 个答案:

答案 0 :(得分:7)

使用TensorFlow等神经网络的现代框架可以很容易地实现这一点。

例如,每层使用100个神经元的双层神经网络在几秒钟内在我的计算机上训练并给出了一个很好的近似值:

enter image description here

代码也很简单:

import tensorflow as tf
import numpy as np

with tf.name_scope('placeholders'):
    x = tf.placeholder('float', [None, 1])
    y = tf.placeholder('float', [None, 1])

with tf.name_scope('neural_network'):
    x1 = tf.contrib.layers.fully_connected(x, 100)
    x2 = tf.contrib.layers.fully_connected(x1, 100)
    result = tf.contrib.layers.fully_connected(x2, 1,
                                               activation_fn=None)

    loss = tf.nn.l2_loss(result - y)

with tf.name_scope('optimizer'):
    train_op = tf.train.AdamOptimizer().minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    # Train the network
    for i in range(10000):
        xpts = np.random.rand(100) * 10
        ypts = np.sin(xpts)

        _, loss_result = sess.run([train_op, loss],
                                  feed_dict={x: xpts[:, None],
                                             y: ypts[:, None]})

        print('iteration {}, loss={}'.format(i, loss_result))

答案 1 :(得分:3)

你绝对不是在尝试不可能的事情。神经网络是universal approximators - 意味着对于任何函数F和误差E,存在一些神经网络(只需要一个隐藏层),它可以近似于F,误差小于E. / p>

当然,发现(那些)网络是完全不同的事情。我能告诉你的最好的是反复试验......这是基本程序:

  1. 将您的数据分成两部分:训练集(~2 / 3)和测试集(~1 / 3)。
  2. 在训练集中的所有项目上训练您的网络。
  3. 测试(但不训练)您的网络测试集中的所有项目并记录平均错误。
  4. 重复步骤2和3,直到达到最小测试错误(当您的网络开始变得非常擅长训练数据而不利于其他任何事情时,这会发生“过度拟合”)或直到您的整体错误停止显着减少(意味着网络尽可能好)。
  5. 如果此时的错误可以接受,那么你就完成了。如果没有,您的网络不够复杂,无法处理您正在训练的功能;添加更多隐藏的神经元并回到起点...
  6. 有时候改变你的激活功能也会产生影响(只是不要使用线性,因为它否定了添加更多图层的能力)。但同样,看看哪种方法效果最好也是反复试验。

    希望有所帮助(对不起,我不能更有用)!

    PS:我也知道这是可能的,因为我已经看到有人用网络近似正弦。我想说她不是使用sigmoid激活功能,但我无法保证我的记忆力......

答案 2 :(得分:0)

我用 keras 尝试了很多东西(不同的激活、层等)

LSTM 的工作,但不是 f(x) -> y ,作为 y 的输入序列。

我也尝试过@Jonas Adler 的回答,它有效(我也将其转换为 tf2 ), 但在每个时期提供 0-10 rad 的 100 个随机样本 - 步骤 不适合我当前的工作流程。

创建训练集和测试集后,使用相同的代码不起作用(非常低)

我最后一次尝试使用 NEAT, 结帐回购或链接。它以 %80 acc 近似所有 360 度。有 45 个样本。 它有16个隐藏单元。 我没有玩过参数或等待足够多的世代来提高准确性,但它可能会更好。 最后,python-neat里还有“sin”激活函数,用了就是作弊。

这是链接实验: https://github.com/firatsarlar/neat_sin_exp/blob/main/sin_exp.ipynb

答案 3 :(得分:0)

与 sklearn.neural_network 类似的实现:

from sklearn.neural_network import MLPRegressor
import numpy as np

f = lambda x: [[x_] for x_ in x]
noise_level = 0.1
X_train_ = np.arange(0, 10, 0.2)
real_sin = np.sin(X_train_)
y_train = real_sin+np.random.normal(0,noise_level,len(X_train_))    
N = 100
regr = MLPRegressor(hidden_layer_sizes= tuple([N]*5)).fit(f(X_train_), y_train)
predicted_sin = regr.predict(f(X_train_))

结果看起来像这样: predicted sin with NN