【发布时间】:2017-07-12 16:41:29
【问题描述】:
我想实现一个 MLP(多层感知器)来解决 XOR 问题。因为我不是一个伟大的科学家,所以我很长时间以来一直在努力,我想确保理解这个程序的每一行。
我将从问题开始:
- 是否有调试神经网络的特定方法? (例如导致预期解决方案的预定义已知权重)
- 以下反向传播算法(伪代码)正确吗?
- 偏差应该在这个算法中吗?如果不是,那么解决 XOR 问题是否需要偏差?如果是,偏差应该是每个神经元 1 个、每层 1 个还是每个网络 1 个?
- 我的 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