前言

无论是线性回归还是逻辑回归都有这样一个缺点,即:当特征太多时,计算的负荷会非常大。

当我们使用$x_1$, $x_2$ 的多次项式进行预测时,我们可以应用的很好。
之前我们已经看到过,使用非线性的多项式项,能够帮助我们建立更好的分类模型。假设我们有非常多的特征,例如大于100个变量,我们希望用这100个特征来构建一个非线性的多项式模型,结果将是数量非常惊人的特征组合,即便我们只采用两两特征的组合$(x_1x_2+x_1x_3+x_1x_4+...+x_2x_3+x_2x_4+...+x_{99}x_{100})$,我们也会有接近5000个组合而成的特征。这对于一般的逻辑回归来说需要计算的特征太多了。普通的逻辑回归模型,不能有效地处理这么多的特征,这时候我们需要神经网络。

前向传播

我们设计出了类似于神经元的神经网络,效果如下:

其中$x_1$, $x_2$, $x_3$是输入单元(input units),我们将原始数据输入给它们。
$a_1$, $a_2$, $a_3$是中间单元,它们负责将数据进行处理,然后呈递到下一层。
最后是输出单元,它负责计算${h_\theta}\left( x \right)$。

神经网络模型是许多逻辑单元按照不同层级组织起来的网络,每一层的输出变量都是下一层的输入变量。下图为一个3层的神经网络,第一层成为输入层(Input Layer),最后一层称为输出层(Output Layer),中间一层成为隐藏层(Hidden Layers)。我们为每一层都增加一个偏差单位(bias unit)。

下面引入一些标记法来帮助描述模型:
$a_{i}^{\left( j \right)}$ 代表第$j$ 层的第 $i$ 个激活单元。${{\theta }^{\left( j \right)}}$代表从第 $j$ 层映射到第$ j+1$ 层时的权重的矩阵,例如${{\theta }^{\left( 1 \right)}}$代表从第一层映射到第二层的权重的矩阵。其尺寸为:以第 $j+1$层的激活单元数量为行数,以第 $j$ 层的激活单元数加一为列数的矩阵。例如:上图所示的神经网络中${{\theta }^{\left( 1 \right)}}$的尺寸为 3*4。

对于上图所示的模型,激活单元和输出分别表达为:

$a_{1}^{(2)}=g(\Theta _{10}^{(1)}{{x}_{0}}+\Theta _{11}^{(1)}{{x}_{1}}+\Theta _{12}^{(1)}{{x}_{2}}+\Theta _{13}^{(1)}{{x}_{3}})$
$a_{2}^{(2)}=g(\Theta _{20}^{(1)}{{x}_{0}}+\Theta _{21}^{(1)}{{x}_{1}}+\Theta _{22}^{(1)}{{x}_{2}}+\Theta _{23}^{(1)}{{x}_{3}})$
$a_{3}^{(2)}=g(\Theta _{30}^{(1)}{{x}_{0}}+\Theta _{31}^{(1)}{{x}_{1}}+\Theta _{32}^{(1)}{{x}_{2}}+\Theta _{33}^{(1)}{{x}_{3}})$
${{h}_{\Theta }}(x)=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)})$

上面进行的讨论中只是将特征矩阵中的一行(一个训练实例)喂给了神经网络,我们需要将整个训练集都喂给我们的神经网络算法来学习模型。

我们可以知道:每一个$a$都是由上一层所有的$x$和每一个$x$所对应的决定的。

(我们把这样从左到右的算法称为前向传播算法( FORWARD PROPAGATION ))

多分类

当我们有不止两种分类时,输入向量$x$有三个维度,两个中间层,输出层4个神经元分别用来表示4类,也就是每一个数据在输出层都会出现${{\left[ a\text{ }b\text{ }c\text{ }d \right]}^{T}}$,且$a,b,c,d$中仅有一个为1,表示当前类,一般采用独热编码。下面是该神经网络的可能结构示例:

如上图,假设神经网络的训练样本有$m$个,每个包含一组输入$x$和一组输出信号$y$,$L$表示神经网络层数,$S_I$表示每层的neuron个数($S_l$表示输出层神经元个数),$S_L$代表最后一层中处理单元的个数。

将神经网络的分类定义为两种情况:二类分类和多类分类,

二类分类:$S_L=0, y=0\, or\, 1$表示哪一类;

