tensorflow - 第一层 MLP 输出在一个 epoch 后为零

标签 tensorflow machine-learning keras neural-network deep-learning

我最近在尝试训练简单的 MLP 时遇到了一个问题。

我基本上试图让一个网络将机器人 ARM 末端执行器的 XYZ 位置和 RPY 方向(6 维输入)映射到机器人 ARM 每个关节到达该位置的角度( 6维输出),所以这是一个回归问题。

我使用角度计算当前位置生成了一个数据集,并生成了包含 5k、500k 和 500M 组值的数据集。

我的问题是我正在使用的 MLP 根本没有学到任何东西。使用 Tensorboard(我使用的是 Keras),我意识到无论我尝试什么,第一层的输出始终为零(参见图 1)。

基本上,我的输入是形状 (6,) 向量,输出也是形状 (6,) 向量。

这是我迄今为止尝试过的方法,但没有成功:

  • 我尝试过 2 层尺寸为 12、24 的 MLP; 2层尺寸48、48; 4 层,尺寸为 12、24、24、48。
  • Adam、SGD、RMSprop 优化器
  • 学习率范围从 0.15 到 0.001,有或没有衰减
  • 均方误差 (MSE) 和平均绝对误差 (MAE) 作为损失函数
  • 对输入数据进行标准化,而不对其进行标准化(前 3 个值在 -3 到 +3 之间,后 3 个值在 -pi 和 pi 之间)
  • 批量大小为 1、10、32
  • 测试了 5k 值、500k 值和 5M 值的所有 3 个数据集的 MLP。
  • 测试的 epoch 数量范围为 10 到 1000
  • 测试了多个初始值设定项的偏差和内核。
  • 测试了 Sequential 模型和 Keras 功能 API(以确保问题不在于我调用模型的方式)
  • 隐藏层的所有 3 个 sigmoid、relu 和 tanh 激活函数(最后一层是线性激活,因为它是回归)

此外,我在 Keras 的基本波士顿房价回归数据集上尝试了完全相同的 MLP 架构,并且网络肯定学到了一些东西,这让我相信我的数据可能存在某种问题。然而,我完全不知道它可能是什么,因为当前状态下的系统根本没有学到任何东西,损失函数只是从第一个时期开始就停止了。

任何帮助或线索将不胜感激,如果需要,我将很乐意提供代码或数据!

谢谢

编辑: 这是我正在使用的 5k 个数据样本的链接。 B-G 列是输出(用于生成位置/方向的角度),H-M 列是输入(XYZ 位置和 RPY 方向)。 https://drive.google.com/file/d/18tQJBQg95ISpxF9T3v156JAWRBJYzeiG/view

此外,这是我正在使用的代码片段:

df = pd.read_csv('kinova_jaco_data_5k.csv', names = ['state0',
                                                      'state1',
                                                      'state2',
                                                      'state3',
                                                      'state4',
                                                      'state5',
                                                      'pose0',
                                                      'pose1',
                                                      'pose2',
                                                      'pose3',
                                                      'pose4',
                                                      'pose5'])
states = np.asarray(
    [df.state0.to_numpy(), df.state1.to_numpy(), df.state2.to_numpy(), df.state3.to_numpy(), df.state4.to_numpy(),
     df.state5.to_numpy()]).transpose()
poses = np.asarray(
    [df.pose0.to_numpy(), df.pose1.to_numpy(), df.pose2.to_numpy(), df.pose3.to_numpy(), df.pose4.to_numpy(),
     df.pose5.to_numpy()]).transpose()

x_train_temp, x_test, y_train_temp, y_test = train_test_split(poses, states, test_size=0.2)
x_train, x_val, y_train, y_val = train_test_split(x_train_temp, y_train_temp, test_size=0.2)

mean = x_train.mean(axis=0)
x_train -= mean
std = x_train.std(axis=0)
x_train /= std

x_test -= mean
x_test /= std
x_val -= mean
x_val /= std

n_epochs = 100
n_hidden_layers=2
n_units=[48, 48]

