前言
这篇博客用来记录深度学习的一些基础知识点。参考了一些别人的文章,同时也结合了自己的思考。
问题
Q1.当训练神经网络来解决分类问题时,应该选用MSE还是CE作为损失函数?
A1: 在解决分类问题时,网络的最后一层通常会是softmax(多分类)或者是sigmoid(二分类),将各个类别维度的输出结果都压缩到0-1的范围,且和为1。此时如果我们搭配的损失函数是MSE,那么极易造成的结果就是在反向传播中出现梯度消失问题。如果大家对具体的推导过程感兴趣,可以参考这篇文章
Q2.如何理解CNN中的的参数共享以及稀疏交互?
A2: 对于一个输入的数据(比如图像或文本序列),在输入数据的不同部位,我们使用完全相同的卷积核(Kernel)进行卷积运算。通过这种方式,我们试图来抽取数据的某个维度的特征信息,这样产生的结果被称为一个feature map。当然在实际情况中,我们会使用多个不同的卷积核来进行数据不同维度特征的提取。同时,相比于对于输入数据的不同部分采用不同的卷积核,卷积核的参数共享可以有效减少模型的参数量,降低模型的训练难度。除了参数共享之外,卷积操作的本质还包含了另一种特性,被称为稀疏交互,相比于全连接神经网络中每一个神经元都与前一层的每个输入相关联,在CNN中,我们的卷积核尺寸一般远小于输入数据的尺寸,即每个输出神经元仅与输入数据的局部区域关联,这种特性被称为稀疏交互,这也是卷积网络参数量远小于一般神经网络的重要原因之一。
Q3.如何理解1x1卷积核的意义?
A3: 1x1卷积的一个最大的作用就是可以改变输入数据的维度,以图像数据为例,假设我们有一张RGB总共3个channel的图像数据,我们可以使用多个1x1的卷积核改变当前图像数据的channel个数,比如我们可以使用5个1x1的卷积核,将channel维度升到5。当然需要注意的一点是1x1的卷积并不会改变图像的尺寸。除此之外,在1x1的卷积操作之后,我们通常会再加上一些非线性激活函数,来增加模型的拟合能力。
Q4.如何理解RNN中的参数共享?
A4:和CNN一样,RNN中也是参数共享的,不同的是,CNN在空间维度上共享参数,而RNN在时间维度上共享参数,即对于不同的时间节点(序列的不同位置),模型的参数一致。一方面,参数共享能够减少模型参数,降低模型训练难度,同时,从模型的泛化性能来说,各个节点参数共享也是十分有必要的。因为参数共享能够保证模型扩展到不同长度的样本时始终保持一定的泛化性能。试想如果对于每一个时间节点都有单独的参数,那么当我们将模型用于哪些在训练集中没有出现过的长度的序列数据时,模型的性能如何保证?
Q5.如何理解RNN中的梯度消失问题?
A5:首先,传统的DNN也存在梯度消失的问题,其主要原因在于某些激活函数的偏导值很容易趋近于0(比如sigmoid),当网络层数加深后,多个激活函数的偏导连乘导致网络前部分的参数的梯度接近于0,也就是梯度消失的现象。但是对于RNN来说,除了激活函数的问题之外,其本身的结构也是导致梯度消失的重要原因。我们知道,RNN在每个节点共享参数,也就是说对于某个权值w来说,它对于loss的影响遍布整个序列的每一个节点。当我们对其求梯度时,会发现存在很多子项中包含大量的连乘项,对映着隐藏层之间的偏导关系。这种大量的连乘项是由RNN的性质决定的,无可避免,而这也是导致出现梯度消失或者爆炸的核心原因。事实上,虽然说梯度中包含着大量的这样的子项,即长时依赖项,但是也包含着短距连乘项,这些子项不易出现梯度消失或爆炸的情况,似乎也就意味着总体来说RNN不易出现象梯度消失的情况。但是这些子项只能帮助RNN的参数进入一个局部最优解,一旦进入后,这些子项就无法帮助RNN继续优化了,而此时,那些长时依赖的子项受到梯度消失的影响,无法发挥作用,导致RNN的参数优化停滞不前。这也是RNN无法在长序列建模任务中发挥作用的原因,即因为梯度消失的原因,无法充分利用长距离的信息。
Q6.RNN在训练时为什么会存在梯度的剧烈波动?
A6:在上一个问题中我们已经说明了RNN存在梯度消失的情况以及其不适合做长序列的建模的原因。但是除了梯度消失的现象,RNN在训练中也会出现梯度爆炸,即模型训练到某个阶段时突然出现梯度陡增,模型的loss出现剧烈的波动。那么这一现象的原因,其实还是归结于RNN在每个时间节点都共享参数,有时它的变化对整体没有影响,但是一旦有影响,其影响会通过不断的累乘而叠加,产生爆炸性的梯度变化,当我们学习率一定时,模型的训练就会变得非常困难。
Q7.LSTM是如何缓解梯度消失问题的?
A7:相对于传统的RNN,LSTM的结构更加复杂,在每一个神经元中,都引入了3个gate,分别是input gate, forget gate,以及output gate。input gate和output gate 顾名思义,分别对应于每个xt的input中信息的流入控制和output的输出控制。最重要的一部分是forget gate,它用于决定在每个时刻保留在memory cell(LSTM中存在一个cell用于保存之前节点的信息)中的信息有多大比例会被下一时间节点继续保留。我们可以通过下面这个公式来看一看这部分的运作流程。 我来解释一下每个部分的意义,首先等式左边的cj 代表当前的memory cell中的信息。等式右边的第一项代表前一节点cj-1 中的信息有多大比例sigmoid(Wf*Xj+bf) 被保留,其中的Wf 和bf 为forget gate的权重参数和偏置项,外层嵌套一层激活函数,一般使用sigmoid 将得到的结果压缩到0-1之间。第二项是input的结果与input gate的乘积,即代表当前输入有多大比例被保留到memory cell。我们知道在RNN中,出现梯度消失的原因是长距离项连乘导致的,即一系列的偏导值的乘积。但是当我们去看LSTM中的情况,比如,cj 对cj-1 的偏导,我们会得到如下结果 这一项的值介于0到1之间,但一般情况下,这些值会接近于0或1。但是即使该值为0,也只是代表forget gate选择忘记之前的信息,这是feature而不是bug。当该值为1时,即保证这部分的梯度永远存在。总结来说,forget gate的存在解决了RNN的长期依赖问题,不管网络的深度,模型能够自主决定信息的存储与否,即只要forget gate一直打开,那么memory中的信息就永远不会被抹去。当然,还有一个梯度爆炸的问题存在,对于LSTM来说,其本身无法解决梯度爆炸的问题,但是由于其复杂的结构中中包含多个激活函数,其发生梯度爆炸的可能性很低。
Q8.简单介绍一下fastText 文本分类器
A8:fastText是FB在2016年开源的一个词向量计算和文本分类工具,其仅仅通过一个浅层的网络,就拥有和深度网络媲美的精度。其核心思想是将整个文本的词以及n-gram向量叠加平均得到文本向量,然后再使用该文本向量表示做softmax多分类。其中最主要的两个特定就是1.使用n-gram特征,该特征的引入可以保留文本的次序信息,提升模型性能。2.在softmax分类时,使用分层softmax代替标准的softmax,使得计算复杂度从O(n)降到O(log(n)),提升训练速度。
Q9.为什么在神经网络中需要引入激活函数?
A9:我们知道一般的神经网络,比如简单的ANN,都只涉及线性操作,但是对于大多数应用场景,数据的分布大多是非线形的,因此引入激活函数的作用就是引入非线形,来增强网络的拟合能力,也正是因为这个原因,大多数激活函数都是非线形的。
Q10.列举常见的激活函数以及它们的特点。
A10: 提到激活函数,最常见的就是sigmoid函数,因为其可以将线形输出结果压缩到(0,1)之间,因此其非常适用于对于概率值的处理,比如在LSTM的各种门的输出我们通常会使用sigmoid进行激活。 但是使用sigmoid函数也有如下几个缺点:1.因为涉及幂运算和除法,其计算量相对偏大。2.对sigmoid函数求导的结果介于0到0.25之间,对于深度的神经网络,使用sigmoid函数会导致梯度反向传播时出现梯度消失的现象。3.sigmoid函数到输出是非0均值的,这样带来的一个不好的后果就是随着网络的加深,每一个隐藏层的数据分布会不断的变化,偏离数据的原始分布。
除了sigmoid,另一种常见的激活函数是tanh函数,其和sigmoid函数十分类似,不同的是其将输出结果压缩到(-1,1)之间,我们可以将其看作是sigmoid函数向下平移拉伸后的结果,其公式为 与sigmoid相比,其解决了输出范围不是0-centered的问题,同时它的导数范围在(0,1)之间,相比sigmoid,梯度消失问题得到部分缓解,但是还是无法完全解决。
除了上述两种激活函数,目前主流的激活函数还有Relu,修正线形单元函数。其表达式非常简单,relu=max(0,x) ,即在输入x<0的时候,返回0,x>=0的时候,返回x。由于在x>=0的时候,relu的导数为1,因此其保证在“链式反应”中不会因为激活函数出现梯度消失的现象,也就意味着梯度下降的强度很大程度上取决于参数权值的大小,在这种情况下,可能会出现梯度爆炸的情况,为例了解决这个问题,我们通常选择权值控制或者梯度裁剪(设置上限)等方法。对于x<0的情况,relu会直接将其设置为0,但是这么做并不是那么合理,或者说过于草率,因为其中可能仍包含一些有效特征,但是因为relu的原因,这部分参数无法继续更新了,即这部分神经元处于‘dead’状态。当我们的学习率设置的过大时,可能存在网络中有很大部分的神经元都处于‘dead’状态,因此,在使用relu激活函数时,我们需要注意不要将学习率设的太高。总结来说,relu激活函数有如下3个特点:1.摒弃了复杂的计算,提升了运算效率。2.解决了梯度消失的问题,但是需要注意梯度爆炸。3.需要设置合理的学习率来防止神经元过早‘dead’的情况。
为了防止模型的‘dead’情况,后来的学者将relu做了进一步的改进,将x<0的部分不直接设置为0,而是设置为一个很小的斜率。 其中ai是一个(1,+∞)的固定参数,当然我们还有其他的变种,比如将ai设置为一个可学习的参数的PRelu,或者将ai设置为一个随机参数的RRelu等等,下面是Relu及其变种的示意图。
Q11.简单介绍一下Batch Normalization以及它的作用
A11:Batch Normalization 的引入本质上是为了解决ICS问题(Internal Covariate Shift),即在神经网络的训练中,随着每一层参数的不断变化,传给下一层的输入分布也在不停的改变。当我们使用sigmoid作为激活函数时,随着网络的加深,输入分布极大概率向sigmoid函数取值区间的上下两端靠近,一旦发生这种情况,紧接着就会出现反向传播时梯度消失的现象,导致模型训练受阻,收敛缓慢。Batch Normalizaton通过一定的规范化手段,把每层神经网络任意神经元输入值的分布强行拉回到均值为0方差为1的标准正态分布,这样使得激活函数的输入值落在非线形函数对输入变化敏感的区域,从而改善梯度消失的情况,提高模型的训练稳定度,加速模型的训练和收敛。
Q12.什么是反向传播算法(Backpropagation)
A12:反向传播算法是当前神经网络训练的核心算法,其大概可以归结为3步,首先随机初始化网络的参数,然后根据现有参数及数据,通过前向传播计算损失(模型预测和真实值的距离),然后以该损失作为起点,利用链式法则反向计算损失函数对模型各个参数的梯度,然后使用梯度下降更新模型参数。反复上述步骤,直至模型收敛。具体来说,反向传播的可以用下面这个式子来表示 等式右边代表最终loss对第l层第n个神经元的梯度,假设该神经元与第l+1层的m个不同的神经元相连,表示该神经元通过影响后一层的这m个神经元来影响最终的loss,所以该梯度可以理解为是后m个神经元的梯度再乘以与它们相连的权重w(n,m) 以及激活函数f 的总和。(根据链式法则)这就是计算每个神经元梯度的核心公式,本质上它是一个迭代式,其中下一层每个神经元的梯度又可以不断地下后迭代直到最后的输出层。
Q13.在设定神经网络的初始值时,是否可以将其均设为0?
A13:当我们考虑一个全连接的神经网络时,在同一层中的每一个神经元都是同构的,它们拥有完全相等的地位,如果再将它们的初始值设为一致,那么它们在训练过程中的变化也会趋于一致,学习的过程陷入一种无用的对称性中,无法发掘真正的特征。因此设为0是一种不正确的做法。一般而言,我们会选择随机初始化,即保证每个神经元有充分的独立学习空间。在我们随机初始化时,一般我们会选择正态分布,为了保证在每一层的传递过程中保证数据的同分布,比如标准正态分布N(0,1) ,我们在初始化与某个神经元相连的权重时,一般会将正态分布的标准差设定为1/sqrt(M) ,其中M为与该神经元相连的个数(前一层),这样能够确保该神经元的输出满足标准正态分布。
Q14.什么是Attention机制
A14:注意力机制最初被用于视觉图像领域,用于模拟人脑对图像不同部分的关注程度的差异。后来在NLP领域尤其是seq2seq模型中被广泛应用。在具体介绍Attention之前,我们先来大概说一说seq2seq模型。简单来说,seq2seq模型的基本结构就是一个encoder加上一个decoder。encoder负责将输入的序列解码,形成一个特定维度的语义向量,用于表征输入序列。然后将得到的语义向量会作为decoder的输入,用于生成目标序列。典型的应用比如文本翻译。一般情况下,我们会使用诸如LSTM,GRU等网络结构作为encoder和decoder。但是目前的这种seq2seq模型存在一个严重的问题,那就是对于一个长序列来说,将整个序列的信息都存储在一个语义向量中,过于强人所难了。一般来说,对于目标序列的每一个词,往往会与输入序列的对应位置的词的关联性更高,即在预测每一个目标序列的词汇时,我们希望能尽可能利用输入序列对应位置的词语信息,即输入序列的每一个位置隐藏层的输出,而不仅仅是最后一个位置的隐藏层输出。顺着这个思路,Bahdanau等人在2015年的一篇名为Neural Machine Translation by Jointly Learning to Align and Translate的文章中,第一次将Attention机制引入NLP任务中。说了这么多,那么究竟什么是Attention呢?一句话总结就是对于不同的特征加权求和的机制。在这篇论文中,作者采取的策略是对于目标序列的每一个位置,都有一个语义向量,而该向量是输入序列不同位置隐藏层输出的加权求和。最终我们会有一个目标序列不同位置和输入序列不同位置构成的权重矩阵。每一个位置的权重代表输入序列的某个位置对于预测目标序列某个位置的贡献程度大小。我们可以对该权重矩阵进行可视化,就能得到一个清晰的权重分布。下面是原论文中的一张图。 除了上述这种attention方法,在之后的时间中,对于不同的NLP任务,又出现了各种不同的attention变种,涉及不同的加权方式,不同的求和方式。但无论是怎样的变化,核心都是加权求和。
|