美文网首页我爱编程程序员
通过代码理解反向传播(backpropagation)

通过代码理解反向传播(backpropagation)

作者: nicktming | 来源:发表于2018-06-22 08:58 被阅读27次

    代码和文档在:https://github.com/nicktming/code/tree/dev/machine_learning/backpropagation

    前言

    继上篇用代码一步步理解梯度下降和神经网络(ANN)),今天这篇的目的主要是通过一个例子来理解反向传播是怎么一回事?

    复习

    前文中已经分析过了单层神经网络(没有隐藏层)的时候如何通过梯度下降法改变参数来使得最终定义的cost_function越来越小.

    单层的时候或许比较好理解,毕竟直接求导就可以求出cost_function关于每个参数的偏导,对于多层的时候,面对那么每一层的每个参数,他们是如何往回传递错误信息的?如果每次都要从头到晚求一遍?是不是很麻烦?想到这里估计脑子就有点乱了,而且直接看公式也不是那么好明白.

    所以我先给出答案哈,改变每一层的参数,都是需要求出cost_function关于每一层每个参数的偏导的,因为这样我才知道你对cost_function的影响有多大?如果你有点看不懂我这里说的,建议先看一下我的前一篇文章用代码一步步理解梯度下降和神经网络(ANN)).至于要怎么求出来的,首先肯定不是从头到晚又求一次,我们先不看公式,先通过自己写的一个例子来看看到底是怎么一个情况?(我高中数学老师的一句话:如果看不懂,那么就把抽象问题具体化,通俗一点就是用例子)

    例子: 2-layer ANN

    图中是一个2层的神经网络,和数组的定义
    激励函数采用sigmoid,cost_function采用最小平方

    Untitled Diagram(1).png
    CodeCogsEqn(40).png
    前向传递forward
    CodeCogsEqn(41).png
    CodeCogsEqn(42).png
    CodeCogsEqn(4).gif

    对应代码

    # training samples 2 inputs and 2 outputs
    X = np.random.rand(m, 2)
    Y = np.random.rand(m, 2)
    
    #layer 2
    W2 = np.ones((2, 3))
    b2 = np.ones((1, 3))
    in2 = np.dot(X, W2) + b2
    out2 = sigmoid(in2)
    
    #layer 3
    W3 = np.ones((3, 2))
    b3 = np.ones((1, 2))
    in3 = np.dot(out2, W3) + b3
    out3 = sigmoid(in3)
    
    #initial cost
    cost = cost_function(out3, Y) 
    print("start:", cost)
    
    反向传播

    反向传播主要是求导,求cost_function关于各个参数的偏导.

    CodeCogsEqn(9).gif
    CodeCogsEqn(10).gif

    先解释一件事情,为什么求参数的偏导,上面求的是cost_function关于in的偏导呢?你可以看一下前向传播中的in的公式,如果我们求出了cost_function关于in的偏导,就可以cost_function求出任意参数的偏导.

    那既然我们已经确定了cost_functionin偏导的作用,那你观察上面的in2in3之间的关联,in2是如何通过in3可以求出来的.

    CodeCogsEqn(12).gif
    CodeCogsEqn(11).gif

    在得到in2in3的关系了后,明显在所有隐藏层中都可以运用这个公式.自然而然输出层的in3是第一步需要求的,因为后面所有隐藏层是依赖于上一层的cost_functionin偏导.

    在明白了如何求得cost_functionin偏导后,可以根据in的前向传递公式就可以求得关于此层中in关于参数的偏导进而就可以得到cost_function关于这个参数的偏导,用矩阵表达式就是上图中的公式.

    对应代码:

        derivative_c_out3 = np.subtract(out3, Y) / m
        derivative_out3_in3 = derivative_sigmoid(in3)
        derivative_c_in3 = np.multiply(derivative_c_out3, derivative_out3_in3)
        #find derivative of cost function to W3 and b3 in layer3
        dw3 = np.dot(out2.T, derivative_c_in3)
        db3 = np.sum(derivative_c_in3, axis=0)
    
        #find derivative of cost function to in2 in layer2
        derivative_out2_in2 = derivative_sigmoid(in2)
        derivative_c_in2 = np.multiply(np.dot(derivative_c_in3, W3.T), derivative_out2_in2)
        #find derivative of cost function to W2 and b2 in layer2
        dw2 = np.dot(X.T, derivative_c_in2)
        db2 = np.sum(derivative_c_in2, axis=0)
    
        #update all variables
        W3 = W3 - step * dw3
        W2 = W2 - step * dw2
        b3 = b3 - step * db3
        b2 = b2 - step * db2
    
    整体代码

    目标是让cost_function的值小于0.1

    import numpy as np
    
    def sigmoid(x):
        return 1/(1+np.exp(-x))
    
    def derivative_sigmoid(x):
        return np.multiply(1 - sigmoid(x), sigmoid(x))
    
    def cost_function(yo, Y):
        return 1./(2*m) * np.sum(np.square(np.subtract(yo, Y)))
    
    #num of samples and learning rate
    m = 10
    step = 0.01
    
    # training samples 2 inputs and 2 outputs
    X = np.random.rand(m, 2)
    Y = np.random.rand(m, 2)
    
    #layer 2
    W2 = np.ones((2, 3))
    b2 = np.ones((1, 3))
    in2 = np.dot(X, W2) + b2
    out2 = sigmoid(in2)
    
    #layer 3
    W3 = np.ones((3, 2))
    b3 = np.ones((1, 2))
    in3 = np.dot(out2, W3) + b3
    out3 = sigmoid(in3)
    
    #initial cost
    cost = cost_function(out3, Y) 
    print("start:", cost)
    
    cnt = 0;
    while not cost < 0.1 :
        #find derivative of cost function to in2 in layer3
        derivative_c_out3 = np.subtract(out3, Y) / m
        derivative_out3_in3 = derivative_sigmoid(in3)
        derivative_c_in3 = np.multiply(derivative_c_out3, derivative_out3_in3)
        #find derivative of cost function to W3 and b3 in layer3
        dw3 = np.dot(out2.T, derivative_c_in3)
        db3 = np.sum(derivative_c_in3, axis=0)
    
        #find derivative of cost function to in2 in layer2
        derivative_out2_in2 = derivative_sigmoid(in2)
        derivative_c_in2 = np.multiply(np.dot(derivative_c_in3, W3.T), derivative_out2_in2)
        #find derivative of cost function to W2 and b2 in layer2
        dw2 = np.dot(X.T, derivative_c_in2)
        db2 = np.sum(derivative_c_in2, axis=0)
    
        #update all variables
        W3 = W3 - step * dw3
        W2 = W2 - step * dw2
        b3 = b3 - step * db3
        b2 = b2 - step * db2
    
        # forward to get new out3 with X
        in2 = np.dot(X, W2) + b2
        out2 = sigmoid(in2)
        in3 = np.dot(out2, W3) + b3
        out3 = sigmoid(in3)
    
        # get new cost with new out3 with X
        cost = cost_function(out3, Y)
        if cnt % 100 == 0:
            print("cost:", cost)
        cnt += 1
    
    #output how many times used to minimize cost
    print("end:", cost)
    print("cnt:", cnt)
    

    结果:

    image.png

    公式

    输出层:


    CodeCogsEqn(15).gif

    隐藏层:


    CodeCogsEqn(14).gif

    最后用一张网上的图来总结:


    WechatIMG435.jpeg

    画图花了不少时间,如果对你有用点个赞哈.

    参考:

    http://www.hankcs.com/ml/back-propagation-neural-network.html

    相关文章

      网友评论

        本文标题:通过代码理解反向传播(backpropagation)

        本文链接:https://www.haomeiwen.com/subject/vyyhyftx.html