吴恩达机器学习作业翻译4——NN back propagation

程序设计练习4:神经网络学习

介绍

    在这个练习中,你将实现神经网络的反向传播算法并将其应用到手写数字识别的任务中。在开始编程之前,我们强烈建议你线观看视频课程并完成相关主题的复习问题。

    要开始练习,你需要下载起始代码并将其内容解压缩到你希望完成练习的目录中。如果需要,请在开始本练习之前使用Octave/MATLAB中的cd命令更改到此目录。

    你也可以在课程网站的“环境设置说明”中找到安装Octave/MATLAB的说明。

本练习包含的文件

ex4.m - 指导你完成练习的Octave/MATLAB脚本
ex4data1.mat - 手写数字识别的训练集
ex4weights.mat - exercise 4的神经网络参数
submit.m -提交作业的脚本
displayData.m - 可视化数据集的脚本
fmincg.m - 最小化函数 (类似于fminunc)
sigmoid.m - S函数
computeNumericalGradient.m - 数值计算梯度
checkNNGradients.m - 帮助检查你的梯度的代码
debugInitializeWeights.m - 初始化权重的函数
predict.m - 神经网络预测函数
[*] sigmoidGradient.m - 计算S函数的梯度
[*] randInitializeWeights.m - 随机初始化权重
[*] nnCostFunction.m - 神经网络代价函数

* 表示你需要完成的文件

    在本练习中,你将使用ex4.m脚本。该脚本为题目设置数据集并且调用你编写的函数。你不需要修改这些脚本,只需要按照作业说明定义其他函数。

在哪里寻求帮助

    本课程的练习使用非常适合数值计算的高级编程语言Octave或MATLAB。如果你没有安装Octave或MATLAB,请参阅课程网站上“环境设置说明”中的安装说明。

    在Octave/MATLAB命令行中输入help紧跟函数名称会显示内建的函数说明。比如输入help plot会显示绘图函数的帮助信息。更多Octave和MATLAB的函数说明请在Octave官网MATLAB官网查阅。

    我们也非常鼓励使用在线讨论与其他学生讨论练习。但是,不要查看任何源代码或与他人共享源代码。


1、神经网络

    在前面的练习中,你实现了神经网络的前馈传播并根据我们提供的权重使用它来预测手写数字的识别。在本练习中,你将实现反向传播算法来学习神经网络的参数。

    ex4.m脚本将指导你逐步完成本练习。

1.1 数据可视化

    在ex4.m的第一部分,代码加载数据集并通过调用displayData函数将其展示在一个二维图中(图1)。


Figure 1: Examples from the dataset

    这和你在前面的练习中使用的是同一个数据集。在ex3data1.mat中有5000个训练样本,每一个训练样本是一个20px * 20px的灰度数字图像。
每个像素由一个浮点数表示,该浮点数表示该位置的灰度强度。20×20像素的网格被“展示”成一个400维的向量。这些训练示例中的每一个都变成了数据矩阵X中的一行。这样就给了我们一个5000×400矩阵X,其中每一行都是手写数字图像的训练示例。

    训练集的第二部分是包含训练集标签的5000维向量y,为了使它与Octave/MATLAB索引更加兼容,在没有零索引的情况下,我们将数字0映射到值10。因此,数字“0”被标记为“10”,而“1”到“9”的数字按其自然顺序被标记为“1”到“9”。

1.2 模型表示

    我们的神经网络如图2所示,总共有3层——一个输入层、一个隐藏层和一个输出层。回想一下,我们的输入是数字图像的像素值。由于图像大小20×20,因此给了我们400个输入层单位(不包括额外的偏差项)。和之前一样,训练数据将被加载到变量X和y中。

    我们已经为你提供了我们训练的一组神经网络参数($θ^{(1)}$,$θ^{(2)}$)。他们存在ex4weights.mat中并可以使用ex4.m加载到Theta1和Theta2中。参数具有针对神经网络的大小,其在第二层中具有25个单元并且具有10个输出单元(对应于10个数字类)。

% Load saved matrices from file
load('ex3weights.mat');
% The matrices Theta1 and Theta2 will now be in your Octave
% environment
% Theta1 has size 25 x 401
% Theta2 has size 10 x 26


