Notes on NNDL(Neural Networks and Deep Learning)

本文详细解释了反向传播算法的基本原理,包括代价函数的定义、反向传播的四个基本方程及其推导过程,并提供了具体的算法实现步骤及Python代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 关于代价函数的假设:
    (1) 代价函数可以被写成一个 在每个训练样本 x上的代价函数Cx的均值C=1nxCx. 反向传播实际上是对一个独立的训练样本计算了CxωCxb. 然后通过在所有训练样本上进行平均化得到CωCb. 实际上,有了这个假设,我们会认为训练样本x已经被固定住了,丢掉其下标,将代价函数Cx看作C.
    (2) 代价可以写成神经网络输出的函数costC=C(aL)

  2. 反向传播的四个基本方程

    反向传播其实是对权重和偏差变化影响代价函数过程的理解,最终的目的就是计算偏导数CωljkCblj. 引入一个中间量,δlj,定义它为lth层第jth个神经元上的误差.

    假设,我们对lth层的第jth个神经元的操作进行一些变化,比如,在神经元的带权输入上增加很小的变化Δzlj,使得神经元输出由δ(zlj)变为δ(zlj+Δzlj). 这个变化将会向后面的层进行传播,最终导致整个代价函数产生CzljΔzlj的变化(可以从微分的数学定义进行验证). 此时,如果Czlj有一个很大的值(或正或负),则可以通过选择与Czlj符号相反的Δzlj来降低代价。相反的,如果Czlj接近0,那么无法通过更改Δzlj来降低代价,此时可以认为神经元已经很接近最优了(这两种假设只能在Δzlj很小的时候才能够满足)。因此,可以有一种启发式的认识:Czlj是神经元误差的度量。根据以上这些描述,定义l层的第jth个神经元上的误差δlj为:

    δljCzlj

    这样,我们就可以使用δl表示关联于l层的误差向量。反向传播算法会告诉我们如何计算每层的δl,然后将这些误差和最终我们需要的量CωljkCblj联系起来.
    • 输出层误差的方程

      δLj=CaLjσ(zLj)

      这是一个很自然的表达式。右边第一项CaLj表示代价随着jth输出激活值的变化而变化的速度。如果C不太依赖一个特定的输出神经元j,那么δLj就会很小。第二项σ(zLj)刻画了在zLj处激活函数σ变化的速度.

      证明:

      δLj=CzLj=kCaLkaLkzLj
      ,这里的求和是对输出层中的所有神经元k进行的. 当然,第k个神经元的输出激活aLk只依赖于第j个神经元的加权输入(当k==j), 因此,当kj时,zLkzLj消失。从而有:
      δLj=CzLj=kCaLkaLkzLj=CaLjaLjzLj
      .
      同时,我们有aLj=σ(zLj), 则aLjzLj=σ(zLj). 最终我们有:
      δLj=CaLjσ(zLj)
      证毕.
    • 使用下一层的误差δl+1来表示当前层的误差δl

      δL=((ωL+1)TδL+1)σ(zL)

      其中(ωL+1)T(L+1)th层的权重矩阵ωL+1的转置. 有了这个方程与第一个方程,我们就可以计算任何层的误差了:首先使用第一个方程计计算δL,然后使用第二个方程来计算δL1,然后不断使用第二个方程,就可以一步一步地反向传播完整个网络.
      证明:因为δLj=CzLj,则有δL+1k=CzL+1k
      δLj=CzLj=kCzL+1kzL+1kzlj=kzL+1kzLjδL+1k

      根据定义,我们有
      zL+1kjωL+1kj+bL+1k=jωL+1kjσ(zLJ)+bL+1k
      则可以得到
      zL+1kzLj=ωL+1kjσ(zLj)

      因此,
      δLj=kωL+1kjδL+1kσ(zLj)

      证毕.
    • 代价函数关于网络中任意偏差的改变率

      CbLj=δLj
    • 代价函数关于任何一个权重的改变率

      CωLjk=aL1kδLj
  3. 反向传播算法
    反向传播方程给出了一种计算代价函数梯度的方法,其显示描述如下:
    (1) 输入x:为输入层设置对应的激活值aL
    (2) 前向传播:对每个l=2,3,...,L, 计算相应的Zl=ωlal1+blal=σ(zl)
    (3) 输出层误差δL: 计算向量δL=aCσ(zL)
    (4) 反向误差传播:对每个l=L1,L2,...,2, 计算δl=((ωl+1)Tδl+1)σ(zl)
    (5) 输出: 代价函数的梯度由Cωljk=al1kδljCblj=δlj.

  4. 反向传播代码注释

    def backprop(self, x, y):
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
# 前向传播
        activation = x
        activations = [x] # list to store all the activations, layer by layer
        zs = [] # list to store all the z vectors, layer by layer
        for b, w in zip(self.biases, self.weights):
            z = np.dot(w, activation)+b # weighted input
            zs.append(z)
            activation = sigmoid(z) $ activations
            activations.append(activation)
# 反向传播
        delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(zs[-1]) # cost_derivative是代价函数对激活值的导数. 此处的delta是第L层的输出误差.
        nabla_b[-1] = delta # 第L层的代价相对于偏置的导数
        nabla_w[-1] = np.dot(delta, activations[-2].transpose()) # 第L层的代价相对于权重的导数

        #进行反向传播,计算L-1,L-2,...,2的导数
        for l in xrange(2, self.num_layers):
            z = zs[-l] # 加权输入
            sp = sigmoid_prime(z) # 加权输入的导数
            delta = np.dot(self.weights[-l+1].transpose(), delta) * sp # 当前层的delta(输出误差)
            nabla_b[-l] = delta #当前层的导数(相对于偏置)
            nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())#当前层的导数(相对于权重)
        return (nabla_b, nabla_w)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值