算法八股整理【Transformer】

Transformer

在这里插入图片描述

1. 注意力机制的目标

A: 帮助模型在处理序列数据的时候,能够关注到输入序列中最重要的部分,允许模型动态地分配不同的权重给输入序列中的不同位置,从而实现对信息的有效筛选和整合。

注意力机制希望打破长序列信息瓶颈,解决长序列信息丢失的问题。

朴素的Seq2Seq模型中,由于用Encoder RNN的最后一个神经元的隐状态作为 Decoder RNN 的初始隐状态,导致Encoder 的最后一个神经元的隐状态Context Vector 承载源句子的所有信息,成为整个模型的“信息”瓶颈

2. Transformer中的数据流转

A: 从端到端的角度来看,数据在Transformer中为四个阶段

(1)Embedding 嵌入

(2)Attention机制 注意力机制

(3)MLPs 多层感知机

(4)Unembedding 从模型表示到最终输出

Attention机制 注意力机制 的 目标

  • 嵌入向量(Embedding Vector)是单词或文本片段的数值表示,它们捕捉了这些单词或文本片段的语义信息
  • 嵌入向量作为输入传递给Transformer的Attention模块时,Attention模块会通过Q、K、V计算注意力权重,从而分析这些向量,使得Embedding向量间能够相互"交流"并根据彼此信息更新自身的值。
  • Attention模块的作用是确定在给定上下文中哪些嵌入向量与当前的任务最相关,并且更新或者调整这些嵌入向量的表示。
  • 这种“相关性”通常基于单词之间的语义关系,即它们如何相互关联以形成有意义的句子或段落。

Attention(注意力机制)的 工作流程:

  • 生成 Q、K、V 向量:
    • 对于输入序列中的每个单词,都会生成对应的Query(查询)、key(键)、Value(值)向量。这些向量通常是通过将单词的嵌入向量 Embadding Vetor 输入到一个线性变换层得到的。
  • 计算Q,K的点积(注意力分数):
    • Attention机制会计算Query向量序列中所有单词的Key向量之间的点积(或者其他的相似性度量),得到一个分数。
    • 这个分数反映Query向量与每个key向量之间的相似度,即每个单词与当前位置单词的关联程度。
  • Softmax 函数归一化(注意力权重):
    • 将分数经过Softmax函数进行归一化,得到每个单词的注意力权重。这些权重表示了在理解当前单词的时候,应该给予序列其他单词多大的关注。
  • 注意力权重加权求和(加权和向量):
    • 这些注意力权重与对应的Value向量进行加权求和,得到加权和向量。
    • 这个加权和向量会被用作当前单词的新表示,包含了丰富的上下文信息。

—— 因此,在处理每一个单词的时候,模型都能考虑到整个输入序列的信息,并且根据单词之间的语义信息来更新单词的表示。这使得Transformer模型能够能够更准确地理解单词在当前上下文中的含义,进而解决上下文依赖问题。

3. 注意力计算 QKV

总体流程:在注意力机制中,Q(Query)、K(Key)、V(Value)通过映射矩阵得到相应的向量,通过计算Q与K的点积相似度并经过softmax归一化得到权重,最后使用这些权重对V进行加权求和得到输出**。**

权重矩阵W: W_Q W_K W_V

  1. 权重矩阵W均是可训练的参数,维度为 (d_model, d_k)
    1. d_model 是 输入嵌入的维度 Embadding的维度
    2. d_k 是Q、K、V 向量的维度 通常为128
  2. 通过训练,模型会学习如何从输入数据中提取对任务有用的特征,并将其映射到Q,K,V向量中
  3. 初始时,这些权重矩阵的值通常是随机初始化的。经过训练后,它们会学习到如何从输入数据中提取出对任务有用的特征。
  4. 模型会通过反向传播算法梯度下降来更新这些权重矩阵W的值,以最小化某个损失函数(如交叉熵损失)。