Figure 2: Neural network model

1.3 前馈和代价函数

    现在你将实现神经网络的代价函数和梯度。首先完成nnCostFunction.m中的代码返回代价。

    回想一下神经网络的代价(没有正则化)

其中$h_θ(x^{(i)})$如图2所示计算,K=10是可能标签的总数。注意,$h_θ(x^{(i)})_k$ = $a_k^{(3)}$是第k个输出单元的激活(输出值)。另外,回想一下,原来的标签(在变量y中)是1,2,…, 10,为了训练神经网络,我们需要将标签重新编码为只包含0或1值的向量,像这样

    例如,如果$x^{(i)}$是一个数字5的图像,那么对应的$y^{(i)}$(你在代价函数中使用的)应该是一个10维的向量,其中$y_5$=1,其他元素为0。

    你应该实现前馈计算,该计算为每个样本计算$h_θ(x^{(i)})$并且对所有样本的代价求和。你的代码应该适用于具有任意数量标签任意规模的数据集(你可以认为总会有至少K≥3个标签)。

实现注意:矩阵X以行为单位包含样本(例如X(i, :)是第i个训练样本,表示为一个n * 1的向量)。当你在nnCostFunction.m中写代码时,你需要在X矩阵中添加全为1的列。神经网络中每个单元的参数用Theta1和Theta2表示为一行。具体地说,Theta1的第一行对应于第二层中的第一个隐藏单元。你可以在示例中使用for循环来计算代价。

    一旦你完成了,ex4.m将使用加载的Theta1和Theta2参数调用nnCostFunction.m。你应该看到成本大约是0.287629。

            ==你现在应该提交答案==

1.4 正则化的代价函数

    正则化的神经网络的代价函数如下:

    假设神经网络有三层——一个输入层,一个隐藏层和一个输出层。但是,你的代码应该适用于任意数量的输入单元、隐藏单元和输出单元。虽然为了清楚起见,我们已明确列出了$Θ^{(1)}$$Θ^{(2)}$的上述索引,但请注意,你的代码应使用任何大小的$Θ^{(1)}$$Θ^{(2)}$

    请注意,你不应该将与偏差对应的那一项正则化。对矩阵Theta1和矩阵Theta2来说,所对应的就是它们的第一列。你现在应该正则化你的代价函数。注意,你可以先使用现有的nnCostFunction.m计算非正则化代价函数J然后为其添加正则项。

    一旦完成,ex4.m将使用加载了Theta1和Theta2的参数集调用你的nnCostFunction,并且λ=1。你应该看到成本约为0.383770。

            ==你现在应该提交答案==

2、反向传播

    在这部分练习中,你将使用反向传播算法为神经网络代价函数计算梯度。你需要完成nnCostFunction.m,以便返回适当的梯度值。 计算出梯度后,你将能够通过使用高级优化器(如fmincg)最小化成本函数J(Θ)来训练神经网络。

    你将首先实现反向传播算法来计算(未正则化的)神经网络的参数的梯度。当你验证了你的梯度计算(非正则化的例子)是正确的之后,你将实现正则化神经网络的梯度。

2.1 Sigmoid梯度

    为了帮你开始这部分练习,你第一个需要实现的是sigmoid梯度函数。sigmoid函数的梯度计算公式如下:

    当你结束之后,尝试在Octave/matlab命令行中通过调用sigmoidGradient(z)来测试一些值。对于z的比较大的值(包括正值和负值),梯度应该接近于0。当z=0时,梯度应该正好是0.25。你的代码还应该处理向量和矩阵。对于矩阵,函数应该对每个元素执行sigmoid梯度函数。

            ==你现在应该提交答案==

2.2 随机初始化

    在训练神经网络时,随机初始化参数以进行对称破坏非常重要。随机初始化比较好的一个策略是在范围[-E,E]中随机均匀地为θ选择值。你应该让E=0.12。这个范围的值确保参数保持在较小的范围内,并使学习更有效。

    你的工作是完成randInitializeWeights.m中的代码为θ初始化权重,修改文件并加入以下代码:

    % Randomly initialize the weights to small values
    epsilon init = 0.12;
    W = rand(L out, 1 + L in) * 2 * epsilon init − epsilon init;

            ==这部分练习不需要提交任何代码==

