【问题标题】:Backpropagation algorithm is stuck in MultiLayer Perceptron反向传播算法卡在多层感知器中
【发布时间】:2017-07-12 16:41:29
【问题描述】:

我想实现一个 MLP(多层感知器)来解决 XOR 问题。因为我不是一个伟大的科学家,所以我很长时间以来一直在努力,我想确保理解这个程序的每一行。

我将从问题开始:

  1. 是否有调试神经网络的特定方法? (例如导致预期解决方案的预定义已知权重)
  2. 以下反向传播算法(伪代码)正确吗?
  3. 偏差应该在这个算法中吗?如果不是,那么解决 XOR 问题是否需要偏差?如果是,偏差应该是每个神经元 1 个、每层 1 个还是每个网络 1 个?
  4. 我的 python 实现是否正确?如果不是,是关于反向传播、前向传播、偏差缺失还是其他?

非常欢迎每一个回复。这不是“家庭作业”,但如果你非常害怕,我会很高兴只有好的提示。我仍然没有正确使用 numpy,因为我更像是一个开发人员而不是科学家,并且有时会遇到矩阵方程的问题(我目前正在研究它)。因此,我很难很好地理解我发现的不同实现。


编辑:该算法现在运行良好,我将重点介绍伪代码/python 实现中存在的不同问题:

理论

  • 权重调整时的伪代码错误(我编辑了代码以修复标记行错误)。我在应该使用输入值的地方使用了输出层输出
  • 有效地可以在没有偏差的情况下解决 XOR 问题,并且只有 1 个隐藏层。有趣的是,它仅适用于隐藏层中的 4 个或更多神经元,但不适用于 3 个。但是,在基准测试之后,添加偏差可以显着加快达到最佳收敛的时间(速度提高 5 倍或更多)

python 实现

  • 权重在 0 和 1 之间随机初始化,而不是在 -1 和 1 之间,不能这样工作。

最后,this resource 对理解“神经元魔法”有很大帮助。它没有帮助我调试反向传播,但现在证明如果没有更多的理论知识,我永远无法让它工作。如果像我一样,你更像是一个开发者而不是科学家,我强烈建议你去看看。


基于 Virginie MATHIVET 的《人工智能开发人员》一书,这里是反向传播算法的伪代码(这是一本法语书,抱歉翻译不好):

While stop criteria is not achieved:
    Initialize d(i)

    For each example:
        Compute output value s(i)                          #1

        For each output neuron weight:                     #2
            d(i) = s(i) * (1 - s(i)) * (y(i) - s(i))
        EndFor

        For each hidden neuron weight:
            sum = 0
            For each link towards output neuron k:
                sum += d(k) * w(i->k)
            EndFor
            d(i) = o(i) * (1 - o(i)) * sum
        EndFor

        For each weight of the network:
            If link towards output neuron:
                w(i) += rate * d(i) * o(i)
            Else
                w(i) += rate * d(i) * s(i) # WRONG: s(i) should be input(i)
            EndIf
        EndFor
    EndFor
EndWhile

在上面,d(x) 是增量,o(x) 是隐藏层输出,s(x) 是输出层输出,y(x) 是预期输出,w(x) 是网络权重。

我了解#1行是正向传播#2(包括)之后的行是关于反向传播。因此,正确的算法可以写成:

While stop criteria is not achieved:
    Initialize d(i)

    For each example:
        output = Forward propagation with example inputs                  #1
        Backpropagation of the error between output and expected output   #2
    EndFor
EndWhile

我的问题是算法似乎与反向传播算法循环,并且权重发生变化,例如这里是隐藏层的输出:

