|
本笔记是作为复试应对面试回答做的一些笔记,后期还要去读一些论文加深理解,参考书为《动手学习深度学习》
作为一个研究者,我需要去读很多的文章,去总结很多不同的优秀的研究者对这个世界的认识,然后形成自己独特的观点是很重要的
读论文
- 读论文的过程:Abstract、Introduction(讲个故事,我们研究的方向,要做什么,以及后面的几节会讲什么);之后给出实验数据,这里一般是做图表对比,刷刷榜;最后可能有 conclusion(少数有 discussion,如 AlexNet)
深度学习基础
损失函数
- \(\hat{y}^{(i)} = \mathbf{w}^\top \mathbf{x}^{(i)} + b\), \(l^{(i)} = \frac{1}{2} (\hat{y}^{(i)} - y^{(i)})^2\), 根据链式法则,可以将其拆分为两步相乘:
\[\frac{\partial l^{(i)}}{\partial \mathbf{w}} = \frac{\partial l^{(i)}}{\partial \hat{y}^{(i)}} \cdot \frac{\partial \hat{y}^{(i)}}{\partial \mathbf{w}}
\]第一步:
\[\frac{\partial l^{(i)}}{\partial \hat{y}^{(i)}} = 2 \cdot \frac{1}{2} (\hat{y}^{(i)} - y^{(i)}) = \hat{y}^{(i)} - y^{(i)} = \mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}
\]第二步:
\[\frac{\partial \hat{y}^{(i)}}{\partial \mathbf{w}} = \frac{\partial (\mathbf{w}^\top \mathbf{x}^{(i)} + b)}{\partial \mathbf{w}} = \mathbf{x}^{(i)}
\]将上面两步的结果相乘,就得到了完整的梯度表达式:
\[\partial_{\mathbf{w}} l^{(i)}(\mathbf{w}, b) = \mathbf{x}^{(i)} \left( \mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)} \right)
\]交叉熵损失也是基于 SoftMax:
\[\text{softmax}(\mathbf{X})_{ij} = \frac{\exp(\mathbf{X}_{ij})}{\sum_k \exp(\mathbf{X}_{ik})}
\]进行极大似然估计得出来的公式,交叉熵损失:
\[l(\mathbf{y}, \hat{\mathbf{y}}) = - \sum_{j=1}^q y_j \log \hat{y}_j
\]
- 为什么在做线性回归等任务时,我们通常会理所当然地选择"均方误差"作为损失函数
\(y = \mathbf{w}^\top \mathbf{x} + b + \epsilon\), 假设噪音 \(\epsilon\) 符合正态分布,对 \(n\) 个样本的概率连乘,求极大似然估计,把无关紧要的常数项都抛开后,剩下的核心部分:
\[\sum_{i=1}^n \left( y^{(i)} - \mathbf{w}^\top \mathbf{x}^{(i)} - b \right)^2
\]这正是我们非常熟悉的均方误差(MSE)公式的内核(即预测值与真实值差值的平方和)。也就是用均方误差去训练模型,本质上就是在做极大似然估计,是在寻找最能解释当前数据的最优参数。
- 做分类任务的时候,采用交叉熵是一个不错的选择。
- 假设我们做一个二分类,模型输出前的逻辑值(Logits)为 \(z\),经过 Sigmoid 激活函数后得到预测概率 \(\hat{y} = \sigma(z)\)。真实标签为 \(y\)。
- 如果我们使用 MSE:\(L_{\text{MSE}} = \frac{1}{2}(\hat{y} - y)^2\),在分类问题中,我们预测的是各个标签的概率,于是在反向传播阶段,我们对 \(z\) 求导(也就是反向传播时传给上一层的梯度):
\[\frac{\partial L_{\text{MSE}}}{\partial z} = (\hat{y} - y) \cdot \sigma'(z)
\]\(\sigma'(z)\) 是 Sigmoid 的导数。
3. 如果模型预测 \(\hat{y}_i \approx 0\),此时 \(z\) 是一个很大的负数,但实际 \(y_i=1\),Sigmoid 在极值处的导数 \(\sigma'(z)\) 会极其接近于 0,那么梯度就接近 0 无法更新权重
\[L_{\text{CE}} = - [y \ln \hat{y} + (1 - y) \ln (1 - \hat{y})]
\]同样对 \(z\) 求导:
\[\frac{\partial L_{\text{CE}}}{\partial z} = \hat{y} - y
\]梯度的物理意义变成了:预测值和真实值的单纯差值。
训练与反向传播
激活函数
- 加入激活函数的原因是因为对于 hidden layer 来说,不加入激活函数实际上与线性层一样,考虑:\(\mathbf{H} = \mathbf{X}\mathbf{W}_1 + \mathbf{b}_1\),\(\mathbf{O} = \mathbf{H}\mathbf{W}_2 + \mathbf{b}_2\),我们把隐藏层 \(\mathbf{H}\) 的等式直接代入到输出层矩阵运算中:
\[\mathbf{O} = (\mathbf{X}\mathbf{W}_1 + \mathbf{b}_1)\mathbf{W}_2 + \mathbf{b}_2
\]利用矩阵乘法的分配律将其展开:
\[\mathbf{O} = \mathbf{X}(\mathbf{W}_1\mathbf{W}_2) + (\mathbf{b}_1\mathbf{W}_2 + \mathbf{b}_2)
\]最终的等式变成了:
\[\mathbf{O} = \mathbf{X}\mathbf{W}' + \mathbf{b}'
\]
- ReLu 在 AlexNet 首次提出,当时大家觉得求导表现得特别好,其实后来发现都差不多,但是 ReLu 比较简单,就都用了
过拟合与欠拟合
- 欠拟合:模型在 train 和 val 的 loss 都很差,误差较小,有理由相信是我们的网络过于简单;
- 过拟合:模型在 train 的 loss 较小,但是 val 上面表现很差
正则化
\[L_{\text{total}} = L_{\text{data}}(\mathbf{w}, b)
\]由于模型非常贪婪,为了让 \(L_{\text{data}}\) 趋近于 0,它会不择手段地调整 \(\mathbf{w}\),甚至把某些权重放大到成千上万,只为了迎合某个微小的噪声点(这就是过拟合)。现在,我们强行给目标函数加了一个"尾巴"(以 \(L_2\) 为例):
\[L_{\text{total}} = L_{\text{data}}(\mathbf{w}, b) + \frac{\lambda}{2} ||\mathbf{w}||^2
\]优化器的目标依然是让整个 \(L_{\text{total}}\) 最小。这时候,博弈就产生了:
* 如果模型依然想把 \(\mathbf{w}\) 设得巨大无比来完美拟合数据(让 \(L_{\text{data}}\) 降为 0),那么后面的惩罚项 \(\frac{\lambda}{2} ||\mathbf{w}||^2\) 就会爆炸式增长,导致总分 \(L_{\text{total}}\) 极高。
* 为了拿到最低的总分,优化器被迫做出妥协:它宁愿让 \(L_{\text{data}}\) 稍微大一点(放弃完美拟合噪声),也要把权重 \(\mathbf{w}\) 的数值压下来,以此来换取惩罚项的大幅降低。
从微积分求导的过程来看,惩罚的作用更加直接:
\[\frac{\partial L_{\text{total}}}{\partial \mathbf{w}} = \frac{\partial L_{\text{data}}}{\partial \mathbf{w}} + \lambda \mathbf{w}
\]\[\mathbf{w} \leftarrow (1 - \eta\lambda)\mathbf{w} - \eta \frac{\partial L_{\text{data}}}{\partial \mathbf{w}}
\]这就是对权重的衰减
- \(L_1\) vs \(L_2\) 的行为偏好:\(L_1\) 产生稀疏性,\(L_2\) 产生平滑性
- \(L_2\) 惩罚(平方)的导数是 \(2\lambda w\):这意味着,惩罚的力度是和权重大小成正比的。当 \(w\) 是 100 的时候,惩罚力度是 \(200\lambda\),逼着它赶紧变小
- \(L_1\) 惩罚(绝对值)的导数是 \(\lambda \cdot \text{sign}(w)\):无论你的 \(w\) 是巨大的 100,还是微小的 0.001,只要你不等于 0,惩罚项给你的推力永远是一个常数 \(\lambda\)
梯度问题与参数初始化
批量规范化
- Batch Normalization:
- 在深度神经网络中,由于层数很多,底层参数的微小变化,经过层层放大,会导致高层输入数据的分布发生剧烈震荡。高层网络被迫不断去"追赶"这种分布的变化,导致模型训练极慢。
- 批量规范化就是在一些网络层中对前面的网络层进行标准化,标准化的参数也是可以学习的
- 提升了训练速度,因为网络层的数据分布被稳定住了,对学习率不敏感了(大学习率也能快速收敛),同样的也不对初始化敏感了(如果开始初始化导致方差爆炸,BN 也能拉回来)
计算机视觉
卷积层
-
卷积是 4 维是因为:如果是 Linear 的话,其实是 5 维,分别是 \([\mathbf{V}]_{i,j,a,b}\):意思是,针对输出图的 \((i,j)\) 这个位置,当偏移量是 \((a,b)\) 时,权重是多少,有 \(c\) 个 RGB
- 由于平移不变性,我们意识到原始位置是没用的,这意味着权重张量 \([\mathbf{V}]_{i,j,a,b}\) 里的 \(i\) 和 \(j\) 完全成了摆设,我们可以直接把它俩踢掉,简化成 \([\mathbf{V}]_{a,b,c}\)
- 局部性:你只需要看它周围一小圈的像素就行了,完全没必要去参考图片角落里距离它几千像素远的背景。它们不能超过一个很小的距离 \(\Delta\)(比如 \(\Delta=1\),也就是只看周围 \(3 \times 3\) 的九宫格)。
- 剩下的一个维度就是通道了,\([\mathbf{V}]_{a,b,c,d}\)
-
卷积核:为了实现"多输入 + 多输出",卷积核(权重张量)必须是一个四维(四阶)的数据结构。这非常关键: 假设输入有 \(c_i\) 个通道,输出想要 \(c_o\) 个通道,卷积核的高和宽分别是 \(k_h\) 和 \(k_w\)。 那么这个卷积核 K 的形状就是:\(c_o \times c_i \times k_h \times k_w\)。
特征映射与感受野
汇聚层
- 汇聚(pooling)层具有双重目的:降低卷积层对位置的敏感性,同时降低对空间采样表示的敏感性。
残差网络(ResNet)
- ResNet 为什么有用?
- 我们想要加深网络来提升性能,但事实上不一定会表现更好,如图,\(f'\) 我们设为最优解,那么 F6 的距离是要比 F3 更远的,而我们确实在向 F6 靠拢,那不如我们说是向右边一样,每次大模型都包含前面的小模型,这样最起码的不会变差![[Pasted image 20260310211425.png|684]]
- ResNet 核心思想就是上述:每个附加层都应该更容易地包含原始函数作为其元素之一。于是,残差块(residual blocks)便诞生了。
转置卷积与全卷积网络(语义分割)
- 转置卷积是好理解的,类似于卷积的逆变换,具体一张图其实就可以看懂
![[Pasted image 20260313235140.png|613]]
- 对于语义分割,我们考虑先进行卷积神经网络,然后把输出为
1x1 特征图,这个小矩阵的感受野是整张图片的,随后我们再使用转置卷积对其进行放大分割,得到物体边界。
- 对于转置卷积的初始化,我们使用双线性插值进行对特征图的放大,也就是上采样
- 单线性插值:这个很简单,我们知道两点 \((x_0,y_0), (x_1, y_1)\),那么给定 \(x\),我们有:
\[y = \frac{x_1 - x}{x_1 - x_0} y_0 + \frac{x - x_0}{x_1 - x_0} y_1
\]
- 双线性插值法:四个已知顶点(在图像中就是四个相邻的像素点):左上:\(Q_{11} = (x_1, y_1)\),其值为 \(f(Q_{11})\);右上:\(Q_{21} = (x_2, y_1)\),其值为 \(f(Q_{21})\);左下:\(Q_{12} = (x_1, y_2)\),其值为 \(f(Q_{12})\);右下:\(Q_{22} = (x_2, y_2)\),其值为 \(f(Q_{22})\);设目标点位 \(P(x, y)\),对应 \(f(x, y)\),我们对其在 \(x\) 轴做一次线性插值,对 \(y\) 轴再做一次即可(先 \(y\) 后 \(x\) 也可以),矩阵面积:\(S = (x_2 - x_1)(y_2 - y_1)\),那么我们有:
\[f(x, y) = \frac{(x_2 - x)(y_2 - y)}{S} f(Q_{11}) + \frac{(x - x_1)(y_2 - y)}{S} f(Q_{21}) + \frac{(x_2 - x)(y - y_1)}{S} f(Q_{12}) + \frac{(x - x_1)(y - y_1)}{S} f(Q_{22})
\]自然语言处理
序列模型
- 自回归模型:直接用观测序列 \(x_{t-1} \dots x_{t-\tau}\) 生成预测,这样的好处是参数的数量是不变的
\[P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1}, \ldots, x_1)
\]实际上就是多个条件概率连乘:
\[P(A, B, C) = P(A) \cdot P(B \mid A) \cdot P(C \mid A, B)
\]
- 接着,我们引用马尔科夫链,这里我们只用一阶马尔可夫模型(\(\tau = 1\)),然后我们对其化简:
\[P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1})
\]如果我们要去预测下一个(即 \(x_{t+1}\)),那么我们需要把今天所有可能的情况算出来,有:
\[P(x_{t+1} \mid x_{t-1})= \sum_{x_t} P(x_{t+1} \mid x_t) P(x_t \mid x_{t-1})
\]
- 隐变量自回归模型:我们总是保留一些对过去观测的总结 \(h_t\),并同时更新预测和总结,这样基于 \(x_t\) 和 \(h_t\) 更新的模型由于 \(h_t\) 从未被观测到,这类模型也被称为隐变量自回归模型
文本预处理与基本概念
-
文本预处理的步骤:
- 将文本作为字符串加载到内存中。
- 将字符串拆分为词元(如单词和字符)。
- 建立一个词表,将拆分的词元映射到数字索引。
- 将文本转换为数字索引序列,方便模型操作。
-
一些基本的概念:
- 词元(token):就是数据集中的字或字符
- 词表(vocabulary):本质是一个哈希表
map,对它们的唯一词元进行统计,得到的统计结果称之为语料(corpus)。然后根据每个唯一词元的出现频率,为其分配一个数字索引。很少出现的词元通常被移除,这可以降低复杂性。
- 涉及一个、两个和三个变量的概率公式分别被称为一元语法(unigram)、二元语法(bigram)和三元语法(trigram)模型。(即
Deep,Deep Learning,Deep Learning is)
- 由于二元和三元词元数量很少,可以用拉普拉斯平滑来计数,但是我们需要存储所有的计数,这完全忽略了单词的意思
循环神经网络(RNN)
- 循环神经网络(RNN),在时间步 \(t\) 引入了一个叫作隐状的变量 \(\mathbf{H}_t\),负责捕获并保留从序列开头一直到当前时间步的所有历史信息,那么我们更新状态就不是 MLP 那样更新了,而是:
\[\mathbf{H}_t = \phi(\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} + \mathbf{b}_h)
\]\(\phi\) 是激活函数
- 困惑度(Perplexity)用于评估基于循环神经网络的模型:即使模型极好,它生成巨著《战争与和平》的总概率,也必定远小于生成短篇《小王子》的概率。这显然是不公平的。我们需要计算每个词元的平均损失(整个序列的负对数似然(交叉熵损失)取平均):
\[\text{Average Cross-Entropy}=\frac{1}{n} \sum_{t=1}^n -\log P(x_t \mid x_{t-1}, \ldots, x_1)
\]NLP 科学家为了让其特殊一点,就在这个交叉熵损失上面做了一次指数(吐槽一下哈哈哈):
\[\text{Perplexity} = \exp(\text{Average Cross-Entropy})
\]
- 梯度裁剪(Gradient Clipping):为了克服梯度爆炸,最简单的办法就是设定一个速度上限(阈值 \(\theta\)):
\[\mathbf{g} \leftarrow \min\left(1, \frac{\theta}{\|\mathbf{g}\|}\right) \mathbf{g}
\]它只改变大小,不改变方向,确保了模型依然在朝着正确的方向优化,只是硬生生把步伐给缩小了,从而赋予了模型极大的稳定性。
门控循环单元(GRU)
- GRU(门控循环单元),相对于 RNN 新增了两个门控单元:
\[\mathbf{R}_t = \sigma(\mathbf{X}_t \mathbf{W}_{xr} + \mathbf{H}_{t-1} \mathbf{W}_{hr} + \mathbf{b}_r)
\]\[\mathbf{Z}_t = \sigma(\mathbf{X}_t \mathbf{W}_{xz} + \mathbf{H}_{t-1} \mathbf{W}_{hz} + \mathbf{b}_z)
\]\(\sigma\) (Sigmoid)激活函数使得这两个门的输出在(0,1)之间,即什么时候放弃,什么时候用之前的记忆是可以学习的,接着我们有:
\[\tilde{\mathbf{H}}_t = \tanh(\mathbf{X}_t \mathbf{W}_{xh} + (\mathbf{R}_t \odot \mathbf{H}_{t-1}) \mathbf{W}_{hh} + \mathbf{b}_h)
\]\(\tilde{\mathbf{H}}_t\) 是候选隐状态,旧记忆 \(\mathbf{H}_{t-1}\) 被重置门 \(\mathbf{R}_t\) 拦截了:\((\mathbf{R}_t \odot \mathbf{H}_{t-1})\) 为什么这里必须使用 Hadamard 积(按元素相乘),而不是矩阵乘法?
* 隐状态 \(\mathbf{H}_{t-1}\) 不是一个单一的数字,而是一个高维向量(如256维度),把这 256 个维度想象成大脑里 256 个独立的神经元,分别记录着不同的信息
* 重置门 \(\mathbf{R}_t\) 也是一个一模一样长度为 256 的向量,里面全是 \((0, 1)\) 之间的数字。
* 当我们做元素相乘 (\(\odot\)) 时,发生的是:\(\mathbf{R}_t\) 的第 1 维只去乘 \(\mathbf{H}_{t-1}\) 的第 1 维,第 10 维只乘第 10 维,让模型拥有了选择性遗忘的能力
对于更新门,我们利用候选隐单元得到当前的隐单元:
\[H_t = \mathbf{Z}_t \odot{H_{t-1}} + (1 - \mathbf{Z}_t) \odot \tilde{\mathbf{H}}_t
\]这些设计可以帮助我们处理循环神经网络中的梯度消失问题,并更好地捕获时间步距离很长的序列的依赖关系![[Pasted image 20260311202827.png|886]]
长短期记忆(LSTM)
- LSTM(长短期记忆):我们来细化一下长短期记忆网络的数学表达。时间步\(t\)的门被定义如下:输入门是\(\mathbf{I}_t \in \mathbb{R}^{n \times h}\),遗忘门是\(\mathbf{F}_t \in \mathbb{R}^{n \times h}\),输出门是\(\mathbf{O}_t \in \mathbb{R}^{n \times h}\)。它们的计算方法如下:
\[\begin{aligned}
\mathbf{I}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xi} + \mathbf{H}_{t-1} \mathbf{W}_{hi} + \mathbf{b}_i),\\
\mathbf{F}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xf} + \mathbf{H}_{t-1} \mathbf{W}_{hf} + \mathbf{b}_f),\\
\mathbf{O}_t &= \sigma(\mathbf{X}_t \mathbf{W}_{xo} + \mathbf{H}_{t-1} \mathbf{W}_{ho} + \mathbf{b}_o),
\end{aligned}
\]候选记忆单元为:
\[\tilde{\mathbf{C}}_t = \tanh(\mathbf{X}_t \mathbf{W}_{xc} + \mathbf{H}_{t-1} \mathbf{W}_{hc} + \mathbf{b}_c),
\]输入门\(\mathbf{I}_t\)控制采用多少来自\(\tilde{\mathbf{C}}_t\)的新数据,而遗忘门\(\mathbf{F}_t\)控制保留多少过去的记忆元\(\mathbf{C}_{t-1} \in \mathbb{R}^{n \times h}\)的内容。使用按元素乘法,得出:
\[\mathbf{C}_t = \mathbf{F}_t \odot \mathbf{C}_{t-1} + \mathbf{I}_t \odot \tilde{\mathbf{C}}_t.
\]最后,我们需要定义如何计算隐状态 \(\mathbf{H}_t \in \mathbb{R}^{n \times h}\),在 LSTM 中,它仅仅是记忆元的\(\tanh\)的门控版本。这就确保了\(\mathbf{H}_t\)的值始终在区间\((-1, 1)\)内:
\[\mathbf{H}_t = \mathbf{O}_t \odot \tanh(\mathbf{C}_t).
\]- <code>![[Pasted image 20260311211845.png|741]]
- </code>
复制代码
- 为什么在循环神经网络中,tanh 和 sigmoid 混着用:
- sigmoid 的作用是起到一个 mask 的作用,就是说我可以选择性的去记忆
- tanh,对于 RNN 来说,如果不加 tanh 对于一个梯度更新,连乘会导致 H 的值指数级爆炸;对于 GRU 和 LSTM 这类存在记忆性的来说,tanh 的 \((-1, 1)\) 的范围允许记忆发生正负方向的相互抵消,内容的 \((-1, 1)\) 决定了吸收的信息是起正向促进作用,还是负向抑制作用。并且 tanh 在 backword 的时候也可以让梯度下降更加平滑
双向循环神经网络(Bi-RNN)
- 双向 RNN(Bi-RNN):
- 为了证明双向 RNN 的合理性,我们引出隐马尔可夫模型(HMM),我们有:
\[P(x_1, \ldots, x_T, h_1, \ldots, h_T) = \prod_{t=1}^T P(h_t \mid h_{t-1})P(x_t \mid h_t)
\]如果我们利用前面和后面的信息要预测中间某个位置的信息(类似于做完形填空)即求 \(P(x_j \mid x_{-j})\),其中 \(x_{-j}={x_1 \dots x_{j-1},x_{j+1} \dots x_t}\),由于 \(h\) 的信息是隐藏的,所以要枚举出所有情况,这样复杂度达到了 \(O(T \cdot k^2)\),考虑优化,我们首先提出 \(h_1\) 相关的项:
\[= \sum_{h_2, \ldots, h_T} \underbrace{\left[ \sum_{h_1} P(h_1)P(x_1 \mid h_1)P(h_2 \mid h_1) \right]}_{\text{定义为 } \pi_2(h_2)} P(x_2 \mid h_2) \prod_{t=3}^T \dots
\]接着我们提出 \(h_2\):
\[= \sum_{h_3, \ldots, h_T} \underbrace{\left[ \sum_{h_2} \pi_2(h_2)P(x_2 \mid h_2)P(h_3 \mid h_2) \right]}_{\text{定义为 } \pi_3(h_3)} P(x_3 \mid h_3) \prod_{t=4}^T \dots
\]最后有:
\[= \sum_{h_T} \pi_T(h_T)P(x_T \mid h_T)
\]于是我们把向前递归写为:
\[\pi_{T+1}(h_{T+1})= \sum_{h_T} \pi_T(h_T)P(x_T \mid h_T)P(h_{T+1}|{h_T})
\]也可以写成:\(\pi_{T+1}=f(\pi_T,\,x_T)\) 于是我们可以把 \(f\) 看做可学习的函数,反向递归也如此,所以双向 RNN 是合理的
* 双向 RNN 不能用于文本生成,因为我们不知道后面的词元是什么
* 双向循环神经网络的计算速度非常慢。其主要原因是网络的前向传播需要在双向层中进行前向和后向递归,并且网络的反向传播还依赖于前向传播的结果。因此,梯度求解将有一个非常长的链。
编码器-解码器架构
-
编码器解码器:
- 编码器是对输入序列进行特征提取和信息压缩,转化成隐藏状态,称为上下文变量
- 解码器在没有引入注意力机制之前,我们的解码器只引用编码器的最后一个隐藏状态
-
预测过程:
- 基础的序列生成策略是将原句子后面加入
,然后填充,喂给编码器,得到最后的隐藏状态
- 将隐藏状态和
送给解码器,然后得到第一个输出,之后把这个输出当作下次预测的输入,这个叫自回归
输出策略与评估
\[\text{BLEU} = \exp\left(\min\left(0, 1 - \frac{\text{len}_{\text{label}}}{\text{len}_{\text{pred}}}\right)\right) \prod_{n=1}^k p_n^{1/2^n}
\]注意力机制
- 一些基本定义
- Query (查询 \(Q\)):代表你的“自主意愿”。比如你想找一本书,这个“找书”的念头就是 Query。
- Key (键 \(K\)):代表环境中物品的“客观线索/特征”。比如红色的杯子、报纸的排版、书的封面。这是非自主的提示。
- Value (值 \(V\)):代表物品的“实质内容”。与 Key 一一对应
- 注意力汇聚(Attention Pooling)的工作逻辑:系统拿着你的意愿(Query),去和环境中所有物品的特征(Keys)一一比对。匹配度越高的 Key,系统就会给它对应的 Value 分配越大的权重(Attention Weight)。最后把你关注到的所有 Value 按权重加起来,就是模型的输出。
Bahdanau注意力
基于注意力机制的编码器-解码器架构,Decoder 仍然没变,在 Decoder 和 Encoder 中间接入了 Attention 机制, Decoder 在这里干三件事:把自己的输出传入 Attention、传入自己的隐状态(但只用到了最后一层)、传入有效字符长度;我们把要 Decoder 输入的最后一层的隐状态作为 \(Q\);对于 Decoder 的输出,我们称为 enc_outputs, 把其作为 \(K, V\);这里 hidden_state[-1] 作为 \(Q\) 是因为它有前面序列的信息,而它要预测下一个序列![[Pasted image 20260312231025.png|926]]
- 这里,我们是 Decoder 拿着自己的 Q 去 Encoder 生成的 \(K, V\) 找线索,这个我们称之为交叉注意力
自注意力(Self-Attention)
- 顾名思义就是自己看自己,也就是说,我们想要预测 \(i\) 位置的词 \(x_i\),那么就把其作为 \(Q\),在标准的注意力机制中,我们是:\(f(\text{Query}, (\text{Key}_1, \text{Value}_1), \dots, (\text{Key}_n, \text{Value}_n))\),自注意力要求自己理解自己,于是就有 \(\mathbf{y}_i = f(\mathbf{x}_i, (\mathbf{x}_1, \mathbf{x}_1), \dots, (\mathbf{x}_n, \mathbf{x}_n))\),这里的 \(x_1 \to x_n\) 为句子里的所有词,这种做法可以让模型更加深入的关注自身的句子,通过语境来给 \(x_i\) 一个不同的权重
- 对于上述的理解,其实就是可以看为,我去抓取一个句子的其他
token,如果我们要预测苹果的真实意思,若句子中出现了 '水果','市场','好吃',等等,那么我们预测该苹果为吃的苹果,若出现了 '股票','芯片'等,那么理解为苹果手机,而这些东西是要自注意力去抓取上下文来理解的
- 事实上,刚才对 \(x_i\) 作为 \(Q\) 的表述只是为了好理解,对于 '苹果' 一词,我们不想它只是一个定死的意思,它有多个语义,为此通过上述的方式更新它的向量表达
- 上面提到上下文能力,由于我们是用 \(Q \times K\),然后利用评估函数对 \(V\) 做匹配,所以 \(x_i\) 与其他任何词的距离为 \(O(1)\),这就是自注意力与其他序列模型不同之处
- 评估函数这里选择的是点积,但不是简单的 \(\text{Score} = X \cdot X_i\),因为这样是存在对称性的,即 \(X \cdot X_i = X_i \cdot X\),所以说我们引入一个可学习的参数,使得:\(\text{Score} = (X W_q) \cdot (X_i W_k)\),还有一个重要的原因,即上面的向量表达,由于 \(X\) 输入序列有很多的向量,我们需要利用可学习的 \(W\) 去进行特征提取以及语义匹配,其中 \(W_q, W_k\) 是特征提取,为了更优的相似度,\(W_v\) 是进行语义匹配
- 有一个缺点,由于我们直接进行 \(Q\times K\),那么我们发现,其实 \(x_i\) 在哪不重要,因为即使整个句子是乱序的也可以正确得到结果,而位置信息往往比较重要,所以我们引入位置编码
- Transformer 也是基于编码器-解码器架构的,与视觉方面类似,引入了块的机制,其架构图如下:![[Pasted image 20260313224827.png]]
- 对于其编码器,
Q,K,V 均来自前一个编码层的输出,其中受到 ResNet 启发,采用了 Residual + LayerNorm,然后接入一个 FFN
- 对于其解码器,
Q 为前一个解码器的输出,K,V 来自编码器的最后一个输出,但是解码器中每个位置只能考虑该位置之前的所有位置(因为不能看到之后的信息),所以保留了自回归的性质
- 这里的注意力评分机制是采用的点积注意力,为什么不采用加性注意力,原因有两个:
- 点积是矩阵乘法,速度较快,加性注意力要引入额外的权重矩阵和做一次
tanh,而且点积之后用一个标量除法 \(\frac{Q K^T}{\sqrt{d_k}}\) 可以有效地拉回分布方差
- 加性注意力计算时要用大量的广播机制,速度很慢,广播机制就是两个矩阵虽然形状不一样,但可以对矩阵做拓展使得可以相加
- 对于位置编码,这里采用了固定位置编码,即三角函数性质的位置编码
- 对于 LayerNorm,它是对一层做均一化,而 BatchNorm 是对一个小批次,例如对于一个 Batch 的数据
X = [[1, 2], [2, 3]], 那么对于 LayerNorm 来说,我们会得到 X = [[-1, 1], [-1, 1]], 它对一个 Layer,即 [1, 2], [2, 3] 做归一化;而 BathNorm 则是从一列,即 [[-1, 1], [1, -1]], 很明显的,token 的词向量特征与其他 token 无关,只与自身的向量特征有关,所以我们要做 LayerNorm
- FFN(前馈网络)是干什么的?
- FFN 的作用在作者的 paper 说是类似于
1x1 卷积,对词元进行升降维度;
- 事实上,FFN 还起到了加入非线性变换的作用,可能的疑问:在计算注意力中有 \(\phi(Q \times K)\),这不就是一个
Softmax 的非线性运算吗?但后面的 \(V\) 是线性的问题没有被解决,所以本质还是引入了非线性变换
- 可以降低词元向量各向异性
- 对于语言模型,应该使用 Transformer 的解码器,如果使用编码器(当它看到第 \(t\) 个位置的时候,它可以利用未来的答案来进行作弊)
- Transformer 可以应用于对图像的分类,可以先用卷积神经网络进行图像的像素特征提取,之后这些像素块的感受野相当于 token,由 Transformer 来更新注意力权重,理解这些图像特征之间的关系,可以做到更好的分类,这个后面再详细看VIT
BERT
-
BERT输入序列的嵌入是词元嵌入、片段嵌入和位置嵌入的和,其中位置编码是可学习的。其输入形式为 segment1 segment2
-
进行下一句预测的时候,我们提取出 作为输入,是因为我们判断两个句子是否连贯,是用宏观的全局语义表示,而 没有对应 token 语义,它负责吸收整个句子的全局逻辑(通过自注意力,提取全局特征),可以去做分类任务;还有一个原因就是,简洁通俗
-
运用 Bert 的时候,Bert 的参数是 Pretrained(因为比 Random 要好),我们对此进行 fine-tune,从 开始做预测,之后的那个 Linear 是随机初始化的(如果做分类,评价的话)。
-
Bert 在做填空预测的时候(给定一定的80%的概率 mask,10%的概率 random,10%的概率不变)是非监督的,对 Bert 的 fine-tune 是监督性的,需要打 label,合起来是 semi-supervise
-
Q-A Robot 的输入为 question document , 输出是答案的起始和终止位置,唯一从头训练的是两个 tensor,尺寸和 Bert 的输出一样,两者分别代表起始位置和终止位置,对 document 做预测,两个 tensor 分别做 inner product 然后分别做 softmax,取 argmax 即可
-
Bert 在做预测(填空)的时候,吃的苹果和苹果电脑这两个完全不同的意思,Bert 在训练完之后,两者的余弦相似度是非常低的,原因可能是 Bert 的 Encoder 毕竟有 Transformer Block,所以可以抓取上下文,比如吃的苹果往往和树,味道相结合,苹果电脑则会和价格,性能结合在一起(但并不一定是对的,参考李宏毅,这个地方就是有待研究的,所以能力不完全在上下文能力中,还有很大研究空间)* 1. 1. 1.
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |