diff --git a/README.md b/README.md index 2b91fea..b4430a1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ ## 3.目录 + + - [推荐系统](docs/rec/README.md) - [1.概要](/docs/rec/1.概要.md) - [2.召回](/docs/rec/2.召回.md) diff --git a/_sidebar.md b/_sidebar.md index ad25703..e683bd1 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,4 +1,11 @@ - [首页](/) +- [深度学习](docs/dl/README.md) + - [1.激活函数](docs/dl/1.激活函数.md) + - [2.KL散度](docs/dl/2.KL散度.md) + - [3.正则化](docs/dl/3.正则化.md) + - [4.损失函数](docs/dl/4.损失函数.md) + - [5.优化器](docs/dl/5.优化器.md) + - [6.评估指标](docs/dl/6.评估指标.md) - [推荐系统](docs/rec/README.md) - [1.概要](/docs/rec/1.概要.md) - [2.召回](/docs/rec/2.召回.md) diff --git "a/docs/dl/1.\346\277\200\346\264\273\345\207\275\346\225\260.md" "b/docs/dl/1.\346\277\200\346\264\273\345\207\275\346\225\260.md" new file mode 100644 index 0000000..bebf4d8 --- /dev/null +++ "b/docs/dl/1.\346\277\200\346\264\273\345\207\275\346\225\260.md" @@ -0,0 +1,291 @@ +# 1.激活函数 + +### 1.激活函数作用 + +神经网络是线性的,无法解决非线性的问题,加入激活函数就是给模型引入非线性能力; + +不同的激活函数,特点和作用不同: + +- `Sigmoid`和`tanh`的特点是将输出限制在`(0,1)`和`(-1,1)`之间,说明`Sigmoid`和`tanh`适合做概率值的处理,例如LSTM中的各种门;而`ReLU`就不行,因为`ReLU`无最大值限制,可能会出现很大值。 +- `ReLU`适合用于深层网络的训练,而`Sigmoid`和`tanh`则不行,因为它们会出现梯度消失。 + +### 2.梯度爆炸和梯度消失 + +模型中的梯度爆炸和梯度消失问题: + +1. 激活函数导致的梯度消失,像 `sigmoid `和 `tanh` 都会导致梯度消失; +2. 矩阵连乘也会导致梯度消失,这个原因导致的梯度消失无法通过更换激活函数来避免。直观的说就是在反向传播时,梯度会连乘,当梯度都小于1.0时,就会出现梯度消失;当梯度都大于1.0时,就会出现梯度爆炸。 + +如何解决梯度爆炸和梯度消失问题: + +1. 上述第一个问题只需要使用像 ReLU 这种激活函数就可以解决; +2. 上述第二个问题没有能够完全解决的方法,目前有一些方法可以很大程度上进行缓解该问题,比如:对梯度做截断解决梯度爆炸问题、残差连接、normalize。由于使用了残差连接和 normalize 之后梯度消失和梯度爆炸已经极少出现了,所以目前可以认为该问题已经解决了。 + +### 3.Sigmoid + +Sigmoid函数公式: + +$$ +\sigma(z)=\frac{1}{1+e^{-z}} +$$ + +导数公式: + +$$ +\sigma^{\prime}(z)=\sigma(z)(1-\sigma(z)) +$$ + +![](image/image_9ED50ulsDw.png) + +优点: + +- 平滑,易于求导; +- 取值范围是`(0, 1)`,可直接用于求概率值的问题或者分类问题;比如 LSTM 中的门,二分类或者多标签分类问题; + +缺点: + +- **计算量大**,包含幂运算,以及除法运算; +- sigmoid 导数的取值范围是 `[0, 0.25]`,最大值都是小于 1 的,反向传播时又是"链式传导",**经过几次相乘之后很容易就会出现梯度消失的问题**; +- **sigmoid 的输出的均值不是0**(即zero-centered),这会导致当前层接收到上一层的非0均值的信号作为输入,随着网络的加深,会改变数据的原始分布; + +### 4.Tanh + +Tanh的函数公式为: + +$$ +\begin{aligned} \tanh (z) & =\frac{e^{z}-e^{-z}}{e^{z}+e^{-z}} \\ & =\frac{2}{1+e^{-2 z}}-1\end{aligned} +$$ + +> 从上述公式的第二行可以看出,tanh 函数可以由 sigmoid 函数经过平移和拉伸得到。tanh 函数的取值范围是`(-1, 1)`。 + +导数公式 + +$$ +\tanh (x)^{\prime}=\frac{\left(e^{x}+e^{-x}\right)^{2}-\left(e^{x}-e^{-x}\right)^{2}}{\left(e^{x}+e^{-x}\right)^{2}}=1-(\tanh (x))^{2} +$$ + +![](image/image_2AtuZrFran.png) + +tanh 函数可以理解为是**基于 sigmoid 函数的一种改进的激活函数**,所以对于 sigmoid 函数的缺点,它能够解决一部分。但是 tanh 函数依然有着不少的缺点。tanh 函数的特点如下: + +- 它的输出范围是`(-1, 1)`,解决了 sigmoid 函数输出的均值不是0(zero-centered)的问题; +- tanh 的导数取值范围是`(0, 1)`,可以看出其在反向传播的"链式传导"过程中的梯度消失问题要比 sigmoid 函数要好一些,但是其依然存在着梯度消失问题; +- **幂运算依然存在,计算量比较大**; + +### 5.ReLU系列 + +#### 5.1 ReLU + +`ReLU `全称为 Rectified Linear Unit,即修正线性单元函数。该函数的公式比较简单,相应的公式和图像如下表所示。 + +![](image/image_2KV3LOKN2S.png) + +相比于 `sigmoid`、`tanh `这两个激活函数,`ReLU `激活函数的优缺点如下: + +- 当 `z>0` 时,ReLU 激活函数的导数恒为常数1,这就避免了 sigmoid 和 tanh 会在神经网络层数比较深的时候出现的梯度消失的问题; +- 计算复杂度低,不再含有幂运算,只需要一个阈值就能够得到其导数; +- 经过实际实验发现,**使用 ReLU 作为激活函数,模型收敛的速度比 sigmoid 和 tanh 快**; +- 当 `z<0`时,ReLU 激活函数的导数恒为常数0,这既带来了一些有利的方面,也导致了一些坏的方面,分别进行描述。 + - 有利的方面:在深度学习中,目标是从大量数据中学习到关键特征,也就是把密集矩阵转化为稀疏矩阵,保留数据的关键信息,去除噪音,这样的模型就有了鲁棒性。ReLU 激活函数中将 `z<0`的部分置为0,就是产生稀疏矩阵的过程。 + - 坏的方面:将 `z<0`的部分梯度直接置为0会导致 Dead ReLU Problem(神经元坏死现象)。**可能会导致部分神经元不再对输入数据做响应,无论输入什么数据,该部分神经元的参数都不会被更新**。(这个问题是一个非常严重的问题,后续不少工作都是在解决这个问题) +- ReLU 有可能会导致梯度爆炸问题,解决方法是梯度截断; +- ReLU 的输出不是 0 均值的,这个和 sigmoid 类似。(后续的优化工作 ELU 在该问题上解决的比较好,ELU 的输出是近似为0的) + +#### 5.2 Leaky ReLU + +为了解决 ReLU 的 Dead ReLU 问题,提出了 渗漏整流线性单元(Leaky ReLU),该方法是 ReLU 的一个变体。其在`z>0`的部分与ReLU一样保持不变;在`z<0`的部分,采用一个非常小的斜率0.01,其公式如下: + +$$ +Leaky \operatorname{ReLU}(z)=\left\{\begin{array}{ll}0.01 z & \text { if } z \leqslant 0 \\ z & \text { if } z>0\end{array}\right. +$$ + +其图像如下所示: + +![](image/image_zrvZp-9GRb.png) + +该方法是 ReLU 的一个变体,能够在一定程度上解决 Dead ReLU 问题,但是该方法的缺点是**效果并不稳定**,所以实际实验中使用该方法的并不多。 + +#### 5.3 PReLU, RReLU + +PReLU 的全称为 Parametric Relu;PReLU 的全称为 Random ReLU。 + +这两个方法和 Leaky ReLU 类似,都是 ReLU 的变体。也都是为了解决 Dead ReLU 问题而提出来的。 + +Leaky ReLU 是在`z<0`时,设置了一个较小的常数0.01作为斜率。由于这种常数值的斜率并不好,所以 PReLU 提出了可学习的斜率,RReLU 提出了随机的斜率,两者具体的公式如下。 + +PReLU的公式如下,这里的$\alpha$是可学习的: + +$$ +\operatorname{PReLU}(z)=\left\{\begin{array}{ll}\alpha \cdot z & \text { if } z \leqslant 0 \\ z & \text { if } z>0\end{array}\right. +$$ + +RReLU 的公式如下,这里的 $\alpha$是从一个高斯分布中随机产生的,在训练过程中每次这个 $\alpha$ 都是不相同的;在推理时会将这个$\alpha$都是不相同的;在推理时会将这个 + +$$ +\operatorname{RReLU}(z)=\left\{\begin{array}{ll}\alpha \cdot z & \text { if } z \leqslant 0 \\ z & \text { if } z>0\end{array}\right. +$$ + +PReLU 和 RReLU 的图像如下所示: + +![](image/image_GlE3RW4neL.png) + +#### 5.4 ELU(指数线性单元) + +ELU 的提出也解决了 ReLU 的问题。与 ReLU 相比,ELU 有负值,这会使激活的平均值接近零,让模型学习得更快。 + +![](image/image_mObw4TwnQV.png) + +$$ +\mathrm{g}(x)=\operatorname{ELU}(x)=\left\{\begin{aligned} x, & x>0 \\ \alpha\left(\mathrm{e}^{x}-1\right), & x \leqslant 0\end{aligned}\right. +$$ + +其中 $\alpha$不是固定的,是通过反向传播学习出来的。ELU的一个小问题是需要exp计算,运算量会更大一些。 + +- 融合了sigmoid和ReLU,左侧具有软饱和性,右侧无饱和性。 +- 右侧线性部分使得ELU能够缓解梯度消失,而左侧软饱能够让ELU对输入变化或噪声更鲁棒。 +- ELU的输出均值接近于零,所以收敛速度更快。 + +### 6.GeLU + +> 出自2016年的论文《Gaussian Error Linear Units (GELUs)》 + +先描述一下 GELU 这个激活函数直觉上是基于一个什么思路设计出来的。然后再具体看其如何近似求解、如何代码实现。 + +#### 6.1 介绍 + +先看一下 ReLU 激活函数是怎样做的,该函数中包含两种映射:一个是恒等映射(identity mapping),当输入值大于零时就是恒等映射;一个是置零映射(zero mapping),当输入值小于等于零时就是置零映射。 + +参考 ReLU 激活函数,设计另外一个包含恒等映射和置零映射的激活函数,并且参考 ReLU 函数来看,新激活函数应该有如下性质: + +1. 在输入 `x` 满足某些条件时,为恒等映射; +2. 在输入 `x` 满足另外一些条件时,为置零映射; +3. 在输入 `x` 是一个较大的正值时,更希望为恒等映射;在输入 `x` 为一个较小的负值时,更希望是一个置零映射; + +以上就是想要新设计的激活函数的性质。 + +下面的图7和图8是标准正态分布的概率密度函数和累积分布函数的图像。接下来根据下图8中的累积分布函数设计一个新的函数。 + +符号定义:输入值用 $x$ 表示,$ϕ(⋅)$表示下图8中的正态分布的累积分布函数,$f(⋅)$表示新设计的函数。 + +设计的新函数:给定输入值 $x$,函数 $f(x)$的输出值以 $ϕ(x)$的概率采用恒等映射,以 $1−ϕ(x)$的概率采用置零映射。也就是下述公式: + +$$ +\begin{aligned} f(x) & =x \cdot \phi(x)+0 \cdot(1-\phi(x)) \\ & =x \cdot \phi(x)\end{aligned} +$$ + +然后看一下,新设计的这个公式是否满足上述的激活函数性质。前两条是肯定满足的,主要看一下第3条性质: + +- 当输入 $x$ 是一个较大的正值时,从图8中可以看出 $ϕ(x)$的函数图像逐渐趋近于1,由于函数 $f(x)$的输出值以 $ϕ(x)$的概率采用恒等映射,所以有接近于1的概率采用恒等映射; +- 当输入 $x$ 是一个较小的负值时,$ϕ(x)$趋近于0,由于函数 $f(x)$以 $1−ϕ(x)$的概率采用置零映射,所以有接近于1的概率采用置零映射; + +可以看出新设计的这个函数是满足上述激活函数的性质的。 + +为了更直观描述设计该函数时的直觉,上述都是采用图8进行描述的,上述公式如果使用图7中的概率密度函数就是如下形式: + +$$ +\begin{aligned} f(x) & =x \cdot p(X 这里描述的设计 GELU 函数的直觉思路是非常简化的版本,只是为了易于理解。实际在设计这个函数时还需要考虑更多的因素,比如该函数的那几条性质和 ReLU 很像,已经有了 ReLU 为什么还要设计这个函数,这个函数在理论上是否能够解决 ReLU 的存在的 Dead ReLU 等问题; + +#### 6.2 函数及导数 + +GeLU 公式为: + +$$ +G E L U=x \cdot \phi(x) +$$ + +使用该函数作为激活函数时,需要求解其导数。对其求导可得: + +$$ +\begin{aligned} \frac{d}{d x} G E L U & =\phi(x)+x \frac{d}{d x} \phi(x) \\ & =\phi(x)+x \cdot p(X=x)\end{aligned} +$$ + +其中$X$是随机变量,$p(X=x)$是图7中的标准正态分布概率密度函数中,随机变量取值为$x$时的值。 + +GELU 函数及其导数的图像如下所示。可以看出其函数图像和 ReLU 非常相似,其导数图像也和 ReLU 的导数图像非常相似,不过该图像是连续的。 + +![](image/image_AHzmMqgKgV.png) + +GELU 激活函数的优缺点: + +- 从其函数图像可以看出,在负值区域,不再全为0,这解决了 Dead ReLU 问题; +- GELU 函数是处处连续、光滑可导的; + +#### 6.3 精确计算 + +对于 GeLU 的加速计算有两种方法。 + +第一种方法是精确求解。有一个函数为 Gauss Error function (gef),由于使用率非常高所以在常见的库(比如TensorFlow、PyTorch)中都有针对该函数的优化,该函数的公式如下。 + +$$ +\operatorname{erf}(y)=\frac{2}{\sqrt{\pi}} \int_{0}^{y} e^{-t^{2}} d t +$$ + +所以如果能够先求解出$erf(\cdot)$,再由该函数求解出 $\phi(x)$,那么可以加快计算。下面省略具体的推导过程,直接给出计算公式: + +$$ +\phi(x)=\frac{1+\operatorname{erf}\left(\frac{x}{\sqrt{2}}\right)}{2} +$$ + +另一种方法是不精确求解,而是求解其近似值。为了加速计算,还可以使用近似计算的方式。GELU 的近似公式如下所示: + +$$ +G E L U=0.5 * x\left(1+\tanh \left[\sqrt{\frac{2}{\pi}}\left(x+0.044715 x^{3}\right)\right]\right) +$$ + +### 7.Swish + +> 出自2017年的论文《Searching for Activation Functions》 + +该激活函数的公式为: + +$$ +f(x)=x \cdot \sigma(x) +$$ + +Swish导数: + +$$ +\begin{array}{l}f^{\prime}(x) \\ =\sigma(x)+x \cdot \sigma(x) \cdot(1-\sigma(x)) \\ =x \cdot \sigma(x)+\sigma(x)(1-x \cdot \sigma(x)) \\ =f(x)+\sigma(x) \cdot(1-f(x))\end{array} +$$ + +该激活函数的图像为: + +![](image/image_vZZ0x7ThiD.png) + +Swish特点: + +- 和ReLU一样,没有上边界,因此不会出现梯度饱和现象 +- 有下边界,可以产生更强的正则化效果(x左半轴慢慢趋近于0) +- 非单调 +- 处处连续且可到,更容易训练 + +关于正则化效果:x轴越靠近左半轴,纵坐标的值越小,甚至接近于0,如果x值是-10,那么经过激活之后的值接近于0,那么就可以一定程度上过滤掉一部分信息,起到[正则化](https://so.csdn.net/so/search?q=正则化\&spm=1001.2101.3001.7020 "正则化")的效果。 + +### 8.GLU + +PaLM 和 LLaMA 中都使用 SwiGLU 替换了 FFN + +> 出自2017年的论文 [Language Modeling with Gated Convolutional Networks](https://arxiv.org/pdf/1612.08083.pdf "Language Modeling with Gated Convolutional Networks") + +GLU 全称为 Gated Linear Unit,即**门控线性单元函数**。 + +参考ReLU激活函数,激活函数GLU的公式为如下公式的形式 + +$$ +\operatorname{GLU}(x)=x \otimes \sigma(g(x)) +$$ + +这里有一个新符号 $g(x)$表示的是向量$x$经过一层MLP或者卷积,$⊗$表示两个向量逐元素相乘,$σ$ 表示sigmoid函数。 + +当$\sigma(g(x))$趋近于0时表示对$x$进行阻断,当$\sigma(g(x))$趋近于1时表示允许$x$通过,以此实现门控激活函数的效果。 diff --git "a/docs/dl/2.KL\346\225\243\345\272\246.md" "b/docs/dl/2.KL\346\225\243\345\272\246.md" new file mode 100644 index 0000000..b6fd82f --- /dev/null +++ "b/docs/dl/2.KL\346\225\243\345\272\246.md" @@ -0,0 +1,84 @@ +# 2.KL散度 + +> 文章来源:[Index - 笔记 (mingchao.wang)](https://mingchao.wang/0ISjGzGG/ "Index - 笔记 (mingchao.wang)") + +### 1.KL散度的定义 + +KL散度是一种**衡量两个概率分布 P 和 Q 的差异**的方法; + +对于连续随机变量的概率分布来说,KL散度公式为:$D_{K L}(p \| q)=\int_{x} p(x) \log \frac{p(x)}{q(x)} d x$ + +对于离散随机变量的概率分布来说,KL散度公式为:$D_{K L}(p \| q)=\sum_{x} p(x) \log \frac{p(x)}{q(x)}$ + +机器学习和深度学习中使用的都是离散随机变量的概率分布,下面将仅讨论离散情况下的KL散度。 + +### 2.在机器学习中KL散度的作用 + +机器学习的目标就是:希望模型学到的分布 $p_{model}$ 与该任务的真实分布 $P_{real}$ 一致。 + +问题在于该任务的真实分布 $P_{real}$是无法获取到的,能够获取到的是训练集的分布 $P_{train}$,我们一般认为训练数据是从总体中独立同分布采样出来的,基于该条件下,就可以认为训练集的分布 $P_{train}$ 与真实分布 $P_{real}$ 是一致的。这样机器学习的目标就是:希望模型学到的分布 $P_{model}$ 与训练集的分布$P_{train}$ 一致。 + +然后剩余的问题就是如何评估两个分布是否一致?答案是使用KL散度进行评估。因为KL散度的定义就是衡量两个概率分布 p 和 q 的差异。 + +**两个分布越相近,KL散度越小;两个分布的差异越大,KL散度也越大**;当两个分布相同时,KL散度为0。 + +### 3.熵、KL散度、交叉熵 + +先对这三个概念给出一个通俗但不严谨的描述: + +- **熵**:可以表示一个事件 A 的自信息量,即 A 包含多少信息; +- **KL散度**:可以表示从事件 A 的角度看,事件 B 有多大的不同; +- **交叉熵**:可以表示从事件 A 的角度看,如何描述事件 B; + +下面使用数据公示给出这三个概念的严谨的表示: + +**熵:** $H(p)=-\sum_{i} p_{i} \log p_{i}$ + +**KL散度:** $D_{K L}(p \| q)=\sum_{i} p_{i} \log \frac{p_{i}}{q_{i}}=\sum_{i} p_{i} \log p_{i}-\sum_{i} p_{i} \log q_{i}$ + +**交叉熵:** $H(p \| q)=-\sum_{i} p_{i} \log q_{i}$ + +> 注意熵和交叉熵公式中都带有一个负号,而KL散度的公式中并没有负号; + +分析一下上面的KL散度的公式,左侧项 $\sum_{i} p_{i} \log p_{i}$ 很像是熵的公式,即 $−H(p)$;右侧项 $-\sum_{i} p_{i} \log q_{i}$ 就是交叉熵的公式,即 $H(p||q)$;所以会推导出如下公式: + +$$ +D_{K L}(p \| q)=H(p \| q)-H(p) +$$ + +即从公式上来说:**KL散度等于交叉熵减熵。** + +### 4.机器学习中为什么多用交叉熵而不是KL散度 + +在第二部分的描述中已经很清晰的提到:机器学习就是将模型分布 $P_{model}$ 学到与训练集分布 $P_{train}$ 一致的过程。而衡量两个分布是否一致最直接的评估方式就是KL散度,那么为什么机器学习中常用交叉熵而不是KL散度? + +在第三部分的最后推导出了一个公式,再次记录如下: + +$$ +\begin{aligned} D_{K L}(p \| q) & =\sum_{i} p_{i} \log \frac{p_{i}}{q_{i}} \\ & =\left[-\sum_{i} p_{i} \log q_{i}\right]-\left[-\sum_{i} p_{i} \log p_{i}\right] \\ & =H(p \| q)-H(p)\end{aligned} +$$ + +将上述公式放到机器学习这个具体应用场景中,公式中的概率分布 `q` 就是需要学习才能得到的模型分布 $P_{model}$,公式中的概率分布 `p` 就是训练集分布 $P_{train}$。 + +我们知道在机器学习中,**训练集是固定的,所以训练集的熵 **$H(p)$** 也是固定的,不随着模型的优化过程而变化**。即在机器学习这个应用场景下 $H(p)$ 是常数。此时使用 $D_{KL}(p||q)$ 对模型优化与使用 $H(p||q)$ 对模型优化是等价的。由于使用交叉熵 $H(p||q)$ 时还能少计算一项,节省计算资源,所以机器学习中一般较多情况使用交叉熵。 + +### 5.KL散度的性质 + +最后记录一下KL散度的两个数学性质: + +- **正定性**:$D_{K L}(p \| q) \geqslant 0$ +- **不对称性**:$D_{K L}(p \| q)!=D_{K L}(q \| p)$ + +由于KL散度不具有**对称性**,所以KL散度不是一种距离(度量)。 + +> 一般来说距离(度量)要满足3个条件:正定性、对称性、三角不等式; + +### 6.一个额外的知识点 + +> 这个是李宏毅在讲RL的课程中提到的。 + +深度学习模型中,如果需要做正则化,常用的方法是 L1、L2,如果是衡量两个分布是否相似,常用的方法是 KL 散度。比如在半监督方法 [UDA](https://arxiv.org/abs/1904.12848 "UDA") 里面,使用 KL 散度来进行一致性训练。然后就有一个问题是说:能不能使用L1、L2来衡量两个模型的分布是否相同?将 L1、L2 放到loss中,与将 KL 散度放到loss中,在学习时的区别是什么? + +解答:对于一个模型 $f_θ$,将 L1、L2 放到loss中,其起到的作用主要是衡量模型的参数本身。比如\*\* L1 会让模型中出现更多的0,L2 会让模型参数的方差尽量的小\*\*。 + +而**将 KL 散度放到loss中,其主要是衡量模型输出结果的分布,即模型的表现**。使用 KL 散度可以让两个模型的输出结果非常相似,但是 KL 散度不关心这两个模型内部参数是否相似,有可能这两个模型的内部参数差异是非常大的,但是它们的输出结果是非常相似的。使用 L1、L2 做约束,可以使得两个模型内部的参数有一定的相似性,但是 L1 和 L2 完全不关心两个模型的输出是否是相似的。 diff --git "a/docs/dl/3.\346\255\243\345\210\231\345\214\226.md" "b/docs/dl/3.\346\255\243\345\210\231\345\214\226.md" new file mode 100644 index 0000000..6b01bba --- /dev/null +++ "b/docs/dl/3.\346\255\243\345\210\231\345\214\226.md" @@ -0,0 +1,110 @@ +# 3.正则化 + +> 文章来源:[Index - 笔记 (mingchao.wang)](https://mingchao.wang/Mt7oEh5j/ "Index - 笔记 (mingchao.wang)") + +1. 正则化常用于缓解模型过拟合。过拟合发生的原因是模型的容量过大,而正则化可以对模型施加某些限制,从而降低模型的有效容量。 +2. 目前有多种正则化策略。 + - 有些正则化策略是向模型添加额外的约束,如增加对参数的限制。这是对参数的硬约束。 + - 有些正则化策略是向目标函数增加额外项。这是对参数的软约束。 +3. 正则化策略代表了某种先验知识,即:倾向于选择简单的模型。 +4. 在深度学习中,大多数正则化策略都是基于对参数进行正则化。正则化以偏差的增加来换取方差的减少,而一个有效的正则化能显著降低方差,并且不会过度增加偏差。 +5. 在深度学习的实际应用中,不要因为害怕过拟合而采用一个小模型,推荐采用一个大模型并使用正则化。 + +## 1.参数约束正则化:L1和L2正则化 + +参数约束正则化主要是指 L1 和 L2 正则化; + +- **L1正则化**:给每个权重减去一个与$sign(\theta_i)$ 同符号的常数因子; +- **L2正则化**(权重衰减):给每个权重值乘上一个常数因子,线性的缩放每个权重值; + +### 1.1 L2正则化 + +正则化项为 $\Omega(\theta)=\frac{1}{2}\|\theta\|_{2}^{2}$,系数 1/2 是为了求导时得到得系数为1;$L_2$\*\*正则化能够使参数 \*\*$\theta$**的方差更接近与0**; + +目标函数:$J(\theta)=L(\theta)+\lambda \Omega(\theta)=L(\theta)+\frac{1}{2} \lambda\|\theta\|_{2}^{2}$ + +梯度:$\nabla_{\theta} J(\theta)=\nabla_{\theta} L(\theta)+\lambda \theta$ + +梯度下降过程,其中$\gamma$为学习率:$\theta \leftarrow \theta-\gamma\left(\nabla_{\theta} L(\theta)+\lambda \theta\right)$ + +整理得:$\theta \leftarrow(1-\gamma \lambda) \theta-\gamma \nabla_{\theta} L(\theta)$ + +L2正则化对梯度更新的影响是:每一步执行更新前,会对权重向量乘以一个常数因子来收缩权重向量,使参数$\theta$的方差更接近0,因此L2也被称为权重衰减。 + +### 1.2 L1正则化 + +正则化项为 $\Omega(\theta)=\|\theta\|_{1}=\sum_{i=1}^{d}\left|\theta_{i}\right|$,即各个参数的绝对值之和; + +目标函数:$J(\theta)=L(\theta)+\Omega(\theta)=L(\theta)+\lambda\|\theta\|_{1}$ + +梯度:$\nabla_{\theta} J(\theta)=\nabla_{\theta} L(\theta)+\lambda \cdot \operatorname{sign}(\theta)$ + +其中 $sign(\cdot)$ 表示取自变量的符号 + +梯度下降过程,其中$\gamma$为学习率:$\theta \leftarrow \theta-\gamma \cdot\left(\nabla_{\theta} L(\theta)+\lambda \cdot \operatorname{sign}(\theta)\right)$ + +整理得:$\theta \leftarrow(\theta-\gamma \cdot \lambda \cdot \operatorname{sign}(\theta))-\gamma \cdot \nabla_{\theta} L(\theta)$ + +> 特别说明:对于带有$L_1$正则的目标函数,由于其不是处处可导,所以一般不使用梯度下降法进行求解,这里只是和$ L_2$正则做一个类似的讨论。在本文的最后一部分会介绍坐标轴下降法,是更常用的用于求解带有$L_1$正则的目标函数的方法; + +## 2.Dropout + +1. **dropout**:在前向传播过程中,对网络中的每个隐藏层,每个隐单元都以一定的概率 $p_{drop}$ 被删除,之后得到一个比原始网络要小的裁剪网络。**在反向传播过程中,仅仅对该裁剪网络进行梯度更新,被删除的隐单元不进行梯度更新**; +2. **对隐单元的删除指的是**:将该隐单元的输出置为0;当其输出为0时,该隐单元对后续神经元的影响均为0; +3. **输入层和输出层的神经元不会被删除**,这两层的神经元的个数是固定的; +4. 关于隐单元删除时的一些细节: + - 不同的样本,其删除的隐单元的集合是不同的,因此得到的裁剪网络也是不同的; + - 不同的样本,每个隐单元被删除的概率是相同的; + - 同一条样本,分两次进入模型训练,那么这两次删除的隐单元也是不同的; + - 在每个梯度更新周期中,被删除的隐单元的集合是不同的,因此得到的裁剪网络也是不同的; + - 在每个梯度更新周期中,隐单元被删除的概率是相同的; +5. **dropout仅仅用于神经网络的训练阶段,在推理阶段不需要删除隐单元,而是使用所有的神经元**; +6. dropout的优点: + - 其不限神经网络的网络结构,都可以使用该技术; + - 其计算非常方便、高效;具体计算过程为:每次产生 n 个随机的二进制数(0和1),然后将这些产生的随机二进制数与 n 个隐单元的输出相乘(与0相乘的隐单元就相当于是被删除了);这个计算开销相比于神经网络的正常计算是非常小的; +7. dropout的缺点: + - **损失函数 Loss 不再被明确的定义,每次迭代都会随机删除一部分隐单元**; +8. dropout使用时的策略:由于dropout的作用是防止过拟合,所以 + - 若某一隐层神经元比较少,过拟合不严重,可以调小概率 $p_{drop}$,甚至该层不使用 dropout; + - 若某一隐层神经元比较多,过拟合严重,可以调大概率 $p_{drop}$; +9. dropout在使用时更多的可能性(也可称作推广): + - 可以对某一层或某几层使用dropout,其他层不使用dropout; + - 可以对不同的层,甚至不同的隐单元分别设置不同的概率 $p_{drop}$,但实际中一般不这么做; + - 可以对每个梯度更新周期设置不同的概率 $p_{drop}$,但实际中一般不这么做; + - 现在对每个隐单元的输出乘的是个二值函数(0或1),不一定必须是二值函数,也可以扩展为乘以其他值,比如:对 n 个隐单元,每个隐单元乘上的值是根据均值为0,方差为1的标准正态分布生成的值。此时单从形式上来看和 L1、L2 正则已经非常相似了;不过实际中一般也很少采用这种方式; + +## 3.数据增强(EDA) + +### 3.1 词汇增强: + +- **基于词典进行替换**:从文本中随机选取一个或多个词语,利用同义词词典将这一个或多个词语替换成其同义词; +- **基于词向量进行替换**:从文本中随机选取一个或多个词语,使用预先训练好的词向量,找到在嵌入空间中与这一个或多个词距离最近的词语,进行替换; +- **基于MLM进行替换**:BERT系列模型是通过MLM进行预训练的,所以可以随机将文本中的某一个或者多个词语mask,使用预训练好的BERT系列模型对mask掉的词语进行生成,以此做增强; +- **基于tf-idf进行替换**:文本中tf-idf较小的词语,对该文本的贡献较小。可以优先对这些词语进行增强,以避免模型错误的将这些词语作为具体任务的主要判断依据; +- **随机插入词语**:向文本的任意位置以一定的概率随机插入词语; +- **随机删除词语**:对文本中任意词语以一定的概率随机进行删除; +- **随机替换词语**:将文本中任意的某一个或多个词语,随机的替换为另外的随机词语; + +### 3.2 回译增强: + +利用机器翻译模型,或百度翻译、谷歌翻译等,将中文文本翻译为其他语种的文本,然后再翻译回中文文本,以此进行增强; + +### 3.3 基于语法解析增强 + +首先使用语法解析工具解析并生成原始文本的依存关系树,之后按照依存关系对其调整,生成增强后的文本。比如:将文本从一个主动语态调整为被动语态; + +### 3.4 直接在输入层注入随机噪声; + +## 4.早停(early stopping) + +在训练时,一般来说是训练集的损失一直下降,而验证集的损失是先下降后上升的。验证集的损失之所以上升就是因为模型已经在训练集上过拟合了。 + +选取验证集损失最小的模型,而不是最新的模型,这种策略就是早停。 + +## 5.对抗训练 + +详情见 [http://mingchao.wang/Kw0SoUUq/](http://mingchao.wang/Kw0SoUUq/ "http://mingchao.wang/Kw0SoUUq/") + +## Reference[#](#reference "#") + +- [https://www.huaxiaozhuan.com/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/chapters/3\_regularization.html](https://www.huaxiaozhuan.com/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/chapters/3_regularization.html "https://www.huaxiaozhuan.com/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/chapters/3_regularization.html") diff --git "a/docs/dl/4.\346\215\237\345\244\261\345\207\275\346\225\260.md" "b/docs/dl/4.\346\215\237\345\244\261\345\207\275\346\225\260.md" new file mode 100644 index 0000000..d3f2741 --- /dev/null +++ "b/docs/dl/4.\346\215\237\345\244\261\345\207\275\346\225\260.md" @@ -0,0 +1,185 @@ +# 4.损失函数 + +损失函数(Loss Function)用于评估模型**的预测值与实际值之间的差异程度**。在训练过程中,损失函数作为优化的目标,通过**最小化损失函数的值**来调整模型参数,从而提高模型的预测准确性。 + +具体来说,损失函数将模型的预测输出(例如,一个分类任务中的类别概率分布)与真实标签(或真实值)进行比较,并计算出一个表示差异的数值。这个数值越大,表示模型的预测越不准确;数值越小,表示模型的预测越接近真实情况。 + +接下来,介绍几个常用的损失函数。 + +- **L1 Loss损失函数**:通常用于**回归任务**中。 +- **NLL Loss损失函数**:在**多分类问题**中广泛应用。 +- **MSE Loss损失函数**:在**多种回归任务**中表现出色。 +- **BCE Loss损失函数**:广泛应用于各类**二分类任务中**。 +- **CrossEntropyLoss交叉熵损失函数**:广泛应用于**多分类问题**中。 + +## 1.L1 Loss损失函数 + +L1 Loss损失函数,也被称为**平均绝对误差(Mean Absolute Error, MAE)**,是深度学习和机器学习中常用的一种损失函数,特别是在**回归任务**中。 + +### 1.1 定义 + +L1Loss计算的是模型预测值f(x)与真实值y之间差的绝对值的平均值。其数学表达式为: + +$$ +text_L1Loss =\frac{1}{n} \sum_{i=1}^{n}\left|y_{i}-f\left(x_{i}\right)\right| +$$ + +其中,`n`是样本数量,$y_i$是第`i`个样本的真实值,$f(xi)$是模型对第`i`个样本的预测值。 + +### 1.2 优缺点 + +**优点** + +1. **稳定性**:L1Loss对于所有输入值都有稳定的梯度,不会导致梯度爆炸问题,因此具有较为稳健的解。 +2. **鲁棒性**:L1Loss对于噪声和异常值(离群点)具有相对较强的鲁棒性,因为它不会因个别异常值而产生过大的误差。 +3. **稀疏性**:L1Loss能够产生稀疏的特征权重,即很多无用或影响较小的特征的权重会被置为0,有助于特征选择和模型简化。 + +**缺点** + +1. **不可导性**:在0点处,L1Loss的梯度不存在(因为绝对值函数在0点不可导),这可能导致在优化过程中,当权重恰好接近0时,梯度下降法无法继续进行。 +2. **收敛速度**:与L2Loss相比,L1Loss在误差较大时,其梯度是恒定的,这可能导致在接近最优解时收敛速度较慢。 + +### 1.3 应用 + +1. L1Loss通常用于**回归任务**中,特别是当模型需要处理的数据集存在较多噪声或异常值。 +2. 或者希望模型**具有稀疏特征**时。 + +然而,由于神经网络通常解决的是复杂问题,且L1 Loss在0点不可导的缺点,它在神经网络中的应用相对较少,尤其是在需要精细调整权重的情况下。 + +## 2.NLL Loss损失函数 + +NLLLoss损失函数,全称为Negative Log Likelihood Loss(**负对数似然损失**),是深度学习中常用的一种损失函数,尤其在处理**多分类问题**时表现出色。 + +#### 2.1 定义与原理 + +NLLLoss衡量的是模型**预测概率分布**与真实标签之间**差异的损失**。在PyTorch等深度学习框架中,它通常用于**多分类任务**。具体来说,NLL Loss计算的是对数概率的负值与真实标签之间的**交叉熵损失**。这样做的目的是通过最小化损失来优化模型参数,使得模型的预测结果更加接近真实标签。 + +#### 2.2 优点与注意 + +NLLLoss损失函数的优点在于它能够**直接反映模型预测的概率分布与真实标签之间的差异**,且计算过程相对简单高效。然而,在使用时需要**注意**以下几点: + +1. **输入要求**:NLLLoss要求输入的对数概率必须是通过**log\_softmax函数计算**得到的,而不能直接使用softmax函数的输出。 +2. **目标标签**:目标**标签需要是整数类型**,表示每个样本的真实类别索引。 +3. **权重调整**:如果需要对不同类别的损失进行权重调整,可以在NLL Loss函数中设置相应的权重参数。 +4. **数值稳定性**:由于NLLLoss涉及对数运算,因此需要注意数值稳定性问题。通过先**应用log\_softmax函数可以避免直接计算softmax时可能出现的上溢或下溢问题**。 + +#### 2.3 应用 + +NLLLoss损失函数在**多分类问题**中广泛应用,包括但不限于自然语言处理(NLP)中的语言模型、情感分类等任务。在这些任务中,模型需要将输入序列映射到输出标签,而NLLLoss能够评估模型预测的概率分布与真实标签之间的差异,从而指导模型的优化方向。 + +## 3.MSE Loss损失函数 + +MSELoss损失函数,全称为Mean Squared Error Loss(**均方误差损失函数**),是深度学习中常用的一种**回归损失函数**。 + +#### 3.1 定义与原理 + +MSELoss通过计算预测值与真实值之间**差的平方的平均值**来衡量模型的性能。具体来说,对于每个样本,它**计算预测值与真实值之差的平方,然后对所有样本的平方误差求和并取平均,得到最终的损失值**。这种损失函数旨在通过最小化预测值与真实值之间的差异来优化模型参数,从而提高模型的预测准确性。 + +对于单个样本,假设预测值为 $\hat y$,真实值为 $y$,则该样本的均方误差为$(\hat y - y)^2$。对于包含 `n` 个样本的数据集,MSELoss的计算公式为: + +$$ +textMSELoss =\frac{1}{n} \sum_{i=1}^{n}\left(\hat{y}_{i}-y_{i}\right)^{2} +$$ + +#### 3.2 优点与注意 + +**优点**: + +1. **优化直观**:MSE结果是一个平滑且凸的优化直观,这有助于使用基于梯度的算法(如梯度下降)进行高效优化。 +2. **唯一极小值**:MSE具有唯一的全局极小值,这简化了优化过程,并在某些情况下可以获得解析解。 +3. **可微性**:MSE在任何地方都是可微的,这使得在训练过程中可以使用基于梯度的优化方法。 +4. **广泛适用性**:MSE是回归问题的标准且广泛使用的损失函数,适用于预测连续的数值。 + +**注意**: + +1. **对异常值敏感**:由于MSE计算的是误差的平方,因此它**对异常值非常敏感**。当数据集中存在极端值时,这些异常值可能会对损失值产生不成比例的影响,从而导致模型性能下降。 +2. **非直观的尺度**:MSE的尺度受到平方差的影响,这可能导致其解释性较差。特别是在与原始数据的尺度相比时,MSE可能难以直观地反映模型预测的准确性。 + +#### 3.3 应用 + +MSELoss在**多种回归任务**中表现出色,包括但不限于房价预测、股票价格预测、气温预测等。在这些任务中,模型需要输出一个**连续的数值预测结果**,而MSELoss能够有效地评估模型预测结果与实际值之间的差异,并指导模型的优化方向。 + +## 4.BCE Loss损失函数 + +BCELoss损失函数,全称为Binary Cross Entropy Loss(二元交叉熵损失函数),是深度学习中常用于二分类问题的一种损失函数。 + +#### 4.1 定义与原理 + +BCELoss通过**计算模型预测的概率分布与实际标签之间的****交叉熵****损失来评估模型的性能**。在**二分类问题**中,每个样本的真实标签是0或1,而模型输出的是一个介于0和1之间的概率值,表示该样本属于正类的概率。BCELoss通过比较这两个值之间的差异,为模型提供一个损失值,该值越大表示模型预测越不准确。 + +对于单个样本,BCELoss的数学公式为: + +$$ +textBCELoss =-(y \log (p)+(1-y) \log (1-p)) +$$ + +其中,`y `是实际标签(0 或 1),`p` 是模型输出的概率值(预测为正类的概率),log 是自然对数。 + +- 当 `y=1` 时,损失函数简化为 $−log($$p$$)$,此时如果 *`p`* 越接近 1,则损失越小; +- 当 `y=0` 时,损失函数简化为$ −log(1−p)$,此时如果 *`p`* 越接近 0,则损失越小。 + +对于一批样本,BCELoss通常是对所有样本的BCELoss求和后取平均值。 + +#### 4.2 优点与注意 + +**优点**: + +1. **直观性**:BCELoss能够**直观地反映**模型预测的概率分布与实际标签之间的差异,从而指导模型的优化方向。 +2. **鲁棒性**:在二分类问题中,BCELoss对正负样本的预测误差都进行了考虑,使得模型在训练过程中能够同时**关注到正负样本的分类**情况。 +3. **易于实现**:在深度学习框架(如PyTorch、TensorFlow等)中,BCELoss通常作为内置函数提供,易于实现和使用。 + +**注意**: + +1. **输入要求**:在使用BCELoss时,需要注意模型输出的概率值应该经过Sigmoid函数或其他适当的**激活函数处理**,以确保其值在0和1之间。 +2. **标签要求**:BCELoss要求真实标签**必须是二值化的**(0或1),而不是其他形式的标签(如类别索引、独热编码等)。 +3. **数值稳定性**:在计算BCELoss时,需要注意数值稳定性问题。例如,当预测概率 *`p`* 非常接近0或1时,$log($$p$$)$ 或 $log(1−p) $的值可能会变得非常大或非常小,导致计算过程中出现数值问题。为了避免这种情况,可以对 *`p`* 进行一些**平滑处理**(如添加一个小的正数 *`ϵ`* 到 *`p`* 和 `1−p` 中)。 + +#### 4.3 应用 + +BCELoss广泛应用于各类**二分类任务中**,如文本情感分析(积极/消极)、垃圾邮件检测(垃圾邮件/非垃圾邮件)、病患诊断(患病/未患病)等。在这些任务中,模型需要输出一个二分类的概率预测结果,而BCELoss能够有效地评估模型预测的准确性,并指导模型的优化方向。 + +## 5.CrossEntropyLoss损失函数 + +CrossEntropyLoss损失函数,也称为**交叉熵损失函数**,是深度学习中**用于分类问题**的一种常用损失函数。**它衡量的是模型预测的概率分布与真实标签的概率分布之间的差异**。尽管它通常与多分类问题相关联,但**也可以用于二分类问题**(在这种情况下,它等价于二元交叉熵损失,即BCELoss的特例)。 + +#### 5.1 定义与原理 + +交叉熵损失函数通过比较模型对每个类别的**预测概率**和真实的标签(通常是独热编码形式)来计算损失。如果模型对某个样本的预测概率分布与真实标签**越接近**,则**交叉熵损失越小**;反之,损失越大。 + +对于多分类问题,假设有\_C\_个类别,对于每个样本,交叉熵损失的计算公式如下: + +$$ +textCrossEntropyLoss =-\sum_{c-1}^{C} y_{c} \log \left(p_{c}\right) +$$ + +其中,$y_c $是样本的真实标签中第 `c` 类的值(在独热编码中,只有一个元素为1,其余为0),$p_c$ 是模型预测的第 `c` 类的概率。 + +注意,在实际计算中,由于$y_c $ 是独热编码的,所以上式中的求和实际上只涉及一个非零项,即真实标签对应类别的预测概率的对数的负值。 + +#### 5.2 优点与注意 + +**优点**: + +1. **直观性**:交叉熵损失能够**直观地反映**模型预测的概率分布与真实标签之间的差异。 +2. **易于优化**:由于交叉熵损失函数是凸函数(在模型输出为softmax概率的情况下),因此可以使用**梯度下降**等优化算法来有效地最小化损失。 +3. **鲁棒性**:交叉熵损失对预测概率的**微小变化敏感**,这有助于模型在训练过程中更准确地逼近真实标签。 + +**注意**: + +1. **输入要求**:在使用交叉熵损失函数时,需要确保**模型输出的是概率值**(通常通过softmax函数进行转换),而真实标签是独热编码形式的。 +2. **数值稳定性**:当预测概率接近0时,log(*p*) 的值会趋于负无穷,这可能导致数值问题。为了解决这个问题,可以在计算对数之前对预测概率进行**平滑处理**(例如,添加一个小的正数 *ϵ* 到预测概率中)。 +3. **权重平衡**:在处理类别不平衡的数据集时,可以为不同类别的损失分配不同的权重,以改善模型的性能。 + +#### 5.3 应用 + +交叉熵损失函数广泛应用于**多分类问题**中,如图像分类、文本分类等。在这些任务中,模型需要输出每个类别的概率预测,而交叉熵损失函数能够有效地评估模型预测的准确性,并指导模型的优化方向。 + +## 6.总结 + +本篇介绍了部分损失函数,损失函数有很多,这些是较为常用的,其余可以自行了解哦\~ + +1. L1Loss损失函数:通常用于**回归任务**中。 +2. NLLLoss损失函数:在**多分类问题**中广泛应用。 +3. MSELoss损失函数:在**多种回归任务**中表现出色。 +4. BCELoss损失函数:广泛应用于各类**二分类任务中**。 +5. CrossEntropyLoss交叉熵损失函数:广泛应用于**多分类问题**中。 diff --git "a/docs/dl/5.\344\274\230\345\214\226\345\231\250.md" "b/docs/dl/5.\344\274\230\345\214\226\345\231\250.md" new file mode 100644 index 0000000..553e1be --- /dev/null +++ "b/docs/dl/5.\344\274\230\345\214\226\345\231\250.md" @@ -0,0 +1,207 @@ +# 5.优化器 + +## 1.梯度下降变形形式 + +### 1.1批量梯度下降(batch gradient descent) + +批量梯度下降,计算整个训练数据集的目标函数对参数 $θ$ 的梯度: + +$$ +\theta=\theta-\eta \cdot \nabla_{\theta} J(\theta) +$$ + +使用批量梯度下降时代码一般如下所示: + +```python +for i in range(nb_epochs): + params_grad = evaluate_gradient(loss_function, data_list, params) + params = params - learning_rate * params_grad + +``` + +批量梯度下降的缺点是其需要计算整个数据集的梯度,然后仅用于执行一次更新。这导致批量梯度下降速度非常慢。另外如果数据量比较大时,内存一般也不足以加载这些数据。 + +批量梯度下降能够保证收敛到凸函数的最小值,或者非凸函数的极小值。 + +### 1.2 随机梯度下降(Stochastic gradient descent) + +随机梯度下降 (SGD) 对每个训练示例 $x(i)$ 和标签 $y(i)$ 执行参数更新: + +$$ +\theta=\theta-\eta \cdot \nabla_{\theta} J\left(\theta ; x^{(i)} ; y^{(i)}\right) +$$ + +上一部分已经说过,批量梯度下降的计算量是非常大的,因为它每次更新都要计算所有数据的梯度。而SGD则是每次仅计算一条数据的梯度,所以SGD的速度更快。但是由于SGD每次只使用一条数据进行更新,所以**其目标函数的值也会出现较大幅度的波动**,如下图所示。 + +![](image/image_VQ92WkZEST.png) + +除了速度以外,SGD还有另一方面的优势。对于非凸函数,批量梯度下降会优化到极小值点,但SGD的波动能够使其跳出极小值点,进入更好的局部最小值。 + +但是上述这种现象也使得SGD的收敛过程变得非常复杂,甚至其不能收敛到局部最小值。有一种方法是随着学习的进行慢慢降低学习率,在这种策略下SGD能够表现出与批量梯度下降较为相似的收敛行为,能够稳定收敛到凸函数的全局最小值,或者非凸函数的局部最小值。 + +下面是使用SGD的一般代码结构: + +```python +for i in range(nb_epochs): + np.random.shuffle(data_list) + for example in data_list: + params_grad = evaluate_gradient(loss_function , example , params) + params = params - learning_rate * params_grad + +``` + +在上述代码中可以看出,每个epoch都会对所有的数据进行一次shuffle,这是一个常规操作。而在批量梯度下降中却没有该操作,原因是批量梯度下降每次都是计算完全量数据的梯度再更新,是否shuffle对它计算出的梯度没有影响。 + +### 1.3 Mini-batch梯度下降(Mini-batch gradient descent) + +Mini-batch梯度下降结合批量梯度下降和SGD两者各自的优势,其每次对一个小批量的 n 个训练样本求梯度,并做一次更新。公式如下: + +$$ +\theta=\theta-\eta \cdot \nabla_{\theta} J\left(\theta ; x^{(i: i+n)} ; y^{(i: i+n)}\right) +$$ + +Mini-batch梯度下降的优势有: + +- 相比于SGD,每次更新时减少了更新的方差,使得收敛比SGD更稳定; +- 相比于批量梯度下降,计算速度大幅提升;同时也有一定的跳出局部最小值的能力; + +目前的深度学习中基本都是使用Mini-batch梯度下降,但是使用术语时一般使用SGD。为了和大部分资料保持一致性,在本文的后面部分也是如此,提到SGD时指的是Mini-batch梯度下降。 + +下面是Mini-batch梯度下降的一般代码结构: + +```python +for i in range(nb_epochs): + np.random.shuffle(data_list) + for batch in get_batches(data_list, batch_size=50): + params_grad = evaluate_gradient(loss_function, batch, params) + params = params - learning_rate * params_grad + +``` + +## 2.梯度下降遇到的挑战 + +上面提到的三种梯度下降的方法都是比较原始的,并不能保证比较好的收敛性,它们存在的问题有: + +- **选择合适的学习率比较困难**。学习率选的太小了会导致收敛缓慢,学习率选的太大了会导致不收敛在最小值附近波动,甚至于发散。 +- 有些策略是在训练的过程中调整学习率,但是这些策略里什么时候需要调整、调整为多大都是在训练前预定义好的,对不同的数据集特征的适应性比较差,换一个数据集可能就不生效了。 +- **鞍点问题**。有些研究表明,很多时候问题并不是梯度下降收敛到了局部最小值点,而是收敛到了鞍点,收敛到鞍点之后可能模型的效果比收敛到局部最小值点还差。 + +## 3.梯度下降优化算法 + +接下来将列举一些被深度学习社区广泛用于解决上述困难的算法,这些算法有个共同之处,**一般是求一阶动量(m)和二阶动量(V),然后利用一阶、二阶动量本身或者他们组合来优化梯度下降**(其中一阶动量为与梯度相关函数,二阶动量为与梯度平方相关的函数) + +首先还是给出梯度下降的公式: + +$$ +\theta_{t+1}=\theta_{t}-\eta \frac{\partial(\text { Loss })}{\partial \theta_{t}} +$$ + +引入梯度下降优化算法后: + +$$ +\theta_{t+1}=\theta_{t}-\eta \frac{m_{t}}{\sqrt{V_{t}}} +$$ + +### 3.1 动量法(Momentum) + +随机梯度下降的方法很难通过峡谷区域(也就是在一个维度梯度变化很大,另一个维度变化较小),这个很好理解,因为梯度下降是梯度更新最大的反方向,如果这个时候一个维度梯度变化很大,那么就很容易在这个方向上振荡,另一个方向就更新很慢,如下图: + +![](image/image_OQIO6bJNUM.png) + +动量法就是为了解决上述问题,能够对朝着极值点的方向加速,并能够一定程度上抑制震荡。使用动量法的优化路径会是下图2b中所示。 + +动量法的具体做法是:**将过去的时间步更新的向量的一部分 **$γ$** 添加到当前更新的向量上**。通过这种方式,历史时间步中使得优化轨迹来回震荡的方向的动量会相互抵消,剩下的主要是朝着极值点的方向的动量。公式如下所示: + +$$ +\begin{aligned}m_{t} & =\gamma m_{t-1}+\eta \nabla_{\theta} J(\theta) \\ +\theta_{t+1} & =\theta_t - m_{t}\end{aligned} +$$ + +动量项 $γ$ 通常设置为 0.9 或类似值。 + +本质上,当使用动量法时:对于梯度指向相同方向的维度,动量项会增加,而对于梯度改变方向的维度,动量项的更新会减少。 结果,我们获得了更快的收敛速度并减少了振荡。 + +### 3.2 NAG(Nesterov accelerated gradient) + +然而,盲目地顺着斜坡滚下山坡的球是非常不令人满意的。 我们想要一个更聪明的球,一个知道它要去哪里的球,这样它就知道在山再次倾斜之前减速。 + +NAG 是一种赋予我们的动量项这种先见之明的方法。 知道我们将使用动量项 $γv_t−1$ 来移动参数 $θ$。 因此,计算 $θ−γv_t−1$ 为我们提供了参数下一个位置的近似值(完全更新时梯度缺失),这是参数将在哪里的粗略概念。 现在可以通过计算梯度来有效地向前看。 + +$$ +\begin{aligned} m_{t} & =\gamma m_{t-1}+\eta \nabla_{\theta} J\left(\theta-\gamma m_{t-1}\right) \\ +\theta_{t+1} & =\theta_t - m_{t}\end{aligned} +$$ + +![](image/image_EkdkFEhzz3.png) + +同样,将动量项 $γ$ 设置为 0.9 左右的值。 Momentum 首先计算当前梯度(图 3 中的小蓝色向量),然后在更新的累积梯度(蓝色大向量)的方向上大跳,而 NAG 首先在前一个累积梯度的方向上大跳( 棕色矢量),测量梯度,然后进行校正(绿色矢量)。 这种预期性的更新可以防止我们走得太快,从而提高响应能力,从而显着提高了 RNN 在许多任务上的性能。 + +既然我们能够使我们的更新适应我们的误差函数的斜率并反过来加速 SGD,我们还希望我们的更新适应每个单独的参数,以根据它们的重要性执行更大或更小的更新。 + +### 3.3 Adagrad + +之前提到过这个问题:对于所有特征,我们的学习率一直没有变。 + +Adagrad算法就是为了解决这个问题,**让学习率学习数据的特征自动调整其大小,Adagrad算法引入了二阶动量**(V),其表达式为: + +$$ +\begin{array}{c}m_{t}=g_{t} \\ V_{t}=\sum_{\tau}^{t} g_{\tau}^{2} \\ \theta_{t+1}=\theta_{t}-\eta \frac{m_{t}}{\sqrt{V_{t}}}\end{array} +$$ + +其中$g(t)$为`t`时刻参数梯度, + +下面来讲解为什么adagrad可以实现不同频率特征对其参数学习率改变,首先,看到二阶动量$V(t)$,它是梯度平方累加和,对于训练数据少的特征,自然对应的参数更新就缓慢,也就是说他们的梯度变化平方累加和就会比较小,所以对应于上面参数更新方程中的学习速率就会变大,所以对于某个特征数据集少,相应参数更新速度就快。为了防止上述分母为0,所以往往添加一个平滑项参数`ε`,参数更新方程也就变成: + +$$ +\theta_{t+1}=\theta_{t}-\eta \frac{m_{t}}{\sqrt{V_{t}+\epsilon}} +$$ + +但是Adagrad同样也有问题,就是其分母随着训练数增加,也会跟着增加,这样会导致学习速率越来越小,最终变的无限小,从而无法有效更新参数。 + +### 3.4 RMSprop + +RMSprop算法由hinton教授提出,它与Adadelta算法公式其实是一样的,他们是在相同时间被独立的提出,公式自然也为: + +$$ +\begin{array}{c}m_{t}=g_{t} \\ V_{t}=\gamma V_{t-1}+(1-\gamma) g_{t}^{2} \\ \theta_{t+1}=\theta_{t}-\eta \frac{m_{t}}{\sqrt{V_{t}+\epsilon}}\end{array} +$$ + +hinton教授建议将$γ$设置为0.9,对于学习率,一个好的固定值为0.001。 + +### 3.5 Adam + +Adam (Adaptive Moment Estimation) **自适应矩估计**,是另一种**自适应学习率的算法**,它是一种将动量和Adadelta或RMSprop结合起来的算法,也就引入了两个参数$β_1$和$β_2$,其一阶和二阶动量公式为: + +$$ +\begin{aligned} m_{t} & =\beta_{1} m_{t-1}+\left(1-\beta_{1}\right) g_{t} \\ V_{t} & =\beta_{2} V_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2}\end{aligned} +$$ + +作者发现一阶和二阶动量初始训练时很小,接近为$0$,因为$β$值很大,于是作者重新计算一个偏差来校正: + +$$ +\begin{array}{l}\hat{m}_{t}=\frac{m_{t}}{1-\beta_{1}^{t}} \\ \hat{v}_{t}=\frac{v_{t}}{1-\beta_{2}^{t}}\end{array} +$$ + +其中`t`代表其`t`次方,所以刚开始训练时,通过除于 `(1-β)` 就可以很好修正学习速率,当训练多轮时,分母部分也接近1,又回到了原始方程,所以最后总的梯度更新方程为: + +$$ +\begin{array}{c}m_{t}=\beta_{1} m_{t-1}+\left(1-\beta_{1}\right) g_{t} \\ V_{t}=\beta_{2} V_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2} \\ \widehat{m}_{t}=\frac{m_{t}}{1-\beta_{1}^{t}} \\ \hat{V}_{t}=\frac{V_{t}}{1-\beta_{2}^{t}} \\ \theta_{t+1}=\theta_{t}-\eta \frac{\widehat{m}_{t}}{\sqrt{\hat{V}_{t}+\epsilon}}\end{array} +$$ + +其中$β1$默认值为0.9,$β2$默认值为0.999, $ε$为10^-8,Adam集合动量和Adadelta两者的优点,从经验中表明Adam在实际中表现很好,同时与其他自适应学习算法相比,更有优势。 + +## 4.可视化优化器 + +![](image/9cf7ce63ee9047df36576f6b5f2ca290__m9AiUI0Ya.gif) + +![](image/1c6290931f35b50f794a8acca445e829_cCz574Huf6.gif) + +## 5.其他SGD优化器 + +1、Shuffling and Curriculum Learning + +2、Batch normalization + +3、Early stopping + +4、Gradient noise diff --git "a/docs/dl/6.\350\257\204\344\274\260\346\214\207\346\240\207.md" "b/docs/dl/6.\350\257\204\344\274\260\346\214\207\346\240\207.md" new file mode 100644 index 0000000..d998200 --- /dev/null +++ "b/docs/dl/6.\350\257\204\344\274\260\346\214\207\346\240\207.md" @@ -0,0 +1,161 @@ +# 6.评估指标 + +## 1.BLEU + +### 1.1 BLEU计算 + +BLEU(Bilingual Evaluation Understudy)是一种在机器翻译领域广泛采用的评估指标,其通过计算机器翻译输出(下称为“候选文本”)与参考翻译文本(下称为“参考文本”)之间的**词汇相似度来评估翻译质量**。BLEU 主要**计算候选文本与参考文本的 **$𝑛$** 元组(𝑛-gram)共现频率**,评分结果在 `[0, 1]` 的区间内, 具体的计算方式如下所示: + +$$ +\mathrm{BLEU}=\mathrm{BP} \times \exp \left(\sum_{n=1}^{N} w_{n} \times \log p_{n}\right) +$$ + +其中,$𝑤_𝑛$ 是 `𝑛` 元组的权重,用于调整不同长度的 `𝑛` 元组对最终评分的影响。具体 实践中,研究者通常设 𝑛 = 4,并平均分配 $𝑤_𝑛$。BP 表示长度惩罚因子,用于修正由于候选文本长度过短导致的评分偏差,其计算方式为: + +$$ +\mathrm{BP}=\left\{\begin{array}{ll}1, & \text { if } l_{c}>l_{r} \\ \exp \left(1-\frac{l_{r}}{l_{c}}\right), & \text { if } l_{c} \leq l_{r}\end{array}\right. +$$ + +这里,$𝑙_𝑐$ 和 $𝑙_𝑟$ 分别表示候选文本的长度和最短的参考文本长度。而公式 BLEU中的 $𝑝_𝑛$ 代表 `𝑛` 元组的精确率,计算公式如下: + +$$ +p_{n}=\frac{\sum_{\mathrm{n}-\text { gram } \in C} \min \left(\operatorname{count}_{C}(\mathrm{n}-\mathrm{gram}), \max _{R \in \mathcal{R}} \operatorname{count}_{R}(\mathrm{n}-\mathrm{gram})\right)}{\sum_{\mathrm{n} \text {-gram } \in C} \operatorname{count}_{C}(\mathrm{n} \text {-gram })} +$$ + +其中,`𝐶` 代表候选文本,`𝑅` 代表所有参考文本集合 `R` 中的一个文本,$count_𝐶 (n-gram)$ 和 $count_𝑅 (n-gram)$ 分别指 `𝑛` 元组在候选文本和参考文本中的出现次数 + +在做 n-gram 划分时,随着 n 的增大得分越来越低。这个是很直观的,当 n 非常大时就等于是要求生成的结果必须和人工标注的译文一摸一样才能得分。 + +### 1.2 BLEU 优缺点[#](#13-bleu "#") + +优点: + +- BLEU 快速且易于计算,特别是与人工翻译速率模型输出相比的话尤为明显。 +- BLEU 无处不在,这使你将模型与同一任务的基准进行比较变得更为轻松。 + +缺点: + +- BLEU 是在计算准确率,所以该指标不能很好的衡量召回的质量。 +- 它不考虑意义; +- 它不直接考虑句子结构; +- 它不能很好地处理形态丰富的语言; +- 它与人类的判断并不相符; + +## 2.ROUGE指标 + +ROUGE(Recall-Oriented Understudy for Gisting Evaluation)指标总共有四种:Rouge-N、Rouge-L、Rouge-W、Rouge-S。相比于 BLEU 计算的是准确率,ROUGE **指标计算的是召回率,即强调文本信息的覆盖度和完整度**。 + +### 2.1 Rouge-N 指标 + +Rouge-N 的全称为 N-gram Co-Occurrence Statistics。 + +简单来说 Rouge-N 就是**将模型生成结果和标注结果按照 n-gram 划分后,计算召回率**。公式为: + +$$ +ROUGE-n=\frac{\sum_{\mathrm{n} \text {-gram } \in R} \min \left(\operatorname{count}_{C}(\mathrm{n} \text {-gram }), \operatorname{count}_{R}(\mathrm{n} \text {-gram })\right)}{\sum_{\mathrm{n} \text {-gram } \in R} \operatorname{count}_{R}(\mathrm{n} \text {-gram })} +$$ + +其中,`𝐶` 代表候选文本,`𝑅` 代表参考文本。在此公式中,分母表示所有参考文本中 `𝑛` 元组的总数,而分子表示候选文本与参考文本中匹配的 `𝑛` 元组的数量 + +和 BLEU 一样,n 越大,得分越低。 + +### 2.2 Rouge-L 指标 + +Rouge-L 的全称为 Longest Common Subsequence。 + +无论 BLEU 指标还是 Rouge-N 指标使用的都是词袋模型,它们都不考虑词语之间的相对顺序,而 Rouge-L 指标则是考虑了词语之间的相对顺序。这个名字里的 L 表示的是Longest Common Subsequence(最长公共子序列:注意这个非连续的)。 + +ROUGE-L 以 F1 分数计算,结合了精确率和召回率的信息。精确率衡量了候选文本中有多少内容是与参考文本相关的,而召回率则衡量了参考文本中有多少内容被候选文本所覆盖。具体计算公式如下: + +$$ +\begin{aligned} \text { Recall } & =\frac{\operatorname{LCS}(C, R)}{\operatorname{length}(R)} \\ \text { Precision } & =\frac{\operatorname{LCS}(C, R)}{\text { length }(C)} \\ \mathrm{F} 1 & =\frac{\left(1+\beta^{2}\right) \cdot \text { Precision } \cdot \text { Recall }}{\left(\beta^{2} \cdot \text { Precision }\right)+\text { Recall }}\end{aligned} +$$ + +在上述公式中,$LCS(𝐶, 𝑅)$ 表示 `𝐶` 和 `𝑅` 之间的最长公共子序列长度。$length(𝐶)$ 和 $length(𝑅)$ 分别代表候选文本和参考文本的长度。在 ROUGE-L 中,$\beta + $ 用于决定召 回率的权重。 + +### 2.3 Rouge-W 指标 + +Rouge-W 的全称为 Weighted Longest Common Subsequence。 + +Rouge-L 指标虽然考虑了词语之间的相对顺序,但是由于其使用最长公共子序列,所以没有考虑到词语之间是否连续的问题。 + +如果使用 Rouge-L 计算的话,得分是相同的。所以提出了 Rouge-W 指标。简单来说,**Rouge-W 就是给连续匹配到的子序列更高的权重,最终让连续匹配的结果要比非连续匹配的结果得分更高一些**。 + +Rouge-W 的计算公式如下: + +$$ +\begin{aligned} R_{w l c s} & =f^{-1}\left(\frac{\mathrm{WLCS}(X, Y)}{f(m)}\right) \\ P_{w l c s} & =f^{-1}\left(\frac{\mathrm{WLCS}(X, Y)}{f(n)}\right) \\ F_{w l c s} & =\frac{\left(1+\beta^{2}\right) R_{u l c s} P_{w l c s}}{R_{w l c s}+\beta^{2} P_{w l c s}}\end{aligned} +$$ + +其中函数 $f(⋅)$ 就是实现给予连续匹配的序列更高权重的函数,比如连续的、相邻的 `x` 和 `y` 的权重 $f(xy)$ 要比不连续的单独的 $f(x)$ 和 $f(y)$ 的分值要高,即:$f(xy)>f(x)+f(y)$。函数 $f^{−1}(⋅)$ 是函数 $f(⋅)$ 的逆函数。$WLCS(⋅)$ 表示带有加权的最长公共子序列,这里加权的权重就是给连续匹配的子序列更高的权重。其他部分的计算和 Rouge-L 是一致的。 + +> 该算法还是比较复杂的,关于函数 $f(⋅)$ 和其逆函数 $f^{−1}(⋅)$ 更多的性质,以及其具体的公式。还有 $WLCS(⋅)$ 算法的细节,请看原始论文:[https://aclanthology.org/W04-1013.pdf](https://aclanthology.org/W04-1013.pdf "https://aclanthology.org/W04-1013.pdf") + +### 2.4 Rouge-S 指标 + +Rouge-S 的全称为 Skip-Bigram Co-Occurrence Statistics。 + +在 Rouge-N 中对文本做 2-gram 划分(也称 bigram 划分)时,都是连续的进行划分。在 Rouge-S 中使用的 skip-bigram 则是在划分时允许跳过一些词。下面先放上计算公式,然后举例进行说明如何计算。 + +Rouge-S 的计算公式如下: + +$$ +\begin{array}{c}R_{s k i p 2}=\frac{\operatorname{SKIP} 2(X, Y)}{C(m, 2)} \\ P_{s k i p 2}=\frac{\operatorname{SKIP} 2(X, Y)}{C(n, 2)} \\ F_{s k i p 2}=\frac{\left(1+\beta^{2}\right) R_{s k i p 2} P_{s k i p 2}}{R_{s k i p 2} 2+\beta^{2} P_{s k i p 2}}\end{array} +$$ + +其中 `X` 表示人工标注的结果,`Y` 表示模型预测的结果,$SKIP2(X,Y)$ 表示标注结果按照 skip-bigram 拆分后与预测结果按照 skip-bigram 拆分后匹配上的个数。$C(m,2)$ 表示人工标注结果按照 skip-bigram 拆分后的个数,$C(n,2)$ 表示预测结果按照 skip-bigram 拆分后的个数。$β$ 是超参数。 + +其中 $SKIP2(X,Y)$ 表示所有样本的标注结果按 n-gram 拆分后与生成结果按 n-gram 拆分后匹配上个数的和;分母表示所有样本的标注结果按 n-gram 拆分后的和。下面举例说明计算方式。 + +## 3.分类指标 + +### 3.1 A、P、R、F1 + +| **混淆矩阵** | | | +| ---------------- | -------------------- | ------------------- | +| | 预测值 **P(Positives)** | 预测值**N(Negatives)** | +| 真实值**T(Ture)** | TP:正样本,预测结果为正(真阳性) | FN:正样本,预测结果为负(假阴性) | +| 真实值**F (False)** | FP:负样本,预测结果为正(假阳性) | TN:负样本,预测结果为负(真阴性) | + +- **准确率**:所有预测正确的正例和负例,占所有样本的比例,其定义为:$Accuracy =\frac{T P+T N}{P+N}$ +- **精确率**:模型**预测为正例的样本中真正为正例的比例**,其定义为:$Precision =\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FP}}$ +- **召回率**:所有**真正为正例的样本中被模型正确预测出来的比例**, 其定义为:$Recall =\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FN}}$ +- **F1分数**:是精确率和召回率的调和平均数,用于衡量模型在分类任 务上的综合性能,其定义为:$F1 =2 \times \frac{\text { Precision } \times \text { Recall }}{\text { Precision }+ \text { Recall }}$ + +### 3.2 P-R曲线 + +P-R曲线:通过选择不同的阈值,得到Recall和Precision,以Recall为横坐标,Precision为纵坐标得到的曲线图。 + +![](image/image_TO2iAcgR7r.png) + +PR曲线性质: + +- 如果一个学习器的P-R曲线被另一个学习器的曲线完全包住,后者性能优于前者; +- 如果两个学习器的曲线相交,可以通过平衡点(如上图所示)来度量性能; +- 如果有个划分点可以把正负样本完全区分开,那么P-R曲线面积是`1*1`; + +阈值下降: + +- **Recall**:不断增加,因为越来越多的样本被划分为正例,假设阈值为0.,全都划分为正样本了,此时recall为1; +- **Precision**:正例被判为正例的变多,但负例被判为正例的也变多了,因此precision会振荡下降,不是严格递减; +- **AP(average precision)**:Precision-recall 曲线下围成的面积,一般一个分类器性能越好,AP值越高。 +- **mAP(mean average precision)**:多个类别AP的平均值。 + +### 3.3 ROC-AUC + +**ROC**(Receiver Operating Characteristic)曲线:**曲线的****横坐标为假正例率(FPR)****,即实际为负的样本有多少被预测为正;****纵坐标为TPR(真正例率)****,即实际为正的样本多少被预测为正**。 + +$$ +F P R=\frac{F P}{F P+T N} +$$ + +$$ +T P R=\frac{T P}{T P+F N}=\text { Recall } +$$ + +TPR和FPR的范围均是`[0,1]`,通过选择不同的阈值得到TPR和FPR,然后绘制ROC曲线。 + +![](image/image_-5-KhHc6vb.png) + +**AUC (Area under Curve)**:即ROC曲线下的面积,介于0.1和1之间,作为数值可以直观的评价分类器的好坏,值`越大越好`。 diff --git a/docs/dl/image/1c6290931f35b50f794a8acca445e829_cCz574Huf6.gif b/docs/dl/image/1c6290931f35b50f794a8acca445e829_cCz574Huf6.gif new file mode 100644 index 0000000..61db246 Binary files /dev/null and b/docs/dl/image/1c6290931f35b50f794a8acca445e829_cCz574Huf6.gif differ diff --git a/docs/dl/image/9cf7ce63ee9047df36576f6b5f2ca290__m9AiUI0Ya.gif b/docs/dl/image/9cf7ce63ee9047df36576f6b5f2ca290__m9AiUI0Ya.gif new file mode 100644 index 0000000..e9d54d0 Binary files /dev/null and b/docs/dl/image/9cf7ce63ee9047df36576f6b5f2ca290__m9AiUI0Ya.gif differ diff --git a/docs/dl/image/image_-5-KhHc6vb.png b/docs/dl/image/image_-5-KhHc6vb.png new file mode 100644 index 0000000..ebaf181 Binary files /dev/null and b/docs/dl/image/image_-5-KhHc6vb.png differ diff --git a/docs/dl/image/image_2AtuZrFran.png b/docs/dl/image/image_2AtuZrFran.png new file mode 100644 index 0000000..237dd9b Binary files /dev/null and b/docs/dl/image/image_2AtuZrFran.png differ diff --git a/docs/dl/image/image_2KV3LOKN2S.png b/docs/dl/image/image_2KV3LOKN2S.png new file mode 100644 index 0000000..ae22436 Binary files /dev/null and b/docs/dl/image/image_2KV3LOKN2S.png differ diff --git a/docs/dl/image/image_9ED50ulsDw.png b/docs/dl/image/image_9ED50ulsDw.png new file mode 100644 index 0000000..8d1919d Binary files /dev/null and b/docs/dl/image/image_9ED50ulsDw.png differ diff --git a/docs/dl/image/image_9PYcDpzk-_.png b/docs/dl/image/image_9PYcDpzk-_.png new file mode 100644 index 0000000..ccbe03b Binary files /dev/null and b/docs/dl/image/image_9PYcDpzk-_.png differ diff --git a/docs/dl/image/image_AHzmMqgKgV.png b/docs/dl/image/image_AHzmMqgKgV.png new file mode 100644 index 0000000..f058d40 Binary files /dev/null and b/docs/dl/image/image_AHzmMqgKgV.png differ diff --git a/docs/dl/image/image_EkdkFEhzz3.png b/docs/dl/image/image_EkdkFEhzz3.png new file mode 100644 index 0000000..dba8a7c Binary files /dev/null and b/docs/dl/image/image_EkdkFEhzz3.png differ diff --git a/docs/dl/image/image_GlE3RW4neL.png b/docs/dl/image/image_GlE3RW4neL.png new file mode 100644 index 0000000..cde11ca Binary files /dev/null and b/docs/dl/image/image_GlE3RW4neL.png differ diff --git a/docs/dl/image/image_OQIO6bJNUM.png b/docs/dl/image/image_OQIO6bJNUM.png new file mode 100644 index 0000000..70771e6 Binary files /dev/null and b/docs/dl/image/image_OQIO6bJNUM.png differ diff --git a/docs/dl/image/image_TO2iAcgR7r.png b/docs/dl/image/image_TO2iAcgR7r.png new file mode 100644 index 0000000..d0eebaa Binary files /dev/null and b/docs/dl/image/image_TO2iAcgR7r.png differ diff --git a/docs/dl/image/image_VQ92WkZEST.png b/docs/dl/image/image_VQ92WkZEST.png new file mode 100644 index 0000000..3eb80fe Binary files /dev/null and b/docs/dl/image/image_VQ92WkZEST.png differ diff --git a/docs/dl/image/image_mObw4TwnQV.png b/docs/dl/image/image_mObw4TwnQV.png new file mode 100644 index 0000000..acf3f9e Binary files /dev/null and b/docs/dl/image/image_mObw4TwnQV.png differ diff --git a/docs/dl/image/image_vZZ0x7ThiD.png b/docs/dl/image/image_vZZ0x7ThiD.png new file mode 100644 index 0000000..1948232 Binary files /dev/null and b/docs/dl/image/image_vZZ0x7ThiD.png differ diff --git a/docs/dl/image/image_zrvZp-9GRb.png b/docs/dl/image/image_zrvZp-9GRb.png new file mode 100644 index 0000000..675adee Binary files /dev/null and b/docs/dl/image/image_zrvZp-9GRb.png differ