[Epoch 0, inputs (1.0, 1.0)]: hidden outputs: None
[Epoch 0, inputs (0.0, 0.0)]: hidden outputs: [ 0.7755638   0.64556638  0.68163599]
[Epoch 0, inputs (1.0, 0.0)]: hidden outputs: [ 0.5  0.5  0.5]
[Epoch 0, inputs (0.0, 1.0)]: hidden outputs: [ 0.60747218  0.58975313  0.55246625]
[Epoch 1, inputs (1.0, 1.0)]: hidden outputs: [ 0.68911554  0.55079694  0.62718831]
[Epoch 1, inputs (1.0, 0.0)]: hidden outputs: [ 0.77449528  0.64107552  0.67770194]
[Epoch 1, inputs (0.0, 0.0)]: hidden outputs: [ 0.60728756  0.58957687  0.55230354]
[Epoch 1, inputs (0.0, 1.0)]: hidden outputs: [ 0.5  0.5  0.5]
[Epoch 2, inputs (0.0, 0.0)]: hidden outputs: [ 0.68877278  0.54872848  0.6254074 ]
[Epoch 2, inputs (1.0, 0.0)]: hidden outputs: [ 0.5  0.5  0.5]
[Epoch 2, inputs (1.0, 1.0)]: hidden outputs: [ 0.60700878  0.58812487  0.5509695 ]
[Epoch 2, inputs (0.0, 1.0)]: hidden outputs: [ 0.77344667  0.63591436  0.67311723]
[Epoch 3, inputs (0.0, 0.0)]: hidden outputs: [ 0.68856723  0.54708942  0.62400827]
[Epoch 3, inputs (1.0, 0.0)]: hidden outputs: [ 0.5  0.5  0.5]

以随机顺序放置示例不会改变任何内容。此外,我尝试了每个学习率(0.05 到 0.95),结果相同,所以我认为这不是收敛性差。这是我的 Python 实现:

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def dsigmoid(y):
    return y * (1.0 - y)

class NeuralNetwork:

    def __init__(self, nb_inputs, nb_hidden, nb_outputs, learning_rate):
        self.nb_inputs = nb_inputs
        self.nb_hidden = nb_hidden
        self.nb_outputs = nb_outputs
        self.learning_rate = learning_rate

        self.output_deltas = None
        self.output_weights = np.random.random((nb_outputs, nb_hidden)) # WRONG: should be between -1 and 1, not 0 and 1
        self.outputs = None
        self.hidden_deltas = None
        self.hidden_weights = np.random.random((nb_hidden, nb_inputs)) # WRONG: should be between -1 and 1, not 0 and 1
        self.hidden_outputs = None

    def forward_propagation(self, inputs):
        self.hidden_outputs = np.zeros((self.nb_hidden,))
        self.outputs = np.zeros((self.nb_outputs,))

        # get outputs for hidden layer
        for i in range(self.nb_hidden):
            aggregated = sum([inputs[j] * self.hidden_weights[i][j] for j in range(self.nb_inputs)])
            self.hidden_outputs[i] = sigmoid(aggregated)

        # get inputs for output layer
        for i in range(self.nb_outputs):
            aggregated = sum([self.hidden_outputs[j] * self.output_weights[i][j] for j in range(self.nb_hidden)])
            self.outputs[i] = sigmoid(aggregated)

    def backpropagation(self, expected_outputs):

        # find deltas for output layer 
        for i in range(self.nb_outputs):
            for j in range(self.nb_hidden):
                self.output_deltas[i][j] = dsigmoid(self.outputs[i]) * (expected_outputs[i] - self.outputs[i])

        # find deltas for hidden layer
        for i in range(self.nb_hidden):
            for j in range(self.nb_inputs):
                total = 0.0
                for k in range(self.nb_outputs):
                    total += self.output_deltas[k][i] * self.output_weights[k][i]
                self.hidden_deltas[i][j] = dsigmoid(self.hidden_outputs[i]) * total

        # change weights for output layer
        for i in range(self.nb_outputs):
            for j in range(self.nb_hidden):
                self.output_weights[i][j] += self.learning_rate * self.output_deltas[i][j] * self.outputs[i] # WRONG: should be self.hidden_outputs[j]

        # change weights for inputs layer
        for i in range(self.nb_hidden):
            for j in range(self.nb_inputs):
                self.hidden_weights[i][j] += self.learning_rate * self.hidden_deltas[i][j] * self.hidden_outputs[i] # WRONG: should be inputs[j]

    def train(self, data, nb_iterations):
        for i in range(nb_iterations):
            # Init deltas
            self.output_deltas = np.zeros((self.nb_outputs, self.nb_hidden), dtype=np.float64)
            self.hidden_deltas = np.zeros((self.nb_hidden, self.nb_inputs), dtype=np.float64)

            # Train on examples with different orders
            for inputs, expected_output in sorted(data.items(), key=lambda x: random.random()):
                expected_outputs = np.array([expected_output])

                self.forward_propagation(inputs)
                self.backpropagation(expected_outputs) # WRONG: need inputs: backpropagation(inputs, expected_outputs)

    def predict(self, inputs):
        self.forward_propagation(inputs)
        return self.outputs

