深度学习
该内容由个人整理和归纳,如有不同见解,还望指教~
为什么要通过梯度下降求解参数?
梯度的方向是函数增长速度最快的方向,那么梯度的反方向就是函数下降最快的方向,通过往函数下降最快的方向走,可以走到函数的极小/最小值点。
Embedding
为什么需要 Embedding?
- 因为有些类别特征转换为onehot编码后会非常稀疏,而深度学习的结构不适合处理稀疏向量,因此需要通过Embedding将稀疏向量转换为稠密向量。
- Embedding 的表达能力相比原始向量更强,可以融合大量有价值信息,是极其重要的特征向量。
初始化
为什么要初始化神经网络权重?(全0初始化的问题?)
全零初始化方法在前向传播过程中会使得隐层神经元的激活值均未0,在反向过程中根据BP公式,不同维度的参数会得到相同的更新。
需要破坏这种“对称性”。
本质是为了让输入输出的方差在一个水平上,让收敛过程稳定,防止输入空间比输出空间稠密太多导致收敛震荡,以及防止输入空间比输出空间稀疏太多收敛过慢。
Glorot(Xavier)初始化器的缺点
因为Xavier的推导过程是基于几个假设的,
-
其中一个是激活函数是线性的,这并不适用于ReLU,sigmoid等非线性激活函数;
-
另一个是激活值关于0对称,这个不适用于sigmoid函数和ReLU函数它们不是关于0对称的。
损失函数
focal loss怎么实现的(字节)
center loss(字节)
优化器
优化方法有哪些?(京东)
-
梯度下降 GD:在参数更新时使用所有样本进行更新。
- 缺点:计算量大,速度慢。
-
小批梯度下降 Mini-batch GD:参数更新时使用一部分样本进行更新。
- 优点:减少了参数更新的次数,可以达到更加稳定收敛结果。
-
随机梯度下降 SGD:参数更新时只使用一个样本来进行更新。
- 优点:训练速度快
- 缺点:由于仅使用一个样本点来进行迭代,导致迭代方向变化很大,使得收敛到局部最优解的过程更加的复杂。
上述算法是从每次更新时使用的样本数量来划分的。
-
牛顿法:采用了二阶导来作为一阶导的学习率来更新梯度。
-
动量梯度下降 Momentum:采用累积加权梯度来作为要更新的梯度。使得算法更关注于趋势而非噪声。
\[v_t = m * v_{t-1} + g_t \\ W_{t} = W_{t-1} - \mu * v_t \]如果衰减率 \(m\) 为 0,那么它与原版梯度下降完全相同。如果衰减率 \(m\) 为1,那么它就会像无摩擦碗中的小球,前后不断地摇摆。通常衰减率选择在0.8-0.9左右,它就像一个有一点摩擦的表面,所以它最终会减慢并停止。
-
动量移动得更快(因为它积累的所有动量)
-
动量有机会逃脱局部极小值(因为动量可能推动它脱离局部极小值)。同样,它也将更好地通过高原区。
- 优点:由于存在历史梯度的累积,因此每次更新震荡相比不采用动量的梯度没那么大。
- 缺点:在临近最小点时,动量也会增加。如果动量增加过大,算法将无法停在正确位置。
-
-
ADAGrad:加入了二阶累积动量的根号项作为当前更新梯度的分母来动态调整学习率。
\[G_t = G_{t-1} + g_{t}^2 \\ W_t = W_{t-1} - \frac{\mu}{\sqrt{G_t}} g_{t} \]对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。
这一方法在稀疏数据场景下表现非常好。但也存在一些问题:因为分母 \(\sqrt{G_t}\) 是单调递增的,会使得学习率单调递减至0,可能会使得训练过程提前结束,即便后续还有数据也无法学到必要的知识。
- 优点:能更好地避开鞍点
- 缺点:到后期更新会非常慢 (因为分母在不停增大)
-
ADADelta / RMSProp(Root Mean Squared Propagation): 不累积全部历史梯度,而只关注过去一段时间窗口(移动平均的思想)的下降梯度。
\[G_t = \lambda * G_{t-1} + (1 - \lambda) * g_{t}^2 \\ W_t = W_{t-1} - \frac{\mu}{\sqrt{G_t}} g_{t} \]优点:避免了二阶动量持续累积、导致训练过程提前结束的问题
-
ADAM:结合了ADADetla和Momentum的特点,既采用了在一阶指数移动平均动量来控制梯度,也采用了二阶指数移动平均动量来控制学习率。
\[v_t = m * v_{t-1} + (1-m) * g_t \\ G_t = \lambda * G_{t-1} + (1 - \lambda) * g_{t}^2 \\ W_{t} = W_{t-1} - \frac{\mu}{\sqrt{G_t}} v_{t} \\ \]m 通常设置为 0.9,\(\lambda\) 通常设置为 0.999。
Adam 的能力来自于动量的速度和 RMSProp 适应不同方向的梯度的能力。这两者的结合使它变得更强大。
为什么有解码器和编码器的模型需要两个优化器?
因为在构建优化器对象时,需要传入模型参数 model.parameters()
作为一个输入,与此同时也可以分别设置不同部分的学习率。
小批梯度下降的样本数 m 怎么选择?
小批梯度下降的样本怎么进行采样?
梯度下降算法中的学习率如何选取?
GD和SGD原理和各自的缺陷?(京东)
ADAM和SGD的优缺点以及讲诉方法(云从)
Mini-Batch SGD相对于One Example SGD的两个优势:梯度更新方向更准确;并行计算速度快;
反向传播 BP 算法:
以目标函数的负梯度方向对参数进行调整并更新参数,\(W \gets W - \alpha \frac{\partial Loss}{\partial W}\)
首先,假设某个神经元的输入为z,经过激活函数\(f_1(·)\)得到输出\(a\)。即函数值\(a=f1(z)\)。如果这里的输入\(z\)又是另一个函数\(f_2\)的输出的话(当然啦,这里的\(f_2\)就是线性映射函数,也就是连接某两层的权重矩阵),即\(z=f_2(x)\),那么如果基于\(a\)来对\(z\)中的变量\(x\)求导的时候,由于
显然只要乘以激活函数\(f_1\)的导数,就不用操心激活函数的输出以及更后面的事儿了(这里的“后面”指的是神经网络的输出端方向),只需要将精力集中在前面的东西,即只需要关注z以及z之前的那些变量和函数就可以了。因此,误差反向传播到某非线性映射层的输出时,只需要乘上该非线性映射函数在z点的导数就算跨过这一层啦。
而由于\(f_2(·)\)是个线性映射函数,即\(f_2(x)=w\cdot x\),因此
因此,当误差反向传播到线性映射层的输出时,若想跨过该层,只需要乘以线性映射函数的参数就可以啦~即乘上w。
而这里的x,又是更后面的非线性映射层的输出,因此误差在深度前馈网络中反向传播时,无非就是反复的跨过非线性层和线性层,也就是反复的乘以非线性函数的导数(即激活函数的导数)和线性函数的导数(即神经网络的参数/权重/连接边)。
- 梯度消失:在反向传播的过程中,导数\(|\sigma'(W^Tx+b)W|<1\),链式求导的连乘效应导致层数较深时,导致计算得到的导数以指数级衰减,导数趋近于0,权重更新缓慢,导致前面几层只是简单的映射层。
- 梯度爆炸:同理,导数\(|\sigma'(W^Tx+b)W|>1\),导致计算得到的导数以指数级增加,导数趋于正无穷。
- 解决:
- 梯度剪切(截断):当梯度超过某个阈值时,则将梯度强制限制在某个范围内。在RNN中可能会导致无法学到很靠前的历史信息。
- 正则化梯度:在损失函数中加入权重的正则化项 \(Loss = (y-W^Tx)^2+\alpha\|W\|^2\),当梯度爆炸时,\(W\) 的范数会非常大,导致损失很大。
- 解决:
- 两种都可解决的方法:
- 用ReLU类激活函数:激活函数的导数为1,权重更新速度相同,收敛快。但由于负数部分为0,导致一些神经元无法激活。
- Batch Normalization:核心思想是通过将每层输出进行标准化到均值为0,方差为1的范围内,从而减小 \(W\) 变化带来的影响。
- 残差网络:通过残差块将还未产生梯度问题的输出和产生梯度问题的输出加和运算并激活,使得梯度仍然存在。实现了隔层线性传递,而不是一味追求非线性关系。
- LSTM:采用门机制来缓解梯度问题。
激活函数
激活函数的作用:增加神经网络的非线性,让其可以逼近任意函数。
-
\(sigmoid(x) = \frac{1}{1+e^{-x}}\),求导后为 \(f'(x) = f(x)(1-f(x))=\frac{e^{-x}}{(1+e^{-x})^2}\)
优点:
- 输出在(0,1)之间,范围有限,优化稳定,可作为输出层
缺点:
- 绝对值大的数值会出现饱和现象,对输入的微小变化不敏感。导致在反向传播时,梯度接近于0,权重基本不更新,容易出现梯度消失。
- 输出非0均值会影响梯度
- 指数形式,计算复杂度高。
-
\(tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}} = 2 * sigmoid(2x) - 1\),是0中心的,同样有 sigmoid 函数的其他优缺点。
优点:
-
\(ReLU(x) = max(0, x)\),
优点
- 计算量小,收敛更快。
- 在输入为正时不会出现梯度饱和、梯度消失的问题
缺点:
- 输出非0均值,它将小于0的值都置为0;使所有参数的更新方向都相同,导致ZigZag现象。
- 在输入为负时出现 dead ReLU 问题,导致该神经元之后的神经元梯度永远为0,相应参数永远不会更新。(原因:参数初始化;学习率太高)
- ReLU 不会对数据做幅度压缩,所以数据的幅度会随着模型层数的增加不断扩张。
-
\(LeakyReLU(x) = max(0.01x,x)\),防止在负数时出现 dead ReLU。
-
\(PReLU(x)=max(\alpha x,x)\),\(\alpha\) 非固定,可学习。
-
\(ELU(x)=\left\{\begin{array}{ll}x & \text { if } x>0 \\ \alpha(e^x-1) & \text { if } x \leq 0\end{array}\right.\)
-
Maxout:一个线性激活层,取所有神经元中最大的那个,可以拟合任意的凸函数。
优点:
- 线性,不饱和
- 不会出现dead ReLU问题
缺点:参数量较其他激活函数大,需要学习并更新权重。
-
Softmax:用于多分类,通过softmax映射成(0,1)的值,这些值的累积和为1,这样就可以理解为概率。在分类任务中,就可选择softmax输出的最大概率的一类。
- 在单分类问题中,softmax的梯度方向是
Softmax的输出概率-1
(求导过程),所以计算比较容易。
Relu在零点不可导,那么在反向传播中怎么处理?
ReLU 在零点虽然不可导,但是我们在做反向传播计算的时候,可以人为地给他赋予一个导数,比如 0 或 1,从而能让0处可导。
Softmax求导出现上溢问题,怎么解决(旷世)
可以尝试将每个元素都减去向量中的最大值后再计算比率进行后续操作。
BN的使用?
对于每个隐层神经元,把因非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。
同时BN为了保证非线性的获得,对变换后的满足均值为0方差为1的x又进行了scale加上shift操作(\(y=scale*x+shift\))
其核心思想是想找到一个线性和非线性的较好平衡点,既能享受非线性的较强表达能力的好处,又避免太靠非线性区两头使得网络收敛速度太慢。
BN放在激活函数之前还是之后? 之前
BN有几个参数:两个
tf.nn.batch_normalization(
x, mean, variance, offset, scale, variance_epsilon, name=None
)
- \(\mathrm{E}[x]\) 表示期望(均值) ,\(\operatorname{Var}[x]\) 表示方差,\(\epsilon\) 是为了保持数值稳定的较小值
- \(\gamma\) 表示 scale 操作:放大操作
- \(\beta\) 表示 offset 操作:移动操作
BN的好处
- 使得网络中每层输入数据的分布相对稳定,不仅仅极大提升了训练速度,收敛过程大大加快;
- 还能增加分类效果,一种解释是这是类似于Dropout的一种防止过拟合的正则化表达方式,所以不用Dropout也能达到相当的效果;
- 使得模型对网络中的参数不那么敏感,简化调参过程,使得网络学习更加稳定,而且可以使用大的学习率等。
BN 在验证/验证阶段是怎么处理的?(字节)
Batch Normalization在测试和训练阶段的不同
BN 在训练阶段使用的是每个 Batch 的均值和方差。而在测试阶段,均值使用的是训练阶段所有的 Batch 的均值的均值;而方差使用的是训练阶段所有 Batch 的方差的无偏估计 \(\frac{m}{m-1}\)。
在 pytorch 中训练集的均值方差的计算采用的是滚动平均法,保存一个到目前为止的 Batch 的均值和方差,对于新的一个 Batch 的均值方差,通过一个动量系数来降历史均值方差和该次均值方差结合(类似于门机制)。而测试集上就停止均值和方差的更新。
x' = (1-momentum)*x + momentum*x''
LayerNorm和BatchNorm有什么区别?LayerNorm有什么优点?
BatchNorm是整个batch的维度内对特征进行标准化,而LayerNorm则是在单个样本的维度进行标准化,一般用在NLP领域会多一点。举个例子,对于 (bxlxd) 维度的张量,BatchNorm 是在 (bxlx1) 的维度进行标准化,而 LayerNorm 则是在 (1xlxd) 的维度进行标准化。
在NLP任务中,由于序列长度 l 可能是变长的,采用 BatchNorm 可能会导致每次统计的均值方差变化较大,而对于同一条样本,其l是相同的,可以确保在反向传播时更加稳定。
Dropout层是怎么做的?有哪些参数?
Dropout层相当于一个一对一的连接层,在训练阶段,对于每一个连接都有 ratio 的概率被断开,没被断开的连接则乘上 \(\frac{1}{1-ratio}\) 以保持总和和未断开前的量级相近。
Dropout的参数为每个神经元在本次前向后向传播被遮蔽的概率。