【问题标题】:Keras Sequential Model Non-linear Regression Model Bad PredictionKeras 序列模型 非线性回归模型 错误预测
【发布时间】:2021-03-12 01:29:30
【问题描述】:

要使用 Keras 测试非线性序列模型, 我做了一些随机数据 x1,x2,x3 和y = a + b*x1 + c*x2^2 + d*x3^3 + e(a、b、c、d、e 是常数)。 损失很快就变低了,但模型实际上预测了一个非常错误的数字。我已经使用具有类似代码的线性模型完成了它,但它工作正常。也许顺序模型设计错误。这是我的代码


import numpy as np

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input, Dense, Dropout
from tensorflow.keras import initializers

# y = 3*x1 + 5*x2 + 10

def gen_sequential_model():
    model = Sequential([Input(3,name='input_layer')),
    Dense(16, activation = 'relu', name = 'hidden_layer1', kernel_initializer=initializers.RandomNormal(mean = 0.0, stddev= 0.05, seed=42)),
    Dense(16, activation = 'relu', name = 'hidden_layer2', kernel_initializer=initializers.RandomNormal(mean = 0.0, stddev= 0.05, seed=42)),
    Dense(1, activation = 'relu', name = 'output_layer', kernel_initializer=initializers.RandomNormal(mean = 0.0, stddev= 0.05, seed=42)),
    ])

    model.summary()
    model.compile(optimizer='adam',loss='mse')
    return model

def gen_linear_regression_dataset(numofsamples=500, a=3, b=5, c=7, d=9, e=11):
    np.random.seed(42)
    X = np.random.rand(numofsamples,3)
    # y = a + bx1 + cx2^2 + dx3^3+ e
    for idx in range(numofsamples):
        X[idx][1] = X[idx][1]**2
        X[idx][2] = X[idx][2]**3
    coef = np.array([b,c,d])
    bias = e

    y = a + np.matmul(X,coef.transpose()) + bias
    return X, y

def plot_loss_curve(history):
    import matplotlib.pyplot as plt
    
    plt.figure(figsize = (15,10))

    plt.plot(history.history['loss'][1:])
    plt.plot(history.history['val_loss'][1:])
    plt.title('model loss')
    plt.ylabel('loss')
    plt.xlabel('epoch')
    plt.legend(['train','test'],loc = 'upper right')
    plt.show()

def predict_new_sample(model, x, a=3, b=5, c=7, d=9, e=11):
    x = x.reshape(1,3)
    y_pred = model.predict(x)[0][0]
    y_actual = a + b*x[0][0] + c*(x[0][1]**2) + d*(x[0][2]**3) + e

    print("y actual value: ", y_actual)
    print("y pred value: ", y_pred)


model = gen_sequential_model()
X,y = gen_linear_regression_dataset(numofsamples=2000)
history = model.fit(X,y,epochs = 100, verbose=2, validation_split=0.3)
plot_loss_curve(history)

predict_new_sample(model, np.array([0.7,0.5,0.5]))

结果:

...
Epoch 99/100
44/44 - 0s - loss: 1.0631e-10 - val_loss: 9.9290e-11
Epoch 100/100
44/44 - 0s - loss: 1.0335e-10 - val_loss: 9.3616e-11
y actual value:  20.375
y pred value:  25.50001

为什么我的预测值与实际值相差如此之大?

【问题讨论】:

  • (+1) 用于发布 reproducible 示例(现在很少见),没有它就不可能发现问题。继续这样...

标签: python tensorflow machine-learning keras regression


【解决方案1】:

尽管在最后一层不正确地使用了activation = 'relu' 并且使用了不推荐的内核初始化,但您的模型工作正常,并且报告的指标是真实的而不是侥幸。

问题不在模型上;问题是您的数据生成函数没有返回您想要返回的内容。

首先,为了看到您的模型确实学习了您要求它学习的内容,让我们按原样运行您的代码,然后使用您的数据生成函数生成一个示例:

X, y_true = gen_linear_regression_dataset(numofsamples=1)
print(X)
print(y_true)

结果:

[[0.37454012 0.90385769 0.39221343]]
[25.72962531]

所以对于这个特定的X,真正的输出是25.72962531;现在让我们使用 predict_new_sample 函数将这个 X 传递给模型:

predict_new_sample(model, X)
# result:
y actual value:  22.134424269890232
y pred value:  25.729633

嗯,预测输出25.729633 非常接近上面计算的真实输出(25.72962531);问题是,您的函数认为真正的输出应该是22.134424269890232,这显然不是的情况。

发生的事情是您的gen_linear_regression_dataset 函数返回数据X您计算了平方和三次分量,这不是您想要的;您希望在计算平方和立方体分量之前返回数据 X,以便您的模型自己学习如何执行此操作。

所以,你需要把函数改成如下:

def gen_linear_regression_dataset(numofsamples=500, a=3, b=5, c=7, d=9, e=11):
    np.random.seed(42)
    X_init = np.random.rand(numofsamples,3)  # data to be returned
    # y = a + bx1 + cx2^2 + dx3^3+ e
    X = X_init.copy()  # temporary data
    for idx in range(numofsamples):
        X[idx][1] = X[idx][1]**2
        X[idx][2] = X[idx][2]**3
    coef = np.array([b,c,d])
    bias = e

    y = a + np.matmul(X,coef.transpose()) + bias
    return X_init, y

修改函数并重新训练模型后(您会注意到验证错误最终会更高,~ 1.3),我们有

X, y_true = gen_linear_regression_dataset(numofsamples=1)
print(X)
print(y_true)

结果:

[[0.37454012 0.95071431 0.73199394]]
[25.72962531]

predict_new_sample(model, X)
# result:
y actual value:  25.729625308532768
y pred value:  25.443237

这是一致的。当然,您仍然不会得到完美的预测,尤其是对于看不见的数据(请记住,现在错误更高了):

predict_new_sample(model, np.array([0.07,0.6,0.5]))
# result:
y actual value:  17.995
y pred value:  19.69147

正如上面简要评论的那样,您应该真正更改模型以摆脱内核初始化程序(即使用默认的、推荐的初始化程序)并为最后一层使用正确的激活函数:

def gen_sequential_model():
    model = Sequential([Input(3,name='input_layer'),
    Dense(16, activation = 'relu', name = 'hidden_layer1'),
    Dense(16, activation = 'relu', name = 'hidden_layer2'),
    Dense(1, activation = 'linear', name = 'output_layer'),
    ])

    model.summary()
    model.compile(optimizer='adam',loss='mse')
    return model

你会发现你得到了更好的验证错误和更好的预测:

predict_new_sample(model, np.array([0.07,0.6,0.5]))
# result:
y actual value:  17.995
y pred value:  18.272991

【讨论】:

    【解决方案2】:

    来自@desertnaut 的好消息。

    只是在@desertnaut 解决方案上添加一些似乎可以改善结果的东西。

    1. 扩展您的数据(即使您总是使用 0-1,它似乎也增加了一点推动力)

    2. 在层之间添加 Dropout

    3. 增加 epoch 数 (150 -200 ?)

    4. 在高原添加降低学习率(试试看)

    5. 向图层添加更多单位

       reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                                     patience=5, min_lr=0.001)
      
       def gen_sequential_model():
           model = Sequential([
               Input(3,name='input_layer'),
           Dense(64, activation = 'relu', name = 'hidden_layer1'),
           Dropout(0.5),
           Dense(64, activation = 'relu', name = 'hidden_layer2'),
           Dropout(0.5),
           Dense(1, name = 'output_layer')
           ])
      
      
      
        history = model.fit(X, y, epochs = 200, verbose=2, validation_split=0.2, callbacks=[reduce_lr])
      
      
        predict_new_sample(model, x=np.array([0.07, 0.6, 0.5]))
      
        y actual value:  17.995
        y pred value:  17.710054
      

    【讨论】:

      猜你喜欢
      • 2019-10-09
      • 1970-01-01
      • 2014-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-25
      • 2019-10-19
      • 1970-01-01
      相关资源
      最近更新 更多