一个时期后,第一层的MLP输出为零

时间:2019-11-18 23:10:39

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

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

我基本上是在尝试建立一个网络,以将机器人手臂(6维输入)的末端执行器的XYZ位置和RPY方向映射到机器人手臂每个关节到达该位置的角度( 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之间,后三个值在-pi和pi之间)
  • 批量大小为1、10、32的
  • 测试了3个5k值,500k值和5M值的所有数据集的MLP。
  • 测试了10到1000个世代的数量
  • 针对bias和kernel测试了多个初始化程序。
  • 测试了顺序模型和Keras功能API(以确保问题不在于我如何调用模型)
  • 隐藏层的Sigmoid,relu和tanh激活函数全部有3个(最后一层是线性激活,因为它是回归函数)

此外,我在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,)向量,其中output [i] = input [i]²网络并没有学到任何东西。我还测试了一个随机数据集,其中输入是一个随机数,输出是输入的线性函数,并且损失很快收敛到0。简而言之,似乎简单的体系结构无法映射非线性函数。

image 1

2 个答案:

答案 0 :(得分:1)

  

第一层的输出始终为零。

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

我的猜测是该模型太小,无法有效地表示数据。我建议您将模型中的参数数量增加10或100倍,然后看看它是否开始出现效果。限制参数数量会对网络产生正则化效果,而强正则化通常会使上述derping变为均值。

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

如此大的变化将在这些点周围引起很大,非常嘈杂的渐变。我不确定网络围绕这些嘈杂的梯度如何工作,但是我建议作为一个实验,尝试将训练数据集限制为一组输出,这些输出在机械臂的配置空间中彼此平滑连接,如果有道理。更进一步,您应该从数据集中删除所有接近此类配置边界的点。为了在推理时弥补这一点,您可能需要对几个附近的点进行采样,然后选择最常见的预测作为最终结果。希望其中一些点将落在平滑的配置区域中。

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

关于其余的超参数:

  • 批次大小为32很好,非常小的批次大小会使梯度过大
  • 损失函数并不重要,MSE和MAE均应起作用
  • 激活功能并不重要,ReLU是很好的默认选择。
  • 默认初始化程序已经足够了。
  • 归一化对于密集层很重要,因此请保留
  • 只要减少训练和验证损失,就可以训练尽可能多的时期。如果验证损失在5到10个时期内都没有下降,那么您最好尽早停止。
  • 亚当是一个很好的默认选择。仅当训练损失在几个时期内持续下降时,才从小的学习率开始,并在训练开始时提高学习率。

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

答案 1 :(得分:0)

我最终用Conv1D层替换了第一层密集层,现在网络似乎学习得不错。这太适合我的数据了,但是我可以接受。

我现在关闭线程,我将花一些时间来研究体系结构。