以下为我的机器学习笔记,参考了黄海广博士的笔记

课程:机器学习 - 斯坦福大学 - 吴恩达 2014 @ Coursera

https://www.coursera.org/course/ml

# 神经网络概述(Representation)

# 非线性假设

这是我们之前学过的一个例子:

通过构建x1x_{1},x2x_{2} 的非线性多项式,能够帮助我们建立比线性多项式更好的分类模型。但上式只有两个特征,构造出来的多项式就如此繁杂,而在很多问题中,我们的特征远多于此。对于线性回归和逻辑回归来说,当特征太多时,计算的负荷会非常大。

🌰举个例子,我们想通过灰度值来判断图片上是否为汽车。我们现在有一堆 50x50 像素的小图片,我们将所有的像素视为特征,则会有 2500 个特征,如果我们要进一步将两两特征组合构成一个多项式模型,则会有约25002/2{ {2500}^{2} }/2 个(接近 3 百万个)特征。

普通的逻辑回归模型,不能有效地处理这么多的特征,这时候我们就需要神经网络。

# 神经元和大脑

神经网络是一种很古老的算法,它最初产生的目的是制造能模拟大脑的机器。毕竟论思考能力,人类的大脑才是 No.1。

神经网络兴起于 20 世纪八九十年代,但由于各种原因,在 90 年代的后期应用减少了。但是三十年河东,三十年河西,最近几年,它又东山再起了。其原因之一得益于计算机运行速度变快了,因为神经网络是计算量有些偏大的算法,之前的计算机算力不足以真正运行起大规模的神经网络。

在介绍神经网络之前,我们先来看看大脑。我们的大脑能处理各种不同的事情,我们的学习,运动,感知等等等等,无一不依赖于大脑。如果想要模仿它,我们似乎得写很多不同的软件来模拟所有这些五花八门的奇妙事情。

不过有没有这样一种可能,大脑实现所有这些功能,并不需要用上千个不同的程序去实现。相反的,大脑处理的方法,只需要一个单一的学习算法就可以了?尽管这只是一个假想,但也并非无迹可寻。

看上面这幅图,大脑的这一小片红色区域是你的听觉皮层。你听周围人说话,靠的是耳朵。耳朵接收到声音信号,并把声音信号传递给你的听觉皮层,然后你才明白别人说了什么。

一些神经系统科学家做了下面这个实验,把耳朵到听觉皮层的神经切断,将其重新接到一个动物的大脑上。这样从眼睛到视神经的信号最终将传到听觉皮层。这样做以后,结果相当的 amazing,实验对象的听觉皮层将会学会 “看”。没错,就是你所理解的” 看 “由听觉皮层完成了。下面再举另一个例子,这块红色的脑组织是躯体的感觉皮层,用来处理触觉。如果你做一个和刚才类似的重接实验,那么躯体感觉皮层也能学会 “看”。

上面的这些实验,被称为 神经重接实验 。它的意义是,如果人体可以用同一块脑组织处理光、声或触觉信号,那么也许存在一种学习算法,可以同时处理视觉、听觉和触觉,而不是需要运行上千个不同的程序,或者上千个不同的算法来实现这类事情。也许我们需要做的就是找出和大脑相似的学习算法,然后实现通过自学掌握如何处理这些不同类型的数据。

下面再举几个例子:

🌰这张图是用舌头学会 “看” 的一个例子。这是一个名为 BrainPort 的系统,它现在正在 FDA (美国食品和药物管理局) 的临床试验阶段。它能帮助失明人士看见事物。其原理是,你在前额上带一个灰度摄像头,它能获取你面前事物的低分辨率的灰度图像。将它连到舌头上安装的电极阵列上,那么每个像素都被映射到你舌头的某个位置上,电压值高的点对应一个暗像素,电压值低的点对应于亮像素。虽然该系统还不完善,但使用这种系统就能让你我在几十分钟里就学会用我们的舌头 “看” 东西。

🌰第二个例子是人体回声定位,或者说人体声纳。现在的一些失明人士或许接受过这样的培训,即利用咂舌头或者打响指,解读从环境反弹回来的声波。YouTube 上介绍了一个令人称奇的孩子,他因为癌症眼球惨遭移除,但是通过打响指,他可以四处走动而不撞到任何东西,他能滑滑板,他可以将篮球投入篮框中。

🌰第三个例子是触觉皮带,如果你把它戴在腰上,蜂鸣器会响,而且总是朝向北时发出嗡嗡声。它可以使人拥有方向感,用类似于鸟类感知方向的方式。

