【问题标题】:My single layer perceptron converges on the OR dataset, but not on the AND dataset我的单层感知器收敛于 OR 数据集,但不收敛于 AND 数据集
【发布时间】:2018-10-29 23:42:00
【问题描述】:

我正在构建我的第一个单层感知器网络,并且我正在对其进行训练以模仿具有两个输入的最简单逻辑门(AND 和 OR)的行为。

网络由两个输入节点和一个偏差组成。采用单层感知器的delta-rule学习算法,激活函数为tanh函数。

在 AND 数据集上进行训练时,当给定输入 (1, 1) 时,网络应给出接近 1 的答案,而对于任何其他输入(例如 (0, 1)(1, 0)(1, 1))给出的答案应为 0。在 OR 数据集上进行训练时,如果给定除 (0, 0) 之外的任何输入,它应该返回接近 1 的答案。

但是它表现出我无法理解的行为。当我在 OR 数据集上训练它时,它收敛得很好(即错误率非常低 - 0.01 或更低):

$ python nn.py
[0 0]: (actual result = [[0.00051257]]). (expected result from training set=0, error rate=[[-0.00051257]])
[0 1]: (actual result = [[0.98865851]]). (expected result from training set=1, error rate=[[0.01134149]])
[1 0]: (actual result = [[0.98865222]]). (expected result from training set=1, error rate=[[0.01134778]])
[1 1]: (actual result = [[0.99993485]]). (expected result from training set=1, error rate=[[6.51512784e-05]])

但是,它在 AND 数据集上不能很好地收敛:

$ python nn.py
[0 0]: (actual result = [[-0.28911014]]). (expected result from training set=0, error rate=[[0.28911014]])
[0 1]: (actual result = [[0.23984154]]). (expected result from training set=0, error rate=[[-0.23984154]])
[1 0]: (actual result = [[0.28911014]]). (expected result from training set=0, error rate=[[-0.28911014]])
[1 1]: (actual result = [[0.68570095]]). (expected result from training set=1, error rate=[[0.31429905]])

我尝试将epoch 调整为500-10000 之间的各种数字,但没有效果。和eta0.11.0 之间的任何地方。

查看下面的收敛图,您会看到 OR 数据集的神经网络如何比 AND 数据集收敛得更好,如不断“变薄”的橙色图所示。

我认为 OR 和 AND 门是彼此相反的,如果网络在其中一个上工作,那么它肯定应该在另一个上工作。我在这里错过了什么?

这里附上nn.py的源码。

注意:当您查看时,您会发现我已将权重矩阵初始化为 1,而不是一些随机值。这仅仅是因为我想要一些确定性来帮助我进行故障排除。据我了解,它不应该影响算法的正确性(尽管它可能会使其收敛速度变慢)。 现在,按照@Dennis Soemers 的建议,权重已正确初始化为一些随机值。问题依然存在。

import numpy as np

def tanh(x):
    return (1.0 - np.exp(-2*x))/(1.0 + np.exp(-2*x))

def tanh_derivative(x):
    return (1 + tanh(x))*(1 - tanh(x))

# AND dataset
training_set = [
    (np.array([0, 0]), 0),
    (np.array([0, 1]), 0),
    (np.array([1, 0]), 0),
    (np.array([1, 1]), 1)
]

# # OR dataset
# training_set = [
#     (np.array([0, 0]), 0),
#     (np.array([0, 1]), 1),
#     (np.array([1, 0]), 1),
#     (np.array([1, 1]), 1)
# ]

weight = np.random.rand(3, 1)

# fit
eta = 0.2
epoch = 5000
for i in range(0, len(training_set)*epoch):
    input_, expected_output = training_set[np.random.randint(0, len(training_set))]
    input_with_bias = np.concatenate((input_, np.ones(1))).reshape(3, 1)
    sum_weights_of_input = np.dot(input_with_bias.T, weight)
    actual_output = tanh(sum_weights_of_input)
    error = expected_output - actual_output
    delta = np.multiply(eta, np.multiply(error, np.multiply(input_with_bias, tanh_derivative(sum_weights_of_input))))
    weight = weight + delta

# print
for input_, expected_output in training_set:
    input_with_bias = np.concatenate((input_, np.ones(1))).reshape(3, 1)
    actual_output = tanh(np.dot(input_with_bias.T, weight))
    error = expected_output - actual_output
    print("{}: (actual result = {}). (expected result from training set={}, error rate={})".format(input_, actual_output, expected_output, error))

【问题讨论】:

  • 一项改进是在循环结束时更新您的 eta(递减)。另外,这是一个非常简单的例子,所以当你最终得到正确的算法时,你可能不需要 5000 个 epoch,应该最多收敛 20 个 epoch 左右