2.3 反向传播


Figure 3: Backpropagation Updates.

    现在你将实现反向传播算法。回想一下,反向传播算法背后的直观理解如下。
给定一个训练样本($x^{(t)}$, $y^{t}$),我们将首先运行一个“向前传递”来计算整个网络中的所有激活,包括假设函数的输出值。然后我们为第l层的每个节点(神经元)j计算误差$δ^{(l)}_j$,它来权衡该节点对输出中的任何错误“负责”的程度。

    对于输出节点,我们可以直接测量网络激活和真实目标值之间的差异,并使用它来定义$δ^{(3)}_j$(因为第3层是输出层)。对于隐藏单元,你将根据(l+1)层中节点的误差项的加权平均值计算$δ^{(l)}_j$

    详细一点就是,这是反向传播算法(图3)。你应该在一个循环中实现步骤1到4,该循环每次处理一个样本。具体来说,你应该为t=1:m实现一个for循环并在for循环中加入下面的四个步骤,第t次迭代在第t个训练样本($x^{(t)}$, $y^{t}$)上执行计算。步骤5将累积梯度除以m得到神经网络代价函数的梯度。

    1、将输入层的值($a^{(1)}$)设置为第t个训练样本$x^{(t)}$。执行一个前馈传递(图2)为第二层和第三层计算激活($z^{(2)}$, $a^{(2)}$, $z^{(3)}$, $a^{(3)}$)。请注意,你需要添加+1项以确保层a(1)和a(2)的激活矢量也包括偏置单元。在Octave/MATLAB中,如果a_1是一个列向量,为列向量添加1对应a_1 = [1; a_1]。

    2、对在第三层(输出层)的每个输出单元k,设置

其中$y_k$∈ {0,1},指示当前训练样本是属于类k($y_k$= 1),还是属于不同的类($y_k$= 0)。
你可能会发现逻辑数组对此任务有帮助(在之前的编程练习中进行了解释)。

    3、对于隐藏层l=2,设置

    4、使用下面这个式子从这个例子中积累梯度。注意,你应该跳过或者移除$δ^{(2)}_0$。在Octave/MATLAB中,移除$δ^{(2)}_0$对应的操作是delta_2 = delta_2(2:end)。

    5、用1除以累积梯度,得到神经网络代价函数的(非正则化)梯度:

Octave/MATLAB技巧:只有在成功完成前馈后才能实现反向传播算法成本函数。 在实现反向传播算法时,如果遇到尺寸不匹配错误(Octave/MATLAB中的“不一致参数”错误),使用size函数打印出正在使用的变量的大小通常很有用。

    在实现反向传播算法之后,脚本ex4.m将对你的实现运行梯度检查。梯度检查会使你增强代码正确计算梯度的信心。

2.4 梯度检查

    在你的神经网络里,你在最小化代价函数J(θ)。要对参数执行梯度检查,可以设想将参数$Θ^{(1)}$$Θ^{(2)}$“展开”为长矢量θ。通过这样做,你可以将成本函数视为J(θ),并使用以下梯度检查程序。

此处数学符号较多,为避免歧义直接贴原图

    这两个值彼此近似的程度将取决于J的细节。但是,假设E= 0.0004,你通常会发现,上面的左边和右边将至少符合4个有效数字(通常更多)。

    我们在computeNumericalGradient.m中实现了计算数值梯度的函数。虽然不要求你修改文件,但我们强烈建议你查看代码以了解它是如何工作的。

    在ex4.m的下一步中,它将运行提供的函数checkNNGradients.m,它将创建一个小的神经网络和数据集,用于检查梯度。如果你的反向传播实现正确,你应该看到相对差异小于1e-9。

实际提示:当执行梯度检查时,使用具有相对较少数量的输入单元和隐藏单元的小型神经网络更加有效,因此具有相对少量的参数。 θ的每个维度需要对成本函数进行两次评估,这可能代价比较高。 在函数checkNNGradients中,我们的代码创建了一个小型随机模型和数据集,与computeNumericalGradient一起用于梯度检查。 此外,在确信梯度计算正确后,应在运行学习算法之前关闭梯度检查。