🌰还有一些离奇的例子:

如果你在青蛙身上插入第三只眼,青蛙也能学会使用那只眼睛。2077 人造杨戬可能不是神话🐶 。如果你能把几乎任何传感器接入到大脑中,大脑的学习算法就能找出学习数据的方法,并处理这些数据。从某种意义上来说,如果我们能找出大脑的学习算法,然后在计算机上执行大脑学习算法或与之相似的算法,也许这将是我们向人工智能迈进做出的最好的尝试。人工智能的梦想就是:有一天能制造出真正的

# 模型表示 1

为了构建神经网络模型,我们需要首先思考大脑中的神经网络是怎样的?每一个神经元都可以被认为是一个 处理单元/神经核(processing unit/Nucleus) ,它含有许多 输入/树突(input/Dendrite) ,并且有一个 输出/轴突(output/Axon) 。神经网络是大量神经元相互链接并通过电脉冲来交流的一个网络。

下面是一组神经元的示意图,神经元利用微弱的电流进行沟通。这些弱电流也称作 动作电位 ,其实就是一些微弱的电流。所以如果神经元想要传递一个消息,它就会就通过它的轴突,发送一段微弱电流给其他神经元。这里是一条连接到输入神经,或者连接另一个神经元树突的神经,接下来这个神经元接收这条消息,做一些计算,它有可能会反过来将在轴突上的自己的消息传给其他神经元。

这就是所有人类思考的模型:我们的神经元把自己的收到的消息进行计算,并向其他神经元传递消息。这也是我们的感觉和肌肉运转的原理。如果你想活动一块肌肉,就会触发一个神经元给你的肌肉发送脉冲,并引起你的肌肉收缩。如果一些感官:比如说眼睛想要给大脑传递一个消息,那么它就像这样发送电脉冲给大脑的。

神经网络模型建立在很多神经元之上,每一个神经元又是一个个学习模型。这些 神经元(activation unit) 接受一些特征作为输入,并且根据本身的模型提供一个输出。下图是一个以逻辑回归模型作为自身学习模型的神经元示例,在神经网络中,参数又可被成为 权重(weight)

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

  • x1x_1, x2x_2, x3x_3 是输入单元,我们将原始数据输入给它们。
  • a1a_1, a2a_2, a3a_3 是中间单元,它们负责将数据进行处理,然后呈递到下一层。
  • 最后是输出单元,它负责计算hθ(x){h_\theta}\left( x \right)

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

下面引入一些标记法来帮助描述模型:

  • ai(j)a_{i}^{\left( j \right)} 代表第jj 层的第 ii 个激活单元。

  • θ(j){ {\theta }^{\left( j \right)} } 代表从第 jj 层映射到第j+1j+1 层时的权重的矩阵,例如θ(1){ {\theta }^{\left( 1 \right)} } 代表从第一层映射到第二层的权重的矩阵。

    其尺寸为:以第 j+1j+1 层的激活单元数量为行数,以第 jj 层的激活单元数 + 1 为列数的矩阵。例如:上图所示的神经网络中θ(1){ {\theta }^{\left( 1 \right)} } 的尺寸为 3*4。

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

a1(2)=g(Θ10(1)x0+Θ11(1)x1+Θ12(1)x2+Θ13(1)x3)a_{1}^{(2)}=g(\Theta _{10}^{(1)}{ {x}_{0} }+\Theta _{11}^{(1)}{ {x}_{1} }+\Theta _{12}^{(1)}{ {x}_{2} }+\Theta _{13}^{(1)}{ {x}_{3} })

a2(2)=g(Θ20(1)x0+Θ21(1)x1+Θ22(1)x2+Θ23(1)x3)a_{2}^{(2)}=g(\Theta _{20}^{(1)}{ {x}_{0} }+\Theta _{21}^{(1)}{ {x}_{1} }+\Theta _{22}^{(1)}{ {x}_{2} }+\Theta _{23}^{(1)}{ {x}_{3} })

a3(2)=g(Θ30(1)x0+Θ31(1)x1+Θ32(1)x2+Θ33(1)x3)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Θ(x)=g(Θ10(2)a0(2)+Θ11(2)a1(2)+Θ12(2)a2(2)+Θ13(2)a3(2)){ {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)})