标签: python machine-learning neural-network perceptron


【解决方案1】:

除了关于权重随机初始化的注释(您现在已经解决了,将该点移至答案的底部),重要的是要注意您使用tanh 作为激活,但您期望输出接近01tanh 更适合您希望在[-1, 1] 中输出而不是[0, 1] 的情况。

我怀疑,对于您的网络架构,根本不可能获得比您已经获得的更接近 AND 问题所需输出的输出。考虑tanh 函数的这个图:

w0 表示偏差的权重(始终为1),w1w2 分别表示第一个和第二个输入x1x2 的权重。我们的输出总是y = tanh(w0 + w1 x1 + w2 x2)

让我们首先考虑x1 = x2 = 0 的情况,我们希望输出大约为0。换句话说,我们想要tanh(w0 + 0 + 0) ~= 0。如果您查看图像,这只有在我们的偏差权重w0 本身也近似于0 时才有可能。

现在,考虑x1 = 1x2 = 1,而另一个输入是1 的情况。同样,所需的输出是0,从上面我们已经知道我们必须有w0 ~= 0。所以,现在我们知道我们希望以下两件事大致正确:

  • tanh(w1 x1) = 0
  • tanh(w2 x2) = 0

如果我们再次查看图像,我们再次看到,只有当权重w1w2 都近似等于0 时,上述两点才能成立。因此,现在只考虑了四个可能的输入中的三个,我们已经坚持希望我们的所有权重大致等于0。如果我们想要这个,我们最终输入的输出注定也大致等于0。因此,总而言之,使用tanh() 激活函数和您为网络选择的特定架构,不可能精确地获得我们想要的 AND 问题的输出值。

注意:如果您采用稍微不那么严格的“解决”概念,您拥有的网络仍然能够成功“解决”AND 问题。请注意,根据您获得的结果,它能够清楚地区分不同的情况。它没有提供非常接近01 的输出,但您可以轻松地提出一个阈值(例如0.5)并说“低于此阈值的每个输出都被视为@ 987654359@,它上面的每个输出都被视为1"。

如果您希望输出更接近精确的01,您可以考虑使用sigmoid function 而不是tanh。它具有非常相似的形状,但仅在[0, 1](正是您想要的输出范围)中生成输出,而不是[-1, 1]


注意:当您查看时,您会看到我已将权重矩阵初始化为 1,而不是一些随机值。这仅仅是因为我想要一些确定性来帮助我进行故障排除。据我了解,它不应该影响算法的正确性(尽管它可能会使其收敛速度变慢)

这确实可能是(或至少是)您的问题的原因。当所有权重具有相同的初始值时,您将获得无法再破坏的对称性。某些权重对将始终具有相同的起始值、相同的梯度、相同的误差,并以完全相同的方式更新(意味着它们始终保持相同)。您还可以在输出和错误中看到这一点;注意有一些数字几乎相同(在 AND 问题的情况下,一个恰好是另一个的负数)。

您将希望使用随机的初始权重,以便从一开始就打破这些对称性。如果你想要确定性,你可以简单地通过为你的随机数生成器使用一个固定的种子来做到这一点,这样你总是得到相同的“随机”初始权重。

【讨论】:

  • 感谢您的建议,我已经尝试过了,但问题仍然存在。
  • 感谢您的反馈 - 我已经尝试过了,但这似乎不是问题的原因。但是,各种激活函数的区别对于我这个新手来说还是一个很好的洞察。至于真正的问题,我在绘制错误率后才意识到,网络实际上并没有在 AND 数据集上收敛。
  • @lolski 我怀疑缺乏收敛仅仅是因为,正如我所描述的,给定的架构 + 激活函数不可能找到完美的解决方案。当你不断地给它一个例子时,它总是会为最近的训练例子转向一个“完美的解决方案”,这对于其他例子来说可能是一个更糟糕的解决方案,从而导致弹跳/振荡错误。
  • @lolski 您可以尝试一次给出所有四个输入-输出对的整个(小)批次,而不是一个一个地给出示例。然后,您可以对四个梯度的平均值而不是单个梯度进行学习,并且您可以绘制四个实例的平均误差,而不是总是绘制单个最近实例的误差。我怀疑平均误差应该收敛;不要0,因为不可能有完美的解决方案,但仍会收敛到一些恒定的平均误差。
猜你喜欢
  • 2018-02-21
  • 2018-10-05
  • 2018-12-14
  • 1970-01-01
  • 2020-08-01
  • 2016-01-19
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
相关资源
最近更新 更多