deeplearning系列(一)浅层神经网络

因为项目的需要,这周开始学习深度学习。为了了解深度神经网络,则需要从浅层网络学起,尤其是通过浅层神经网络的推导,掌握反向传播算法的实现原理。本文以一个3层神经网络为例,对从前向传播到反向传播的整个训练过程进行推导,并给出了python代码实现。

1. 前向传播算法

deeplearning系列(一)浅层神经网络_第1张图片
上图给出一个简单的三层神经网络,最左边一层为输入层 L1 ,中间层为隐藏层 L2 ,最右边一层为输出层 L3

本神经网络有参数 (W,b)=(W(1),b(1),W(2),b(2)) ,其中 W(l)ij 表示第 l 层第 j 个单元到第 l+1 层第 i 个单元之间的连接权值, b(l)i 表示第 l+1 层第 i 个单元的偏置项。我们用 z(l)i 表示第 l 层第 i 个单元的输入加权和,用 a(l)i 表示第 l 层第 i 个单元的激活值。则本例神经网络的计算步骤(前向传播步骤)如下:

z(2)1=W(1)11x1+W(1)12x2+b(1)1,a(2)1=f1(z(2)1)z(2)2=W(1)21x1+W(1)22x2+b(1)2,a(2)2=f1(z(2)2)z(2)3=W(1)31x1+W(1)32x2+b(1)3,a(2)3=f1(z(2)3)z(2)4=W(1)41x1+W(1)42x2+b(1)4,a(2)4=f1(z(2)4)z(2)5=W(1)51x1+W(1)52x2+b(1)5,a(2)5=f1(z(2)5)z(3)1=W(2)11a(2)1+W(2)12a(2)2+W(2)13a(2)3+W(2)14a(2)4+W(2)15a(2)5+b(2)1z(3)2=W(2)21a(2)1+W(2)22a(2)2+W(2)23a(2)3+W(2)24a(2)4+W(2)25a(2)5+b(2)2hW,b(x)=a(3)=f2(z(3))

其中 隐藏层的激活函数为双曲正切函数(tanh):
f1(z)=tanh(z)=ezezez+ez

输出层的激活函数为softmax函数,该函数将一个包含任意实数值的向量转化为包含取值范围为[0,1]的实数且实数的和为1的向量。在本例中 f2(z(3)) 所做的转换为:
[z1,z2]>[ez1kezk,ez2kezk]

转换后向量中的每个元素可以理解神经网络输出该类别的概率。使用这个函数的好处是可以方便地将模型推广到包含多个输出(大于等于三个)的情况。


前向传播过程的矩阵化表示为:

z(2)=W(1)x+b(1)a(2)=f1(z(2))z(3)=W(2)a(2)+b(2)hW,b(x)=a(3)=f2(z(3))


2. 反向传播算法

给定一个样本集 {(x(1),y(1)),...,(x(m),y(m))} ,包含 m 个样例,表示成矩阵的形式为 {X,y} ,其中 X 为2*m大小的矩阵,每一列为一个样例。使用softmax函数作为输出层激活函数的神经网络,目标函数可以表示为:

J(W,b)=i=1mk=1K1{y(i)=k}log(ezinezn)

最小化误差相当于最大化预测正确的概率。

然后可以通过批量梯度下降法最小化目标函数来求得神经网络的最优参数 (W,b) ,参数更新的关键是求偏导数,梯度下降法每次迭代如下公式对参数 (W,b) 进行更新:

W(l)ij=W(l)ijαJ(W,b)W(l)ijb(l)i=b(l)iαJ(W,b)b(l)i

其中 α 学习率。对 (W,b) 偏导数求解可以进一步转化为:
J(W,b)W(l)ij=J(W,b)s(l)is(l)iW(l)ij=δ(l)ia(l1)jJ(W,b)b(l)i=δ(l)i

a(l1)j 可以通过前向传播有效求解,求偏导数的问题也就转化为如何求 残差 δ(l)i 。而残差可以通过 反向传播算法有效地计算。可以证明对于softmax输出情况下,输出层的残差可以表示为:
δ(3)i=(yisoftmax(z(3)))