上面进行的讨论中只是将特征矩阵中的一行(一个训练实例)喂给了神经网络,我们需要将整个训练集都喂给我们的神经网络算法来学习模型。我们可以知道:每一个aa 都是由上一层所有的xx 和每一个xx 所对应的决定的。我们把这样从左到右的算法称为 前向传播算法( FORWARD PROPAGATION)

xx, θ\theta, aa 分别用矩阵表示:

我们可以得到θX=a\theta\cdot X=a

# 模型表示 2

相对于使用循环来编码,利用向量化的方法会使得计算更为简便。以上面的神经网络为例,试着计算第二层的值:

我们令 z(2)=θ(1)x{ {z}^{\left( 2 \right)} }={ {\theta }^{\left( 1 \right)} }x,则 a(2)=g(z(2)){ {a}^{\left( 2 \right)} }=g({ {z}^{\left( 2 \right)} }) ,计算后添加 a0(2)=1a_{0}^{\left( 2 \right)}=1。 计算输出的值为:

我们令 z(3)=θ(2)a(2){ {z}^{\left( 3 \right)} }={ {\theta }^{\left( 2 \right)} }{ {a}^{\left( 2 \right)} },则 hθ(x)=a(3)=g(z(3))h_\theta(x)={ {a}^{\left( 3 \right)} }=g({ {z}^{\left( 3 \right)} })
这只是针对训练集中一个训练实例所进行的计算。如果我们要对整个训练集进行计算,我们需要将训练集特征矩阵进行转置,使得同一个实例的特征都在同一列里。即:

z(2)=Θ(1)×XT{ {z}^{\left( 2 \right)} }={ {\Theta }^{\left( 1 \right)} }\times { {X}^{T} }

a(2)=g(z(2)){ {a}^{\left( 2 \right)} }=g({ {z}^{\left( 2 \right)} })

为了更好了解神经网络的工作原理,我们先把左半部分遮住:

右半部分其实就是以a0,a1,a2,a3a_0, a_1, a_2, a_3, 按照逻辑回归的方式输出hθ(x)h_\theta(x)

其实神经网络就像是逻辑回归,只不过把逻辑回归中的输入向量[x1x3]\left[ x_1\sim {x_3} \right] 变成了中间层的[a1(2)a3(2)]\left[ a_1^{(2)}\sim a_3^{(2)} \right], 即:

hθ(x)=g(Θ0(2)a0(2)+Θ1(2)a1(2)+Θ2(2)a2(2)+Θ3(2)a3(2))h_\theta(x)=g\left( \Theta_0^{\left( 2 \right)}a_0^{\left( 2 \right)}+\Theta_1^{\left( 2 \right)}a_1^{\left( 2 \right)}+\Theta_{2}^{\left( 2 \right)}a_{2}^{\left( 2 \right)}+\Theta_{3}^{\left( 2 \right)}a_{3}^{\left( 2 \right)} \right)

我们可以把a0,a1,a2,a3a_0, a_1, a_2, a_3 看成更为高级的特征值,也就是x0,x1,x2,x3x_0, x_1, x_2, x_3 的进化体,并且它们是由 xxθ\theta 决定的,因为是梯度下降的,所以aa 是变化的,并且变得越来越厉害,所以这些更高级的特征值远比仅仅将 xx 次方厉害,也能更好的预测新数据。这就是神经网络相比于逻辑回归和线性回归的优势。

# 特征和直观理解 1

从本质上讲,神经网络能够通过学习得出其自身的一系列特征。在普通的逻辑回归中,我们能使用的只有原始特征x1,x2,...,xnx_1,x_2,...,{ {x}_{n} },尽管我们可以使用一些二项式项来组合这些特征,但是我们仍然受到这些原始特征的限制。在神经网络中,原始特征只是输入层,在我们上面的例子中,第三层也就是输出层,做出的预测利用的是第二层的特征,而非输入层中的原始特征,我们可以认为第二层中的特征是神经网络通过学习后自己得出的一系列用于预测输出变量的新特征。

神经网络中,单层神经元(无中间层)的计算可用来表示逻辑运算,比如 逻辑与(AND)逻辑或(OR)

举例说明:逻辑与 (AND);下图中左半部分是神经网络的设计与输出层表达式,右边上部分是 sigmod 函数,下半部分是真值表。

我们可以用这样的一个神经网络表示 AND 函数:

其中θ0=30,θ1=20,θ2=20\theta_0 = -30, \theta_1 = 20, \theta_2 = 20
我们的输出函数hθ(x)h_\theta(x) 即为:hΘ(x)=g(30+20x1+20x2)h_\Theta(x)=g\left( -30+20x_1+20x_2 \right)

