大语言模型实战(四)——Transformer 网络架构源码剖析

1. 主流大语言模型(LLM)核心技术参数的对比表

模型 结构 位置编码 激活函数 layer norm方法 补充说明
原生Transformer Encoder-Decoder Sinusoidal编码 ReLU Post layer norm 完整Transformer架构,适用于机器翻译等序列转换任务
BERT Encoder 绝对位置编码 GeLU Post layer norm 仅用编码器,擅长双向语义理解(文本分类、问答等)
LLaMA Casual decoder RoPE(旋转位置编码) SwiGLU Pre RMS Norm 解码器+掩码,生成式大模型,RoPE适配长文本,Pre RMS Norm提升训练稳定性
ChatGLM-6B Prefix decoder RoPE(旋转位置编码) GeGLU Post Deep Norm 解码器变体,通过前缀调优增强对话能力,Deep Norm适配深层模型
Bloom Casual decoder AliBi(相对位置编码) GeLU Pre Layer Norm 解码器+掩码,AliBi支持任意长度输入,Pre Layer Norm提升训练稳定性

2. 输入嵌入(Input Embedding)的实现与结构

2.1 模块结构描述

Input Embedding是Transformer处理文本的首个核心模块,核心作用是将离散的单词索引(如"苹果"对应索引100)转换为连续的、固定维度的稠密向量(词向量),为后续的注意力计算、特征提取提供可数值化的输入。

其核心结构设计要点:

  1. 核心组件 :基于查表法实现的嵌入层(Embedding Layer),本质是一个形状为[vocab_size, d_model]的可训练参数矩阵;
  2. 缩放操作 :将嵌入层输出的词向量乘以√d_model,目的是平衡词向量与后续位置编码的数值量级,避免某一部分特征主导计算;
  3. 输入输出
    • 输入:单词的索引序列(shape: [batch_size, seq_len]);
    • 输出:维度统一的词向量序列(shape: [batch_size, seq_len, d_model])。
2.2 完整代码实现(PyTorch)
python 复制代码
import math
import torch
import torch.nn as nn

