wordpress网站加密,广东广东深圳网站建设,个人业务网站制作,西安网络推广培训今儿和大家聊一个非常重要的话题#xff1a;Transformer整体架构#xff0c;记得收藏#xff01;~
Transformer编码器-解码器堆叠结构与信息流动路径#xff0c;希望通过这部分内容#xff0c;让大家理解Transformer的整体架构。
老规矩#xff1a;如果大家觉得近期文章还…今儿和大家聊一个非常重要的话题Transformer整体架构记得收藏~Transformer编码器-解码器堆叠结构与信息流动路径希望通过这部分内容让大家理解Transformer的整体架构。老规矩如果大家觉得近期文章还不错大家点个赞、转个发**文末赠送******[大模型全套资料]哦~****文末可取本文PDF版本~事实上可以把 Transformer 想象成一个“聪明的翻译官”两个主要部分组成编码器和解码器。编码器就像先听懂一句话的各个部分把它们的意思“拆解”并转化成一种内部表示。解码器再根据这种内部表示生成新的输出比如翻译成另一种语言的句子。整个过程的关键在于“注意力机制”也就是模型在处理每个单词时会去关注输入句子中所有其它单词的重要性。通过层层叠加堆叠多个编码器层和解码器层模型不断提炼和整合信息使得最终输出更加准确和流畅。Transformer 架构详细解析1. 架构整体与堆叠结构Transformer 模型主要分为两大部分编码器Encoder一般由 层相同结构的编码器单元组成。每一层包括多头自注意力Multi-head Self-Attention让模型在当前输入中寻找各个位置间的联系。前馈神经网络Feed-Forward Network, FFN对每个位置的表示进行进一步非线性变换。每个子层后都有残差连接Residual Connection和层归一化Layer Normalization以保持信息稳定传递。解码器Decoder同样由 层堆叠而成但每层多了一个额外的注意力子层用于结合编码器的输出自注意力层和编码器类似但在训练时采用遮蔽masking机制防止看到未来的输出信息。编码器–解码器注意力层使解码器能够“查找”编码器的输出信息获取输入中对应的关键信息。前馈神经网络层对处理后的信息再做一次非线性变换同样加上残差连接和层归一化。2. 信息流动路径输入处理每个输入单词先转换为向量词嵌入再加入位置编码以保留单词在序列中的位置信息。编码器中的信息流动初始嵌入进入第一层编码器通过多头自注意力机制各个单词在表达上会互相“交流”捕捉全局信息。经由前馈神经网络后每层都会输出一个新的表示这个表示包含了输入中各个单词之间的依赖关系。经过 层堆叠后编码器的输出就成为一个“记忆”包含了整个输入句子的综合信息。编码器–解码器的信息交互在解码器中每个时刻生成下一个单词时除了利用自己之前已生成的单词通过自注意力捕捉上下文信息还会利用来自编码器的“记忆”信息通过编码器–解码器注意力层获取输入对应的关键信息。解码器生成输出最后经过线性变换和 Softmax 层解码器输出概率分布选择最合适的词作为输出完成整个生成过程。一点原理位置编码由于 Transformer 没有 RNN 那种天然的序列顺序信息需要通过位置编码来提供每个词的位置其中表示词在序列中的位置表示编码维度的下标是词向量的维度。这种设计使得不同位置的编码在不同频率上呈现周期性变化从而模型可以通过加减操作获得词与词之间的相对位置信息。Scaled Dot-Product Attention注意力机制的核心是计算查询Query、键Key和值Value之间的相似度。公式如下其中是查询矩阵 是键矩阵 是值矩阵是键向量的维度用于缩放防止点积过大导致梯度消失或饱和先计算 与 的点积再除以 后做 softmax 得到注意力分布最后将该分布用于加权求和值 。Multi-head Attention为了让模型能够从不同子空间中捕捉信息Transformer 使用了多头注意力机制。公式为其中每个头的计算为是各自头的投影矩阵是最后拼接后进行线性变换的矩阵。这种设计允许模型同时从多个角度子空间对信息进行捕捉和融合。前馈神经网络Feed-Forward Network, FFN每个编码器和解码器层中都有一个位置-wise 前馈神经网络对每个位置的表示单独进行非线性变换其中和 是权重矩阵 和 是偏置项这里 表示 ReLU 激活函数。残差连接和层归一化为了解决深层网络中梯度消失的问题并加快收敛速度每个子层后面都使用残差连接并接着做层归一化这样可以使信息在网络中更平稳地流动同时让每一层学习到与输入的差异。解码器中的额外注意力层解码器除自注意力和前馈网络外还增加了一个编码器–解码器注意力层其计算方法与标准注意力类似查询来自解码器当前层键和值则是编码器的输出即输入信息的“记忆”。这种设计让解码器在生成每个输出时既能考虑之前生成的内容又能参考输入的整体信息从而生成更准确的结果。完整案例这里给到大家一个关于 Transformer 编码器–解码器堆叠结构及其信息流动路径的完整案例说明。在 Transformer 模型中信息流动主要体现在以下几个方面嵌入与位置编码将离散的词或标记转换为连续向量并加入位置信息以弥补模型不具备顺序感知能力的不足。自注意力机制允许模型在序列内部任意位置之间建立直接联系从而捕捉长距离依赖关系。编码器–解码器交互解码器通过注意力机制从编码器提取相关信息帮助生成更符合上下文逻辑的输出序列。堆叠结构多层编码器和解码器的堆叠使得模型能够捕捉更丰富、更抽象的语义特征同时每层都能将信息进一步细化和增强。接下来我们将通过一个具体的案例对上述原理进行验证和展示。数据集数据集任务为“序列翻转”给定一个随机生成的整数序列模拟“源语言”目标序列为该序列的逆序排列模拟“目标语言”。这一任务虽然简单但能充分展示编码器–解码器的映射能力和注意力机制如何对齐输入与输出之间的关系。具体数据集构造思路如下词汇表假定词汇总数为vocab_size。其中定义特殊标记BOS开始标记用于解码器输入起始编号设为 0EOS结束标记用于标识序列结束编号设为 1其他标记从 2 到vocab_size-1。输入序列随机生成长度固定例如 10的整数序列取值范围 2 到 vocab_size-1。目标序列在输入序列前后分别添加BOS与EOS并将中间部分取逆序。这样的数据集不仅能检验模型学习到简单映射的能力同时也能让我们利用注意力图观察模型如何“关注”输入中的各个位置。模型构建与关键组件编码器与解码器模块我们采用堆叠多个自定义的编码器层来构建编码器每个编码器层包括多头自注意力模块对输入进行自注意力计算同时返回注意力权重便于后续的可视化前馈网络包含两层全连接网络并使用 ReLU 作为激活函数残差连接与层归一化保证梯度流动稳定加速训练收敛。解码器部分则利用 PyTorch 内置的nn.TransformerDecoderLayer并配合嵌入、位置编码和线性映射层将解码器输出映射到词汇表上。多头注意力机制及信息流动多头注意力机制是 Transformer 的核心。每个注意力头通过对输入序列进行线性变换计算 Query、Key 和 Value然后利用缩放点积计算注意力分布。多个注意力头并行工作后再拼接和线性变换输出既保证了信息的多样性也能捕捉到不同语义的关系。在本案例中我们在编码器的每一层都保存了自注意力的权重方便后续观察信息在各层之间如何传递和分布。位置编码由于 Transformer 模型完全基于注意力机制无法像 RNN 那样顺序遍历输入序列因此需要通过位置编码来向模型提供序列中各个位置的信息。位置编码一般使用正弦和余弦函数生成不同频率的周期信号将这些信号与词嵌入相加从而使模型能够区分不同位置。我们将在后续图形中展示位置编码在不同维度上的变化曲线直观感受其规律。import mathimport randomimport numpy as npimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimimport matplotlib.pyplot as pltimport matplotlib.ticker as ticker# 设置随机种子确保结果可复现torch.manual_seed(42)np.random.seed(42)random.seed(42)# 1. 超参数设置与数据集构造vocab_size 50 # 词汇表大小包括BOS和EOSd_model 32 # 词向量及隐藏层维度nhead 4 # 注意力头数num_encoder_layers 3 # 编码器堆叠层数num_decoder_layers 3 # 解码器堆叠层数dim_feedforward 64 # 前馈网络隐藏层维度dropout 0.1 # dropout 概率seq_length 10 # 输入序列长度batch_size 32 # 批次大小num_batches 200 # 总批次数控制训练样本数量num_epochs 20 # 训练轮数learning_rate 0.001 # 学习率# 特殊标记BOS_token 0 # 开始标记EOS_token 1 # 结束标记def generate_sample(seq_length): 生成一个样本输入为随机整数序列目标为该序列的逆序并加上BOS和EOS标记。 # 随机生成序列取值范围 2 到 vocab_size-1 seq [random.randint(2, vocab_size-1) for _ in range(seq_length)] # 目标序列在翻转后的序列前后添加特殊标记 tgt [BOS_token] list(reversed(seq)) [EOS_token] return seq, tgtdef generate_batch(batch_size, seq_length): src_batch, tgt_batch [], [] for _ in range(batch_size): src, tgt generate_sample(seq_length) src_batch.append(src) tgt_batch.append(tgt) # 转换为 tensor并转置以适应 Transformer (seq_len, batch_size) src_tensor torch.tensor(src_batch, dtypetorch.long).transpose(0, 1) tgt_tensor torch.tensor(tgt_batch, dtypetorch.long).transpose(0, 1) return src_tensor, tgt_tensor# 2. 位置编码模块class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len5000): 实现正弦-余弦位置编码给定最大长度 max_len 和词嵌入维度 d_model super(PositionalEncoding, self).__init__() pe torch.zeros(max_len, d_model) # (max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(1) # (max_len, 1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) # 按照公式PE(pos, 2i) sin(pos/10000^(2i/d_model)) pe[:, 0::2] torch.sin(position * div_term) # PE(pos, 2i1) cos(pos/10000^(2i/d_model)) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(1) # (max_len, 1, d_model) self.register_buffer(pe, pe) def forward(self, x): 参数 x 的形状应为 (seq_len, batch_size, d_model) x x self.pe[:x.size(0)] return x# 3. 自定义编码器层返回注意力权重class CustomTransformerEncoderLayer(nn.Module): def __init__(self, d_model, nhead, dim_feedforward64, dropout0.1): super(CustomTransformerEncoderLayer, self).__init__() self.self_attn nn.MultiheadAttention(d_model, nhead, dropoutdropout) self.linear1 nn.Linear(d_model, dim_feedforward) self.dropout nn.Dropout(dropout) self.linear2 nn.Linear(dim_feedforward, d_model) self.norm1 nn.LayerNorm(d_model) self.norm2 nn.LayerNorm(d_model) self.dropout1 nn.Dropout(dropout) self.dropout2 nn.Dropout(dropout) def forward(self, src, src_maskNone, src_key_padding_maskNone): # 自注意力计算同时返回注意力权重 attn_output, attn_weights self.self_attn(src, src, src, attn_masksrc_mask, key_padding_masksrc_key_padding_mask, need_weightsTrue) src2 self.dropout1(attn_output) src self.norm1(src src2) # 前馈网络部分 ff_output self.linear2(self.dropout(F.relu(self.linear1(src)))) src2 self.dropout2(ff_output) src self.norm2(src src2) return src, attn_weights # 返回当前层输出及注意力权重# 4. Transformer 模型构建编码器-解码器结构class CustomTransformer(nn.Module): def __init__(self, src_vocab_size, tgt_vocab_size, d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout0.1): super(CustomTransformer, self).__init__() self.d_model d_model # 词嵌入层 self.src_tok_emb nn.Embedding(src_vocab_size, d_model) self.tgt_tok_emb nn.Embedding(tgt_vocab_size, d_model) # 位置编码 self.positional_encoding PositionalEncoding(d_model) # 编码器堆叠层 self.encoder_layers nn.ModuleList( [CustomTransformerEncoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_encoder_layers)] ) # 解码器使用 PyTorch 内置的层 decoder_layer nn.TransformerDecoderLayer(d_model, nhead, dim_feedforward, dropout) self.decoder nn.TransformerDecoder(decoder_layer, num_decoder_layers) # 输出层将解码器输出映射至词汇表 self.fc_out nn.Linear(d_model, tgt_vocab_size) def encode(self, src, src_maskNone): # src: (seq_len, batch_size) src_emb self.src_tok_emb(src) * math.sqrt(self.d_model) # 缩放嵌入 src_emb self.positional_encoding(src_emb) # 加入位置编码 attn_weights_all [] # 保存所有编码器层的注意力权重 for layer in self.encoder_layers: src_emb, attn_weights layer(src_emb, src_mask) attn_weights_all.append(attn_weights.detach().cpu().numpy()) return src_emb, attn_weights_all def decode(self, tgt, memory, tgt_maskNone): # tgt: (tgt_seq_len, batch_size) tgt_emb self.tgt_tok_emb(tgt) * math.sqrt(self.d_model) tgt_emb self.positional_encoding(tgt_emb) output self.decoder(tgt_emb, memory, tgt_masktgt_mask) return output def forward(self, src, tgt, src_maskNone, tgt_maskNone): memory, attn_weights_all self.encode(src, src_mask) decoder_output self.decode(tgt, memory, tgt_mask) output self.fc_out(decoder_output) return output, attn_weights_all# 5. 构造模型、损失函数与优化器model CustomTransformer(src_vocab_sizevocab_size, tgt_vocab_sizevocab_size, d_modeld_model, nheadnhead, num_encoder_layersnum_encoder_layers, num_decoder_layersnum_decoder_layers, dim_feedforwarddim_feedforward, dropoutdropout)criterion nn.CrossEntropyLoss(ignore_index0) # 忽略填充标记optimizer optim.Adam(model.parameters(), lrlearning_rate)# 6. 模型训练loss_history []for epoch in range(num_epochs): model.train() epoch_loss 0.0 for _ in range(num_batches): src, tgt generate_batch(batch_size, seq_length) # 对于解码器输入为目标序列去掉最后一个标记输出为目标序列去掉第一个标记实现 teacher forcing tgt_input tgt[:-1, :] tgt_out tgt[1:, :] optimizer.zero_grad() output, _ model(src, tgt_input) # 输出形状: (tgt_seq_len, batch_size, vocab_size) output_dim output.shape[-1] output output.view(-1, output_dim) tgt_out tgt_out.contiguous().view(-1) loss criterion(output, tgt_out) loss.backward() optimizer.step() epoch_loss loss.item() avg_loss epoch_loss / num_batches loss_history.append(avg_loss) print(fEpoch: {epoch1}/{num_epochs}, Loss: {avg_loss:.4f})# 7. 模型评估选取一个样本并获取编码器注意力权重model.eval()src_sample, tgt_sample generate_batch(1, seq_length) # 单个样本# 构造解码器输入只使用 BOS 作为初始输入tgt_input_sample tgt_sample[:-1, :] # 不同于训练这里仅作展示with torch.no_grad(): output_sample, attn_weights_all model(src_sample, tgt_input_sample)# 注意力权重 attn_weights_all 是一个列表每一项对应一层编码器自注意力的权重形状为 (batch_size, seq_len, seq_len)# 8. 可视化函数def plot_training_loss(loss_history): 图 1训练过程中损失值随轮次的变化曲线 说明该图展示了模型在训练过程中损失值Loss的下降趋势反映了模型逐步拟合数据的效果。图中曲线配色鲜艳 直观地显示了训练稳定性和收敛速度。 plt.figure(figsize(8,5)) plt.plot(range(1, len(loss_history)1), loss_history, markero, linestyle-, colormagenta, linewidth2) plt.xlabel(Epoch, fontsize14) plt.ylabel(Loss, fontsize14) plt.title(Training Loss Curve, fontsize16) plt.grid(True, linestyle--, alpha0.6) plt.tight_layout() plt.show()def plot_attention_heatmap(attn_weights, layer -1): 图 2展示编码器某一层自注意力权重的热力图 说明通过热力图可以观察到模型在处理输入序列时不同位置之间的关注程度。横纵坐标分别表示输入序列的位置 热度颜色越深表示注意力越集中。该图有助于理解模型如何捕捉长距离依赖和序列内部关系。 # 选择最后一层的注意力权重形状[batch, seq_len, seq_len] attn attn_weights[layer][0] # 选取 batch 中第一个样本 plt.figure(figsize(6,5)) plt.imshow(attn, cmapplasma, interpolationnearest) plt.colorbar() plt.xlabel(Input Sequence Position, fontsize12) plt.ylabel(Input Sequence Position, fontsize12) plt.title(fAttention Heatmap (Layer {layer1}), fontsize14) plt.xticks(ticksrange(seq_length), labelsrange(1, seq_length1)) plt.yticks(ticksrange(seq_length), labelsrange(1, seq_length1)) plt.tight_layout() plt.show()def plot_positional_encoding(d_model, max_len100): 图 3展示位置编码中不同维度正弦余弦波形的变化曲线 说明该图直观显示了 Transformer 模型中位置编码的计算方式不同颜色曲线代表不同维度的编码值随位置变化的趋势 说明模型如何将位置信息引入到输入嵌入中从而帮助模型捕捉序列顺序信息。 pe torch.zeros(max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.numpy() plt.figure(figsize(10,6)) for i in range(min(8, d_model)): # 仅展示前8个维度 plt.plot(np.arange(max_len), pe[:, i], labelfDim {i}, linewidth2) plt.xlabel(Position, fontsize14) plt.ylabel(Positional Encoding Value, fontsize14) plt.title(Positional Encoding Visualization, fontsize16) plt.legend() plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() plt.show()def plot_prediction_vs_groundtruth(model, src, tgt): 图 4展示样本输入、真实目标与模型预测输出的对比 说明该图将一个样本的源序列、目标序列翻转后的真实结果和模型生成的预测结果进行对比 直观展示模型的预测效果和误差情况。 model.eval() # 初始解码器输入为 BOS tgt_input torch.tensor([[BOS_token]], dtypetorch.long) max_tgt_len tgt.size(0) generated [BOS_token] with torch.no_grad(): memory, _ model.encode(src) for i in range(max_tgt_len - 1): tgt_in torch.tensor(generated, dtypetorch.long).unsqueeze(1) tgt_out model.decode(tgt_in, memory) output model.fc_out(tgt_out) next_token output.argmax(dim-1)[-1, 0].item() generated.append(next_token) if next_token EOS_token: break # 将 tensor 转换为列表去掉 BOS 和 EOS 便于显示 src_seq src.squeeze(1).tolist() tgt_seq tgt.squeeze(1).tolist()[1:-1] # 去除 BOS 和 EOS pred_seq generated[1:-1] if EOS_token in generated else generated[1:] # 取三个序列的最小长度 common_len min(len(src_seq), len(tgt_seq), len(pred_seq)) src_seq src_seq[:common_len] tgt_seq tgt_seq[:common_len] pred_seq pred_seq[:common_len] index np.arange(common_len) width 0.25 plt.figure(figsize(10, 4)) plt.bar(index - width, src_seq, widthwidth, colorcyan, labelInput Sequence) plt.bar(index, tgt_seq, widthwidth, colorlime, labelTarget (Reversed)) plt.bar(index width, pred_seq, widthwidth, colororange, labelPrediction) plt.xlabel(Position, fontsize14) plt.ylabel(Token ID, fontsize14) plt.title(Comparison: Input vs. Target vs. Prediction, fontsize16) plt.xticks(index, labels[str(i 1) for i in index]) plt.legend() plt.tight_layout() plt.show()# 9. 绘制各数据分析图形# 图 1训练损失曲线plot_training_loss(loss_history)# 图 2编码器最后一层自注意力权重热力图plot_attention_heatmap(attn_weights_all, layer-1)# 图 3位置编码的正弦余弦波曲线plot_positional_encoding(d_model, max_len100)# 图 4样本输入、目标序列与模型预测对比图plot_prediction_vs_groundtruth(model, src_sample, tgt_sample)训练过程中损失值随轮次变化曲线横轴代表训练轮数Epoch纵轴代表每个 Epoch 内平均计算的损失值Loss。曲线颜色采用鲜艳的洋红色magenta并在数据点处以圆圈标记以便观察训练初期损失的下降趋势和后期收敛情况。随着训练轮数的增加损失值逐步降低表明模型逐渐捕捉到了输入序列与目标序列翻转关系之间的映射规律。如果损失曲线平稳下降且趋于稳定则说明模型训练收敛良好反之则可能需要调整超参数或优化训练策略。编码器中自注意力权重的热力图横轴和纵轴分别表示输入序列中各个位置的索引颜色越深代表对应位置之间的注意力分数越高。图中展示的是编码器最后一层的自注意力权重直观呈现了每个位置在计算注意力时与其他位置的关联程度。能够帮助大家理解模型如何在编码器内部建立全局信息联系。例如在序列翻转任务中模型可能会对远处的位置赋予较高的注意力以捕捉逆序关系。观察热力图可以发现是否存在对角线结构或特殊的注意力分布模式从而为模型解释性提供依据。位置编码函数中正弦余弦波形的变化曲线图中展示了位置编码中不同维度例如前 8 个维度的数值随位置变化的趋势每个维度对应一条曲线曲线颜色各异且线条粗细均匀。横轴表示序列中的位置纵轴表示对应维度的编码值。位置编码是 Transformer 模型中弥补序列顺序信息不足的关键机制。该图直观展示了正弦和余弦函数如何随位置变化产生周期性波形使得不同位置可以通过不同频率的波形区别开来。这种周期性信息能帮助模型捕捉到相对位置和距离信息从而提高序列建模能力。样本输入、目标序列与模型预测结果对比图采用分组条形图展示同一位置上三个序列的 token 值输入序列颜色为青色、目标翻转序列颜色为亮绿色以及模型预测序列颜色为橙色。横轴为序列位置三个条形并排展示对比情况。大家可以直观观察模型预测结果与真实目标的吻合程度。若预测序列与目标序列在各个位置基本一致则说明模型已成功捕捉到序列翻转的映射关系若存在偏差则可进一步分析误差原因为模型调参和改进提供参考。总结一下模型训练部分通过构造简单的序列翻转任务验证了 Transformer 模型能够有效地捕捉到输入与目标之间的映射关系。多头注意力机制通过热力图展示注意力分布使得模型内部信息传递过程一目了然。位置编码直观展示正弦余弦波形证明了位置编码在区分序列中各个位置的重要作用。预测对比图展示模型预测结果与真实目标的差异为模型性能评估提供直观依据。整个内容涵盖了 Transformer 的各个关键模块和流程最后给大家通过丰富的图形展示帮助我们理解模型内部信息流动及注意力机制的工作原理。调整各部分超参数、增加训练样本和训练轮数还可以进一步探索模型在复杂任务中的表现与潜力。最后读者福利如果大家对大模型感兴趣这套大模型学习资料一定对你有用对于0基础小白入门如果你是零基础小白想快速入门大模型是可以考虑的。一方面是学习时间相对较短学习内容更全面更集中。二方面是可以根据这些资料规划好学习计划和方向。作为一名老互联网人看着AI越来越火也总想为大家做点啥。干脆把我这几年整理的AI大模型干货全拿出来了。包括入门指南、学习路径图、精选书籍、视频课还有我录的一些实战讲解。全部免费不搞虚的。学习从来都是自己的事我能做的就是帮你把路铺平一点。资料都放在下面了有需要的直接拿能用到多少就看你自己了。这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以点击文章最下方的VX名片免费领取【保真100%】