Transformer 模型自 2017 年在论文《Attention Is All You Need》中提出以来已成为自然语言处理乃至整个深度学习领域最重要的架构之一。本文将结合模型结构、代码实现与使用示例系统性地解析一个完整的 Transformer 模型并指出实际实现中需要注意的关键细节。整体架构原始 Transformer 是一个典型的 Encoder-Decoder 架构包含以下核心组件Token Embedding词嵌入将离散的 token ID 映射为稠密向量。Positional Encoding位置编码为模型注入序列顺序信息弥补自注意力机制对位置不敏感的缺陷。Encoder由 N 层堆叠而成每层包含多头自注意力Multi-Head Self-Attention和前馈网络Feed-Forward Network。Decoder同样由 N 层组成每层包含掩码多头自注意力、多头交叉注意力用于关注 Encoder 输出以及前馈网络。输出层通过线性投影LM Head将 Decoder 的输出映射回词表空间再经 Softmax 得到概率分布。值得注意的是尽管原始论文图示采用“Post-Norm”结构LayerNorm 在 Attention/FFN 之后但其官方代码及后续大多数大语言模型LLM实践均采用“Pre-Norm”结构LayerNorm 在子层之前。Pre-Norm 被证明能带来更稳定的训练过程和更低的损失波动因此现代实现普遍优先选择该结构。代码实现解析以下是一个简化但完整的 Transformer 模型实现基于 Pre-Norm 风格classTransformer(nn.Module):def__init__(self,args):super().__init__()assertargs.vocab_sizeisnotNoneassertargs.block_sizeisnotNoneself.argsargs self.transformernn.ModuleDict(dict(wtenn.Embedding(args.vocab_size,args.n_embd),wpePositionalEncoding(args),dropnn.Dropout(args.dropout),encoderEncoder(args),decoderDecoder(args),))self.lm_headnn.Linear(args.n_embd,args.vocab_size,biasFalse)self.apply(self._init_weights)print(number of parameters: %.2fM%(self.get_num_params()/1e6,))defget_num_params(self,non_embeddingFalse):n_paramssum(p.numel()forpinself.parameters())ifnon_embedding:n_params-self.transformer.wte.weight.numel()returnn_paramsdef_init_weights(self,module):ifisinstance(module,nn.Linear):torch.nn.init.normal_(module.weight,mean0.0,std0.02)ifmodule.biasisnotNone:torch.nn.init.zeros_(module.bias)elifisinstance(module,nn.Embedding):torch.nn.init.normal_(module.weight,mean0.0,std0.02)defforward(self,idx,targetsNone):b,tidx.size()asserttself.args.block_size tok_embself.transformer.wte(idx)pos_embself.transformer.wpe(tok_emb)xself.transformer.drop(pos_emb)enc_outself.transformer.encoder(x)xself.transformer.decoder(x,enc_out)iftargetsisnotNone:logitsself.lm_head(x)lossF.cross_entropy(logits.view(-1,logits.size(-1)),targets.view(-1),ignore_index-1)else:logitsself.lm_head(x[:,[-1],:])lossNonereturnlogits,loss关键点说明初始化策略线性层和嵌入层采用均值为 0、标准差为 0.02 的正态分布初始化这是 GPT 系列模型的常用做法。参数统计get_num_params函数支持排除嵌入层参数便于分析模型的有效训练规模。训练与推理分离训练时计算整个序列的损失推理时仅取最后一个时间步的输出用于自回归生成。位置编码实现通常采用固定的正弦/余弦函数也可使用可学习的位置嵌入。潜在问题提醒Decoder 输入设计在标准机器翻译任务中Decoder 应接收目标序列右移一位而非源序列。当前代码将源序列x同时传给 Encoder 和 Decoder这不符合经典 Encoder-Decoder 范式。若用于语言建模如 GPT则应移除 Encoder仅保留 Decoder 并施加因果掩码。任务适配性现代大语言模型多采用 Decoder-only 架构。若目标是复现 LLM建议调整结构以匹配自回归生成任务。使用示例为验证模型可运行性我们提供一个完整的使用示例包含占位模块和主调用逻辑importtorchimporttorch.nnasnnimporttorch.nn.functionalasFfromargparseimportNamespaceclassPositionalEncoding(nn.Module):def__init__(self,args):super().__init__()petorch.zeros(args.block_size,args.n_embd)positiontorch.arange(0,args.block_size,dtypetorch.float).unsqueeze(1)div_termtorch.exp(torch.arange(0,args.n_embd,2).float()*(-torch.log(torch.tensor(10000.0))/args.n_embd))pe[:,0::2]torch.sin(position*div_term)pe[:,1::2]torch.cos(position*div_term)pepe.unsqueeze(0)self.register_buffer(pe,pe)self.dropoutnn.Dropout(args.dropout)defforward(self,x):xxself.pe[:,:x.size(1),:]returnself.dropout(x)classEncoder(nn.Module):def__init__(self,args):super().__init__()self.layersnn.ModuleList([nn.Identity()for_inrange(args.n_layer)])defforward(self,x):forlayerinself.layers:xlayer(x)# 实际应包含多层 EncoderBlockreturnxclassDecoder(nn.Module):def__init__(self,args):super().__init__()self.layersnn.ModuleList([nn.Identity()for_inrange(args.n_layer)])defforward(self,x,enc_out):forlayerinself.layers:xlayer(x)# 实际应包含多层 DecoderBlockreturnxclassTransformer(nn.Module):def__init__(self,args):super().__init__()assertargs.vocab_sizeisnotNoneassertargs.block_sizeisnotNoneself.argsargs self.transformernn.ModuleDict(dict(wtenn.Embedding(args.vocab_size,args.n_embd),wpePositionalEncoding(args),dropnn.Dropout(args.dropout),encoderEncoder(args),decoderDecoder(args),))self.lm_headnn.Linear(args.n_embd,args.vocab_size,biasFalse)self.apply(self._init_weights)print(number of parameters: %.2fM%(self.get_num_params()/1e6,))defget_num_params(self,non_embeddingFalse):n_paramssum(p.numel()forpinself.parameters())ifnon_embedding:n_params-self.transformer.wte.weight.numel()returnn_paramsdef_init_weights(self,module):ifisinstance(module,nn.Linear):torch.nn.init.normal_(module.weight,mean0.0,std0.02)ifmodule.biasisnotNone:torch.nn.init.zeros_(module.bias)elifisinstance(module,nn.Embedding):torch.nn.init.normal_(module.weight,mean0.0,std0.02)defforward(self,idx,targetsNone):b,tidx.size()asserttself.args.block_size tok_embself.transformer.wte(idx)pos_embself.transformer.wpe(tok_emb)xself.transformer.drop(pos_emb)enc_outself.transformer.encoder(x)xself.transformer.decoder(x,enc_out)iftargetsisnotNone:logitsself.lm_head(x)lossF.cross_entropy(logits.view(-1,logits.size(-1)),targets.view(-1),ignore_index-1)else:logitsself.lm_head(x[:,[-1],:])lossNonereturnlogits,lossif__name____main__:devicecudaiftorch.cuda.is_available()elsecpuargsNamespace(vocab_size1000,block_size32,n_embd128,n_layer2,dropout0.1)modelTransformer(args).to(device)B,T4,10idxtorch.randint(0,args.vocab_size,(B,T)).to(device)targetstorch.randint(0,args.vocab_size,(B,T)).to(device)# 训练模式model.train()logits,lossmodel(idx,targets)print(f训练模式 - logits shape:{logits.shape}, loss:{loss.item():.4f})# 推理模式model.eval()withtorch.no_grad():logits,lossmodel(idx)print(f推理模式 - logits shape:{logits.shape}, loss:{loss})运行该脚本将输出类似以下内容number of parameters: 0.52M 训练模式 - logits shape: torch.Size([4, 10, 1000]), loss: 6.9078 推理模式 - logits shape: torch.Size([4, 1, 1000]), loss: None此示例验证了模型的前向传播逻辑正确且能区分训练与推理行为。总结实现一个完整的 Transformer 模型不仅需要理解其理论结构还需注意工程细节如 LayerNorm 的位置、初始化策略、输入输出对齐等。虽然本文提供的代码保留了原始 Encoder-Decoder 形式但在实际大语言模型开发中Decoder-only 架构更为常见。开发者应根据具体任务机器翻译、文本生成、语言建模等灵活调整模型结构。