神经网络不学习乘法(玩具示例)

时间:2018-05-09 19:08:38

标签: python machine-learning neural-network keras

玩具数据集

  • 输入:两个整数:ab
  • 输出:单个整数,应该是ab
  • 的乘积
  • 8000培训示例

我的X_train示例:

    array([[ 6220, 15403],
           [ 3197,  8054],
           [ 1723,  3711],
           ...,
           [ 9500, 14979],
           [ 2642, 16547],
           [15169, 19332]], dtype=int64)

我的Y_train示例:

    array([ 95806660,  25748638,   6394053, ..., 142300500,  43717174,
            293247108], dtype=int64)

模型

    def get_model():
        model = Sequential()
        model.add(Dense(20, input_shape=(2,), kernel_initializer='normal', activation='linear'))
        model.add(LeakyReLU(alpha=.001))
        model.add(Dense(20, kernel_initializer='normal', activation='linear'))
        model.add(LeakyReLU(alpha=.001))
        model.add(Dense(20, kernel_initializer='normal', activation='linear'))
        model.add(LeakyReLU(alpha=.001))
        model.add(Dense(20, kernel_initializer='normal', activation='linear'))
        model.add(LeakyReLU(alpha=.001))
        model.add(Dense(1, activation=None))
        model.compile(loss='mean_squared_error', optimizer='adam')
        return model

    estimator = KerasRegressor(build_fn=get_model, epochs=20, batch_size=20,  verbose=1)
    estimator.fit(np.array(X_train), np.array(Y_train))

问题

似乎在一些时代之后趋同,伴随着巨大的训练损失:

Epoch 1/20
8000/8000 [==============================] - 3s 378us/step - loss: 8970757661335224.0000
Epoch 2/20
8000/8000 [==============================] - 1s 187us/step - loss: 1368236980395048.7500
Epoch 3/20
8000/8000 [==============================] - 2s 189us/step - loss: 731455474934743.0000
Epoch 4/20
8000/8000 [==============================] - 2s 200us/step - loss: 731256021644738.6250
Epoch 5/20
8000/8000 [==============================] - 2s 209us/step - loss: 729734634673274.8750
Epoch 6/20
8000/8000 [==============================] - 2s 215us/step - loss: 730761901553746.0000
Epoch 7/20
8000/8000 [==============================] - 2s 224us/step - loss: 729841294691532.7500
Epoch 8/20
8000/8000 [==============================] - 2s 235us/step - loss: 728911536487137.2500
Epoch 9/20
8000/8000 [==============================] - 2s 229us/step - loss: 731467433524592.6250
Epoch 10/20

我尝试了什么?

  • 不同的学习率,学习率衰减
  • 或多或少的隐藏图层/隐藏单元
  • 不同的激活功能(→ReLU,Leaky ReLU)
  • 仔细检查我的输入和标签(→似乎是正确的)

所有这些行动都不会改善损失。使用较少的层会使结果更糟。

修改

如果有人想玩它 - 我已经创建了一个(IPython / Google Colab)笔记本here

我现在也尝试过:

  • 使用glorot_normal进行初始化→无显着性更改
  • 使用sklearn.preprocessing.StandardScaler通过sc.fit_transform(dataset)进行规范化并推断sc.inverse_transform(result)→改进自~7.3e14至~2.0e11
  • 改变批量大小→无显着性变化
  • 更多数据→16.000例→从〜2.0e11到~1.0e11
  • 稍微改进一点
  • 通过math.log进行规范化(将c = a * b转换为log(c) = log(a) + log(b),使用exp(predicted)进行推理→看起来更好→1.02e9,但它仍然很远从准确 - 在一个简单的任务,如乘法

3 个答案:

答案 0 :(得分:2)

规范化您的数据(输入输出),使其具有零均值和单位差异。

在第二步中,将初始值设定项更改为glorot_normal

答案 1 :(得分:0)

您正在使用非常大的值。查看平均相对绝对误差(id=:arg0),以便在评估过程中更好地估计模型的性能,而与输入比例无关。

进一步考虑使用较小的值,例如在mean(abs((output - target) / target))范围内,将输出限制在[0; 10]范围内,以避免爆炸梯度。您可以将输入除以某些[0; 100]scale),然后将输出乘以>> 1

如果您不使用scale^2ln的技巧来将乘法转换为加法,则需要更多的层,还应考虑残差连接。

答案 2 :(得分:0)

建模存在几个问题:

  1. 网络太深。对于这个简单的问题,具有4个S型神经元的1个隐藏层就足够了。太深的网络只会使其难以融合。
  2. 输入/输出范围太大。输入/输出的绝对值将影响梯度和学习率的值。如果您使用大量输入,则一开始需要使用非常大的学习率,然后逐渐降低它。此外,如果ab具有不同的范围,则它们的参数需要不同的学习率。为了避免所有这些问题,您应该将数据按比例缩小,例如缩小为0均值,1方差。但是这种缩放可能会影响乘法精度。更适合此问题的是日志缩放。 请注意,如果您使用对数缩放,则问题甚至更简单,只需将两个数字相加即可。您只能将1个输出层与1个线性神经元一起使用,而无需隐藏层。

但是,主要问题是框架/硬件
即使使用精确的权重([[1.,1.],[0.]]),模型输出仍然不准确,测试集上的MSE仍然约为10 ^ 4。我认为这是因为在TF和/或Colab中计算精度较低的浮点数,因此无法正确计算大数。