Q 的计算(权重矩阵W_Q 计算Query)

  • 在Transformer中 Q = E * W_Q (E 是输入数据的嵌入矩阵)
    • E —— shape [batch_size, sequence_length, d_model]
    • W_Q —— shape [d_model,d_k]
    • Q —— shape [batch_size, sequence_length,d_k]
    • 对于Q中的每一个嵌入向量q_i(形状为(d_model)),Q中的一个向量q_i可以通过q_i = e_i * W_Q计算得到。
  • 权重矩阵W_Q的定义:
    • 在Transformer模型中,权重矩阵W是用于将输入数据(如词嵌入)映射到Q、K、V(Query、Key、Value)向量的线性变换矩阵。对于Query(Q),有一个专门的权重矩阵W_Q。
    • W_Q的维度通常是(d_model, d_k),其中d_model是输入嵌入的维度(也是模型的维度),而d_k是Q/K/V向量的维度。假设d_k被设定为128

K 的计算(权重矩阵W_K 计算 key)

  • 在Transformer中 K = E * W_K (E 是输入数据的嵌入矩阵)
    • E —— shape [batch_size, sequence_length, d_model]
    • W_K —— shape [d_model,d_k]
    • K —— shape [batch_size, sequence_length,d_k]
    • 对于K中的每一个嵌入向量k_i(形状为(d_model)),K中的一个向量k_i可以通过k_i = e_i * W_K计算得到。
  • 与Q的计算一致 只是权重矩阵不同

V 的计算(权重矩阵W_V 计算 value)

  • 在Transformer模型中,Value(V)是通过将输入数据的嵌入矩阵E与权重矩阵W_V相乘得到的。V = E * W_V

Q、K、V计算:Q用于查询,K用于匹配,V提供被加权的信息。通过计算Q和K的点积来衡量注意力分数,进而决定V的加权方式。

4. 三种注意力机制

Transformer注意力层:在Transformer架构中,有3种不同的注意力层:

  • Self Attention自注意力
  • Cross Attention 交叉注意力
  • Causal Attention因果注意力。

编码器输入序列 通过Multi-Head Self Attention(多头自注意力)计算注意力权重。

  • 自注意力层QKV均是编码器前一层的输出
  • 自注意力层中,所有的键、值和查询都来自同一个地方,即编码器前一层的输出。编码器中的每个位置都可以关注编码器前一层中的所有位置。

编码器-解码器 两个序列通过Multi-Head Cross Attention(多头交叉注意力)进行注意力转移。

  • 交叉注意力层
    • Q:前一层解码器的输出
    • K:编码器的输出
    • V:编码器的输出
  • 解码器中的交叉注意力层:查询来自前一层解码器,而记忆键和值则来自编码器的输出。这使得解码器中的每个位置都能关注输入序列中的所有位置。

解码器 的单个序列 通过Multi-Head Causal Self Attention(多头因果自注意力)进行注意力计算。

  • 解码器中的因果自注意力层:允许解码器中的每个位置关注解码器中包括该位置在内的所有位置。这时需要防止解码器中的信息向左流动,以保持自回归属性,通过将softmax输入中对应非法连接的所有值掩盖掉(设为-∞)来实现这一点

5. Transformer总体架构

Transformer也遵循编码器-解码器总体架构,使用堆叠的自注意力机制和逐位置的全连接层,分别用于编码器和解码器,如图中的左半部分和右半部分所示。

  • Encoder编码器:Transformer的编码器由6个相同的层组成,**每个层包括两个子层:一个多头自注意力层和一个逐位置的前馈神经网络。**在每个子层之后,都会使用残差连接和层归一化操作,这些操作统称为Add&Normalize。这样的结构帮助编码器捕获输入序列中所有位置的依赖关系

  • Decoder解码器:Transformer的解码器由6个相同的层组成,每层包含三个子层:**掩蔽自注意力层、Encoder-Decoder注意力层和逐位置的前馈神经网络。**每个子层后都有残差连接和层归一化操作,简称Add&Normalize。这样的结构确保解码器在生成序列时,能够考虑到之前的输出,并避免未来信息的影响。

6. Self-Attention