我们知道g(x)g(x) 的图像是:

所以我们有:hΘ(x)x1ANDx2h_\Theta(x) \approx \text{x}_1 \text{AND} \, \text{x}_2,所以我们的:$h_\Theta (x) $ 这就是 AND 函数。

接下来再介绍一个 OR 函数:

OR 与 AND 整体一样,区别只在于的取值不同。

# 样本和直观理解 II

二元逻辑运算符 (BINARY LOGICAL OPERATORS) 当输入特征为布尔值(0 或 1)时,我们可以用一个单一的激活层可以作为二元逻辑运算符,为了表示不同的运算符,我们只需要选择不同的权重即可。

下图的神经元(三个权重分别为 - 30,20,20)可以被视为作用同于逻辑与(AND):

下图的神经元(三个权重分别为 - 10,20,20)可以被视为作用等同于逻辑或(OR):

下图的神经元(两个权重分别为 10,-20)可以被视为作用等同于逻辑非(NOT):

我们可以利用神经元来组合成更为复杂的神经网络以实现更复杂的运算。例如我们要实现异或功能(输入的两个值必须一样,均为 1 或均为 0),即

XNOR=(x1ANDx2)OR((NOTx1)AND(NOTx2))\text{XNOR}=( \text{x}_1\, \text{AND}\, \text{x}_2 )\, \text{OR} \left( \left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) \right)

首先构造一个能表达(NOTx1)AND(NOTx2)\left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) 部分的神经元:

然后将表示 AND 的神经元和表示(NOTx1)AND(NOTx2)\left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) 的神经元以及表示 OR 的神经元进行组合:

我们就得到了一个能实现 XNOR\text{XNOR} 运算符功能的神经网络。按这种方法我们可以逐渐构造出越来越复杂的函数,也能得到更加厉害的特征值。这就是神经网络的厉害之处。

# 多类分类

当我们有不止两种分类时(也就是y=1,2,3.y=1,2,3….),比如以下这种情况,该怎么办?如果我们要训练一个神经网络算法来识别路人、汽车、摩托车和卡车,在输出层我们应该有 4 个值。例如,第一个值用于预测是否是行人,第二个值用于判断是否为汽车。

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

神经网络算法的输出结果为四种可能情形之一:

# 神经网络的学习 (Learning)

# 代价函数

首先引入一些新的标记方法,方面后续的讨论:

假设神经网络的训练样本有mm 个,每个包含一组输入信号xx 和一组输出信号yyLL 表示神经网络层数,SIS_I 表示每层的神经元(neuron)个数,SLS_L 代表最后一层中处理单元的个数。

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

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

KK 类分类:SL=k,yi=1S_L=k, y_i = 1 表示分到第ii 类;(k>2)(k>2)

image-20210215154826681

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

J(θ)=1m[i=1my(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))]+λ2mj=1nθj2J(\theta)=-\frac{1}{m}[\sum_{i=1}^{m}{y}^{(i)}\log{h_\theta({x}^{(i)})}+(1-{y}^{(i)})\log(1-h_\theta({x}^{(i)}))]+\frac{\lambda}{2m}\sum_{j=1}^{n}\theta_j^2

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

hθ(x)RKh_\theta\left(x\right)\in \mathbb{R}^{K}

(hθ(x))i=ithoutput{\left({h_\theta}\left(x\right)\right)}_{i}={i}^{th} \text{output}

