机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现

本文是对机器学习中遇到的后向传播算法进行理解,假设读者已经知道神经网络中的神经元的含义,激励函数的定义,也知道了后向传播算法那个传播公式等。本文主要是为了理解为什么后向传播算法中的 δ 是安照那个传播方式往后传播。

机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现_第1张图片

如上图,其中,L是神经网络的层数,a是神经元的输出, θ 是权重(参数)。
对于最后一层的神经元来说,偏差E我们可以很容易地定义:

E=12(a(L)1y)2
所以对 θ(L1)11 求偏导:
Eθ(L1)11=Ea(L)1a(L)1z(L)1z(L)1θ(L1)11

其中, z(L)1=a(L1)1θ(L1)11+a(L1)2θ(L1)12+...+a(L1)Mθ(L1)1M

在这里, δ(L)1=Ea(L)1a(L)1z(L)1

所以, Eθ(L1)11=δ(L)1z(L)1θ(L1)11=δ(L)1a(L1)1

显然,由于我们知道了 a(L)1 ,所以我们很容易就可以得出结果,即:

Eθ(L1)11=(a(L)1y)a(L)1(1a(L)1)a(L1)1

现在,让我们往后一层来看。

机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现_第2张图片

在这一层,我们要对 θ(L2)1j 求偏导,则:

Eθ(L2)1j=Ea(L1)1a(L1)1z(L1)1z(L1)1θ(L2)1j

根据我们对 δ 的定义,上式也可以写为:

Eθ(L2)1j=δ(L1)1a(L2)j

那么接下来我们的目标就是要求出 δ(L1)1

δ(L1)1=Ez(L)1z(L)1a(L1)1a(L1)1z(L1)1=Ea(L)1a(L)1z(L)1z(L)1a(L1)1a(L1)1z(L1)1=δ(L)1θ(L1)11a(L1)1(1a(L1)1)

这样我们就找到了 δ(L1)1 δ(L)1 之间的关系了。同理,我们可以得到:
δ(L1)1=δ(L)1θ(L1)12a(L1)1(1a(L1)1)......δ(L1)M=δ(L)1θ(L1)1Ma(L1)1(1a(L1)1)

以此类推,再往后一层:
机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现_第3张图片

在这一层,我们要对 θ(L3)ji 求偏导,则:

Eθ(L3)ji=Ea(L2)ja(L2)jz(L2)jz(L2)jθ(L3)ji=mM(Ez(L1)mz(L1)ma(L2)j)a(L2)jz(L2)jz(L2)jθ(L3)ji=mM(Ea(L1)ma(L1)mz(L1)mθ(L2)mj)a(L2)jz(L2)jz(L2)jθ(L3)ji=mM(δ(L1)mθ(L2)mj)a(L2)jz(L2)jz(L2)jθ(L3)ji

所以,只要我们找到每一层的 δ 就可以算出偏导数了,而每一层 δ 都可以由后一层的 δ 算出。这样递归到了最后一层(输出层)。我们就可以找到任意一层的 δ 了。然后我们就可以算出 Eθ(l)ij


现在,让我们来考虑任意一层的情况了。
机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现_第4张图片

假设 a(l)R1×M(l) 为第 l 层的输出,其中 M(l) 是第 l 层的神经元个数。
所以,

Ea(l)=δ(l+1)Θ(l)T

其中, Θ(l)RM(l)×M(l+1) 是第 l 层到第 l+1 层的权重参数矩阵。

δ(l+1)R1×M(l+1)

代表矩阵的乘法运算。

这样我们就得到了 Ea(l)R1×M(l) 。一般在代码中,它就是第 l 层的error,相当于输出层的E。

接下来我们要求 δ(l)

δ(l)=Ea(l)a(l)(1a(l))

其中, 代表矩阵对应元素相乘。

最后,我们就可以求出第 l1 层的权重参数矩阵的偏导数了。

EΘ(l1)=a(l1)Tδ(l)


最后,我们用python实现一个简单的神经网络的训练。假设我们的训练集如下图所示:
机器学习:对于反向传播算法(backpropagation)的理解以及python代码实现_第5张图片

# -*- coding: utf-8
import numpy as np

# define sigmoid function
def nonlin(x,deriv=False):
    if(deriv==True):
        return x*(1-x)

    return 1/(1+np.exp(-x))


# input dataset 总共有4组输入
X = np.array([  [0,0,1],
                [0,1,1],
                [1,0,1],
                [1,1,1] ])

# output dataset 四组输出
y = np.array([[0,1,1,0]]).T

#seed random numbers to make calculation
np.random.seed(1)

# initialize weights randomly with mean 0
#theta0 是一个3*4的参数矩阵,输入层有3个输入节点(神经元),隐藏层有4个节点(神经元),所以参数是3*4d的矩阵
theta0 = 2*np.random.random((3,4)) - 1

#theta1是一个4*1的参数矩阵,隐藏层有4个节点(神经元),输出层有1个节点(神经元)
theta1 = 2*np.random.random((4,1)) - 1

for j in xrange(60000):
    a0 = X  #a0表示第一层(输入层),a0的每一行表示一组输入数据
    a1 = nonlin(np.dot(a0,theta0)) #a0与theta0的相乘得到的就是z1,经过sigmod函数就是a1了。a1是4*4的矩阵。注意是批量运算,a1的每一行代表一组训练数据。
    a2 = nonlin(np.dot(a1,theta1)) #跟上一个语句一样的道理,a2是一个4*1的矩阵,每一行代表一组训练数据

    E = y - a2 #获得偏差E,4*1的矩阵,每一行代表一组训练数据

    if (j% 10000) == 0:
        print "Error:" + str(np.mean(np.abs(E)))

    a2_delta = E*nonlin(a2,deriv=True) #这才是点乘,对应元素相乘,a2_delta是一个4*1的矩阵,每一行代表一组训练数据
    a1_error = a2_delta.dot(theta1.T) # a1__error其实就是偏差对a1求偏导对应输出层的E,也是每一行代表一组训练数据
    a1_delta = a1_error*nonlin(a1,deriv=True)

    theta1 = theta1 + a1.T.dot(a2_delta)
    theta0 = theta0 + a0.T.dot(a1_delta)

print "output after training:"
print a2

代码参考自:http://iamtrask.github.io/2015/07/12/basic-python-network/

你可能感兴趣的:(Machine,Learning)