反向传播示例代码全解析

四个基本公式

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


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


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


(4).网络的代价函数相对于权重的改变速率的等式:
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为什么直接使用了激活输出减去目标值,其实这一项是代价函数的导数项,并且此处使用了平方代价函数。也就是说对于一个样本来说有

C x = 1 2 | | y a L | | 2

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

附sigmod函数求导

g ( x ) = 1 1 + e x


g ( x ) = ( 1 + e x ) 2 ( e x )

g ( x ) = e x ( 1 + e x ) 2

g ( x ) = 1 1 + e x e x 1 + e x

g ( x ) = ( 1 + e x 1 + e x e x 1 + e x ) e x 1 + e x


g ( x ) = ( 1 g ( x ) ) g ( x )

猜你喜欢

转载自blog.csdn.net/u011031257/article/details/80925170