J(Θ)=1m[i=1mk=1kyk(i)log(hΘ(x(i)))+(1yk(i))log(1(hΘ(x(i))))]+λ2ml=1L1i=1slj=1sl+1(Θji(l))2J(\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

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

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

# 反向传播算法

我们在计算神经网络的预测结果时采用了一种正向传播方法,我们从第一层开始一层一层地进行计算,直到最后一层的hθ(x)h_{\theta}\left(x\right)

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

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

前向传播算法:

image-20210215235200423

我们从最后一层的误差开始计算,误差是激活单元的预测(a(4){a^{(4)}})与实际值(yky^k)之间的误差,(k=1:kk=1:k),其步骤如下:

  1. 我们用δ\delta 来表示误差,则:δ(4)=a(4)y\delta^{(4)}=a^{(4)}-y

  2. 我们利用这个误差值来计算前一层的误差:δ(3)=(Θ(3))Tδ(4)g(z(3))\delta^{(3)}=\left({\Theta^{(3)}}\right)^{T}\delta^{(4)}\ast g'\left(z^{(3)}\right)
    其中 g(z(3))g'(z^{(3)})SS 形函数的导数,g(z(3))=a(3)(1a(3))g'(z^{(3)})=a^{(3)}\ast(1-a^{(3)})。而(θ(3))Tδ(4)(θ^{(3)})^{T}\delta^{(4)} 则是权重导致的误差的和。

  3. 下一步是继续计算第二层的误差:δ(2)=(Θ(2))Tδ(3)g(z(2))\delta^{(2)}=(\Theta^{(2)})^{T}\delta^{(3)}\ast g'(z^{(2)})

  4. 因为第一层是输入变量,不存在误差,故不作计算。

我们有了所有的误差的表达式后,便可以计算代价函数的偏导数了,假设λ=0λ=0,即我们不做任何正则化处理时有:

Θij(l)J(Θ)=aj(l)δil+1\frac{\partial}{\partial\Theta_{ij}^{(l)} }J(\Theta)=a_{j}^{(l)} \delta_{i}^{l+1}

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

  • ll 代表目前所计算的是第几层。

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

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

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

我们的算法表示为:

image-20210217091936635

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

在求出了Δij(l)\Delta_{ij}^{(l)} 之后,我们便可以计算代价函数的偏导数了,计算方法如下:

Dij(l):=1mΔij(l)+λΘij(l)ifj0D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}+\lambda\Theta_{ij}^{(l)}\space\space\space{if}\; j \neq 0

Dij(l):=1mΔij(l)ifj=0D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}\space\space\space{if}\; j = 0

在编程过程中,如果我们要使用 优化算法来求解求出权重矩阵,我们需要将矩阵先展开成为向量,利用算法求出最优解后再重新转换回矩阵。

# 反向传播算法的直观理解

反向传播算法给人的直观感受是步骤繁杂,这是很正常的,在很多情况下你不需要深入了解它,只要会用即可。不过为了更好地理解反向传播算法,我们还是来仔细研究一下它们的原理:

前向传播算法:

image-20210217092054986

反向传播算法做的是:

image-20210217092118861

image-20210217092135354

感悟:上图中的 δj(l)=error"ofcostforaj(l)(unitjinlayerl)\delta^{(l)}_{j}=``error" \ of \ cost \ for \ a^{(l)}_{j} \ (unit \ j \ in \ layer \ l) 理解如下:

δj(l)\delta^{(l)}_{j} 相当于是第 ll 层的第 jj 单元中得到的激活项的 “误差”,即” 正确 “的 aj(l)a^{(l)}_{j} 与计算得到的 aj(l)a^{(l)}_{j} 的差。

aj(l)=g(z(l))a^{(l)}_{j}=g(z^{(l)}) ,(g 为 sigmoid 函数)。我们可以想象 δj(l)\delta^{(l)}_{j} 为函数求导时迈出的那一丁点微分,所以更准确的说 δj(l)=zj(l)cost(i)\delta^{(l)}_{j}=\frac{\partial}{\partial z^{(l)}_{j}}cost(i)

# 梯度检验

当我们对一个较为复杂的模型(例如神经网络)使用梯度下降算法时,可能会存在一些不容易察觉的错误,这意味着,虽然代价看上去在不断减小,但最终的结果可能并不是最优解。

为了避免这样的问题,我们采取一种叫做 梯度的数值检验(Numerical Gradient Checking) 方法。这种方法的思想是通过估计梯度值来检验我们计算的导数值是否真的符合我们的要求。

对梯度的估计采用的方法是在代价函数上沿着切线的方向选择离两个非常近的点然后计算两个点的平均值用以估计梯度。即对于某个特定的 θ\theta,我们计算出在 θ\theta-$\varepsilon $ 处和 θ\theta+$\varepsilon $ 的代价值($\varepsilon $ 是一个非常小的值,通常选取 0.001),然后求两个代价的平均,用以估计在 θ\theta 处的代价值。

image-20210217092204943

θ\theta 是一个向量时,我们则需要对偏导数进行检验。因为代价函数的偏导数检验只针对一个参数的改变进行检验,下面是一个只针对θ1\theta_1 进行检验的示例:

θ1=J(θ1+ε1,θ2,θ3...θn)J(θ1ε1,θ2,θ3...θn)2ε\frac{\partial}{\partial\theta_1}=\frac{J\left(\theta_1+\varepsilon_1,\theta_2,\theta_3...\theta_n \right)-J \left( \theta_1-\varepsilon_1,\theta_2,\theta_3...\theta_n \right)}{2\varepsilon}

