【问题标题】:Approximating the sine function with a neural network用神经网络逼近正弦函数
【发布时间】:2012-12-03 13:18:39
【问题描述】:

我已经实现了一个简单的神经网络框架,它只支持多层感知器和简单的反向传播。它适用于线性分类和通常的 XOR 问题,但对于正弦函数逼近,结果并不那么令人满意。

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

我查看了encog 以供参考,但即使如此,我也无法通过简单的反向传播使其工作(通过切换到弹性传播,它开始变得更好,但仍然比@987654322 提供的超级流畅的 R 脚本差得多@)。那么我真的在尝试做一些不可能的事情吗?用简单的反向传播(没有动量,没有动态学习率)不可能近似正弦吗? R中神经网络库实际使用的方法是什么?

编辑:我知道即使使用简单的反向传播(如果您对初始权重非常幸运),也绝对可能找到足够好的近似值,但我实际上更想知道这是否是一种可行的方法。与我的实现甚至 encog 的弹性传播相比,我链接到的 R 脚本似乎收敛得非常快和健壮(在 40 个 epoch 中只有很少的学习样本)。我只是想知道我是否可以做一些事情来改进我的反向传播算法以获得相同的性能,或者我是否必须研究一些更高级的学习方法?

【问题讨论】:

  • 你有没有让它工作?面临同样的问题。
  • 不这么认为,但已经记不起所有细节了,因为这是 4 年前的事了。上面提到的 nnet 包是用 C 实现的,只有 700 行代码,然后在其上封装了一些 R。也许调查一下会给你一些想法。
  • 我在 C/C++ 中实现这个。 My Network 在单个隐藏层使用 6 个神经元,在隐藏层使用 tanh 激活,在输出层使用线性激活。它在 1600 个 epoch 中收敛,不使用动量或优化器,这是您所要求的,还是 40 个 epoch 是您目标的基准?虽然,我正在努力为我的网络添加优化器和动力,但我会在这里分享。到目前为止,我应该分享我的方法吗?
  • 如果你有一个表现良好的模型,并且可以提供清晰简洁的答案,请分享你的工作,我会接受答案。

标签: machine-learning neural-network


【解决方案1】:

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

结果如下所示:

【讨论】:

    【解决方案2】:

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

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

    代码也很简单:

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

    【讨论】:

    • 您的代码实际上实现了 3 层神经网络,而不是 2 层。命名方案包括隐藏层和输出层,所以你的三层是x1x2result
    【解决方案3】:

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

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

    1. 将数据分成两部分:训练集 (~2/3) 和测试集 (~1/3)。
    2. 在训练集中的所有项目上训练您的网络。
    3. 在测试集中的所有项目上测试(但不训练)您的网络并记录平均错误。
    4. 重复第 2 步和第 3 步,直到您达到最小测试错误(当您的网络开始在训练数据上变得超级好而损害其他所有内容时,“过度拟合”会发生这种情况)或直到您的整体错误停止显着减少(暗示网络将达到最佳状态)。
    5. 如果此时的错误是可以接受的低,那么您就完成了。如果不是,您的网络还不够复杂,无法处理您正在为其训练的功能;添加更多隐藏的神经元并回到开头...

    有时更改激活函数也会产生影响(只是不要使用线性,因为它会抵消添加更多层的力量)。但同样,要知道什么最有效,需要反复试验。

    希望对您有所帮助(抱歉,我不能再有用了)!

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

    【讨论】:

    • 谢谢!这实际上是我已经在做的事情,如果我有点不清楚,我很抱歉。我知道这是可能,但我更想知道我使用的简单学习方法对于这个特定问题是否可行
    • @Muton - 明白了。在这种情况下,我唯一的建议是在您当前的设置中添加一个动量项。应该在两个方面有所帮助:它会加快学习速度并让您摆脱一些局部最小值。不过,我无法想象它会产生巨大的性能差异。
    猜你喜欢
    • 2018-09-10
    • 2017-11-26
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    • 2017-04-01
    相关资源
    最近更新 更多