【问题讨论】:

  • the algorithm seems to go in circles
  • 感谢您的回复。不幸的是,我尝试了很多学习率(0.05 到 0.95),结果完全相同。我以这种精确度编辑了我的帖子
  • 您可以为每个节点和每个层设置一个偏差,添加这些偏差也很常见。没有偏差就无法解决 XOR 问题,除了使用 3 个隐藏神经元,其中一个实际上充当偏差。

标签: python algorithm machine-learning neural-network


【解决方案1】:

很长一段时间以来我一直在努力,因为我不是一个伟大的人 科学家,我想确保理解这一点 程序。

你得到了我的答案。像这样继续下去,你会摇滚的!

免责声明:部分回答。我可能会随着时间改进它。

是否有调试神经网络的特定方法? (如 导致预期解决方案的预定义已知权重)

一般不会。由于权重的数量,在大多数实际情况下这几乎是不可能的。您仍然可以尝试监控神经元活动(代码中的 aggregated 变量),例如连续两次向网络发送相似的输入,看看它是否学习,即它越来越接近正确的值。

下面的反向传播算法(伪代码)是否正确?

会尝试检查。是你的吗?

这个算法应该有偏差吗?如果不是,是否需要偏差 解决异或问题?如果是,偏差应该是 1 per 神经元,每层 1 个还是每个网络 1 个?

通常每个神经元有 1 个偏差。如果你忽略它也没问题。

我的 python 实现是否正确?如果不是,是不是关于 反向传播、前向传播、偏差缺失或 其他的?

会检查。没有偏见是可以的。

作为脚注,我会推荐这本在线“书”:http://neuralnetworksanddeeplearning.com/chap1.html 有很多数学,不要把时间花在数学上,试着理解这个概念。我觉得它超级有教养。

希望对您有所帮助(有点)
pltrdy

【讨论】:

  • 谢谢,非常有动力!我确信我不会错过任何调试方法。我将尝试监控汇总值。关于偏差,上面 Jodo 的回答说解决 XOR 问题需要一个偏差,你确定我可以在没有它的情况下制作一个工作程序吗?在其他与 SO 相关的问题中,我没有找到明确的答案。伪代码来自 Virginie MATHIVET 的法语书籍《Intelligence artificielle pour les développeurs》,非常感谢您的资源,我会尽快查看!你帮了大忙!
  • 我知道偏差仅用于移动激活函数(此处为 sigmoid),但我认为在 XOR 问题中不需要它,因为我们需要 0 到 1 之间的范围输出,但我可能错了?
  • 我的直觉是,没有偏见并非不可能。我不明白它怎么可能。从理论上讲,更多的层/神经元无论如何都可以解决这个问题。尽管如此,它显然还是有用的。可能是您的设置(nlayers x hidden_​​neurons)没有偏见就无法学习。
  • 考虑到您的第二点,sigmoid 以 0 为中心,因此确实需要 shift 为 0/1 值
  • 我想今晚我会运行你的代码。我现在和你一样想要答案哈哈
猜你喜欢
  • 2012-04-18
  • 2013-03-04
  • 1970-01-01
  • 2015-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-28
  • 2012-03-14
相关资源
最近更新 更多