机器学习 Week3 —— 神经网络,反向传播算法

2019-05-07  本文已影响0人  Hardy_

之前介绍了用于回归问题的模型:线性回归模型,和用于分类问题的算法:Logistic 回归,使用这两种算法,我们可以很好地匹配线性的特征,而如果想要得到非线性的模型,我们就需要手动加入非线性的特征。比如在 Logistic 回归中,我们可以加入非线性特征 x_1^2,x_1^2x_2,x_2^2等等,但是这样大多数情况下是不实用的,因为即使对于只有x_1,x_2的情况,想要加入非线性特征的话就可以加x_1^2,x_2^2,x_1x_2,x_1^3...等等非常多的特征,这样会导致计算量急剧增大,难以实现。而如果是处理图像的话,一张图片的每个像素都是一个特征,在这么多的特征的基础上再加入非线性特征,计算量是无法想象的。因此我们需要引入新的机器学习模型——神经网络模型(Neural Networks)
先简单介绍一下神经网络模型的背景:它最初是用来模拟大脑的,在上世纪80年代很流行,后来衰退了,但是最近又风靡起来,成为很受欢迎的模型,有很多应用,主要的原因是算力起来了,能够支持神经网络模型了。

神经网络模型

一个简单的神经网络模型包括输入层、隐藏层、输出层:
\begin{bmatrix}x_0 \newline x_1 \newline x_2 \newline x_3\end{bmatrix}\rightarrow\begin{bmatrix}a_1^{(2)} \newline a_2^{(2)} \newline a_3^{(2)} \newline \end{bmatrix}\rightarrow h_\theta(x)
最后输出层的h_{\theta}(x)就是之前所说的假设函数
每层的运算过程使用的是前向传播(Forward Propagation),由输入层到隐藏层的计算过程如下:
\begin{align*} a_1^{(2)} = g(\Theta_{10}^{(1)}x_0 + \Theta_{11}^{(1)}x_1 + \Theta_{12}^{(1)}x_2 + \Theta_{13}^{(1)}x_3) \newline a_2^{(2)} = g(\Theta_{20}^{(1)}x_0 + \Theta_{21}^{(1)}x_1 + \Theta_{22}^{(1)}x_2 + \Theta_{23}^{(1)}x_3) \newline a_3^{(2)} = g(\Theta_{30}^{(1)}x_0 + \Theta_{31}^{(1)}x_1 + \Theta_{32}^{(1)}x_2 + \Theta_{33}^{(1)}x_3) \newline \end{align*}
其中上标(2)代表是第二层,g(x)代表Logistic函数,\theta叫做权重(Weights)或者参数,可以看到隐藏层中结点a_1^{(2)},a_2^{(2)},a_3^{(2)}的值都是用输入层中的结点x_0,x_1...乘以一个\Theta^{(1)}的矩阵,再使用一个Logistic函数得到的。
而最后的输出层也是类似地通过将隐藏层中的结点分别乘以参数求和,然后使用Logistic函数得到的:
h_\Theta(x) = a_1^{(3)} = g(\Theta_{10}^{(2)}a_0^{(2)} + \Theta_{11}^{(2)}a_1^{(2)} + \Theta_{12}^{(2)}a_2^{(2)} + \Theta_{13}^{(2)}a_3^{(2)})
可以看到如果某一层有s_j个神经元而下一层有s_{j+1}个神经元,那么此时\theta就是一个s_{j+1}*(s_j+1)的矩阵,之所以后面要加一是因为我们每一层都要额外加一个偏置(Bias)结点a_0^{(i)}进去
下图就是刚刚构建的一个最简单的神经网络的结构,输入层有三个结点,隐藏层有三个结点,输出层有一个结点,隐藏层的每个结点都是由输入层的每个结点共同运算得到的,输出层的结点也是由隐藏层的每个结点共同运算得到的:

Neural network with one hidden layer
当然,除了这种结构,你也可以设计其他的神经网络模型的结构,比如多个隐藏层,在隐藏层中设置更多结点,等等,更复杂的结构可以得到更复杂的非线性的特征。不管是什么结构,你只需要记住如何使用前向传播算法计算得到每一层的值,那么这些不同的结构都是万变不离其宗
刚刚所介绍的模型中输出层都只有一个结点,如果我们要在多分类(One-vs-All)问题中应用神经网络模型,可以在输出层设置n个结点:
Multiple output units
最终输出层的结果中,对于某一类,对应的单元为1,其余单元为0,比如四分类:
四分类

神经网络模型的损失函数

神经网络模型的损失函数和 Logistic 回归的损失函数基本上是一样的,只是求和多了一些,因为输出层可能有不止一个输出h_{\theta}(x),并且在正则化的时候考虑了所有层中的参数\Theta,损失函数为:
J(\Theta) = - \frac{1}{m} \sum_{i=1}^m \sum_{k=1}^K \left[y^{(i)}_k \log ((h_\Theta (x^{(i)}))_k) + (1 - y^{(i)}_k)\log (1 - (h_\Theta(x^{(i)}))_k)\right] + \frac{\lambda}{2m}\sum_{l=1}^{L-1} \sum_{i=1}^{s_l} \sum_{j=1}^{s_{l+1}} ( \Theta_{j,i}^{(l)})^2
其中,l是指神经网络模型中的第几层,L是指总的层数,s_l指第l层中的单元总数(不包含偏置单元),k指输出层的结点
其实这个损失函数的公式就是将输出层中的所有h_{\theta}(x)的损失求和,正则化的部分就是将所有的参数\Theta平方求和

