本系列文章都是关于UFLDL Tutorial的学习笔记
Neural Networks
- 对于一个有监督的学习问题,训练样本输入形式为(x(i),y(i))。使用神经网络我们可以找到一个复杂的非线性的假设h(x(i))可以拟合我们的数据y(i)。我们先观察一个神经元的机制:
- 每个神经元是一个计算单元,输入为x1,x2,x3,输出为:
- 其中f()是激活函数,常用的激活函数是S函数:
- S函数的形状如下,它有一个很好的性质就是导数很方便求:f’(z) = f(z)(1 ? f(z)):
- 还有一个常见的激活函数是双曲正切函数tanh:
- 它的导数f’(z) = 1 ? (f(z))^2):
- softmax激活函数的导数:f’(z)=f(z)?f(z)^2
- S函数的取值在[0,1]之间,而tan函数的取值在[-1,1]之间.
Neural Network model
- 神经网络就是将上面的单个神经元连接成一个复杂的网络:
- 如图所示的三层神经网络包含一个输入层(3个输入单元),一个隐藏层(3个计算单元),一个输出层(一个输出单元)。我们的所有参数描述为(W,b) = (W(1),b(1),W(2),b(2))。Ws_ij表示的是第s层的第j个神经元到第s+1层的第i个神经元的权值,同理bs_i表示第s+1层的第i个神经元的偏差。可知,偏差b的数目等于总的神经元的个数减去输入层的神经元个数(输入层不需要偏差),而权值w的数目等于神经网络的连接数。最后的输出计算如下:
- 更紧凑的写法就是讲其写成向量的积,这样以矩阵的形式存储系数可以加速计算。其中z表示该层所有神经元的输入,a表示该层的输出:
- 我们把上面这种求最终输出的算法称为向前传播(feedforward)算法。对于输入层,我们可以用a1=x表示。给定l层的激活值al,计算l+1层的激活值的公式如下:
Backpropagation Algorithm
- 假设我们现在有一个固定大小为m的训练集{(x1,y1),(x2,y2)…(xm,ym)},我们使用批梯度下降法来训练我们的网络。对于每个训练样本(x,y),我们计算它的损失函数如下:
- 引入规范化(权重衰减项:weight decay),使得系数尽可能的小,总的损失函数如下:
- 需要注意的是通常规范化不会使用在偏差b上,因为对b使用规范化最终获得网络和之前没有太大区别。这里的规范化其实是贝叶斯规范化的一个变体,具体可以看CS229 (Machine Learning) at Stanford的视频。
- 上面的损失函数通常在分类和回归问题中被用到。在分类中通常y取值为0,1,而我们的S函数的取值范围是在[0,1]之间。而如果使用tanh函数,由于取值范围是[-1,1],我们可以将-1表示0,1表示1,可以将0作为分界值。对于回归问题我们则需要先将我们的输出按比例缩小到[0,1]之间,然后最后预测时相应的放大。
- 我们的目标是最小化损失函数J:首先随机初始化w和b,由于梯度下降法容易局部最优,因此要进行多次试验,每次随机选择的参数不能相同。计算完所有样本的损失后,更新w和b的公式如下,其中α是学习率:
- 对于这个更新公式,最核心的是计算偏导。我们采用反向传播( backpropagation)算法来计算偏导。反向传播能够帮助解释网络的权重和偏置的改变是如何改变代价函数的。归根结底,它的意思是指计算偏导数?C/?wl_jk和?C/?bl_j。但是为了计算这些偏导数,我们首先介绍一个中间量,δl_j,我们管它叫做第l层的第j个神经元的错误量(error)。我们可以先计算一个样本产生的梯度向量,最后求所有样本梯度的平均即可:
反向传播具体推导如下:
- 首先使用向前传播计算出L2,L3…以及输出层的激活值。
- 对于输出层的每一个输出单元计算错误量(a=f(z)利用偏导的链式法则):
- 对于中间的隐藏层,我们计算每个神经元的错误量。其中括号里面可以理解为l+1层所有与l层该神经元相连的偏导乘以权值即为该神经元的损失值:
- 定义偏导如下:
- 训练神经网络的伪代码如下(后面的λW是规范化项):
根据neural networks and deep learning这本书中对于反向传播是这么理解的:
- 对于第l层第j个神经元,如果zl_j变为zl_j+Δzl_j,那么会对最终整体的损失带来(?C/?zl_j)*Δzl_j的改变。反向传播的目的是找到这个Δzl_j,使得最终的损失函数更小。假设?C/?zl_j的值很大(不论正负),我们期望找到一个和?C/?zl_j符号相反的Δzl_j使得损失降低。假设?C/?zl_j的值趋近于0,那么Δzl_j对损失的改变是微乎其微的,表示这个神经元以及训练接近最优了。这里以一个启发式的感觉将?C/?zl_j看成度量一个神经元的误差的方法。
- 受上面的启发,我们可以定义第l层第j个神经元的误差是:
- 输出层误差的方程,这个是根据偏导数链式法则 ?C/?z= (?C/?a)*(?a/?z) :
右式第一项表示代价随着第j个神经元的输出值的变化而变化的速度。假如C不太依赖一个特定的神经元j,那么δl_j就会很小,这也是我们想要的效果。右式第二项刻画了在zl_j处激活函数σ变化的速度。如果使用二次代价函数,那么?C/?al_j = (aj ? yj)很容易计算。
- 使用下一层的误差δl+1来表示当前层的误差δl,因为输出层是可以确定的计算出来,因此计算其它层要倒着向前传播:
其中 (wl+1)T是第l+1层权重矩阵 wl+1的转置。假设我们知道第l+1层的误差δl+1,当我们应用转置的权重矩阵(wl+1)T,我们可以凭直觉地把它看作是在沿着网络反向移动误差,给了我们度量在第l层输出的误差方法,我们进行Hadamard(向量对应位置相乘)乘积运算 ⊙σ′(zl)。这会让误差通过 l 层的激活函数反向传递回来并给出在第 l 层的带权输入的误差 δ向量。
- 代价函数关于网络中任意偏置的改变率:
误差 δl_j 和偏导数值?C/?bl_j 完全一致,针对同一个神经元。
- 代价函数关于任何一个权重的改变率:
这告诉我们如何计算偏导数?C/?wl_jk,其中 δl 和 al?1 这些量我们都已经知道如何计算了。
- 将其向量化:
其中 ain是输入给权重 w 的神经元的激活值, δout 是输出自权重 w 的神经元的误差。当激活值 ain 很小, ain ≈ 0,梯度?C/?w 也会趋向很小。这样,我们就说权重缓慢学习,表示在梯度下降的时候,这个权重不会改变太多。换言之, 来自低激活值神经元的权重学习会非常缓慢。
- 当 σ(zl_j) 近似为 0 或者 1 的时候 σ 函数变得非常平。这时σ’(zl_j) ≈ 0。所以如果输出神经元处于或者低激活值( ≈ 0)或者高激活值( ≈1)时,最终层的权重学习缓慢。这样的情形,我们常常称输出神经元已经饱和了,并且,权重学习也会终止(或者学习非常缓慢)。如果输入神经元激活值很低,或者输出神经元已经饱和了(过高或者过低的激活值),权重会学习缓慢。
- 第二个方程的证明
- 反向传播过程给出了一种计算代价函数梯度的方法:
- 给定一个大小为 m 的小批量数据,在这个小批量数据的基础上应用一步梯度下降学习算法:
- 对l层的第j个神经元的权值做一点修改,会导致一些列激活值的变化:
- ?wl_jk 导致了在第l层 第j个神经元的激活值的变化 ?al_j。
- ?al_j 的变化将会导致下一层所有激活值的变化,我们聚焦到其中一个激活值上看 看影响的情况,不妨设 al+1_q :
- 这个变化 ?al+1_q 又会去下一层的激活值。实际上,我们可以想象出一条从 wl_jk到 C 的路径,然后每个激活值的变化会导致下一层的激活值的变化,最终是输出层的代价的变化。假设激活值的序列如下 al_j, al+1_q, …,
aL-1_n, aL_m,那么结果的表达式就是:
- 我们用这个公式计算 C 关于网络中一个权重的变化率。这个公式告诉我们的是:两个神经元之间的连接其实是关联于一个变化率因子,这个因子是一个神经元的激活值相对于其他神经元的激活值的偏导数。从第一个权重到第一个神经元的变化率因子是 ?al_j/?wl_jk。路径的变化率因子其实就是这条路径上的众多因子的乘积。而整个的变化率 ?C/?wjk l就是对于所有可能的从初始权重到最终输出的代价函数的路径的变化率因子的和。针对某一个路径,这个过程解释如下:
Gradient checking and advanced optimization
- 在本节中,我们描述了一个数值方法用来检查你求解导数的代码是否正确,进行导数检查过程将大大增加你的代码的正确性。
- 假设我们想最小化J(θ),我们可以进行梯度下降:
- 假设我们找到一个函数g(θ)等于这个导数,那么我们如何确认这个g(θ)是否正确呢?回忆导数的定义:
- 我们可以比较上式和g(θ)是否一样来检验函数g是否正确,通常ε设置为一个很小的数(比如10^-4)。假定ε=10^-4,通常你会发现上面两个式子至少有4位有效数字是一样的(通常会更多)
- 现在考虑θ是个向量而不是一个值,我们定义:
- 其中θi+和θ几乎相同,除了第i个位置上增加ε。
- 我们可以对每个i 检查下式是否成立,进而验证gi(θ)的正确性:
- 再利用反向传播求解神经网络时,正确的算法会得到下面这样的导数,我们需要使用上面的方法来验证得到的导数是都正确:
时间: 2024-10-24 16:20:29