inputs = Input(shape=(6,), dtype= 'float32', name = 'input')
x = Dense(units=n_units[0], activation=relu, name='dense1')(inputs)
for i in range(1, n_hidden_layers):
    x = Dense(units=n_units[i], activation=activation, name='dense'+str(i+1))(x)

out = Dense(units=6, activation='linear', name='output_layer')(x)
model = Model(inputs=inputs, outputs=out)

optimizer = SGD(lr=0.1, momentum=0.4)
model.compile(optimizer=optimizer, loss='mse', metrics=['mse', 'mae'])

history = model.fit(x_train,
                    y_train,
                    epochs=n_epochs,
                    verbose=1,
                    validation_data=(x_test, y_test),
                    batch_size=32)

编辑2 我使用随机数据集测试了该架构,其中输入是 (6,) 向量,其中 input[i] 是随机数,输出是 (6,) 向量,其中输出[i] = 输入[i]²并且网络没有学到任何东西。我还测试了一个随机数据集,其中输入是随机数,输出是输入的线性函数,并且损失很快收敛到 0。简而言之,简单的架构似乎无法映射非线性函数。

image 1

最佳答案

the output of my very first layer is always zero.

这通常意味着网络根本“看不到”输入中的任何模式,这导致它始终预测整个训练集上目标的平均值,而不管输入如何。您的输出在 -𝜋 到 𝜋 范围内,预期值可能为 0,因此它会检查出来。

我的猜测是模型太小,无法有效地表示数据。我建议您将模型中的参数数量增加 10 或 100 倍,看看它是否开始看到一些东西。限制参数数量对网络具有正则化作用,强正则化通常会导致上述的derping趋于均值。

我绝不是机器人专家,但我猜想在很多情况下,输出参数的微小调整都会导致输入发生较大变化。假设我正在尝试用左手挠背 - 我的手向左移动得越远,任务就变得越困难,因此在某些时候我可能想要换手,这是一种不连续的配置更改。当然,这是一个不好的类比,但我希望它能证明我的预感,即配置空间中的某些地方,小的目标更改会导致大的配置更改。

如此大的变化将导致这些点周围出现非常大、非常嘈杂的梯度。我不确定网络在这些噪声梯度上的工作效果如何,但我建议作为一个实验,您尝试将训练数据集限制为一组在 ARM 的配置空间中相互平滑连接的输出,如果有道理的话。更进一步,您应该从数据集中删除靠近此类配置边界的任何点。为了在推理时弥补这一点,您可能想要对几个附近的点进行采样,并选择最常见的预测作为最终结果。希望其中一些点能够落在平稳的配置区域中。

此外,在每个密集层之前添加批量归一化将有助于平滑梯度并提供更可靠的训练。

至于其余的超参数:

  • 批量大小为 32 就很好,非常小的批量大小会使梯度变得太嘈杂
  • 损失函数并不重要,MSE 和 MAE 都应该起作用
  • 激活函数并不重要,ReLU 是一个不错的默认选择。
  • 默认的初始化器已经足够好了。
  • 归一化对于密集层很重要,因此请保留它
  • 只要训练和验证损失都在下降,就可以根据需要训练任意数量的 epoch。如果验证损失在 5-10 个 epoch 内都没有下降,您不妨尽早停止。
  • Adam 是一个不错的默认选择。从较小的学习率开始,只有当训练损失在几个时期内持续下降时才增加训练开始时的学习率。

进一步阅读:37 Reasons why your Neural Network is not working

关于tensorflow - 第一层 MLP 输出在一个 epoch 后为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58924277/

相关文章:

python - 光学字符识别多行检测

python - 当数据集大小不是批量大小的倍数时,Keras 会发生什么情况?

python - 未设置 Tensorflow 恢复权重

python - KFold 交叉验证无法修复过度拟合

machine-learning - 当输入有多个输出值时,我可以使用神经网络进行回归吗?

nlp - 通过自然语言处理进行逻辑谬误检测和/或识别

python - 构建多个输出的神经网络

python - Numpy 数组中图像的图像数据生成器

python - 类型错误 : An op outside of the function building code is being passed a Graph tensor

python - 具有非方形图像的 CNN 自动编码器