反向传播算法(Back Propagation,BP)

有了损失函数之后,下一步就是使用算法最小化损失函数J(\Theta),以得到最优的参数\Theta,比如在线性回归和 Logistic 回归中,我们使用的是梯度下降法。但是梯度下降法涉及到计算损失函数的偏导数,线性回归和 Logistic 回归中的损失函数的偏导数可以直接计算,但是要计算神经网络模型的偏导数\dfrac{\partial}{\partial \Theta_{i,j}^{(l)}}J(\Theta),我们就需要使用一种算法:反向传播算法。下面介绍一下使用反向传播算法计算偏导数的流程。
首先,给定训练集\lbrace (x^{(1)}, y^{(1)}) \cdots (x^{(m)}, y^{(m)})\rbrace之后,对于每组数据(x^{(t)},y^{(t)}),利用前向传播算法得到每一层的结果a^{(l)},之后,对于输出层a^{(L)},计算:
\delta^{(L)}=a^{(L)}-y^{(t)}
L指输出层的层数,可以看出这个式子计算的就是神经网络最后的输出结果和给定的训练集的y^{(t)}的差值。接下来,要得到上一层的\delta^{(l)},我们就需要用到下面的方程,可以让我们从右到左反向计算\delta^{(L-1)},\delta^{(L-2)}一直到\delta^{(2)}
\delta^{(l)} = ((\Theta^{(l)})^T \delta^{(l+1)})\ .*\ g'(z^{(l)})
其中g'(z^{(l)})=a^{(l)}\ .*\ (1 - a^{(l)})
接下来,将\Delta_{i,j}^{(l)}初始化为一个全0的矩阵,然后使用:
\Delta_{i,j}^{(l)}=\Delta_{i,j}^{(l)}+a_j^{(l)}\delta_i^{(l+1)}
或者使用矩阵化的形式:
\Delta^{(l)}=\Delta^{(l)}+\delta^{(l+1)}(a^{(l)})^T
来更新\Delta矩阵。最后,使用方程:
D^{(l)}_{i,j} := \dfrac{1}{m}\left(\Delta^{(l)}_{i,j} + \lambda\Theta^{(l)}_{i,j}\right)\;\;\;if \;j\ne0
D^{(l)}_{i,j} := \dfrac{1}{m}\Delta^{(l)}_{i,j}\;\;\;if \;j=0
最终,我们就可以得到:
\frac \partial {\partial \Theta_{ij}^{(l)}} J(\Theta)=D_{i,j}^{(l)}

梯度检验(Gradient Checking)

使用反向传播算法我们可以计算出损失函数的偏导数,而梯度检验则是用来检测反向传播算法是否算出了正确的偏导数。
为什么要使用梯度检验呢?两者都可以算出偏导数,而梯度检验使用的是计算导数的原始方法,那么如果两者的结果相近,说明你在模型种使用的反向传播算法是正确的,如果结果相差很大,则说明你需要更正你的算法。注意由于这种原始的方法运算量很大,因此训练模型的时候不要使用,而是只使用反向传播算法,检测的时候再用。
这种原始的算导数的方法是:
\dfrac{\partial}{\partial\Theta}J(\Theta) \approx \dfrac{J(\Theta + \epsilon) - J(\Theta - \epsilon)}{2\epsilon}
也就是使用两个相距很近的点的斜率来近似导数
那么在神经网络模型中,对于每个\Theta_jJ(\Theta)的偏导数就是:
\dfrac{\partial}{\partial\Theta_j}J(\Theta) \approx \dfrac{J(\Theta_1, \dots, \Theta_j + \epsilon, \dots, \Theta_n) - J(\Theta_1, \dots, \Theta_j - \epsilon, \dots, \Theta_n)}{2\epsilon}

权重(Weights)的初始化

接下来只剩下初始化权重(参数)的问题了,如果我们将所有参数\Theta初始化成一样的,那么结果就是我们每次反向传播的时候都不会对参数进行优化,因此我们需要进行随机初始化(Random Initialization)来破除这种对称性,如果想在[-\epsilon,\epsilon]之间随机初始化一个值,算法是:
\Theta=rand(10,11)*2*\epsilon-\epsilon
rand(10,11)意思是初始化一个10x11的矩阵,里面的元素都是0-1的随机数

构建神经网络——总结

总结一下构建神经网络模型的步骤:
首先选择一种架构:确定输入、输出的维度,有几层隐藏层,每层有几个单元。默认的结构是含一个隐藏层;隐藏层越多,模型越准确,但是带来的问题是计算量增加;如果不止一层隐藏层,推荐每层隐藏层的单元数目相同;
接下来就是神经网络模型的训练了,训练过程大致分为以下的步骤:

上一篇下一篇

猜你喜欢

热点阅读