实用提示:梯度检查适用于任何计算成本和梯度的函数。具体来说,可以使用相同的computeNumericalGradient。函数来检查其他练习的梯度实现是否也正确(例如,逻辑回归的成本函数)。

            ==一旦成本函数通过(非正则化)神经网络成本函数的梯度检查,就应该提交神经网络梯度函数(反向传播)。==

2.5 正则化神经网络

    在你成功地实现了反向传播算法之后,你将向梯度添加正则化。为了解释正则化,在使用反向传播计算梯度之后,可以将其作为附加项添加进来。

    具体地说,在你计算完$\Delta^{l}_{ij}$之后使用反向传播,你应该使用

    注意,你不能正则化用于偏差项的$θ^{(l)}$的第一项。还有就是,参数θ的i是从1开始索引的,j是从0开始索引的。因此,

    令人困惑的是,在Octave/MATLAB中索引是从1开始的(所有的i和j都是),因此Theta1(2,1)实际上对应的是$θ^{(l)}_{2,0}$

    现在,修改在nnCostFunction中计算梯度的代码,使之符合正则化。完成后,执行ex4.m脚本将继续在你的实现上运行梯度检查。如果你的代码是正确的,你应该期望看到的相对差异小于1e-9。

            ==你现在应该提交答案==

2.6 使用fmincg学习参数

    成功实现神经网络成本函数和梯度计算后,ex4.m脚本的下一步将使用fmincg来学习一个好的集合参数。

    训练完成后,ex4.m脚本将通过计算正确的示例百分比来继续报告分类器的训练准确性。 如果你的实现是正确的,你应该看到报告训练精度约为95.3%(由于随机初始化,这可能会变化约1%)。 通过训练神经网络进行更多迭代,可以获得更高的训练精度。 我们鼓励你尝试训练神经网络以进行更多迭代(例如,将MaxIter设置为400)和改变正则化参数λ。 通过正确的学习设置,可以使神经网络完全适合训练集。

3、可视化隐藏层

    理解神经网络学习内容的一种方法是可视化隐藏单元捕获的表示。 非正式地,给定一个特定的隐藏单元,可视化其计算内容的一种方法是找到一个输入x,使其激活(即激活值$(a^{(l)}_i)$接近1)。 对于你训练的神经网络,请注意第i行$Θ^{(1)}$是401维向量,该向量表示第i个隐藏单元的参数。 如果我们丢弃偏差项,我们得到一个400维向量,表示从每个输入像素到隐藏单位的权重。

    因此,将隐藏单元捕获的“表示”可视化的一种方法是将这个400维的向量重新塑造成20×20的图像并显示出来。ex4.m的下一步是使用displayData函数,它将向你显示一个包含25个单元的图像(类似于图4),每个单元对应于网络中的一个隐藏单元。

    在经过训练的网络中,你应该发现隐藏的单元大致对应于在输入中查找笔画和其他模式的检测器。


Figure 4: Visualization of Hidden Units.

3.1 可选(不评分)练习

    这部分练习中,你将尝试不同的神经网络学习设置,以了解神经网络的性能如何随正则化参数λ和训练步骤数(使用fmincg时的MaxIter选项)而变化。

    神经网络是非常强大的模型,可以形成高度复杂的决策边界。 如果没有正则化,神经网络可以“过度拟合”训练集,使其在训练集上获得接近100%的准确度,但对于之前未见过的新例子则不然。 你可以将正则化λ设置为较小的值,将MaxIter参数设置为较高的迭代次数,以便为你自己查看。

    当你更改学习参数λ和MaxIter时,你还可以自己查看隐藏单元可视化的变化。

            ==这部分不需要提交作业==

提交作业和评分

    完成各个部分之后,请使用提交功能将你的代码提交到我们的服务器。以下是本次作业评分的细则。

    你可以多次提交作业,但我们只考虑最高分。

点个赞呗:程序员虾说 » 吴恩达机器学习作业翻译4——NN back propagation

赞 (6) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

请作者喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