【问题标题】:Neural network for square (x^2) approximation用于平方 (x^2) 近似的神经网络
【发布时间】:2019-08-05 19:35:54
【问题描述】:

我是 TensorFlow 和数据科学的新手。我做了一个简单的模块,应该弄清楚输入和输出数字之间的关系。在这种情况下,x 和 x 平方。 Python中的代码:

import numpy as np
import tensorflow as tf

# TensorFlow only log error messages.
tf.logging.set_verbosity(tf.logging.ERROR)

features = np.array([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
                    9, 10], dtype = float)
labels = np.array([100, 81, 64, 49, 36, 25, 16, 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64,
                    81, 100], dtype = float)

model = tf.keras.Sequential([
    tf.keras.layers.Dense(units = 1, input_shape = [1])
])

model.compile(loss = "mean_squared_error", optimizer = tf.keras.optimizers.Adam(0.0001))
model.fit(features, labels, epochs = 50000, verbose = False)
print(model.predict([4, 11, 20]))

我尝试了不同数量的单元,并添加了更多层,甚至使用了relu 激活函数,但结果总是错误的。 它适用于其他关系,如 x 和 2x。 这里有什么问题?

【问题讨论】:

    标签: python tensorflow machine-learning keras neural-network


    【解决方案1】:

    问题在于x*xa*x 完全不同。

    请注意通常的“神经网络”的作用:它将y = f(W*x + b) 堆叠几次,从不将x 与自身相乘。因此,您将永远无法完美重建x*x。除非你设置f(x) = x*x 或类似的。

    您可以获得的是训练期间呈现的值范围的近似值(可能还有一点点外推)。无论如何,我建议您使用较小范围的值,这样会更容易优化问题。

    在哲学上:在机器学习中,我发现思考好/坏而不是正确/错误更有用。尤其是回归,除非你有确切的模型,否则你无法得到“正确”的结果。在这种情况下,没有什么可学的。


    实际上有一些神经网络架构将f(x)g(x) 相乘,最值得注意的是LSTMsHighway networks。但即使这些也有f(x)g(s) 中的一个或两个有界(通过逻辑 sigmoid 或 tanh),因此无法完全建模 x*x


    由于在cmets中表达了一些误解,所以我强调几点:

    1. 可以近似您的数据。
    2. 要想在任何意义上做得好,您都需要一个隐藏层
    3. 但是没有更多数据是必要的,不过如果你覆盖了空间,模型会更贴合,请参阅desernaut's answer

    例如,下面是一个模型的结果,该模型具有 10 个单位的单个隐藏层并激活 tanh,由 SGD 训练,学习率为 1e-3,进行 15k 次迭代以最小化数据的 MSE。最好的五场比赛:

    这里是重现结果的完整代码。不幸的是,我无法在当前环境中安装 Keras/TF,但我希望 PyTorch 代码可以访问 :-)

    #!/usr/bin/env python
    import torch
    import torch.nn as nn
    import matplotlib.pyplot as plt
    
    X = torch.tensor([range(-10,11)]).float().view(-1, 1)
    Y = X*X
    
    model = nn.Sequential(
        nn.Linear(1, 10),
        nn.Tanh(),
        nn.Linear(10, 1)
    )
    
    optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
    loss_func = nn.MSELoss()
    for _ in range(15000):
        optimizer.zero_grad()
        pred = model(X)
        loss = loss_func(pred, Y)
        loss.backward()
        optimizer.step()
    
    x = torch.linspace(-12, 12, steps=200).view(-1, 1)
    y = model(x)
    f = x*x
    
    plt.plot(x.detach().view(-1).numpy(), y.detach().view(-1).numpy(), 'r.', linestyle='None')
    plt.plot(x.detach().view(-1).numpy(), f.detach().view(-1).numpy(), 'b')
    plt.show()
    

    【讨论】:

    • 但是由于神经网络永远不会将x与自身相乘,因此这种方法无法解决问题。如何让它自己乘以x没有明确地告诉它这样做,因为如果我告诉它做什么,它就不会是Machine Learning
    • 嗯...这不是首先用 ML 解决的问题 ;-) 如果学习,请使用不同噪声量的拟合数据。绘制预测并观察不同模型如何适应不同范围的数据。总体而言:尽管最近大肆宣传,但所谓的神经网络只是输入的参数化函数。所以在任何情况下你都会给他们一些结构。如果输入之间没有相乘,则输入永远不会相乘。如果您知道/怀疑您的任务需要成倍增加,请告诉网络这样做。
    【解决方案2】:

    你犯了两个非常基本的错误:

    • 您的超简单模型(具有单个单元的单层网络)根本不符合神经网络的条件,更不用说“深度学习”模型(因为您的问题已被标记)
    • 同样,您的数据集(仅 20 个样本)也非常小

    当然,如果神经网络要解决像x*x 这样“简单”的问题,就需要具有一定的复杂性;而它们真正闪耀的地方是在输入大型训练数据集时。

    尝试解决此类函数近似的方法不仅仅是列出(少数可能的)输入,然后将其连同所需的输出一起馈送到模型中;请记住,NN 通过示例学习,而不是通过符号推理。而且例子越多越好。在类似情况下,我们通常会生成大量示例,然后将这些示例输入模型进行训练。

    话虽如此,这里是一个相当简单的 Keras 3 层神经网络演示,用于逼近函数 x*x,使用在 [-50, 50] 中生成的 10,000 个随机数作为输入:

    import numpy as np
    import keras
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.optimizers import Adam
    from keras import regularizers
    import matplotlib.pyplot as plt
    
    model = Sequential()
    model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001), input_shape = (1,)))
    model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001)))
    model.add(Dense(1))
    
    model.compile(optimizer=Adam(),loss='mse')
    
    # generate 10,000 random numbers in [-50, 50], along with their squares
    x = np.random.random((10000,1))*100-50
    y = x**2
    
    # fit the model, keeping 2,000 samples as validation set
    hist = model.fit(x,y,validation_split=0.2,
                 epochs= 15000,
                 batch_size=256)
    
    # check some predictions:
    print(model.predict([4, -4, 11, 20, 8, -5]))
    # result:
    [[ 16.633354]
     [ 15.031291]
     [121.26833 ]
     [397.78638 ]
     [ 65.70035 ]
     [ 27.040245]]
    

    嗯,没那么糟糕!请记住,NN 是函数逼近器:我们应该期望它们既不完全再现函数关系,也不“知道”4-4 的结果应该是一样的。

    让我们在[-50,50] 中生成一些新的随机数据(请记住,出于所有实际目的,这些都是模型的unseen数据)并将它们与原始数据一起绘制,以获得更多大图:

    plt.figure(figsize=(14,5))
    plt.subplot(1,2,1)
    p = np.random.random((1000,1))*100-50 # new random data in [-50, 50]
    plt.plot(p,model.predict(p), '.')
    plt.xlabel('x')
    plt.ylabel('prediction')
    plt.title('Predictions on NEW data in [-50,50]')
    
    plt.subplot(1,2,2)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.plot(x,y,'.')
    plt.title('Original data')
    

    结果:

    嗯,可以说它确实看起来确实是一个很好的近似值......

    您还可以查看this thread 以获得正弦近似值。

    最后要记住的是,虽然我们确实得到了一个不错的近似值,即使使用我们相对简单的模型,我们应该期望的是外推,即在[-50, 50]之外表现良好;详情请看我在Is deep learning bad at fitting simple non linear functions outside training scope?的回答

    【讨论】:

    • 所以你的意思是在[-50, 50]之外的数字上得到更准确的结果,我应该训练它并在我需要的范围内给出例子。
    • @AmeerTaweel 确实
    • 但是您怎么知道 8/8/1 NN 可以解决问题?
    • @TonyEnnis 我没有(问题实际上与此无关)。我只知道像 OP 这样的单层单单元模型无法完成这项工作。剩下的只是简单的试错,根据经验(现在不记得了,但我想我第一次尝试就知道了)。
    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    • 2018-09-10
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 2017-03-01
    相关资源
    最近更新 更多