基本知识
标量、向量、矩阵、张量的关系
-
点——标量(scalar)
-
线——向量(vector)
-
⾯——矩阵(matrix)
-
体——张量(tensor)
标量、向量、矩阵和张量是线性代数与机器学习中常用的数据结构,它们之间存在层级递进的关系,从简单到复杂依次扩展。
标量(Scalar)
标量是单个数值,没有方向,只有大小。通常表示为实数或复数。
x = 5 # 标量示例
向量(Vector)
向量是一维数组,由多个标量组成,具有方向和大小。通常表示为列向量或行向量。
import numpy as np
v = np.array([1, 2, 3]) # 向量示例
矩阵(Matrix)
矩阵是二维数组,由多个向量组成。行和列的每个交叉点是一个标量。常用于表示线性变换。
M = np.array([[1, 2], [3, 4]]) # 矩阵示例
张量(Tensor)
张量是更高维度的数组,可以看作矩阵的推广。标量是0维张量,向量是1维张量,矩阵是2维张量。张量在深度学习中广泛应用。
T = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 3维张量示例
关系总结
- 标量是0维张量。
- 向量是1维张量。
- 矩阵是2维张量。
- 张量是n维数组(n ≥ 0)。
词向量(Embedding)是什么?
假设我们有⼀个句⼦:“The teacher said”,词向量如下:
$$\text{Embedding}_{\text{The}} = [0.9, 2.1, 4.3]$$
$$\text{Embedding}_{\text{teacher}} = [1.2, 3.4, 5.6]$$
$$\text{Embedding}_{\text{said}} = [2.5, 3.6, 4.7]$$
你可能看了不下于几十篇关于 Transformer 的视频或文章,但最后对于 Q、K、V 的计算依然是一头雾水,这是很多学习者的共同困惑。
注意力机制是什么呢?
我去了几次咖啡店?
"昨天,我在一个繁忙的一天结束后,决定去我最喜欢的咖啡店放松一下。我走进咖啡店,点了一杯拿铁,然后找了一个靠窗的位置坐下。我喝着咖啡,看着窗外的人们匆匆忙忙,感觉非常惬意。然后,我从咖啡店出来,回到了家中。"
在这个例子中,“咖啡店”出现了三次,但并非每次都是关键信息。
• 当我们理解“我走进咖啡店,点了一杯拿铁”时,“走进”和“点了一杯拿铁”是关键动作,而“咖啡店”的信息已经被我们知道了。
• 同样,当理解“我从咖啡店出来,回到了家中”时,“从咖啡店出来”和“回到了家中”是关键信息,而“咖啡店”的信息仍然是冗余的。
注意力机制就是帮助模型在处理这样的句子时,能够更好地关注到关键的信息,而忽略冗余的信息。是一种让每个词根据上下文来动态调整它的自身表示(即向量)的机制。即对于每个词,会根据与上下文其他词的相关性来重新计算,以得到新的向量表示。从而帮助神经网络模型更好的捕捉到词与词之间的动态紧密关系,从而实现更准确的预测输出。
为什么要有注意力机制?
在处理自然语言文本的过程中,存在一个显而易见的问题:一个句子的下一个词(也就是神经网络需要预测的),取决于前面所有的词,并且很可能更依赖于之前的某几个词。比如在下面的句子中:
“达米安有一个秘密女儿,是个金发碧眼的女孩。他在遗嘱中写道:所有财产连同魔法水晶球都将属于____"
需要预测的空白处的词可以是“她”或者“他”,这取决于句子前面的词“女孩”。“女孩”这个重要词的位置并不固定,当你换一种表达方式,关联词的位置有可能发生变化。
模型中神经元的特定位置对最终预测结果的影响(也就是这个位置的重要性)是固定的。那么问题来了:与预测结果最相关的词实际上可能处于每一层的任意位置,也就是说,词的重要性不能仅取决于位置,而更取决于其内容以及上下文。比如上面的“女孩”这个词的重要性,并不取决于它的位置。那么怎样让预测中输入词的“重要性”变成动态的呢?答案就是自注意力机制。
1. 注意力机制有助于克服循环神经网络(RNNs)的一些挑战,例如输入序列长度增加时性能下降和顺序处理输入导致的计算效率低下。
2. 在自然语言处理(NLP)、计算机视觉(Computer Vision)、跨模态任务和推荐系统等多个领域中,注意力机制已成为多项任务中的最先进模型,取得了显著的性能提升。
3. 注意力机制不仅可以提高主要任务的性能,还具有其他优势。它们被广泛用于提高神经网络的可解释性,帮助解释模型的决策过程,使得原本被认为是黑盒模型的神经网络变得更易解释。这对于人们对机器学习模型的公平性、可追溯性和透明度的关注具有重要意义。
循环神经网络(RNN)到底有什么问题呢?
循环神经网络(RNN)虽然在序列数据处理(如时间序列、自然语言处理)中表现优异,但仍存在一些根本性问题,以下是主要问题及其原因分析:
梯度消失/爆炸
-
问题:RNN通过时间反向传播训练时,梯度需要沿时间步连续相乘。若梯度值过小,多次连乘后趋近于0(消失);若梯度值过大,则指数级增长(爆炸)。
-
影响:
-
梯度消失:早期时间步的参数无法更新,模型无法学习长期依赖(如预测句子开头对结尾的影响)。
-
梯度爆炸:参数更新失控,训练不稳定。
-
-
解决方案:
-
使用LSTM或GRU(门控循环单元),通过门控机制选择性保留梯度。
-
梯度裁剪控制爆炸。
-
长期依赖学习困难
-
问题:即使使用LSTM/GRU,RNN对超长序列(如数百步以上)的依赖关系仍难以捕捉。
-
原因:门控机制本身会引入衰减,信息仍会随时间步逐渐丢失。
-
例子:在文本生成中,RNN可能忘记段落开头的主题。
-
解决方案:
-
改用Transformer(自注意力机制直接建模任意距离的依赖)。
-
结合外部记忆(如Memory Networks)。
-
串行计算效率低
-
问题:RNN必须按时间步顺序计算,无法并行化。
-
影响:训练速度慢,尤其对长序列(如视频、长文档)计算成本高。
-
对比:Transformer的Self-Attention可并行处理所有时间步。
-
解决方案:
-
使用CNN+RNN混合模型(如WaveNet用空洞卷积加速)。
-
直接替换为Transformer架构。
-
内存消耗大
-
问题:RNN需存储所有中间状态以计算梯度,显存占用随序列长度线性增长。
-
影响:难以处理超长序列(如小时级音频)。
-
解决方案:
-
使用Truncated BPTT(截断反向传播),但会损失部分长程信息。
-
优化实现(如CUDA加速)。
-
对输入顺序的强依赖
-
问题:RNN假设数据严格按时间顺序输入,但对某些任务(如双向语言建模),顺序可能不是最优的。
-
解决方案:
-
使用双向RNN(Bi-RNN),但计算量翻倍。
-
Transformer通过位置编码(Positional Encoding)灵活处理顺序。
-
难以处理变长序列的批量训练
-
问题:RNN批处理需填充(Padding)到相同长度,浪费计算资源。
-
解决方案:
-
动态RNN(如TensorFlow的
dynamic_rnn
)跳过填充部分计算。 -
使用Packaged Sequence(如PyTorch的
pack_padded_sequence
)。
-
注意力机制怎么实现?
用老师上课来举例子。老师上课,三个学生听课,每个学生各自记笔记。
传统的 RNN 实现:
-
每听到一个词,就写在笔记本上,但只能记住最近几个词(短期记忆)
-
记录时,只参考当前的词和上一刻的笔记(隐藏状态),无法回顾更早的内容
-
如果老师提到“牛顿第一定律是惯性定律”,学生可能会因为记忆有限,只记住“惯性定律”而忘记“牛顿第一定律”
-
击鼓传花,存在信息丢失:A -> B -> C -> D
RNN 的本质问题:
-
短时记忆问题:RNN 的隐藏状态只能保留有限的历史信息,长期依赖难以捕捉
-
顺序依赖:必须逐词处理,无法并行计算
注意力机制的实现:
-
对每个词(如“惯性”),同时计算它与所有其他词(如“牛顿”“定律”)的关系(自注意力)
-
直接标记出“惯性”和“牛顿第一定律”的强关联,笔记逻辑更完整
-
听到“爱因斯坦相对论”时,会自动关联到之前提到的“牛顿力学”,并对比记录差异
-
多种形式结合:笔记、录音、视频、补充材料
-
全局性:三个学生的笔记(A + B + C -> D)
注意力机制的核心优势:
-
并行处理:同时分析所有词的关系,无需按顺序
-
全局依赖:任意两个词的距离不影响关联计算(彻底解决长程依赖)
接下来稍微扩展一下。
$$\text{h}_{\text{i}}$$ | 编码器在第 i 个时间步的隐藏状态,存储输入序列第 i 步的信息(如词向量编码后的表示) |
$$\text{s}_{\text{t-1}}$$ | 解码器在第 t−1 个时间步的隐藏状态,存储解码器生成第 t−1 个输出时的上下文信息 |
$$\text{α}_{\text{t,i}}$$ | 解码器第 t 步对编码器第 i 步的注意力权重,衡量编码器第 i 步对解码器第 t 步输出的影响程度 |
$$\text{C}_{\text{t}}$$ | 解码器第 t 步的上下文向量,汇总编码器隐藏状态的加权信息,供解码器生成当前步输出 |
$$\text{e}_{\text{t,i}}$$ | 点积注意力,对解码器当前隐藏状态和所有编码器隐藏状态计算相似度 |