反向传播示例代码全解析

四个基本公式

(1). 输出层错误量的等式:
δLj=CaLjσ(zLj) δ j L = ∂ C ∂ a j L σ ′ ( z j L )


(2).依据下一层错误量 δl+1 δ l + 1 获取错误量 δl δ l 的等式:
δl=((wl+1)Tδl+1)σ(zl) δ l = ( ( w l + 1 ) T δ l + 1 ) ⊙ σ ′ ( z l )


(3).网络的代价函数相对于偏置的改变速率的等式:
Cblj=δlj ∂ C ∂ b j l = δ j l


(4).网络的代价函数相对于权重的改变速率的等式:
Cwljk=al1kδlj ∂ C ∂ w j k l = a k l − 1 δ j l

示例代码

class Network(object):
...
    def backprop(self, x, y):#x,y是矩阵形式,可查看numpy的array
            """建立临时变量nabla_b和nabla_w来保存偏置矩阵和权重举证初识都为0矩阵"""
            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] # 存放各层激活输出值的列表,第一项存入输入矩阵
            zs = [] # 存放各层加权输入的列表
            for b, w in zip(self.biases, self.weights):#遍历各层权重和偏置
                z = np.dot(w, activation)+b #加权输入矩阵
                zs.append(z)#存入列表
                activation = sigmoid(z)#激活输出矩阵
                activations.append(activation)#存入列表
            #反向传播
            delta = self.cost_derivative(activations[-1], y) * \
                sigmoid_prime(zs[-1])#此处delta为输出层的错误量根据公式(1)得出,为何是cost_derivative之后会解释
            nabla_b[-1] = delta #根据公式(3)
            nabla_w[-1] = np.dot(delta, activations[-2].transpose())#根据公式(4)
            for l in xrange(2, self.num_layers):
                z = zs[-l]
                sp = sigmoid_prime(z)#对z求导,激活函数是sigmod
                delta = np.dot(self.weights[-l+1].transpose(), delta) * sp#根据公式(2)
                nabla_b[-l] = delta#公式(3)
                nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
            return (nabla_b, nabla_w)#公式(4)

    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)

def sigmoid(z):
    """The sigmoid function."""
    return 1.0/(1.0+np.exp(-z))

def sigmoid_prime(z):#可查阅求导公式
    """Derivative of the sigmoid function."""
    return sigmoid(z)*(1-sigmoid(z))

可以看出该代码充分利用了这4个公式来体现反向传播算法的过程,这个反向我觉得就是先利用公式(1)计算输出层的错误量,再利用公式(3)、(4)计算该层的偏置和权重的改变速率。有了最后一层的各项数据,再利用公式(2)反向传播(所以我觉得这个公式很重要,要不然为什么叫做反向传播)计算上一层一直到得到所有权重和偏置的更新量为止。值得注意的是这里cost_derivative为什么直接使用了激活输出减去目标值,其实这一项是代价函数的导数项,并且此处使用了平方代价函数。也就是说对于一个样本来说有

Cx=12||yaL||2 C x = 1 2 | | y − a L | | 2

对激活输出a求导其实就是 aLy a L − y 也就是函数cost_derivative定义的那样

附sigmod函数求导

g(x)=11+ex g ( x ) = 1 1 + e − x


g(x)=(1+ex)2(ex) g ′ ( x ) = − ( 1 + e − x ) − 2 ( − e − x )

g(x)=ex(1+ex)2 g ′ ( x ) = e − x ( 1 + e − x ) 2

g(x)=11+exex1+ex g ′ ( x ) = 1 1 + e − x e − x 1 + e − x

g(x)=(1+ex1+exex1+ex)ex1+ex g ′ ( x ) = ( 1 + e − x 1 + e − x − e − x 1 + e − x ) e − x 1 + e − x


g(x)=(1g(x))g(x) g ′ ( x ) = ( 1 − g ( x ) ) g ( x )

你可能感兴趣的:(神经网络与深度学习,反向传播,公式与代码)