class InputEmbedding(nn.Module):
    """
    Transformer输入嵌入模块
    :param vocab_size: 词汇表总大小(所有唯一单词的数量)
    :param d_model: 词向量的维度(Transformer的特征维度,通常设为512/1024)
    """
    def __init__(self, vocab_size: int, d_model: int):
        super().__init__()
        # 1. 定义嵌入层:将单词索引映射为d_model维向量
        self.d_model = d_model
        self.vocab_size = vocab_size
        self.embedding = nn.Embedding(vocab_size, d_model)  # 核心嵌入层
    
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        前向传播:将单词索引转换为缩放后的词向量
        :param x: 输入的单词索引序列,shape=[batch_size, seq_len]
        :return: 缩放后的词向量,shape=[batch_size, seq_len, d_model]
        """
        # 2. 嵌入层查表得到词向量 + 缩放(√d_model)
        embed_output = self.embedding(x) * math.sqrt(self.d_model)
        return embed_output


# ------------------- 测试示例 -------------------
if __name__ == "__main__":
    # 超参数设置(符合Transformer原始论文)
    VOCAB_SIZE = 10000  # 假设词汇表有10000个单词
    D_MODEL = 512       # 词向量维度设为512
    BATCH_SIZE = 2      # 批次大小
    SEQ_LEN = 10        # 句子长度(每个句子包含10个单词)
    
    # 1. 初始化嵌入模块
    input_embedding = InputEmbedding(VOCAB_SIZE, D_MODEL)
    
    # 2. 构造测试输入:随机生成单词索引(范围0~9999)
    test_input = torch.randint(0, VOCAB_SIZE, (BATCH_SIZE, SEQ_LEN))
    print("输入形状(batch_size, seq_len):", test_input.shape)  # torch.Size([2, 10])
    
    # 3. 前向传播得到词向量
    embed_output = input_embedding(test_input)
    print("输出形状(batch_size, seq_len, d_model):", embed_output.shape)  # torch.Size([2, 10, 512])
2.3 关键细节说明
  1. nn.Embedding的本质
    nn.Embedding(vocab_size, d_model)会初始化一个可训练的矩阵,每行对应一个单词的词向量,训练过程中模型会自动优化这些向量,让语义相似的单词向量更接近。

  2. 缩放操作的必要性

    乘以√d_model是为了让词向量的方差接近1(与自注意力中QK^T的缩放逻辑一致),避免后续与位置编码相加后数值量级失衡,保证模型训练稳定。

  3. 与位置编码的衔接

    实际使用中,Input Embedding的输出会与"位置编码(Positional Encoding)"的输出相加,得到最终的输入向量(既包含单词语义,又包含位置信息),再送入编码器。

  4. Input Embedding的核心是通过可训练的嵌入层完成"单词索引→词向量"的转换,是Transformer处理文本的基础;

  5. 代码实现的核心是nn.Embedding层 + 缩放操作,保证输出向量的数值量级适配后续计算;

  6. 该模块的输出会结合位置编码,为Transformer提供"语义+位置"的完整输入特征。

3 .位置编码(Positional Encoding)的实现与作用

3.1 位置编码的核心作用

Transformer的注意力机制本身不具备"感知文本顺序"的能力(比如"我吃苹果"和"苹果吃我",纯注意力无法区分顺序)。位置编码的核心作用是:

给每个位置的词向量添加位置信息,让模型能识别单词在句子中的顺序,理解文本的时序关系。

3.2 位置编码的数学原理(Sinusoidal编码)

Transformer原生采用正弦/余弦位置编码 ,对应图中的公式:
PE(pos,2i)=sin⁡(pos/100002i/dmodel)PE(pos,2i+1)=cos⁡(pos/100002i/dmodel) \begin{align*} PE_{(pos, 2i)} &= \sin\left(pos / 10000^{2i/d_{\text{model}}}\right) \\ PE_{(pos, 2i+1)} &= \cos\left(pos / 10000^{2i/d_{\text{model}}}\right) \end{align*} PE(pos,2i)PE(pos,2i+1)=sin(pos/100002i/dmodel)=cos(pos/100002i/dmodel)

  • pos:单词在句子中的位置(如第1个词、第2个词);
  • i:词向量的维度索引(如512维向量的第0维、第1维);
  • d_model:词向量的维度(如512)。
  • 逻辑:通过正弦/余弦函数生成位置向量,既保证不同位置的向量唯一,又能体现位置间的相对关系(如位置pos+kpos的编码关系固定)。
3.3 位置编码的代码实现(PyTorch)

以下是图中PositionalEncoding类的完整实现及解析:

python 复制代码
import math
import torch
import torch.nn as nn

class PositionalEncoding(nn.Module):
    def __init__(self, dim: int, dropout: float, max_len=5000):
        """
        :param dim: 词向量维度(需为偶数,因为要分sin/cos)
        :param dropout: dropout比例
        :param max_len: 最大句子长度(预先生成对应长度的位置编码)
        """
        super().__init__()
        # 检查维度是否为偶数
        if dim % 2 != 0:
            raise ValueError("不能使用sin/cos位置编码,应该使用偶数维度")
        
        # 1. 初始化位置编码矩阵pe(shape: [max_len, dim])
        pe = torch.zeros(max_len, dim)
        # 2. 构造位置索引pos(shape: [max_len, 1])
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        # 3. 计算公式中的分母项:10000^(2i/d_model)
        div_term = torch.exp(torch.arange(0, dim, 2).float() * (-math.log(10000.0) / dim))
        
        # 4. 偶数维度用sin,奇数维度用cos
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        
        # 5. 注册为缓存(不参与训练,仅作为常量使用)
        self.register_buffer('pe', pe)
        self.dropout = nn.Dropout(p=dropout)
        self.dim = dim

    def forward(self, emb, step=None):
        """
        :param emb: Input Embedding的输出(词向量,shape: [batch_size, seq_len, dim])
        :param step: 可选,指定取第step个位置的编码(用于生成式任务)
        :return: 融合位置信息的词向量(shape: [batch_size, seq_len, dim])
        """
        # 缩放词向量(与Input Embedding的缩放逻辑一致)
        emb = emb * math.sqrt(self.dim)
        # 拼接词向量与位置编码
        if step is None:
            emb = emb + self.pe[:emb.size(1)]  # 取前seq_len个位置的编码
        else:
            emb = emb + self.pe[step]  # 取指定step位置的编码
        # 添加dropout防止过拟合
        return self.dropout(emb)
3.4 关键细节解析
  1. 为什么用sin/cos函数?
    正弦/余弦的周期性让模型能更好地学习"相对位置"(比如位置pospos+5的编码关系固定),适配长文本场景。
  2. register_buffer的作用?
    位置编码是固定常量 ,不参与模型训练,用register_buffer将其存到缓存中,避免重复计算,节省内存。
  3. 与Input Embedding的配合
    位置编码的输出会与Input Embedding的词向量相加,最终得到"语义信息+位置信息"的输入特征,这是Transformer理解文本顺序的核心前提。

4 自注意力(Self-Attention)的实现与作用

图中为多头注意力,自注意力为其子模块。

4.1 自注意力的核心作用

自注意力(Self-Attention)是Transformer的核心组件 ,作用是让模型在处理文本时,动态关注句子中不同位置的单词(比如理解"他喜欢苹果"时,让"他"和"苹果"建立关联),从而捕捉单词间的语义依赖关系。

4.2 自注意力的数学原理

图中右上角的公式是自注意力的核心计算逻辑:
Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)=softmax(dk QKT)V

  • QQQ(Query):查询矩阵,代表当前单词"要找什么";
  • KKK(Key):键矩阵,代表其他单词"提供什么信息";
  • VVV(Value):值矩阵,代表其他单词"具体的信息内容";
  • dkd_kdk:KKK的维度,dk\sqrt{d_k}dk 是缩放因子(避免QKTQK^TQKT数值过大导致softmax梯度消失)。
4.3 自注意力的代码实现(PyTorch)

以下是图中self_attention函数的完整解析:

python 复制代码
import math
import torch
import torch.nn.functional as F

def self_attention(q, k, v, d_k, mask=None, dropout=None):
    """
    :param q: 查询矩阵Q,shape: [batch_size, n_heads, seq_len, d_k]
    :param k: 键矩阵K,shape: [batch_size, n_heads, seq_len, d_k]
    :param v: 值矩阵V,shape: [batch_size, n_heads, seq_len, d_k]
    :param d_k: K的维度
    :param mask: 掩码(用于遮挡不需要关注的位置,如生成式任务中的"未来词")
    :param dropout: dropout层(防止过拟合)
    :return: 自注意力的输出,shape: [batch_size, n_heads, seq_len, d_k]
    """
    # 1. 计算Q与K的相似度得分:Q*K^T / √d_k
    scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
    
    # 2. 应用掩码(若有):将需要遮挡的位置得分设为极小值(-1e9)
    if mask is not None:
        mask = mask.unsqueeze(1)  # 扩展维度以匹配scores的形状
        scores = scores.masked_fill(mask == 0, -1e9)  # 掩码位置填充-1e9
    
    # 3. 对得分做softmax,转换为注意力权重(总和为1)
    scores = F.softmax(scores, dim=-1)
    
    # 4. 应用dropout(若有)
    if dropout is not None:
        scores = dropout(scores)
    
    # 5. 注意力权重与V相乘,得到最终输出
    output = torch.matmul(scores, v)
    return output
4.4 代码执行流程解析
  1. 计算相似度得分
    通过torch.matmul(q, k.transpose(-2, -1))计算Q与K的点积(代表单词间的关联程度),再除以dk\sqrt{d_k}dk 缩放,避免数值过大。
  2. 应用掩码
    若传入mask(如生成式任务中,遮挡"未来还未生成的词"),将掩码位置的得分设为−1e9-1e9−1e9------softmax后这些位置的权重会趋近于0,模型不会关注这些位置。
  3. 生成注意力权重
    对得分做softmax,将得分转换为"0~1"的权重(权重越高,代表该位置的单词越重要)。
  4. 计算输出
    注意力权重与V相乘,得到融合了"关键信息"的输出(即模型关注的单词信息会被放大)。
4.5 与"多头注意力(Multi-Head Attention)"的关系

图中红色框标注的"Multi-Head Attention"是自注意力的扩展:

  • 原理:将Q、K、V拆分为多个"头"(如8个),每个头独立计算自注意力,再将结果拼接------让模型同时从多个角度关注单词间的关联(比如一个头关注语法,一个头关注语义)。
  • 本质:图中的self_attention是"单头注意力",而"多头注意力"是多个单头注意力的并行计算+拼接。

5 多头注意力(Multi-Head Attention)的实现与作用

5.1 多头注意力的核心作用

多头注意力是自注意力的扩展升级,核心是让模型同时从多个不同的角度捕捉单词间的语义关联(比如一个"头"关注语法结构,一个"头"关注语义逻辑),相比单头自注意力,能更全面地理解文本的复杂关系。

5.2 多头注意力的实现逻辑

多头注意力的核心流程是:

  1. 拆分Q/K/V:将输入的Q、K、V通过线性层映射后,拆分为多个"头"(如8个);
  2. 单头注意力并行计算:每个头独立执行自注意力计算;
  3. 拼接输出:将所有头的输出拼接,再通过线性层得到最终结果。
5.3 多头注意力的代码实现(PyTorch)

以下是图中MultiHeadAttention类的完整解析(需结合前文的self_attention函数):

python 复制代码
import torch
import torch.nn as nn
# 需引入前文定义的self_attention函数

class MultiHeadAttention(nn.Module):
    def __init__(self, heads, d_model, dropout=0.1):
        """
        :param heads: 注意力头的数量(如8)
        :param d_model: 模型的特征维度(需被heads整除)
        :param dropout: dropout比例
        """
        super().__init__()
        self.d_model = d_model
        self.d_k = d_model // heads  # 每个头的特征维度
        self.h = heads  # 注意力头数量

        # 定义Q/K/V对应的线性层(将输入映射到d_model维度)
        self.q_linear = nn.Linear(d_model, d_model)
        self.v_linear = nn.Linear(d_model, d_model)
        self.k_linear = nn.Linear(d_model, d_model)
        
        self.dropout = nn.Dropout(dropout)
        self.out = nn.Linear(d_model, d_model)  # 最终输出的线性层

    def forward(self, q, k, v, mask=None):
        """
        :param q: 查询矩阵Q,shape: [batch_size, seq_len, d_model]
        :param k: 键矩阵K,shape: [batch_size, seq_len, d_model]
        :param v: 值矩阵V,shape: [batch_size, seq_len, d_model]
        :param mask: 掩码(同自注意力)
        :return: 多头注意力的输出,shape: [batch_size, seq_len, d_model]
        """
        bs = q.size(0)  # 获取批次大小

        # 1. 线性映射 + 拆分注意力头
        k = self.k_linear(k).view(bs, -1, self.h, self.d_k)
        q = self.q_linear(q).view(bs, -1, self.h, self.d_k)
        v = self.v_linear(v).view(bs, -1, self.h, self.d_k)

        # 2. 调整维度顺序:[batch_size, 头数, 序列长度, 每个头的维度]
        k = k.transpose(1, 2)
        q = q.transpose(1, 2)
        v = v.transpose(1, 2)

        # 3. 每个头独立计算自注意力
        scores = self_attention(q, k, v, self.d_k, mask, self.dropout)

        # 4. 拼接所有头的输出:恢复维度顺序 + 合并头
        concat = scores.transpose(1, 2).contiguous()  # 调整维度为[bs, seq_len, h, d_k]
        concat = concat.view(bs, -1, self.d_model)  # 合并为[bs, seq_len, d_model]

        # 5. 最终线性层输出
        output = self.out(concat)
        return output
5.4 代码执行流程解析
  1. 线性映射与拆头
    通过q_linear/k_linear/v_linear将输入映射到d_model维度,再用view拆分为heads个独立的头(每个头维度为d_k)。
  2. 维度调整
    transpose将"头数"维度提前,保证每个头的自注意力计算独立。
  3. 单头注意力并行计算
    调用前文的self_attention函数,每个头并行执行自注意力。
  4. 拼接与输出
    将所有头的输出拼接,再通过out线性层整合为最终的d_model维度输出。
5.5 多头注意力的优势

相比单头自注意力,多头注意力的核心优势是**"多视角语义捕捉"**:

  • 比如处理句子"猫追老鼠"时,一个头可能关注"猫"和"追"的动作关联,另一个头关注"追"和"老鼠"的对象关联,最终拼接的结果能更全面地表达句子的语义。

6. Add & Norm(残差连接+层归一化)的实现与作用

6.1 Add & Norm的核心作用

Add & Norm是Transformer中稳定训练、加速收敛的关键模块,由"残差连接(Add)"和"层归一化(Norm)"两部分组成:

  • 残差连接:解决深层模型的梯度消失问题,让模型能训练更深的层数;
  • 层归一化:对每一层的输出做归一化(均值为0、方差为1),避免数值波动过大,稳定训练过程。
6.2 层归一化(LayerNorm)的原理与实现

层归一化的核心是对每个样本的特征维度 做归一化,公式为:
Z~j=γj⋅Zj−μjσj2+ϵ+βj\tilde{Z}_j = \gamma_j \cdot \frac{Z_j - \mu_j}{\sqrt{\sigma_j^2 + \epsilon}} + \beta_jZ~j=γj⋅σj2+ϵ Zj−μj+βj

  • μj\mu_jμj:特征的均值,σj2\sigma_j^2σj2:特征的方差;
  • γ、β\gamma、\betaγ、β:可训练的缩放/偏移参数(让模型自主调整归一化的幅度);
  • ϵ\epsilonϵ:防止分母为0的小常数。

代码实现(图中LayerNorm类)

python 复制代码
import torch
import torch.nn as nn

class LayerNorm(nn.Module):
    def __init__(self, x_size, eps=1e-6):
        """
        :param x_size: 特征维度大小
        :param eps: 防止分母为0的小常数
        """
        super().__init__()
        # 可训练的缩放参数(初始为1)
        self.ones_tensor = nn.Parameter(torch.ones(x_size))
        # 可训练的偏移参数(初始为0)
        self.zeros_tensor = nn.Parameter(torch.zeros(x_size))
        self.eps = eps

    def forward(self, x):
        # 计算均值(按特征维度)
        mean = x.mean(-1, keepdim=True)
        # 计算标准差
        std = x.std(-1, keepdim=True)
        # 层归一化计算:(x-均值)/标准差 * 缩放 + 偏移
        return self.ones_tensor * (x - mean) / (std + self.eps) + self.zeros_tensor
6.3 残差连接+层归一化(SublayerConnection)的实现

图中的SublayerConnection类实现了"残差连接+层归一化"的组合逻辑,对应Transformer架构中的"Add & Norm"环节:

代码实现(图中SublayerConnection类)

python 复制代码
class SublayerConnection(nn.Module):
    def __init__(self, size, dropout=0.1):
        """
        :param size: 特征维度大小(与d_model一致)
        :param dropout: dropout比例
        """
        super().__init__()
        # 层归一化模块
        self.layer_norm = LayerNorm(size)
        # Dropout层(防止过拟合)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, x, sublayer):
        """
        :param x: 模块的输入(残差连接的"原始输入")
        :param sublayer: 当前子模块(如多头注意力、前馈网络)
        :return: 残差连接+层归一化后的输出
        """
        # 逻辑:层归一化(原始输入 + 子模块输出) → 再做Dropout
        return self.dropout(self.layer_norm(x + sublayer(x)))
6.4 代码执行流程解析
  1. 残差连接
    将"原始输入x"与"子模块(如多头注意力)的输出sublayer(x)"相加,保留原始信息,避免梯度消失。
  2. 层归一化
    对残差连接的结果做层归一化,稳定数值分布。
  3. Dropout
    对归一化后的结果做Dropout,防止模型过拟合。
6.5 Add & Norm在Transformer中的位置

从左侧架构图可见,Transformer的编码器/解码器中,每个子模块(多头注意力、前馈网络)之后都会接一个Add & Norm

  • 例如:多头注意力的输出 → 残差连接(+原始输入)→ 层归一化 → 送入前馈网络。

Add & Norm是Transformer的"训练稳定器",由残差连接和层归一化组成:

  • 残差连接解决深层梯度消失问题;
  • 层归一化稳定数值分布;
  • 代码实现中,LayerNorm负责归一化计算,SublayerConnection负责将"残差连接+层归一化+Dropout"组合为一个可复用的模块,是Transformer能训练深层结构的关键保障。

7 Feed Forward(前馈网络)的实现与作用

7.1 Feed Forward的核心作用

Feed Forward(也称为FFN,前馈神经网络)是Transformer中增强特征表达能力的模块,在多头注意力之后对特征做非线性变换,进一步提取更复杂的语义信息。

7.2 Feed Forward的结构设计

Transformer中的Feed Forward是两层线性网络+激活函数 的结构,通常会将中间层的维度放大(比如原始论文中d_ff=2048,是d_model=512的4倍),目的是增加模型的表达能力。

7.3 Feed Forward的代码实现(PyTorch)

以下是图中FeedForward类的完整解析:

python 复制代码
import torch
import torch.nn as nn

class FeedForward(nn.Module):
    def __init__(self, d_model: int, d_ff: int, dropout=0.1):
        """
        :param d_model: 输入/输出的特征维度(与Transformer的d_model一致)
        :param d_ff: 中间隐藏层的维度(通常是d_model的4倍)
        :param dropout: dropout比例
        """
        super().__init__()
        # 第一层线性层:d_model → d_ff
        self.w_1 = nn.Linear(d_model, d_ff)
        # 第二层线性层:d_ff → d_model
        self.w_2 = nn.Linear(d_ff, d_model)
        # 层归一化(稳定训练)
        self.layer_norm = nn.LayerNorm(d_model, eps=1e-6)
        # Dropout层(防止过拟合)
        self.dropout_1 = nn.Dropout(dropout)
        # ReLU激活函数(引入非线性)
        self.relu = nn.ReLU()
        self.dropout_2 = nn.Dropout(dropout)

    def forward(self, x):
        """
        :param x: 输入特征,shape: [batch_size, seq_len, d_model]
        :return: 输出特征,shape: [batch_size, seq_len, d_model]
        """
        # 1. 层归一化 → 第一层线性变换 → ReLU激活 → Dropout
        inter = self.dropout_1(self.relu(self.w_1(self.layer_norm(x))))
        # 2. 第二层线性变换 → Dropout
        output = self.dropout_2(self.w_2(inter))
        # 3. 残差连接(原始输入 + 输出)
        return output + x
7.4 代码执行流程解析
  1. 层归一化 :先对输入x做层归一化,稳定数值分布;
  2. 第一层线性变换+激活 :通过w_1将特征维度从d_model放大到d_ff,再用ReLU引入非线性,之后做Dropout;
  3. 第二层线性变换 :通过w_2将特征维度从d_ff缩回到d_model,再做Dropout;
  4. 残差连接 :将输出与原始输入x相加,保留原始信息,避免梯度消失。
7.5 Feed Forward在Transformer中的位置

从左侧架构图可见,Transformer的编码器/解码器中,每个多头注意力模块之后都会接一个Feed Forward

  • 流程:多头注意力输出 → Add & Norm → Feed Forward → Add & Norm。

Feed Forward是Transformer中增强特征表达的模块,核心是"两层线性变换+ReLU激活+残差连接"的结构:

  • 中间层放大维度(d_ff),提升模型的非线性表达能力;
  • 残差连接和层归一化保证训练稳定;
  • 它与多头注意力配合,让模型既能捕捉单词间的关联(注意力),又能提炼更复杂的语义特征(前馈网络)。

8 Encoder(编码器)的实现与作用

8.1 Encoder的核心作用

Encoder(编码器)是Transformer的"语义提取模块",负责将输入文本(如待翻译的句子)编码为包含全局语义信息的特征向量,为后续的解码器提供输入。

8.2 Encoder的结构设计

Encoder由N个相同的EncoderLayer(编码器层)堆叠而成(原始论文中N=6),每个EncoderLayer包含两个核心子模块:

  1. 多头注意力(Multi-Head Attention);
  2. 前馈网络(Feed Forward);
    每个子模块后都搭配"Add & Norm"(残差连接+层归一化)。
8.3 核心辅助函数:clone_module_to_modulist

图中clone_module_to_modulist函数用于复制多个相同的模块(如将1个EncoderLayer复制为6个),是构建多层Encoder的基础:

python 复制代码
import copy
import torch.nn as nn

def clone_module_to_modulist(module, module_num):
    """
    :param module: 待复制的模块(如EncoderLayer)
    :param module_num: 复制的数量
    :return: 包含module_num个相同模块的ModuleList
    """
    return nn.ModuleList([copy.deepcopy(module) for _ in range(module_num)])
8.4 EncoderLayer(编码器层)的实现

EncoderLayer是Encoder的基本单元,包含"多头注意力+前馈网络"的完整流程:

python 复制代码
class EncoderLayer(nn.Module):
    def __init__(self, size, attn, feed_forward, dropout=0.1):
        """
        :param size: 特征维度(与d_model一致)
        :param attn: 多头注意力模块
        :param feed_forward: 前馈网络模块
        :param dropout: dropout比例
        """
        super().__init__()
        self.attn = attn
        self.feed_forward = feed_forward
        # 复制2个SublayerConnection(分别对应注意力、前馈网络的Add & Norm)
        self.sublayer_connection_list = clone_module_to_modulist(
            SublayerConnection(size, dropout), 2
        )
        self.size = size

    def forward(self, x, mask):
        """
        :param x: 输入特征
        :param mask: 掩码(遮挡无效位置,如填充词)
        :return: 编码器层的输出
        """
        # 第一步:多头注意力 + Add & Norm
        x = self.sublayer_connection_list[0](
            x, lambda x: self.attn(x, x, x, mask)  # 自注意力:Q=K=V=x
        )
        # 第二步:前馈网络 + Add & Norm
        return self.sublayer_connection_list[1](x, self.feed_forward)
8.5 Encoder(编码器)的实现

Encoder通过堆叠N个EncoderLayer,实现深层语义编码:

python 复制代码
class Encoder(nn.Module):
    def __init__(self, n, encoder_layer):
        """
        :param n: EncoderLayer的堆叠层数
        :param encoder_layer: 单个EncoderLayer模块
        """
        super().__init__()
        # 复制n个EncoderLayer
        self.encoder_layer_list = clone_module_to_modulist(encoder_layer, n)

    def forward(self, x, src_mask):
        """
        :param x: 输入文本的预处理特征(Input Embedding + 位置编码)
        :param src_mask: 输入文本的掩码
        :return: 编码器的最终输出(全局语义特征)
        """
        # 依次经过每个EncoderLayer
        for encoder_layer in self.encoder_layer_list:
            x = encoder_layer(x, src_mask)
        return x
8.6 代码执行流程解析
  1. EncoderLayer的前向传播
    输入x先经过"多头自注意力+Add & Norm",再经过"前馈网络+Add & Norm",输出提炼后的特征。
  2. Encoder的前向传播
    输入特征依次经过N个EncoderLayer,每一层都逐步增强语义表达,最终输出包含全局信息的编码结果。
8.7 Encoder在Transformer中的位置

从左侧架构图可见,Encoder是Transformer的左侧模块

  • 输入:经过Input Embedding + 位置编码的文本特征;
  • 输出:全局语义编码向量,送入Decoder(解码器)做后续生成。

Encoder是Transformer的"语义编码器",核心是多层EncoderLayer的堆叠

  • 每个EncoderLayer包含"多头自注意力+前馈网络+Add & Norm",实现语义的逐步提炼;
  • clone_module_to_modulist辅助函数实现模块的批量复制,是构建深层网络的关键;
  • 最终输出的全局语义向量,是解码器生成目标文本的基础。

9 Decoder(解码器)的实现与作用

9.1 Decoder的核心作用

Decoder(解码器)是Transformer的"生成模块",负责基于Encoder输出的全局语义特征,逐步生成目标文本(如翻译后的句子、对话回复等)。

9.2 Decoder的结构设计

Decoder由N个相同的DecoderLayer(解码器层)堆叠而成(原始论文中N=6),每个DecoderLayer包含3个核心子模块:

  1. Masked Multi-Head Attention(掩码多头注意力,防止"偷看未来词");
  2. Multi-Head Attention(交叉注意力,关注Encoder的语义特征);
  3. Feed Forward(前馈网络);
    每个子模块后都搭配"Add & Norm"(残差连接+层归一化)。
9.3 DecoderLayer(解码器层)的实现

DecoderLayer是Decoder的基本单元,包含"掩码注意力+交叉注意力+前馈网络"的完整流程:

python 复制代码
import torch.nn as nn
# 需引入前文的SublayerConnection、clone_module_to_modulist

class DecoderLayer(nn.Module):
    def __init__(self, d_model, attn, feed_forward, sublayer_num, dropout=0.1):
        """
        :param d_model: 特征维度
        :param attn: 多头注意力模块
        :param feed_forward: 前馈网络模块
        :param sublayer_num: 子模块数量(通常为3)
        :param dropout: dropout比例
        """
        super().__init__()
        self.self_attn = attn  # 掩码自注意力
        self.feed_forward = feed_forward
        # 复制sublayer_num个SublayerConnection(对应3个子模块)
        self.sublayer_connection_list = clone_module_to_modulist(
            SublayerConnection(d_model, dropout), sublayer_num
        )
        self.d_model = d_model

    def forward(self, x, lr_memory, src_mask, trg_mask):
        """
        :param x: 解码器的输入(已生成的部分文本特征)
        :param lr_memory: Encoder的输出(全局语义特征)
        :param src_mask: 输入文本的掩码
        :param trg_mask: 目标文本的掩码(遮挡未来词)
        :return: 解码器层的输出
        """
        # 1. 掩码多头自注意力 + Add & Norm(防止偷看未来词)
        x = self.sublayer_connection_list[0](
            x, lambda x: self.self_attn(x, x, x, trg_mask)
        )
        # 2. 交叉注意力 + Add & Norm(关注Encoder的语义特征)
        x = self.sublayer_connection_list[1](
            x, lambda x: self.self_attn(x, lr_memory, lr_memory, src_mask)
        )
        # 3. 前馈网络 + Add & Norm
        return self.sublayer_connection_list[2](x, self.feed_forward)
9.4 Decoder(解码器)的实现

Decoder通过堆叠N个DecoderLayer,实现目标文本的逐步生成:

python 复制代码
class Decoder(nn.Module):
    def __init__(self, n_layers, decoder_layer):
        """
        :param n_layers: DecoderLayer的堆叠层数
        :param decoder_layer: 单个DecoderLayer模块
        """
        super().__init__()
        # 复制n_layers个DecoderLayer
        self.decoder_layer_list = clone_module_to_modulist(decoder_layer, n_layers)

    def forward(self, x, memory, src_mask, trg_mask):
        """
        :param x: 目标文本的预处理特征(Output Embedding + 位置编码)
        :param memory: Encoder的输出(全局语义特征)
        :param src_mask: 输入文本的掩码
        :param trg_mask: 目标文本的掩码
        :return: 解码器的最终输出
        """
        # 依次经过每个DecoderLayer
        for decoder_layer in self.decoder_layer_list:
            x = decoder_layer(x, memory, src_mask, trg_mask)
        return x
9.5 代码执行流程解析
  1. 掩码自注意力
    对解码器输入x做自注意力,但通过trg_mask遮挡"未来还未生成的词",保证生成顺序的合理性。
  2. 交叉注意力
    以解码器当前特征为Q,Encoder输出的memoryK/V,让解码器关注输入文本的全局语义。
  3. 前馈网络
    对交叉注意力的输出做非线性变换,提炼生成特征。
  4. Decoder的前向传播
    输入特征依次经过N个DecoderLayer,逐步生成目标文本的特征表示。
9.6 Decoder在Transformer中的位置

从左侧架构图可见,Decoder是Transformer的右侧模块

  • 输入:经过Output Embedding + 位置编码的目标文本特征(已生成部分)、Encoder输出的memory
  • 输出:目标文本的特征表示,送入后续的Linear+Softmax生成最终的单词概率。

Decoder是Transformer的"文本生成器",核心是多层DecoderLayer的堆叠

  • 每个DecoderLayer通过"掩码自注意力(保证顺序)+交叉注意力(关联输入语义)+前馈网络(提炼特征)",实现目标文本的逐步生成;
  • 依赖Encoder输出的memory,保证生成内容与输入文本的语义一致性;
  • 最终输出的特征经过Linear+Softmax,得到每个位置的单词概率,完成文本生成。

10 WordProbGenerator(词概率生成器)的实现与作用

10.1 WordProbGenerator的核心作用

WordProbGenerator是Transformer的最终输出模块 ,负责将Decoder输出的特征向量转换为词汇表中每个单词的概率,完成文本生成的最后一步。

10.2 WordProbGenerator的结构设计

该模块由线性层(Linear)+ Softmax函数组成:

  • 线性层:将Decoder输出的d_model维特征映射到"词汇表大小"的维度;
  • Softmax函数:将映射后的结果转换为"0~1"的概率分布(每个位置对应一个单词的概率)。
10.3 WordProbGenerator的代码实现(PyTorch)
python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

class WordProbGenerator(nn.Module):
    def __init__(self, d_model: int, vocab_size: int):
        """
        :param d_model: Decoder输出的特征维度
        :param vocab_size: 词汇表的总单词数
        """
        super().__init__()
        # 线性层:将d_model维特征映射到vocab_size维
        self.linear = nn.Linear(d_model, vocab_size)

    def forward(self, x):
        """
        :param x: Decoder的输出特征,shape: [batch_size, seq_len, d_model]
        :return: 每个位置的单词对数概率,shape: [batch_size, seq_len, vocab_size]
        """
        # 1. 线性层映射:d_model → vocab_size
        linear_out = self.linear(x)
        # 2. Softmax转换为概率分布(用log_softmax便于后续计算损失)
        return F.log_softmax(linear_out, dim=-1)
10.4 代码执行流程解析
  1. 线性层映射
    接收Decoder输出的[batch_size, seq_len, d_model]特征,通过nn.Linear(d_model, vocab_size)将每个位置的特征映射为"词汇表大小"的向量(每个元素对应一个单词的得分)。
  2. Softmax概率转换
    对映射后的向量做log_softmax(在dim=-1维度,即词汇表维度),将得分转换为"对数概率"(既保证概率总和为1,又便于计算交叉熵损失)。
10.5 WordProbGenerator在Transformer中的位置

从架构图可见,WordProbGenerator是Transformer的最顶层模块

  • 输入:Decoder输出的特征向量;
  • 输出:每个位置的单词概率分布,用于选择概率最高的单词作为生成结果。

WordProbGenerator是Transformer的"输出终端",核心是线性层+Softmax的组合:

  • 线性层负责"特征→词汇表维度"的映射;
  • Softmax负责将得分转换为概率分布;
  • 最终输出的概率分布,是Transformer生成文本的直接依据(通常选择概率最高的单词作为当前位置的输出)。

11 Transformer完整模型的实现与工作流程

11.1 Transformer完整模型的核心作用

Transformer完整模型是端到端的序列转换模型(如机器翻译、文本生成),通过"编码器+解码器+输出层"的组合,实现从输入文本到目标文本的转换。

11.2 Transformer完整模型的结构设计

完整模型由3个核心部分组成:

  1. Encoder(编码器):处理输入文本,输出全局语义特征;
  2. Decoder(解码器):基于编码器特征和已生成的目标文本,生成新的文本特征;
  3. 输出线性层:将解码器输出映射为词汇表概率分布。
11.3 Transformer完整模型的代码实现(PyTorch)
python 复制代码
import torch.nn as nn
# 需引入前文的Encoder、Decoder

class Transformer(nn.Module):
    def __init__(self, src_vocab, trg_vocab, d_model, N, heads, dropout):
        """
        :param src_vocab: 输入文本的词汇表大小
        :param trg_vocab: 目标文本的词汇表大小
        :param d_model: 模型特征维度
        :param N: 编码器/解码器的堆叠层数
        :param heads: 多头注意力的头数
        :param dropout: dropout比例
        """
        super().__init__()
        # 初始化编码器
        self.encoder = Encoder(src_vocab, d_model, N, heads, dropout)
        # 初始化解码器
        self.decoder = Decoder(trg_vocab, d_model, N, heads, dropout)
        # 输出线性层:将解码器特征映射到目标词汇表维度
        self.out = nn.Linear(d_model, trg_vocab)

    def forward(self, src, trg, src_mask, trg_mask):
        """
        :param src: 输入文本的索引序列,shape: [batch_size, src_seq_len]
        :param trg: 目标文本的索引序列(已生成部分),shape: [batch_size, trg_seq_len]
        :param src_mask: 输入文本的掩码
        :param trg_mask: 目标文本的掩码
        :return: 目标文本的概率分布,shape: [batch_size, trg_seq_len, trg_vocab]
        """
        # 1. 编码器处理输入文本,得到全局语义特征
        e_outputs = self.encoder(src, src_mask)
        # 2. 解码器基于编码器特征和目标文本,生成新特征
        d_output = self.decoder(trg, e_outputs, src_mask, trg_mask)
        # 3. 线性层映射为词汇表概率分布
        output = self.out(d_output)
        return output
11.4 完整模型的工作流程解析

以"机器翻译"任务为例,流程如下:

  1. 输入预处理
    输入文本(如英文句子)转换为索引序列src,目标文本(如中文句子)转换为索引序列trg,并生成对应的掩码src_mask(遮挡填充词)、trg_mask(遮挡未来词)。
  2. 编码器编码
    src经过Input Embedding + 位置编码后,送入Encoder得到全局语义特征e_outputs
  3. 解码器生成
    trg经过Output Embedding + 位置编码后,结合e_outputs送入Decoder,生成当前位置的文本特征d_output
  4. 输出概率分布
    d_output经过线性层out,转换为目标词汇表的概率分布,选择概率最高的单词作为当前位置的输出。
  5. 迭代生成
    将新生成的单词加入trg,重复步骤2-4,直到生成结束符(如<EOS>)。
11.5 Transformer完整模型的意义

Transformer是现代大语言模型的基础架构(如BERT、GPT均基于Transformer的子结构),其核心优势是:

  • 并行计算:相比RNN的串行计算,注意力机制支持并行处理文本,训练/推理效率更高;
  • 长距离依赖:自注意力能直接捕捉文本中长距离的单词关联,更适合处理长文本;
  • 可扩展性:通过堆叠层数、增加头数等方式,可灵活扩展模型能力。

Transformer完整模型是端到端的序列转换框架,核心是"编码器-解码器"结构:

  • 编码器负责提取输入文本的全局语义;
  • 解码器负责基于语义特征生成目标文本;
  • 输出层将特征映射为词汇表概率,完成文本生成;
    它的出现彻底改变了自然语言处理的技术路线,是当前大模型的核心基础。
相关推荐
IT_陈寒2 小时前
JavaScript 性能优化:7 个 V8 引擎偏爱的编码模式让你提速 40%
前端·人工智能·后端
格林威2 小时前
双目视觉标定:消除视差误差的7种核心方案,附OpenCV+Halcon实现代码!
人工智能·数码相机·opencv·计算机视觉·视觉检测·制造
chasemydreamidea2 小时前
书生大模型训练营6期L1 探索大模型能力边界
人工智能·语言模型
却道天凉_好个秋2 小时前
OpenCV(四十四):SIFT计算描述子
人工智能·opencv·计算机视觉
LiYingL2 小时前
USO“,一种基于分离和奖励学习的新方法:走在将风格和主题融为一体的图像生成的最前沿
人工智能·学习·计算机视觉
一方热衷.2 小时前
对图像分割的图片进行缩放的同时调整JSON标签
人工智能·计算机视觉·json
liliangcsdn2 小时前
大模型融合访问开源工具 - LiteLLM
人工智能
ICscholar2 小时前
深度Q网络(DQN)及其变体双深度Q网络(DDQN)对比学习
人工智能·神经网络·学习
serve the people2 小时前
TensorFlow 2.0 手写数字分类教程之SparseCategoricalCrossentropy 核心原理(一)
人工智能·分类·tensorflow