$K$类分类:$S_L=k, y_i = 1$表示分到第$i$类;$(k>2)$

我们回顾逻辑回归问题中我们的代价函数为:

$ J\left(\theta \right)=-\frac{1}{m}\left[\sum_\limits{i=1}^{m}{y}^{(i)}\log{h_\theta({x}^{(i)})}+\left(1-{y}^{(i)}\right)log\left(1-h_\theta\left({x}^{(i)}\right)\right)\right]+\frac{\lambda}{2m}\sum_\limits{j=1}^{n}{\theta_j}^{2} $

在逻辑回归中,我们只有一个输出变量,又称标量(scalar),也只有一个因变量$y$,但是在神经网络中,我们可以有很多输出变量,我们的$h_\theta(x)$是一个维度为$K$的向量,并且我们训练集中的因变量也是同样维度的一个向量,因此我们的代价函数会比逻辑回归更加复杂一些,为:$h_\theta\left(x\right)\in \mathbb{R}^{K}$

$$ J(\Theta) = -\frac{1}{m} \left[ \sum\limits_{i=1}^{m} \sum\limits_{k=1}^{k} {y_k}^{(i)} \log {(h_\Theta(x^{(i)}))} + \left( 1 - y_k^{(i)} \right) \log \left( 1- {\left( h_\Theta \left( x^{(i)} \right) \right)} \right) \right] + \frac{\lambda}{2m} \sum\limits_{l=1}^{L-1} \sum\limits_{i=1}^{s_l} \sum\limits_{j=1}^{s_{l+1}} \left( \Theta_{ji}^{(l)} \right)^2 $$

这个看起来复杂很多的代价函数背后的思想还是一样的,我们希望通过代价函数来观察算法预测的结果与真实情况的误差有多大,唯一不同的是,对于每一行特征,我们都会给出$K​$个预测,基本上我们可以利用循环,对每一行特征都预测$K​$个不同结果,然后在利用循环在$K​$个预测中选择可能性最高的一个,将其与$y​$中的实际数据进行比较。

正则化的那一项只是排除了每一层$\theta_0$后,每一层的$\theta$ 矩阵的和。最里层的循环$j$循环所有的行(由$s_{l+1}$ 层的激活单元数决定),循环$i$则循环所有的列,由该层($s_l$层)的激活单元数所决定。即:$h_\theta(x)$与真实值之间的距离为每个样本-每个类输出的加和,对参数进行regularizationbias项处理所有参数的平方和。

反向传播

我们定义L代表神经网络算法的层数,$a_{i}^{\left( j \right)}$ 代表第$j$ 层的第 $i$ 个激活单元。${{\theta }^{\left( j \right)}}$代表从第 $j$ 层映射到第$ j+1$ 层时的权重的矩阵,定义$z^{\left(j \right)} = \theta^{\left(j-1 \right)}a^{\left(j-1 \right)}$。

现在,为了计算代价函数的偏导数$\frac{\partial}{\partial\Theta^{(l)}_{ij}}J\left(\Theta\right)$,我们需要采用一种反向传播算法,也就是首先计算最后一层的误差,然后再一层一层反向求出各层的误差,直到倒数第二层。

相关公式:

  1. cost funtion

    $$ J(\Theta) = -\frac{1}{m} \left[ \sum\limits_{i=1}^{m} \sum\limits_{k=1}^{k} {y_k}^{(i)} \log{(h_\Theta(x^{(i)}))} + \left( 1 - y_k^{(i)} \right) \log \left( 1-{\left( h_\Theta \left( x^{(i)} \right) \right)} \right) \right] + \frac{\lambda}{2m} \sum\limits_{l=1}^{L-1} \sum\limits_{i=1}^{s_l} \sum\limits_{j=1}^{s_{l+1}} \left( \Theta_{ji}^{(l)} \right)^2 $$

  2. 每层的偏差

    $$ \begin{aligned} \delta_{j}^{(L)}&=a_{j}^{(L)}-y_{j} \\ \delta^{(l)}&=(\Theta^{(l)})^{T}\delta^{(l+1)}\ast g'(z^{(l)}) (l​ \neq L) \end{aligned} $$

  3. cost funtion的偏导数
    $λ=0$,不做任何正则化处理时:$\frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta)=a_{j}^{(l)} \delta_{i}^{l+1}$
    $λ \neq 0$,做正则化处理时:$ D_{ij}^{(l)} :=\frac{1}{m}(\Delta_{ij}^{(l)}+\lambda\Theta_{ij}^{(l)})$ $({if}\; j \neq 0)$ ,$ D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}$ $({if}\; j = 0)$
    其中:$\Delta_{ij}^{(l)} = \sum\limits_{i=1}^{m}a_{j}^{(l)} \delta_{i}^{l+1}$, $\frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta) = D_{ij}^{(l)}$