在这里插入图片描述

  • Self-Attention(自注意力机制):使输入序列中的每个元素能够关注并加权整个序列中的其他元素,生成新的输出表示,不依赖外部信息或历史状态。
  • Self-Attention(自注意力机制):通过生成查询、键和值向量,计算并归一化注意力分数,最终对值向量进行加权求和,从而得到输入序列中每个位置的加权表示。
  • Self-Attention允许输入序列中的每个元素都与序列中的其他所有元素进行交互。
  • 它通过计算每个元素对其他所有元素的注意力权重,然后将这些权重应用于对应元素的表示,从而得到一个加权和的输出表示。
  • Self-Attention不依赖于外部信息或先前的隐藏状态,完全基于输入序列本身。

工作流程!!!

  1. 生成Q,K,V:
    在这里插入图片描述

**输入:**接收一个由嵌入向量组成的输入序列,这些嵌入向量可以是词嵌入加上位置嵌入。

处理:使用三个独立的线性层(或称为密集层)为每个输入向量生成查询(Q)、键(K)和值(V)向量。

  • 查询向量用于表示当前焦点或希望获取的信息。
  • 键向量用于确定与查询向量匹配的信息。
  • 值向量包含与相应的键向量关联的实际信息。
  1. 注意力矩阵的计算
    在这里插入图片描述

处理:计算查询向量和所有键向量之间的点积,形成一个注意力分数矩阵。

  1. 归一化注意力分数

处理:应用softmax函数对注意力分数矩阵进行归一化。

  • 归一化后,每行的和为1,每个分数表示对应位置信息的权重
  • 在应用softmax之前,通常会除以一个缩放因子(如查询或键向量维度的平方根)来稳定梯度
    在这里插入图片描述
  1. 加权和输出

处理:使用归一化后的注意力权重对值向量进行加权求和。

  • 加权求和的结果是自注意力机制的输出,它包含了输入序列中所有位置的加权信息
  • 输出向量的每个元素都是输入向量的加权和,权重由注意力机制决定。

在这里插入图片描述

7.Multi-Head Attention 多头注意力机制

  • Multi-Head Attention(多头注意力机制):通过并行运行多个Self-Attention层并综合其结果,能够同时捕捉输入序列在不同子空间中的信息,从而增强模型的表达能力。
  • 通过将输入的查询、键和值矩阵分割成多个头,并在每个头中独立计算注意力,再将这些头的输出拼接并线性变换,从而实现在不同表示子空间中同时捕获和整合多种交互信息,提升模型的表达能力。
  • Multi-Head Attention实际上是多个并行的Self-Attention层,每个“头”都独立地学习不同的注意力权重。
  • 这些“头”的输出随后被合并(通常是拼接后再通过一个线性层),以产生最终的输出表示。
  • 通过这种方式,Multi-Head Attention能够同时关注来自输入序列的不同子空间的信息。

工作流程!!!
在这里插入图片描述

  • 初始化: 首先,初始化必要的参数,包括查询、键和值矩阵的权重,以及多头注意力中的头数。这些权重将用于后续的线性变换。
  • 线性变换: 对输入的查询、键和值矩阵进行线性变换。这些线性变换是通过与相应的权重矩阵相乘来实现的。变换后的矩阵将用于后续的多头注意力计算。
  • 分割与投影: 将线性变换后的查询、键和值矩阵分割成多个头。每个头都有自己的查询、键和值矩阵。然后,在每个头中独立地计算注意力分数。
  • 缩放与Softmax: 对每个头的注意力分数进行缩放,以避免梯度消失或爆炸的问题。然后,应用Softmax函数将注意力分数归一化,使得每个位置的权重之和为1。
  • 加权求和: 使用归一化后的注意力权重对值矩阵进行加权求和,得到每个头的输出矩阵。
  • 拼接与线性变换: 将所有头的输出矩阵拼接在一起,形成一个大的输出矩阵。然后,对这个输出矩阵进行线性变换,得到最终的输出。

8. Self-Attention和Multi-Head Attention的对比