输出层之前的几层的残差则需要通过反向传播算法求出。反向传播算法类似于动态规划的思想,当前层( l )的残差可以通过下一层( l+1 )的残差推导得出,具体过程可以由下图表示:
deeplearning系列(一)浅层神经网络_第2张图片


反向传播过程矩阵化表示为:

δ(3)=(ysoftmax(z(3)))δ(2)=(W(2))Tδ(3)(1tanh2(z(2)))J(W,b)W(2)=δ(3)(a(2))TJ(W,b)b(2)=δ(3)J(W,b)W(1)=δ(2)xTJ(W,b)b(1)=δ(2)


3. 权重衰减

神经网络因其参数多,对数据的表达能力强,因此很容易过拟合。为了防止过拟合,措施之一是在原目标函数的基础上加上一项正则化项,也称为权重衰减项,用来减小权重的幅度,防止过拟合。需要注意的是在权重衰减项里面不使用偏置项 b(l) ,若对偏置项也施加和 W(l) 同样的约束,最后的效果和不添加任何正则化项的效果相同。权重衰减参数 λ 控制两项之间的相对重要性。

J(W,b)=[i=1mk=1K1{y(i)=k}log(ezinezn)]+λ/2l=12||W(l)||2

加上权重衰减项之后,反向传播的过程不受任何影响,仅需要在反向传播过程结束后,在偏导数项中加入权重衰减项的偏导。


完整的反向传播过程矩阵化表示为:

δ(3)=(ysoftmax(z(3)))δ(2)=(W(2))Tδ(3)(1tanh2(z(2)))J(W,b)W(2)=δ(3)(a(2))T+λW(2)J(W,b)b(2)=δ(3)J(W,b)W(1)=δ(2)xT+λW(1)J(W,b)b(1)=δ(2)


4. python代码实现

根据前向传播和反向传播的矩阵化表示,批量梯度下降法的一次迭代的步骤的代码如下:

        #Parameter setup
        nn_input_dim = 2
        nn_hdim = 3
        nn_output_dim = 2
        epsilion = 0.01 #learning rate
        reg_lambda = 0.01 #regularization parameter

        #Initialize the parameter to random values
        W1 = np.random.randn(nn_hdim, nn_input_dim)/np.sqrt(nn_input_dim)
        b1 = np.zeros((nn_hdim, 1))
        W2 = np.random.randn(nn_output_dim, nn_hdim)/np.sqrt(nn_hdim)
        b2 = np.zeros((nn_output_dim, 1))

        #Forward propagation
        z2 = W1.dot(X) + b1
        a2 = np.tanh(z2)
        z3 = W2.dot(a2) + b2
        exp_scores = np.exp(z3)
        probs = exp_scores/np.sum(exp_scores, axis=0, keepdims=True)

        # Back propagation
        delta3 = probs
        delta3[y, range(num_examples)] -= 1
        dW2 = delta3.dot(a2.T)
        db2 = np.sum(delta3, axis=1, keepdims=True)
        delta2 = W2.T.dot(delta3)*(1-np.power(a2, 2))
        dW1 = delta2.dot(X)
        db1 = np.sum(delta2, axis=1, keepdims=True)

        # add regularization term
        dW2 += reg_lambda*W2
        dW1 += reg_lambda*W1

        # gradient descent parameter update
        W1 += -epsilion*dW1
        b1 += -epsilion*db1
        W2 += -epsilion*dW2
        b2 += -epsilion*db2

对于下面这样数据库,使用隐藏层包含3个单元的网络训练出的结果为:
deeplearning系列(一)浅层神经网络_第3张图片
deeplearning系列(一)浅层神经网络_第4张图片
完整的python代码地址为:
https://github.com/dumengnanbuaa/neuralnetwork_python

参考内容:
1.https://github.com/dennybritz/nn-from-scratch/blob/master/nn-from-scratch.ipynb
2.http://ufldl.stanford.edu/wiki/index.php/UFLDL_Tutorial
3.台湾大学机器学习技法课程

你可能感兴趣的:(deep-learning)