美文网首页
Lecture4,5,6:Neural Networks

Lecture4,5,6:Neural Networks

作者: dapulser | 来源:发表于2018-08-20 20:58 被阅读0次

    Lecture4,5,6是把神经网络的一些东西分开讲了,个人在笔记的顺序上没有按照原文来,我内容重新编排后整理融合成了这一篇文章

    Lecture4,5,6:Neural Networks

    1. 神经网络抽象

    1.1 抽象生物神经元

        我们在高中就学过神经元是什么样的了。就是他前面有突触,突触可以传递递质,兴奋性递质到达的时候,神经元电位上升,抑制性递质到达,电位下降。总的来说就是接受前面的很多输入,经过一定处理后输出。这是不是跟之前的 Linear Classification一样?也就是说,我们可以将人脑单个神经元的操作视为一个线性分类器。记住,不同突触的能力不一样,有的很厉害,一个突触就可以影响整个神经元的电位,因此,我们还需要一个权重。还有一点,我们知道神经元还有一个“兴奋”的过程,在电位达到一定程度的时候神经元会达到兴奋状态,向后发送脉冲,没达到时是不会发送脉冲的,为了模拟这一点,我们设定一个“激活函数”。总的来说,一个神经元的运行可以理解为,执行操作
    output = activation(W\cdot input)

    1.2 人工神经网络(Artificial Neural Network)

        什么叫做神经网络?很多个神经元在一起连接成网就叫神经网络【滑稽.jpg】。最简单的神经网络可以看成是这样的。



    我们将不同神经元之间分层,这样做有方便计算的考虑。在后面的反向传播中我们会提到这一点。

    2. 神经网络基本计算

    2.1 前向传播 Forward Propogation

        其实很容易发现,神经网络的前向计算方式跟线性分类器其实是一样的,实际上,线性分类器可以看作是一个只有输入和输出的神经网络。
    不过由于激活函数的存在对每一层需要进行两次运算即:
    a = W\cdot x_{input} + b
    x_{output} = activation(a)

    2.2 反向传播 Backward Propogation

        如果我没记错的话,在前面一片文章里,我就提到了一句求导好像就没有下文了,这里比较详细的说说。我们仍然需要简化问题……毕竟……太复杂算得太麻烦,而如果平时只使用框架也不需要频繁进行BP推导。

        我们先从最简单的开始。我们假设我们的网络输出只有一个数字。也就是说,网络是下面这样的,其中W是一个n维行向量,b是一个数字,x是一个n维列向量,y是正确预测结果。我们先看下这是种什么情况。
    向前传播是x \to z = W\cdot x + b \to a = \sigma(z),\hat{y} = a\to L=(\hat{y} - y)^2
    那么我们从最右边开始倒推我们首先计算\frac{dL}{d\hat{y}} = 2\hat{y} - 2y
    接着是\frac{d\hat{y}}{dz} = \hat{y}(1 - \hat{y})
    其中z展开之后是z = w_1x_1 + w_2x_2 + …… + b
    因此有\frac{dz}{dw} = x , \frac{dz}{db} = 1
    最后相乘就得到了参数更新所需的梯度。到现在为止还是简单的链式法则。

        这个还比较简单,我们下面看看当输出有很多个的时候的反向传播。我们先前进一小步,把上面的W改成一个m\times n的矩阵,这样b就是一个列向量了,x是输入还不变,还是n维列向量,当然相对应的y,也变成向量了,m维。
    向前传播还是x \to z = W\cdot x + b \to a = \sigma(z),\hat{y} = a\to L=(\hat{y} - y)^2
    现在我们开始从右面倒推,下面的表达式不是严格的数学表达式,理解意思即可
    首先还是d\hat{y} =da = 2\hat{y} - 2y注意,这个式子里面的都是向量
    接着是{dz} = d\hat{y} (\hat{y}(1 - \hat{y}))这个向量相乘,是逐元素相乘
    db =dz
    我们观察发现z_i = \sum_j W_{i,j} x_j于是有 dW_{i,j} = dz_ix_j因此dW = dz\times x^T
    现在我们已经完成了多输入多输出的反向推导。这不就是神经网络中的一层吗?我们接下来给出更通用的形式。

    2.3 神经网络中一层的计算

    2.3.1 参数

        我们用l表示现在的层数,a^{l - 1}表示这一层从上一层接受的输入向量,W表示这一层的权重,b表示这一层加入的线性偏置,z为这一层的中间变量,a^l表示这一层的输出值。

    2.3.2 Forward Propogation(整个网络的前向传播也称“推理”inference)

    Input:a^{l - 1},Output:a^{l},Cache:z^l

    z^l = W\times a^{l - 1}
    a^l = avtivation(z^l)

    2.3.3 Backward Propogation

    Input:da^{l + 1},Output:da^{l},Cache:dW^l,db^l

    dz^l = da^{l + 1} * activation'(z^{l})
    dW^l = dz^l\times a^{l - 1}
    db^l = dz^l
    da^{l} = (W^l)^T \times z^l
    注意:

    • 这里写的是activation'(z^{l})但是上面举的例子里面是{dz} = d\hat{y} (\hat{y}(1 - \hat{y})),这里的\hat{y}(1 - \hat{y})就是求导结果,不是写错了(真写错了记得留个言)。
    • 关于da^{l}的推导,和上面dW的推导一样,写出式子,整理就行了。

    2.3.4 trian

        接下来根据我们获得的dW,db来更新参数就可以了,更新方式并不止一种,在本文3.5节有介绍。

    2.4 激活函数 Activation Function

        激活函数在之前不太好提,就是因为反向传播说的不很详细,不好讲激活函数的优缺点,下面是几种激活函数的介绍。

    2.4.1 Sigmoid函数

    \sigma (x) = \frac{1}{1 + e^{-x}}

    • 我们看到,这个函数两侧,太平了,所以如果处理不当,会导致“梯度消失”的问题。我们看出这个函数输出是[0,1]的,于是,我们可以想象,其实一层层下去,这个函数会慢慢右移,最后,就会无法学习,初始化权重比较大也会导致同样的问题。
    • 同样是因为函数输出是[0,1]的。如果输入神经元的数据总是正数,那么梯度在反向传播的过程中,将会要么全部是正数,要么全部是负数(具体依整个表达式而定)。这将会导致梯度下降权重更新时出现z字型的下降。

    2.4.2 Tanh函数

    tanh(x) = 2\sigma(2x) - 1
    和sigmoid一样,它也存在饱和问题,但是和sigmoid不同的是,它的输出是零中心的。因此,在实际操作中,tanh比sigmoid更受欢迎。注意,tanh是一个简单放大的sigmoid.

    2.4.3 ReLU函数

    ReLU(x) = max(0,x)
    线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元

    • 优点:相较于sigmoid和tanh函数,ReLU对于随机梯度下降的收敛有巨大的加速作用( Krizhevsky 的论文指出有6倍之多)。这是由它的线性,非饱和的公式导致的。
    • 优点:sigmoid和tanh含有指数运算等耗费计算资源的操作,而ReLU可以简单地通过对一个矩阵进行阈值计算得到。
    • 缺点:在训练的时候,ReLU单元比较脆弱并且可能“死掉”。举例来说,当一个很大的梯度流过ReLU的神经元的时候,可能会导致梯度更新到一种特别的状态,在这种状态下神经元将无法被其他任何数据点再次激活。如果这种情况发生,那么从此所以流过这个神经元的梯度将都变成0。也就是说,这个ReLU单元在训练中将不可逆转的死亡,因为这导致了数据多样化的丢失。(负数没梯度导致的?)
    • 其实我个人一直对ReLU感觉很奇怪……毕竟这看上去……就是个线性单元嘛……谁知道他为啥有用,……不过确实有用

    2.4.4 Leaky ReLU

    \begin{equation} f(x)=\left\{ \begin{aligned} \alpha x (x<0) \\ 0 (x=0) \\ x (x>0) \\ \end{aligned} \right. \end{equation}
    Leaky ReLU是为解决“ReLU死亡”问题的尝试。其中\alpha为一个比较小的数比如0.01.

    3. 训练神经网络

    3.1 数据预处理

        在数据预处理中我们有三个常用记号:数据矩阵X,数据大小[N \times D],其中N代表样本数量,D代表数据维度

    3.1.1 均值减法(Mean subtraction)

        均值减法(Mean subtraction) 是预处理最常用的形式。它对数据中每个独立特征减去平均值,从几何上可以理解为在每个维度上都将数据云的中心都迁移到原点。

    3.1.2 归一化(Normalization)

        归一化(Normalization) 是指将数据的所有维度都归一化,使其数值范围都近似相等。有两种常用方法可以实现归一化。第一种是先对数据做零中心化(zero-centered)(其实就是上面的均值减法)处理,然后每个维度都除以其标准差。第二种方法是对每个维度都做归一化,使得每个维度的最大和最小值是1和-1。但是这个预处理操作只有在确信不同的输入特征有不同的数值范围(或计量单位)时才有意义。在图像处理中,由于像素的数值范围几乎是一致的(都在0-255之间),所以进行这个额外的预处理步骤并不是很必要。


    可视化结果

    3.2 权值初始化

    3.2.1 一种错误的方案:全零初始化

       如果我们的权重是全零的,那么他们的输出也相同,梯度也相同,什么都是一样的,这样用很多神经元就没有意义了。所以,全零初始化是一种错误的初始化。

    3.2.2 随机初始化

       我们使用很多神经元的目的就是为了让他们各自不一样,以此来学习出不同的特征,加大训练的准确度,那怎么着就不一样了呢?干脆随机初始化吧。就这样。但是这样还会有一个不很容易注意到的小问题,在实践中会遇到,我们生成的随机数越多,他们的方差就越大,以常用的Python中的numpy为例,numpy默认生成的是高斯分布,他的均值是指定好的,数字越多,方差自然越大,我们可以这样做

    w = np.random.randn(n) / sqrt(n)
    

    这样做会使得生成的方差都为1,使得神经网络在一开始的时候每一层生成相似的结果。实践证明,这可以提高收敛速度。

    3.3 批量归一化 Batch Normalization

       我们在数据预处理中介绍了归一化,Batch Normalization说简单了就是在神经网络内部进行归一化处理,比如说



    在实践中,使用了批量归一化的网络对于不好的初始值有更强的鲁棒性。

    3.4 正则化

       我们在之前介绍过L2正则化,现在,介绍另一种正则化Dropout。
       Dropout就是在训练的时候随机废掉一些节点,相当于把网络搞小了。用图片来表示就是这样的:


       核心思路:在训练过程中,随机失活可以被认为是对完整的神经网络抽样出一些子集,每次基于输入数据只更新子网络的参数(然而,数量巨大的子网络们并不是相互独立的,因为它们都共享参数)。在测试过程中不使用随机失活,可以理解为是对数量巨大的子网络们做了模型集成(model ensemble),以此来计算出一个平均的预测。
       需要注意的是,我们在训练的时候会规定一个参数

       在这里引入了一个初始化为0的变量v和一个超参数mu。说得不恰当一点,这个变量(mu)在最优化的过程中被看做动量(一般值设为0.9),但其物理意义与摩擦系数更一致。这个变量有效地抑制了速度,降低了系统的动能,不然质点在山底永远不会停下来。通过交叉验证,这个参数通常设为[0.5,0.9,0.95,0.99]中的一个。和学习率随着时间退火(下文有)类似,动量随时间变化有时能略微改善优化的效果,其中动量在学习过程的后阶段会上升。一个典型的设置是刚开始将动量设为0.5而在后面的多个训练轮次中慢慢提升到0.99。

    3.5.3 Nesterov动量更新

       Nesterov动量更新说实话我没怎么看明白他到底想讲什么意思……有时间看论文原文再回来填坑吧。
    v_{pre} = v
    v = mu * v ‐ learningrate * dx
    x =x ‐mu * v_{pre} + (1 + mu) * v

    3.5.4 学习率退火

       我们在之前已经提到过,学习率过大会导致在训练后期网络难以收敛,在最优解附近跳来跳去,为了解决这个问题,我们将使学习率不断下降,常用的有两种。

    • 指数衰减:\alpha = \alpha_0e^{-kt}其中k是超参数,t是迭代次数
    • 1/t衰减:\alpha = \frac{\alpha_0}{1 + kt}其中k是超参数,t是迭代次数

    3.5.5 逐参数适应学习率方法

    我们前面讨论的方案都是对全局学习率进行操控,但是,我们知道,神经网络每一点都是不同的,如果我们对每个参数都用不同的学习率怎么样呢?
    下面为了方便(懒得打公式,下面的式子写成写程序都简单,写公式麻烦的一比)
    下面的结论都是没有推导的(如果我看视频没走神的话),想看可以找原论文看

    3.5.5.1 Adagrad
    cache += dx**2
    x += ‐ learning_rate * dx / (np.sqrt(cache) + eps)
    

    其中eqs一般设置为[0.000000001,0.0001]防止除0。

    3.5.5.2 RMSprop
    cache = decay_rate * cache + (1 ‐ decay_rate) * dx**2
    x += ‐ learning_rate * dx / (np.sqrt(cache) + eps)
    

    decay_rate是一个超参数,常用的值是[0.9,0.99,0.999]。

    3.5.5.3 Adam
    m = beta1*m + (1‐beta1)*dx
    v = beta2*v + (1‐beta2)*(dx**2)
    x += ‐ learning_rate * m / (np.sqrt(v) + eps)
    

    RMSProp的动量版【滑稽.jpg】推荐的参数值eps=0.00000001, beta1=0.9, beta2=0.999

    相关文章

      网友评论

          本文标题:Lecture4,5,6:Neural Networks

          本文链接:https://www.haomeiwen.com/subject/ahtriftx.html