├── README.md ├── Transformer.docx └── imgs ├── 001.png ├── 002.png ├── 003.png ├── 004.png ├── 005.png ├── 006.png ├── 007.png ├── 008.png └── 009.png /README.md: -------------------------------------------------------------------------------- 1 | # Transformer-interview 2 | Transformer面试常见八股 3 | # Transformer 4 | ![img1](./imgs/001.png) 5 | 6 | ## Positional Encoding 7 | 由于自注意力机制是对所有输入元素进行加权求和,它无法区分序列中元素的顺序。因此需要位置编码来为输入序列中的每个位置添加位置信息 8 | ### 位置编码的形式 9 | 在论文中,位置编码使用正弦和余弦函数来生成,是一个与词嵌入维度相同的向量: 10 | ![img2](./imgs/002.png) 11 | - pos是序列中的位置(从0开始) 12 | - i是维度索引(从0开始) 13 | - dmodel​是词嵌入的维度 14 | ### 其他位置编码方式 15 | 可学习的位置编码、相对位置编码、旋转位置编码(RoPE) 16 | 17 | ## Attention 18 | ![img3](./imgs/003.png) 19 | 1. 输入:x维度为[batch_size, seq_length, embed_dim] 20 | 2. 线性投影:将输入x,分别乘以w_q, w_k, w_v,生成Q、K、V 21 | 其中,w的维度都是 [batch_size, embed_dim, embed_dim] 22 | Q, K, V的维度都是 [batch_size, seq_length, embed_dim] 23 | 3. 计算注意力: 24 | ![img4](./imgs/004.png) 25 | 26 | ## Multi-Head Attention 27 | ![img5](./imgs/005.png) 28 | 29 | 和单头的区别: 30 | 使用多组不同的线性投影(权重矩阵),将输入x投影到多个不同的子空间中。 31 | 每个头都有自己的QKV 32 | 1. 输入:x维度为[batch_size, seq_length, embed_dim] 33 | 还需要输入头的个数 h 34 | 2. 线性投影:将输入x,对于第 H_i 个头,乘以w_q^i, w_k^i, w_v^i,生成Q_i、K_i、V_i 35 | 其中,w的维度都是 [batch_size, embed_dim, d_k] 36 | d_k = embed_dim // h (head头数) d_k是子空间的维度 37 | Q_i, K_i, V_i的维度都是 [batch_size, seq_length, d_k] 38 | 3. 分别计算每个头的注意力 39 | 4. concat还原维度,做线性投影 40 | ```python 41 | class MultiHeadAttention(nn.Module): 42 | def __init__(self, hidden_dim, nums_head) -> None: 43 | super().__init__() 44 | self.nums_head = nums_head 45 | 46 | self.head_dim = hidden_dim // nums_head 47 | self.hidden_dim = hidden_dim 48 | 49 | self.q_proj = nn.Linear(hidden_dim, hidden_dim) 50 | self.k_proj = nn.Linear(hidden_dim, hidden_dim) 51 | self.v_proj = nn.Linear(hidden_dim, hidden_dim) 52 | self.o_proj = nn.Linear(hidden_dim, hidden_dim) 53 | 54 | def forward(self, x): 55 | batch_size, seq_len, _ = x.size() 56 | 57 | Q = self.q_proj(x) 58 | K = self.k_proj(x) 59 | V = self.v_proj(x) 60 | 61 | q_state=Q.view(batch_size,seq_len,self.nums_head, self.head_dim).permute(0, 2, 1, 3) 62 | k_state=K.view(batch_size,seq_len,self.nums_head, self.head_dim).transpose(1, 2) 63 | v_state=V.view(batch_size,seq_len,self.nums_head, self.head_dim).transpose(1, 2) 64 | 65 | # MatMul and Scale 66 | attention_weight = ( 67 | q_state@k_state.transpose(-1, -2) / math.sqrt(self.hidden_dim) 68 | ) 69 | 70 | # Mask (opt.) 71 | if attention_mask is not None: 72 | attention_weight=attention_weight.masked_fill(attention_mask == 0, float("-1e20")) 73 | 74 | # Softmax 75 | attention_weight = torch.softmax(attention_weight, dim=-1) 76 | 77 | output_mid = attention_weight @ v_state 78 | output_mid = output_mid.transpose(1, 2).contiguous() 79 | 80 | output = output_mid.view(batch_size, seq_len, -1) 81 | output = self.o_proj(output) 82 | return output 83 | ``` 84 | 85 | ## 为什么Q、K、V 相同 86 | 自注意力机制中,Q、K、V都是从同一个输入序列x中生成的,是因为: 87 | - 自注意力 的目标是捕捉输入序列中元素之间的依赖关系,因此需要让每个元素同时作为Query、Key和Value 88 | - 通过这种方式,模型可以计算每个元素与其他元素之间的关系,并生成上下文相关的表示 89 | 90 | 91 | ## Cross Attention 92 | ![img6](./imgs/006.png) 93 | 在Decoder的 交叉注意力机制(Cross-Attention) 中,Q、K、V 的来源不同: 94 | - Query (Q):来自 Decoder 的输入(目标序列) 95 | - Key(K)和Value(V):来自 Encoder 的输出(源序列的上下文表示) 96 | 这种设计使得 Decoder 能够根据 Encoder 的输出生成目标序列 97 | 98 | ## Decoder的MHA为什么要做Mask 99 | ![img7](./imgs/007.png) 100 | 101 | 使用Mask主要是为了防止信息泄露 102 | - 防止信息泄露 103 | - 自回归生成:在生成任务中,Decoder需要逐个生成输出序列的每个元素。Mask确保在生成第t个元素时,只能看到前t−1个元素,防止模型利用未来信息 104 | - 训练一致性:训练时,Decoder需要模拟生成过程,确保每个时间步只能依赖已生成的部分,保持训练与推理的一致性 105 | - 处理变长序列 106 | - 填充部分屏蔽:对于变长序列,填充部分需要被Mask掉,避免模型关注无效信息 107 | 108 | ## Attention、FFN计算的复杂度 109 | n方乘以d、n乘以d方 110 | 111 | ## 为什么使用多头 112 | - 捕捉更多样的特征 113 | - 单头 只能从一个子空间计算注意力权重,可能无法充分捕捉输入序列中复杂的依赖关系 114 | - 多头 通过将输入映射到多个子空间,每个头可以关注不同的特征或模式 115 | - 增强模型的表达能力 116 | - 提高泛化能力 117 | - 并行计算 多头注意力机制可以并行计算多个注意力头,充分利用GPU的并行计算能力 118 | 119 | ## 为什么用点积注意力 120 | ![img8](./imgs/008.png) 121 | 点积能够有效衡量两个向量的相似性。在注意力机制中,通过计算查询向量(Query)和键向量(Key)的点积,可以评估它们之间的相关性,从而决定注意力权重。而且 122 | - 点积在数学上更简单且易于优化,允许同时计算所有位置的注意力权重,便于并行计算 123 | - 加性注意力需要额外的全连接层和非线性变换,计算复杂度高,且不好并行 124 | - 点积可通过除以根号下dk进行缩放缓解梯度问题,加性注意力的不如其稳定 125 | 如果面的是搜广推或者多模态相关岗位,可能被问到点积和余弦相似度的比较 126 | 127 | 128 | ## 为什么要除以根号下dk 129 | 缩放点积注意力分数,从而避免注意力分数过大或过小,导致梯度不稳定或Softmax函数进入饱和区 130 | ### 点积的大小问题 131 | - 当dk​较大时,点积的值可能会变得非常大。这是因为点积是dk​个维度求和,随着dk​的增加,点积的值也会增加 132 | - 如果点积的值过大,Softmax函数的输入会变得非常大,导致梯度非常小(梯度消失问题),从而影响模型的训练 133 | ### 缩放点积的原因 134 | 为了缓解上述问题,Transformer引入了缩放因子√dk​​,将点积的结果缩小 135 | 这样做可以: 136 | 1. 控制点积的方差: 137 | - 假设Q和K的每个元素是均值为0、方差为1的随机变量,那么点积QK^T的方差为dk​ 138 | - 通过除以dk​​,可以将点积的方差重新缩放为1,从而避免点积的值过大或过小 139 | 2. 稳定梯度: 140 | - Softmax函数对输入的尺度非常敏感。如果输入过大,Softmax的输出会接近一个one-hot向量,导致梯度非常小 141 | - 缩放点积可以确保Softmax的输入在一个合理的范围内,从而避免梯度消失问题 142 | 3. 提高模型性能: 143 | - 论文实验表明,缩放点积可以显著提高模型的训练稳定性和性能 144 | 145 | ## Encoder和Decoder有什么不同 146 | ### 功能不同 147 | - Encoder 148 | - 负责将输入序列编码为一系列上下文相关的表示 149 | - 捕捉输入序列的全局信息,并将其压缩为固定长度的向量(或序列) 150 | - 适用于文本分类、句子表示、命名实体识别等任务 151 | - Decoder 152 | - 负责根据Encoder的输出和之前的输出生成目标序列(如翻译结果) 153 | - 它是一个自回归模型,逐步生成输出序列的每个元素 154 | - 适用于机器翻译、文本生成等任务 155 | ### 结构不同 156 | - Encoder 157 | - 由多层相同的Encoder层堆叠而成 158 | - 每个Encoder层包含两个子层: 159 | 1. 多头自注意力机制(Multi-Head Self-Attention):计算输入序列中每个元素与其他元素的关系 160 | 2. 前馈神经网络(FFN):对每个位置的表示进行非线性变换 161 | - 每个子层后面都有残差连接(Residual Connection)和层归一化(Layer Normalization) 162 | - Decoder 163 | - 由多层相同的Decoder层堆叠而成 164 | - 每个Decoder层包含三个子层: 165 | 1. 掩码多头自注意力机制(Masked Multi-Head Self-Attention):只允许当前位置关注之前的位置(防止信息泄露) 166 | 2. 多头交叉注意力机制(Multi-Head Cross-Attention):将Encoder的输出与Decoder的表示结合 167 | 3. 前馈神经网络(Feed-Forward Network, FFN):对每个位置的表示进行非线性变换。 168 | - 每个子层后面也有残差连接和层归一化 169 | ### 注意力机制不同 170 | - Encoder 171 | - 使用自注意力机制(Self-Attention),计算输入序列中所有元素之间的关系 172 | - Decoder 173 | - 使用掩码自注意力机制(Masked Self-Attention),确保当前位置只能访问之前的位置(防止未来信息泄露) 174 | - 使用交叉注意力机制(Cross-Attention),将Encoder的输出与Decoder的表示结合,以捕捉输入序列和目标序列之间的关系 175 | ### 输入和输出不同 176 | - Encoder 177 | - 输入:源序列(如待翻译的句子) 178 | - 输出:源序列的上下文表示(Contextual Representations),通常是一个向量序列 179 | - Decoder 180 | - 输入: 181 | 1. 目标序列的已生成部分(自回归生成时) 182 | 2. Encoder的输出(通过交叉注意力机制) 183 | - 输出:目标序列的下一个元素(如翻译结果的下一个词) 184 | ### 训练和推理时的行为不同 185 | - Encoder 186 | - 在训练和推理时行为一致,直接处理整个输入序列 187 | - Decoder 188 | - 训练时:使用教师强制(Teacher Forcing),将目标序列的完整输入提供给Decoder 189 | - 推理时:逐步生成目标序列,每次生成一个元素并将其作为下一步的输入 190 | ```python 191 | class EncoderLayer: 192 | def __init__(self): 193 | self.self_attention = MultiHeadAttention() 194 | self.ffn = FeedForwardNetwork() 195 | self.norm1 = LayerNormalization() 196 | self.norm2 = LayerNormalization() 197 | 198 | def forward(self, x): 199 | # Self-Attention 200 | attn_output = self.self_attention(x, x, x) 201 | x = self.norm1(x + attn_output) # Residual + Norm 202 | # FFN 203 | ffn_output = self.ffn(x) 204 | x = self.norm2(x + ffn_output) # Residual + Norm 205 | return x 206 | 207 | # Decoder Layer 208 | class DecoderLayer: 209 | def __init__(self): 210 | self.masked_self_attention = MultiHeadAttention() 211 | self.cross_attention = MultiHeadAttention() 212 | self.ffn = FeedForwardNetwork() 213 | self.norm1 = LayerNormalization() 214 | self.norm2 = LayerNormalization() 215 | self.norm3 = LayerNormalization() 216 | 217 | def forward(self, x, encoder_output): 218 | # Masked Self-Attention 219 | attn_output = self.masked_self_attention(x, x, x) 220 | x = self.norm1(x + attn_output) # Residual + Norm 221 | # Cross-Attention 222 | cross_output = self.cross_attention(x, encoder_output, encoder_output) 223 | x = self.norm2(x + cross_output) # Residual + Norm 224 | # FFN 225 | ffn_output = self.ffn(x) 226 | x = self.norm3(x + ffn_output) # Residual + Norm 227 | return x 228 | ``` 229 | 230 | ## FFN 231 | ![img9](./imgs/009.png) 232 | 233 | ```python 234 | self.linear1 = Linear(d_model, dim_feedforward) 235 | self.activation = Relu() 236 | self.linear2 = Linear(dim_feedforward, d_model) 237 | self.dropout = Dropout(dropout) 238 | ``` 239 | 其中,activation指激活函数,Transformer最开始用是ReLU, 240 | 241 | 之后的模型对这部分有改进,依次是: 242 | 243 | ReLU → GELU → Swish(SiLU) → SwiGLU 244 | 245 | 现在主流的LLM比如Llama、Qwen大多采用SwiGLU 246 | 247 | ## Transformer训练的时候主要是什么数据在使用显存 248 | 很奇怪的问题,以下答案仅做参考:模型权重、梯度、softmax的值... 249 | 250 | ## Transformer使用的归一化方法是什么?为什么不用BN 251 | Layer Normalization 252 | - BN对Batch Size敏感 253 | - 在计算均值和方差时,BN会跨序列长度维度进行归一化。对于变长序列数据。BN的计算复杂且不稳定。LN对每个样本做归一化,不受序列长度影响,更适合处理变长序列数据 254 | - BN在推理时带来了额外的复杂性。在训练时,BN会维护一个移动平均值(running mean 和 running variance),用于推理的归一化 255 | - 论文中,Transformer的作者通过实验验证了LN比BN更合适 256 | 257 | ## 残差连接的意义 258 | 防止梯度消失,提升模型表达能力,稳定深层网络训练 259 | 260 | ## Transformer和RNN LSTM的区别 261 | RNN/LSTM适合于简单的文本分类、短文本生成等任务 262 | Transformer适用于机器翻译、长文本生成等任务 263 | 核心区别在于序列建模的方式和计算效率 264 | ### 序列建模方式 265 | #### RNN/LSTM 266 | - RNN(循环神经网络) 267 | - 通过循环结构逐步处理序列,每个时间步的隐藏状态依赖于前一个时间步的隐藏状态 268 | - 优点是结构简单,适合处理短序列 269 | - 缺点是难以捕捉长距离依赖,容易发生梯度消失或梯度爆炸 270 | - LSTM(长短期记忆网络) 271 | - 引入门控机制(输入门、遗忘门、输出门)缓解梯度消失问题,能更好地捕捉长距离依赖 272 | - 但仍然需要逐步处理序列,计算效率较低 273 | #### Transformer 274 | - 使用Self-Attention直接建模序列中所有token之间的关系,无需逐步处理 275 | - 优点:能并行处理整个序列,计算效率高。更好地捕捉长距离依赖,适合处理长序列 276 | - 缺点:需更多的计算资源,需额外引入位置编码 277 | ### 计算效率 278 | #### RNN/LSTM 279 | - 顺序计算:必须按时间步逐步处理序列,无法并行化 280 | - 时间复杂度:对于长度为n的序列,时间复杂度为O(n) 281 | #### Transformer 282 | - 并行计算:通过自注意力机制同时处理整个序列,可以充分利用GPU等硬件加速。 283 | - 时间复杂度:自注意力机制的时间复杂度为O(n方)(n是序列长度),但对于短到中等长度的序列,实际计算效率仍然很高 284 | 285 | ## Transformer的并行体现在哪?哪些部分不能并行 286 | Self-Attention、FFN、Multi-Head Attention、嵌入层和位置编码、Layer Normalization和残差连接这些都可以并行化 287 | 但Decoder的自回归生成和训练的掩码机制这些不能并行 288 | -------------------------------------------------------------------------------- /Transformer.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/Transformer.docx -------------------------------------------------------------------------------- /imgs/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/001.png -------------------------------------------------------------------------------- /imgs/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/002.png -------------------------------------------------------------------------------- /imgs/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/003.png -------------------------------------------------------------------------------- /imgs/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/004.png -------------------------------------------------------------------------------- /imgs/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/005.png -------------------------------------------------------------------------------- /imgs/006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/006.png -------------------------------------------------------------------------------- /imgs/007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/007.png -------------------------------------------------------------------------------- /imgs/008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/008.png -------------------------------------------------------------------------------- /imgs/009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3nboyu/Transformer-interview/989af53d07eb54fb82243236a5c7eb70d6cc843d/imgs/009.png --------------------------------------------------------------------------------