理解 Michael Nielsen 的反向传播代码
Understanding Michael Nielsen's backpropagation code
我正在尝试 understand/run Michael Neilsen 的神经网络和深度学习第 2 章中关于反向传播的代码:http://neuralnetworksanddeeplearning.com/chap2.html#the_code_for_backpropagation。
在向后传递开始时,它有:
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
前向传递创建 activations
列表,其中 activations[i]
包含层 i
中神经元的激活向量。所以activations[-1]
是最后一层。 y
是所需的输出。
cost_derivative
定义为:
def cost_derivative(self, output_activations, y):
"""Return the vector of partial derivatives \partial C_x /
\partial a for the output activations."""
return (output_activations-y)
所以第一行输出一个与我们的输出层形状相同的向量。所以我的问题是第 4 行的 np.dot
应该如何工作?我的理解是 activations[-2]
是倒数第二层神经元激活的向量,它可以有任意数量的神经元,所以我不确定我们如何点积它(或其t运行spose) 与 delta,它具有输出层的形状。
我 运行 代码 (https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network.py) 添加了一些调试行来尝试理解这一点,但它似乎不起作用:
>>> from network import *; net = Network([2,1,2])
>>> net.backprop([1,2], [3,4])
Activations[0]
[1, 2]
Activations[1]
[[ 0.33579893]]
Activations[2]
[[ 0.37944698]
[ 0.45005939]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<snip>/neural-networks-and-deep-learning/src/network.py", line 117, in backprop
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
ValueError: shapes (2,2) and (1,1) not aligned: 2 (dim 1) != 1 (dim 0)
activations
看起来完全符合我的预期 - 2 次激活,然后 1 次,然后 2 次。失败发生在我不清楚的线上,并且如我所料失败。但是,大概这本书中的代码已经过测试(这本书很棒),我一定是做错了什么。我正在编写一个独立的实现并遇到了同样的问题,所以我希望能够将这段代码分开来弄清楚 - 但我无法弄清楚它应该如何工作,或者为什么它对作者有效.
对于我在这里遗漏的任何见解,我将不胜感激。谢谢! :)
为什么反向传播中的形状匹配
假设网络架构为[...,N,M]
,即最后一层输出大小为M
的向量,前一层输出大小为N
的向量(让我们关注最后两层并忽略其余部分)。 N
和 M
可以是任意的。另外,让我们忽略批处理,就像您的问题一样:我们只提供一个输入和一个标签。
在这种情况下,最后一个权重矩阵,即 self.weights[-1]
,将具有 [M,N]
形状,因此必须是 nabla_w[-1]
才能正确执行更新。现在:
delta
将具有 [M,1]
形状(对应于输出)。
activations[-2]
将具有 [N,1]
形状,因此转置为 [1,N]
.
- 他们的点积产生
[M,1]*[1,N] -> [M,N]
形状,这正是我们需要的。
为什么你的测试 运行 失败了
因为在 numpy 中形状 (2,)
与 [1,2]
或 [2,1]
不同:
>>> np.array([1, 2]).shape
(2,)
网络架构区分 x
和 y
的行和列,您必须提供两者的正确形状才能工作。否则,你会得到意想不到的广播和形状不匹配。试试这个例子看看它的实际效果:
net = Network([2,1,2])
x = np.array([1, 2]).reshape([2, 1]) # one example of size 2
y = np.array([3, 4]).reshape([2, 1]) # one example of size 2
net.backprop(x, y)
我正在尝试 understand/run Michael Neilsen 的神经网络和深度学习第 2 章中关于反向传播的代码:http://neuralnetworksanddeeplearning.com/chap2.html#the_code_for_backpropagation。
在向后传递开始时,它有:
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
前向传递创建 activations
列表,其中 activations[i]
包含层 i
中神经元的激活向量。所以activations[-1]
是最后一层。 y
是所需的输出。
cost_derivative
定义为:
def cost_derivative(self, output_activations, y):
"""Return the vector of partial derivatives \partial C_x /
\partial a for the output activations."""
return (output_activations-y)
所以第一行输出一个与我们的输出层形状相同的向量。所以我的问题是第 4 行的 np.dot
应该如何工作?我的理解是 activations[-2]
是倒数第二层神经元激活的向量,它可以有任意数量的神经元,所以我不确定我们如何点积它(或其t运行spose) 与 delta,它具有输出层的形状。
我 运行 代码 (https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network.py) 添加了一些调试行来尝试理解这一点,但它似乎不起作用:
>>> from network import *; net = Network([2,1,2])
>>> net.backprop([1,2], [3,4])
Activations[0]
[1, 2]
Activations[1]
[[ 0.33579893]]
Activations[2]
[[ 0.37944698]
[ 0.45005939]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<snip>/neural-networks-and-deep-learning/src/network.py", line 117, in backprop
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
ValueError: shapes (2,2) and (1,1) not aligned: 2 (dim 1) != 1 (dim 0)
activations
看起来完全符合我的预期 - 2 次激活,然后 1 次,然后 2 次。失败发生在我不清楚的线上,并且如我所料失败。但是,大概这本书中的代码已经过测试(这本书很棒),我一定是做错了什么。我正在编写一个独立的实现并遇到了同样的问题,所以我希望能够将这段代码分开来弄清楚 - 但我无法弄清楚它应该如何工作,或者为什么它对作者有效.
对于我在这里遗漏的任何见解,我将不胜感激。谢谢! :)
为什么反向传播中的形状匹配
假设网络架构为[...,N,M]
,即最后一层输出大小为M
的向量,前一层输出大小为N
的向量(让我们关注最后两层并忽略其余部分)。 N
和 M
可以是任意的。另外,让我们忽略批处理,就像您的问题一样:我们只提供一个输入和一个标签。
在这种情况下,最后一个权重矩阵,即 self.weights[-1]
,将具有 [M,N]
形状,因此必须是 nabla_w[-1]
才能正确执行更新。现在:
delta
将具有[M,1]
形状(对应于输出)。activations[-2]
将具有[N,1]
形状,因此转置为[1,N]
.- 他们的点积产生
[M,1]*[1,N] -> [M,N]
形状,这正是我们需要的。
为什么你的测试 运行 失败了
因为在 numpy 中形状 (2,)
与 [1,2]
或 [2,1]
不同:
>>> np.array([1, 2]).shape
(2,)
网络架构区分 x
和 y
的行和列,您必须提供两者的正确形状才能工作。否则,你会得到意想不到的广播和形状不匹配。试试这个例子看看它的实际效果:
net = Network([2,1,2])
x = np.array([1, 2]).reshape([2, 1]) # one example of size 2
y = np.array([3, 4]).reshape([2, 1]) # one example of size 2
net.backprop(x, y)