为了计算代价函数的偏导数$\frac{\partial}{\partial\Theta^{(l)}_{ij}}J\left(\Theta\right)$,我们需要采用一种反向传播算法,也就是首先计算最后一层的误差,然后再一层一层反向求出各层的误差,直到倒数第二层。
以一个例子来说明反向传播算法。

假设我们的训练集只有一个样本$\left({x}^{(1)},{y}^{(1)}\right)$,我们的神经网络是一个四层的神经网络,其中$K=4,S_{L}=4,L=4$:

我们从最后一层的误差开始计算,误差是激活单元的预测(${a^{(4)}}$)与实际值($y^k$)之间的误差,($k=1:k$)。
我们用$\delta$来表示误差,则:$\delta^{(4)}=a^{(4)}-y$
我们利用这个误差值来计算前一层的误差:$\delta^{(3)}=\left({\Theta^{(3)}}\right)^{T}\delta^{(4)}\ast g'\left(z^{(3)}\right)$
其中 $g'(z^{(3)})$是 $S$ 形函数的导数,$g'(z^{(3)})=a^{(3)}\ast(1-a^{(3)})$。而$(θ^{(3)})^{T}\delta^{(4)}$则是权重导致的误差的和。下一步是继续计算第二层的误差:
$ \delta^{(2)}=(\Theta^{(2)})^{T}\delta^{(3)}\ast g'(z^{(2)})$
因为第一层是输入变量,不存在误差。我们有了所有的误差的表达式后,便可以计算代价函数的偏导数了,假设$λ=0$,即我们不做任何正则化处理时有:
$\frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta)=a_{j}^{(l)} \delta_{i}^{l+1}$

重要的是清楚地知道上面式子中上下标的含义:

$l$ 代表目前所计算的是第几层。

$j$ 代表目前计算层中的激活单元的下标,也将是下一层的第$j$个输入变量的下标。

$i$ 代表下一层中误差单元的下标,是受到权重矩阵中第$i$行影响的下一层中的误差单元的下标。

如果我们考虑正则化处理,并且我们的训练集是一个特征矩阵而非向量。在上面的特殊情况中,我们需要计算每一层的误差单元来计算代价函数的偏导数。在更为一般的情况中,我们同样需要计算每一层的误差单元,但是我们需要为整个训练集计算误差单元,此时的误差单元也是一个矩阵,我们用$\Delta^{(l)}_{ij}$来表示这个误差矩阵。第 $l$ 层的第 $i$ 个激活单元受到第 $j$ 个参数影响而导致的误差。

我们的算法表示为:

即首先用正向传播方法计算出每一层的激活单元,利用训练集的结果与神经网络预测的结果求出最后一层的误差,然后利用该误差运用反向传播法计算出直至第二层的所有误差。

在求出了$\Delta_{ij}^{(l)}$之后,我们便可以计算代价函数的偏导数了,计算方法如下:
$ D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}+\lambda\Theta_{ij}^{(l)}$ $({if}\; j \neq 0)$

$ D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}$ $({if}\; j = 0)$

反向传播推导

对于每一层的偏差公式与损失函数的偏导数公式推导如下:
首先忽略正则项,即$λ=0$,同样我们假设训练样本只有一个,并忽略常数m。则损失函数如下所示:
$J(\theta) = - \sum\limits_{k=1}^{k} {y_k}^{(i)} \log{(h_\theta(x^{(i)}))} + \left( 1 - y_k^{(i)} \right) \log \left( 1- {\left( h_\theta \left( x^{(i)} \right) \right)} \right)$

当l=L-1时,运用链式求导法则,求损失函数的偏导数:

$$ \begin{aligned} \frac{\partial}{\partial\theta_{ij}^{(L-1)}}J(\theta)&=\frac{\partial J(\theta)}{\partial a_{j}^{L}} \frac{\partial a_{j}^{L}}{\partial z_{j}^{L}} \frac{\partial z_{j}^{L}}{\partial \theta_{j}^{L-1}} \\ &=-(\frac{y_j}{a_{j}^{L}}-\frac{1-y_j}{1-a_{j}^{L}}) * g'\left( z_{j}^{L}\right) * a_{j}^{L-1} \\ &=-(\frac{y_j}{a_{j}^{L}}-\frac{1-y_j}{1-a_{j}^{L}}) * a_{j}^{L}(1-a_{j}^{L}) * a_{j}^{L-1} \\ &=(a_{j}^{L}-y_j)* a_{j}^{L-1} \end{aligned} $$

令$\delta_{j}^{(L)}=a_{j}^{(L)}-y_{j}$,则$\frac{\partial}{\partial\theta_{ij}^{(l)}}J(\theta)=a_{j}^{(l)} \delta_{j}^{l+1}$

当l=L-2时,运用链式求导法则,求损失函数的偏导数:

$$ \begin{aligned} \frac{\partial}{\partial\theta_{ij}^{(L-2)}}J(\theta)&=\frac{\partial J(\theta)}{\partial a_{j}^{L}} \frac{\partial a_{j}^{L}}{\partial z_{j}^{L}} \frac{\partial z_{j}^{L}}{\partial a_{j}^{L-1}} \frac{\partial a_{j}^{L-1}}{\partial z_{j}^{L-1}} \frac{\partial z_{j}^{L-1}}{\partial \theta_{j}^{L-2}} \\ &=(\sum\limits_{j=1}^{k} \delta_{j}^{L} * \frac{\partial z_{j}^{L}}{\partial a_{j}^{L-1}}) * g'\left( z_{j}^{L-1}\right) * a_{j}^{L-2}\\ &=(\theta_{j}^{L-1})^{T}*\delta^{L}* g'\left( z_{j}^{L-1}\right) * a_{j}^{L-2} \end{aligned} $$

令$\delta_{j}^{L-1}=(\theta_{j}^{L-1})^{T}*\delta^{L}* g'\left( z_{j}^{L-1}\right)$,则$\frac{\partial J(\theta)}{\partial\Theta_{ij}^{(L-2)}}=a_{j}^{(L-2)} \delta_{j}^{L-1}$

这里有个需要注意的地方:使用链式法则求$J(\theta)$对$a_{j}^{(L-1)}$求偏导的时候,不要忘记求和符号,因为输出层的每一个节点都是$a_{j}^{(L-1)}$的函数。
按照上面的步骤依次类推下去,我们发现后面的每一个偏导数,都可以写成

$$ \begin{aligned} \frac{\partial J(\theta)}{\partial\theta_{ij}^{l}}&=(\theta_{j}^{l})^{T}*\delta^{l+1}* g'\left( z_{i}^{l}\right) * a_{j}^{l} \\ &=\delta^{l+1}* a_{j}^{l} \end{aligned} $$

总结

任何优化算法都需要一些初始的参数。到目前为止我们都是初始所有参数为0,这样的初始方法对于逻辑回归来说是可行的,但是对于神经网络来说是不可行的。如果我们令所有的初始参数都为0,这将意味着我们第二层的所有激活单元都会有相同的值。同理,如果我们初始所有的参数都为一个非0的数,结果也是一样的。

小结一下使用神经网络时的步骤:

网络结构:第一件要做的事是选择网络结构,即决定选择多少层以及决定每层分别有多少个单元。
第一层的单元数即我们训练集的特征数量。
最后一层的单元数是我们训练集的结果的类的数量。
如果隐藏层数大于1,确保每个隐藏层的单元个数相同,通常情况下隐藏层单元的个数越多越好。
我们真正要决定的是隐藏层的层数和每个中间层的单元数。

训练神经网络:

  1. 参数的随机初始化
  2. 利用正向传播方法计算所有的$h_{\theta}(x)$
  3. 编写计算代价函数 $J$ 的代码
  4. 利用反向传播方法计算所有偏导数
  5. 利用数值检验方法检验这些偏导数
  6. 使用优化算法来最小化代价函数
最后修改:2022 年 12 月 20 日
如果觉得我的文章对你有用,请随意赞赏