首页 > 解决方案 > 无法训练 keras 模型来逼近一个简单的函数

问题描述

我刚开始学习机器学习,我尝试编写一个简单的程序,其中 nn 将学习简单的函数 y = f(x) = 2x。

这是代码:

#x is a 1D array of 1 to 1000
x = np.arange(1,1000, 1)
y = x*2

xtrain = x[:750]
ytrain = y[:750]
xtest = x[750:]
ytest = y[750:]

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten, Conv2D

model = Sequential()

model.add(Dense(128, input_dim=1, activation='relu'))

model.add(Dense(1, activation='relu'))

model.compile(loss='mean_squared_error', 
          optimizer='sgd', 
          metrics=['accuracy'])

model.summary()

history = model.fit(xtrain, ytrain, 
                batch_size=100, 
                epochs=20, 
                verbose=1, 
                validation_split=0.2)

无论我如何更改架构或超参数,我都会得到以下输出:

79999/79999 [==============================] - 1s 13us/step - loss: 8533120007.8465 - acc: 0.0000e+00 - val_loss: 32532613324.8000 - val_acc: 0.0000e+00

准确率一直为0。我究竟做错了什么?

标签: pythonmachine-learningkerasdeep-learning

解决方案


如果您盲目地运行并期望梯度下降方法学习任何功能,这实际上就是您所期望的。您观察到的行为源于两个原因:

  1. SGD 用于更新权重的导数实际上取决于输入。举一个很简单的例子,关于y = f(wx + b)的导数是使用链式法则。因此,当有一个非常大/非标准化的输入更新时,它会爆炸。现在更新基本是,所以权重突然变小了,实际上是负数。ywf'(wx + b)*xw' = w - alpha*gradient
  2. 在单次梯度更新后,输出变为负数,因为 SGD 刚刚过冲。由于您再次relu在最后一层,它只输出 0 并且训练停止,因为当输出为负导数时relu为 0。

您可以将数据大小减少到np.arange(1, 10)并将隐藏神经元的数量减少到 12 个(更多的神经元使输出在单次更新后变得更加负,因为它们的所有权重也变为负),您将能够训练网络。


推荐阅读