最后我们还需要对通过反向传播方法计算出的偏导数进行检验。

根据上面的算法,计算出的偏导数存储在矩阵 Dij(l)D_{ij}^{(l)} 中。检验时,我们要将该矩阵展开成为向量,同时我们也将 θ\theta 矩阵展开为向量,我们针对每一个 θ\theta 都计算一个近似的梯度值,将这些值存储于一个近似梯度矩阵中,最终将得出的这个矩阵同 Dij(l)D_{ij}^{(l)} 进行比较。

image-20210217092226382

# 随机初始化

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

我们通常初始参数为正负 ε 之间的随机值,假设我们要随机初始一个尺寸为 10×11 的参数矩阵,代码如下:

Theta1 = rand(10, 11) * (2*eps) – eps

# 综合起来

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

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

训练神经网络:

  1. 参数的随机初始化
  2. 利用正向传播方法计算所有的hθ(x)h_{\theta}(x)
  3. 编写计算代价函数 JJ 的代码
  4. 利用反向传播方法计算所有偏导数
  5. 利用数值检验方法检验这些偏导数
  6. 使用优化算法来最小化代价函数

# 自主驾驶

下面一节,我们将介绍一个利用神经网络学习的重要例子。那就是使用神经网络来实现自动驾驶,也就是说使汽车通过学习来自己驾驶。下面视频的作者是 Dean Pomerleau,任职于美国东海岸的卡耐基梅隆大学。

image-20210217092319514

我们来看看上面这幅图,它由四个部分组成。左下角的部分是一条道路的图像,右下角的则是各种参数和道路的可视化图像。

而左上角这部分显示的是驾驶的方向,白色区段靠左显示左转,靠右显示右转。这里的白色区段有两条,上方的区段是人类驾驶者选择的方向,下方的是学习算法选出的方向。实际上,在神经网络开始学习之前,你会看到网络的输出是一条灰色的区段,几乎覆盖了整个区域,这显示出神经网络已经随机初始化了,并且初始化时,我们并不知道汽车如何行驶,或者说我们并不知道所选行驶方向。只有在学习算法运行了足够长的时间之后,才会有这条白色的区段出现。这表示在这时候已经选出了一个明确的行驶方向。

image-20210217092345412

ALVINN (Autonomous Land Vehicle In a Neural Network) 是一个基于神经网络的智能系统,它通过观察人类的驾驶来学习驾驶。上面是一辆改装版军用悍马,这辆悍马装载了传感器、计算机和驱动器用来进行自动驾驶的导航试验。实现 ALVINN 功能的第一步,是对它进行训练,也就是训练一个人驾驶汽车。

image-20210217092412865

ALVINN 每两秒会将前方的路况图生成一张数字化图片,并且记录驾驶者的驾驶方向,得到的训练集图片被压缩为 30x32 像素,并且作为输入提供给 ALVINN 的三层神经网络,通过使用反向传播学习算法,ALVINN 会训练得到一个与人类驾驶员操纵方向基本相近的结果。一开始,我们的网络选择出的方向是随机的,大约经过两分钟的训练后,我们的神经网络便能够准确地模拟人类驾驶者的驾驶方向,对其他道路类型,也重复进行这个训练过程,当网络被训练完成后,操作者就可按下运行按钮,车辆便开始行驶了。

image-20210217092439691

每秒钟 ALVINN 生成 12 次数字化图片,并且将图像传送给神经网络进行训练,多个神经网络同时工作,每一个网络都生成一个行驶方向,以及一个预测置信度的参数,预测置信度最高的那个神经网络得到的行驶方向。比如这里,在这条单行道上训练出的网络将被最终用于控制车辆方向,车辆前方突然出现了一个交叉十字路口,当车辆到达这个十字路口时,我们单行道网络对应的置信度骤减,当它穿过这个十字路口时,前方的双车道将进入其视线,双车道网络的置信度便开始上升,当它的置信度上升时,双车道的网络,将被选择来控制行驶方向,车辆将被安全地引导进入双车道路。

这就是基于神经网络的自动驾驶技术。当然,我们还有很多更加先进的试验来实现自动驾驶技术。在美国,欧洲等一些国家和地区,他们提供了一些比这个方法更加稳定的驾驶控制技术。但我认为,使用这样一个简单的基于反向传播的神经网络,训练出如此强大的自动驾驶汽车,的确是一次令人惊讶的成就。