!!!必背

  • Self-Attention关注序列内每个位置对其他所有位置的重要性
  • Multi-Head Attention则通过在多个子空间中并行计算注意力,使模型能够同时捕获和整合不同方面的上下文信息,从而增强了对复杂数据内在结构的建模能力。
### 常见的算法经典问题及固定解法模式 #### 1. 动态规划(Dynamic Programming) 动态规划适用于具有重叠子问题和最优子结构性质的问题。通过将原问题分解为更简单的子问题,并存储每个子问题的解以避免重复计算,从而提高效率。常见的动态规划问题包括: - **背包问题**:如0/1背包、完全背包等。 - **最长公共子序列(LCS)**:用于比较两个序列之间的相似性。 - **斐波那契数列**:使用记忆化技术优化递归调用[^1]。 #### 2. KMP 算法(Knuth-Morris-Pratt) KMP 算法是一种高效的字符串匹配算法,其核心在于预处理模式串生成部分匹配表(也称失败函数),从而在匹配过程中避免主串指针回溯。时间复杂度为 O(n + m),其中 n 是主串长度,m 是模式串长度。此算法广泛应用于大规模文本搜索和模式匹配领域[^2]。 #### 3. 贪心算法(Greedy Algorithm) 贪心算法每次选择当前状态下的局部最优解,期望最终得到全局最优解。常见问题包括: - **集合覆盖问题**:从多个集合中选择最少数量的集合来覆盖所有元素。 - **活动选择问题**:选择最多的互不重叠活动。 - **霍夫曼编码**:数据压缩中的最优前缀编码方法[^2]。 #### 4. 快慢指针技巧(Two Pointers Technique) 快慢指针是解决链表或数组问题的常用技巧,例如检测环形链表、查找中间节点等。空间复杂度通常为 O(1),时间复杂度为 O(n)。例如,判断一个数字是否为快乐数时可以使用快慢指针进行循环检测[^3]。 #### 5. 哈希表(Hash Table) 哈希表提供常数时间复杂度的插入和查找操作,适合解决涉及查找、去重、频率统计等问题。例如,在 LeetCode 中查找是否存在特定距离内的重复元素时,可以使用哈希表快速实现: ```cpp class Solution { public: bool containsNearbyDuplicate(vector<int>& nums, int k) { unordered_map<int, int> hash; for (int i = 0; i < nums.size(); i++) { if (hash.count(nums[i]) && abs(hash[nums[i]] - i) <= k) { return true; } else { hash[nums[i]] = i; } } return false; } }; ``` 该代码片段展示了如何使用哈希表记录最近出现的索引并检查是否存在满足条件的重复元素[^5]。 #### 6. 回溯算法(Backtracking) 回溯算法是一种试探性的搜索方法,通常用于组合、排列、子集等问题。例如 N 皇后问题、全排列生成、数独求解等。该方法基于深度优先搜索(DFS)实现,并在不符合条件时“剪枝”以减少不必要的计算。 #### 7. 分治算法(Divide and Conquer) 分治算法将问题划分为若干个子问题,分别求解后再合并结果。典型应用包括: - **归并排序**:将数组分成两半排序后合并。 - **快速排序**:选择基准元素将数组划分后递归排序。 - **最大子数组和问题(Kadane’s Algorithm)**:寻找连续子数组的最大和。 #### 8. 最短路径算法(Shortest Path Algorithms) 最短路径算法用于图结构中寻找两点之间的最短路径,常见算法包括: - **Dijkstra 算法**:适用于带权重的有向图,单源最短路径。 - **Floyd-Warshall 算法**:多源最短路径,适用于稠密图。 - **Bellman-Ford 算法**:支持负权边但无负权环的图。 #### 9. 图遍历算法(Graph Traversal) 图遍历主要包括广度优先搜索(BFS)和深度优先搜索(DFS),用于访问图中的所有节点。BFS 常用于寻找最短路径,而 DFS 更适合探索所有可能路径。 #### 10. 并查集(Union-Find) 并查集是一种高效的数据结构,用于动态维护一组不相交集合,并支持合并与查询操作。它常用于解决连通性问题,如 Kruskal 算法中的最小生成树构建。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值