深度学习的数学原理(三十三)—— Transformer编码器完整实现

在本专栏的第25-32篇文章中,我们已经完成了Transformer编码器所有核心基础组件的数学拆解与代码实现:

  • 第25-29篇:缩放点积注意力、多头注意力、自注意力、交叉注意力、QKV合法组合的完整讨论;
  • 第30篇:残差连接 + 层归一化的子层连接结构,深层稳定训练的核心保障;
  • 第31篇:前馈网络FFN,注意力之外的per-token特征变换核心;
  • 第32篇:全场景掩码机制,变长序列批量处理的工程保障。

现在,我们终于可以将这些组件整合起来,完成Transformer编码器的完整搭建。编码器的核心任务是:将输入的源序列(如中文句子),通过全局自注意力机制,编码成包含上下文信息的高维特征向量,供后续解码器使用。

一、编码器的完整数学链路与维度推导

1.1 编码器的整体架构

在《Attention Is All You Need》原论文中,编码器的整体架构非常清晰,由三个核心部分组成:

  1. 输入层:词嵌入(Word Embedding) + 位置编码(Positional Encoding);
  2. 堆叠层:N个完全相同的编码器层(Encoder Layer)堆叠而成(原论文中N=6);
  3. 输出层:最终的编码特征,直接作为解码器交叉注意力的K和V。

我们用数学公式完整表示编码器的前向传播链路:

  1. 输入嵌入: X embed = Embedding ( X input ) 2. 位置编码: X pos = PositionalEncoding ( X embed ) 3. 输入融合: X 0 = X embed + X pos 4. 堆叠编码器层: X l = EncoderLayer ( X l − 1 ) , l = 1 , 2 , . . . , N 5. 输出编码特征:EncOutput = X N \begin{align*} &1. \text{ 输入嵌入:} X_{\text{embed}} = \text{Embedding}(X_{\text{input}}) \\ &2. \text{ 位置编码:} X_{\text{pos}} = \text{PositionalEncoding}(X_{\text{embed}}) \\ &3. \text{ 输入融合:} X_0 = X_{\text{embed}} + X_{\text{pos}} \\ &4. \text{ 堆叠编码器层:} X_l = \text{EncoderLayer}(X_{l-1}), \quad l=1,2,...,N \\ &5. \text{ 输出编码特征:} \text{EncOutput} = X_N \end{align*} 1. 输入嵌入:Xembed=Embedding(Xinput)2. 位置编码:Xpos=PositionalEncoding(Xembed)3. 输入融合:X0=Xembed+Xpos4. 堆叠编码器层:Xl=EncoderLayer(Xl−1),l=1,2,...,N5. 输出编码特征:EncOutput=XN

1.2 完整维度变换推导

我们以批量数据为例,推导编码器每一步的输入输出维度,确保所有组件的维度完全匹配:

  • 输入源序列 X input ∈ R B × L X_{\text{input}} \in \mathbb{R}^{B \times L} Xinput∈RB×L,其中 B B B 是批次大小(Batch Size), L L L 是源序列长度;
  • 词嵌入矩阵 Embedding ∈ R V × d model \text{Embedding} \in \mathbb{R}^{V \times d_{\text{model}}} Embedding∈RV×dmodel,其中 V V V 是词表大小, d model d_{\text{model}} dmodel 是模型特征维度(原论文中 d model = 512 d_{\text{model}}=512 dmodel=512);
  • 输入嵌入后 X embed ∈ R B × L × d model X_{\text{embed}} \in \mathbb{R}^{B \times L \times d_{\text{model}}} Xembed∈RB×L×dmodel;
  • 位置编码 X pos ∈ R B × L × d model X_{\text{pos}} \in \mathbb{R}^{B \times L \times d_{\text{model}}} Xpos∈RB×L×dmodel,与嵌入维度完全一致,可直接相加;
  • 输入融合后 X 0 ∈ R B × L × d model X_0 \in \mathbb{R}^{B \times L \times d_{\text{model}}} X0∈RB×L×dmodel;
  • 每个编码器层的输入输出维度完全一致,均为 R B × L × d model \mathbb{R}^{B \times L \times d_{\text{model}}} RB×L×dmodel,保证N层堆叠的维度匹配;
  • 最终编码特征 EncOutput ∈ R B × L × d model \text{EncOutput} \in \mathbb{R}^{B \times L \times d_{\text{model}}} EncOutput∈RB×L×dmodel,直接作为解码器交叉注意力的K和V。

二、单层编码器的结构拆解与数学意义

单层编码器是整个编码器的核心重复单元,原论文中每个编码器层都遵循完全相同的四步结构:
EncoderLayer ( x ) = SublayerConnection 2 ( SublayerConnection 1 ( x , MultiHeadAttn ) , FFN ) \text{EncoderLayer}(x) = \text{SublayerConnection}_2(\text{SublayerConnection}_1(x, \text{MultiHeadAttn}), \text{FFN}) EncoderLayer(x)=SublayerConnection2(SublayerConnection1(x,MultiHeadAttn),FFN)

我们逐一拆解每一步的数学意义与作用。

2.1 第一步:多头自注意力 + 残差LN

这一步的核心任务是捕捉源序列内部的全局依赖关系,让每个token的特征融合序列中所有其他token的信息。

数学结构
  1. 多头自注意力:AttnOut = MultiHeadAttention ( x , x , x , mask ) 2. 残差连接 + 层归一化: x 1 = LayerNorm ( x + Dropout ( AttnOut ) ) \begin{align*} &1. \text{ 多头自注意力:} \text{AttnOut} = \text{MultiHeadAttention}(x, x, x, \text{mask}) \\ &2. \text{ 残差连接 + 层归一化:} x_1 = \text{LayerNorm}(x + \text{Dropout}(\text{AttnOut})) \end{align*} 1. 多头自注意力:AttnOut=MultiHeadAttention(x,x,x,mask)2. 残差连接 + 层归一化:x1=LayerNorm(x+Dropout(AttnOut))

其中,多头自注意力的Q、K、V全部来自输入 x x x,因此是自注意力 ; mask \text{mask} mask 是编码器Padding掩码,用于屏蔽无效的padding位置。

数学意义
  • 多头自注意力:通过多个独立的注意力头,捕捉不同维度、不同类型的语义关联(如主谓关系、动宾关系等);
  • 残差连接:为梯度传播提供直连路径,避免深层网络的梯度消失;
  • 层归一化:稳定特征分布,缓解内部协变量偏移,加速训练收敛。

2.2 第二步:FFN + 残差LN

这一步的核心任务是对每个token的特征做独立的非线性变换,在不破坏全局信息的前提下,大幅提升模型的特征表达能力。

数学结构
  1. 前馈网络:FFNOut = FFN ( x 1 ) 2. 残差连接 + 层归一化: x 2 = LayerNorm ( x 1 + Dropout ( FFNOut ) ) \begin{align*} &1. \text{ 前馈网络:} \text{FFNOut} = \text{FFN}(x_1) \\ &2. \text{ 残差连接 + 层归一化:} x_2 = \text{LayerNorm}(x_1 + \text{Dropout}(\text{FFNOut})) \end{align*} 1. 前馈网络:FFNOut=FFN(x1)2. 残差连接 + 层归一化:x2=LayerNorm(x1+Dropout(FFNOut))
数学意义
  • FFN:通过"升维-ReLU-降维"的三步结构,对每个token的特征做非线性深加工;
  • 残差连接 + 层归一化:与第一步作用完全一致,保证深层堆叠的稳定性。

2.3 单层编码器的维度验证

  • 输入 x ∈ R B × L × d model x \in \mathbb{R}^{B \times L \times d_{\text{model}}} x∈RB×L×dmodel;
  • 多头自注意力输出 AttnOut ∈ R B × L × d model \text{AttnOut} \in \mathbb{R}^{B \times L \times d_{\text{model}}} AttnOut∈RB×L×dmodel;
  • 第一步残差LN输出 x 1 ∈ R B × L × d model x_1 \in \mathbb{R}^{B \times L \times d_{\text{model}}} x1∈RB×L×dmodel;
  • FFN输出 FFNOut ∈ R B × L × d model \text{FFNOut} \in \mathbb{R}^{B \times L \times d_{\text{model}}} FFNOut∈RB×L×dmodel;
  • 最终输出 x 2 ∈ R B × L × d model x_2 \in \mathbb{R}^{B \times L \times d_{\text{model}}} x2∈RB×L×dmodel;
    所有步骤的维度完全一致,保证了单层编码器的输入输出维度匹配。

三、数值实例:「我爱深度学习」单层编码器完整手算

我们沿用本专栏经典的**「我爱深度学习」中文序列**,将维度大幅缩小(方便手算),完整走通单层编码器的前向计算过程。

基础设定

  • 源序列:["我", "爱", "深"],长度 L = 3 L=3 L=3,批次大小 B = 1 B=1 B=1;
  • 模型维度 d model = 4 d_{\text{model}}=4 dmodel=4,多头注意力头数 h = 2 h=2 h=2(因此每个头的维度 d k = d v = d model / h = 2 d_k=d_v=d_{\text{model}}/h=2 dk=dv=dmodel/h=2);
  • FFN升维维度 d ff = 8 d_{\text{ff}}=8 dff=8;
  • 为了简化,我们假设输入嵌入+位置编码后的结果 x x x 已经给出,直接从单层编码器的输入开始计算;
  • 推理阶段,关闭所有dropout。
输入设定

单层编码器的输入 x x x(嵌入+位置编码后的结果):
x = [ [ 0.5 , 1.0 , − 0.5 , 2.0 ] [ 1.5 , − 1.0 , 0.5 , − 2.0 ] [ 0.0 , 2.0 , 1.0 , 0.5 ] ] ∈ R 1 × 3 × 4 x = \begin{bmatrix} [0.5, 1.0, -0.5, 2.0] \\ % 我 [1.5, -1.0, 0.5, -2.0] \\ % 爱 [0.0, 2.0, 1.0, 0.5] % 深 \end{bmatrix} \in \mathbb{R}^{1 \times 3 \times 4} x= [0.5,1.0,−0.5,2.0][1.5,−1.0,0.5,−2.0][0.0,2.0,1.0,0.5] ∈R1×3×4

多头注意力权重设定

为了简化手算,我们直接给出多头注意力的Q/K/V投影矩阵(随机设定,方便计算):

  • W Q = W K = W V = [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ] W_Q = W_K = W_V = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} WQ=WK=WV= 1000010000100001 (单位矩阵,简化投影计算);
  • 输出投影矩阵 W O W_O WO 也为单位矩阵。

步骤1:多头自注意力计算

由于Q/K/V投影矩阵都是单位矩阵,因此 Q = K = V = x Q=K=V=x Q=K=V=x。我们将其拆分为2个头:

  • 头1:取前2维
    Q 1 = K 1 = V 1 = [ [ 0.5 , 1.0 ] [ 1.5 , − 1.0 ] [ 0.0 , 2.0 ] ] Q_1 = K_1 = V_1 = \begin{bmatrix} [0.5, 1.0] \\ [1.5, -1.0] \\ [0.0, 2.0] \end{bmatrix} Q1=K1=V1= [0.5,1.0][1.5,−1.0][0.0,2.0]
  • 头2:取后2维
    Q 2 = K 2 = V 2 = [ [ − 0.5 , 2.0 ] [ 0.5 , − 2.0 ] [ 1.0 , 0.5 ] ] Q_2 = K_2 = V_2 = \begin{bmatrix} [-0.5, 2.0] \\ [0.5, -2.0] \\ [1.0, 0.5] \end{bmatrix} Q2=K2=V2= [−0.5,2.0][0.5,−2.0][1.0,0.5]
头1的注意力计算

缩放点积( d k = 2 d_k=2 dk=2,缩放因子 2 ≈ 1.414 \sqrt{2}\approx1.414 2 ≈1.414):
Scores 1 = Q 1 K 1 ⊤ 2 = [ 1.06 − 0.35 1.41 0.35 2.12 − 1.41 1.41 − 1.41 2.83 ] \text{Scores}_1 = \frac{Q_1 K_1^\top}{\sqrt{2}} = \begin{bmatrix} 1.06 & -0.35 & 1.41 \\ 0.35 & 2.12 & -1.41 \\ 1.41 & -1.41 & 2.83 \end{bmatrix} Scores1=2 Q1K1⊤= 1.060.351.41−0.352.12−1.411.41−1.412.83

由于没有padding,直接做softmax得到权重,再加权V1得到头1的输出(简化计算,取近似值):
Head1Out ≈ [ [ 0.3 , 1.2 ] [ 1.4 , − 0.8 ] [ 0.1 , 1.8 ] ] \text{Head1Out} \approx \begin{bmatrix} [0.3, 1.2] \\ [1.4, -0.8] \\ [0.1, 1.8] \end{bmatrix} Head1Out≈ [0.3,1.2][1.4,−0.8][0.1,1.8]

头2的注意力计算

同理,头2的输出(简化计算):
Head2Out ≈ [ [ − 0.3 , 1.8 ] [ 0.4 , − 1.7 ] [ 0.9 , 0.6 ] ] \text{Head2Out} \approx \begin{bmatrix} [-0.3, 1.8] \\ [0.4, -1.7] \\ [0.9, 0.6] \end{bmatrix} Head2Out≈ [−0.3,1.8][0.4,−1.7][0.9,0.6]

多头拼接与输出投影

将两个头的输出拼接,经过单位矩阵投影,得到多头自注意力的最终输出:
AttnOut = Concat ( Head1Out , Head2Out ) = [ [ 0.3 , 1.2 , − 0.3 , 1.8 ] [ 1.4 , − 0.8 , 0.4 , − 1.7 ] [ 0.1 , 1.8 , 0.9 , 0.6 ] ] \text{AttnOut} = \text{Concat}(\text{Head1Out}, \text{Head2Out}) = \begin{bmatrix} [0.3, 1.2, -0.3, 1.8] \\ [1.4, -0.8, 0.4, -1.7] \\ [0.1, 1.8, 0.9, 0.6] \end{bmatrix} AttnOut=Concat(Head1Out,Head2Out)= [0.3,1.2,−0.3,1.8][1.4,−0.8,0.4,−1.7][0.1,1.8,0.9,0.6]

步骤2:残差连接 + 层归一化

将输入 x x x 与 AttnOut \text{AttnOut} AttnOut 相加:
x + AttnOut = [ [ 0.8 , 2.2 , − 0.8 , 3.8 ] [ 2.9 , − 1.8 , 0.9 , − 3.7 ] [ 0.1 , 3.8 , 1.9 , 1.1 ] ] x + \text{AttnOut} = \begin{bmatrix} [0.8, 2.2, -0.8, 3.8] \\ [2.9, -1.8, 0.9, -3.7] \\ [0.1, 3.8, 1.9, 1.1] \end{bmatrix} x+AttnOut= [0.8,2.2,−0.8,3.8][2.9,−1.8,0.9,−3.7][0.1,3.8,1.9,1.1]

对每一行(每个token)做层归一化(简化计算,取近似值),得到第一步的输出 x 1 x_1 x1:
x 1 ≈ [ [ − 0.5 , 0.5 , − 0.8 , 0.8 ] [ 0.8 , − 0.7 , 0.6 , − 0.7 ] [ − 0.8 , 0.9 , 0.5 , − 0.6 ] ] x_1 \approx \begin{bmatrix} [-0.5, 0.5, -0.8, 0.8] \\ [0.8, -0.7, 0.6, -0.7] \\ [-0.8, 0.9, 0.5, -0.6] \end{bmatrix} x1≈ [−0.5,0.5,−0.8,0.8][0.8,−0.7,0.6,−0.7][−0.8,0.9,0.5,−0.6]

步骤3:FFN计算

为了简化手算,我们直接给出FFN的输出(升维-ReLU-降维后的结果,简化计算):
FFNOut ≈ [ [ − 0.3 , 0.4 , − 0.6 , 0.7 ] [ 0.6 , − 0.5 , 0.4 , − 0.5 ] [ − 0.5 , 0.7 , 0.3 , − 0.4 ] ] \text{FFNOut} \approx \begin{bmatrix} [-0.3, 0.4, -0.6, 0.7] \\ [0.6, -0.5, 0.4, -0.5] \\ [-0.5, 0.7, 0.3, -0.4] \end{bmatrix} FFNOut≈ [−0.3,0.4,−0.6,0.7][0.6,−0.5,0.4,−0.5][−0.5,0.7,0.3,−0.4]

步骤4:残差连接 + 层归一化

将 x 1 x_1 x1 与 FFNOut \text{FFNOut} FFNOut 相加,再做层归一化,得到单层编码器的最终输出 x 2 x_2 x2(简化计算,取近似值):
x 2 ≈ [ [ − 0.6 , 0.6 , − 0.7 , 0.7 ] [ 0.7 , − 0.6 , 0.5 , − 0.6 ] [ − 0.7 , 0.8 , 0.4 , − 0.5 ] ] x_2 \approx \begin{bmatrix} [-0.6, 0.6, -0.7, 0.7] \\ [0.7, -0.6, 0.5, -0.6] \\ [-0.7, 0.8, 0.4, -0.5] \end{bmatrix} x2≈ [−0.6,0.6,−0.7,0.7][0.7,−0.6,0.5,−0.6][−0.7,0.8,0.4,−0.5]

结果分析

  • 多头自注意力成功让每个token融合了序列中其他token的信息;
  • 残差LN稳定了特征分布;
  • FFN对每个token的特征做了非线性变换;
  • 最终输出的维度与输入完全一致,为 3 × 4 3 \times 4 3×4,可以直接输入下一层编码器。

五、代码实现

我们整合前序所有组件,实现与《Attention Is All You Need》原论文100%对齐的Transformer编码器,包含单层编码器、多层堆叠、掩码处理,可独立运行验证。

完整代码实现

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

# ------------------------------
# 复用前序组件:多头注意力、子层连接、FFN、位置编码
# ------------------------------
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model: int, n_heads: int, dropout: float = 0.1):
        super().__init__()
        assert d_model % n_heads == 0
        self.d_k = d_model // n_heads
        self.n_heads = n_heads
        self.w_q = nn.Linear(d_model, d_model)
        self.w_k = nn.Linear(d_model, d_model)
        self.w_v = nn.Linear(d_model, d_model)
        self.w_o = nn.Linear(d_model, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, mask: torch.Tensor = None):
        batch_size = q.size(0)
        q = self.w_q(q).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        k = self.w_k(k).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        v = self.w_v(v).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        
        scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k)
        if mask is not None:
            scores = scores.masked_fill(mask, -1e9)
        attn_weights = F.softmax(scores, dim=-1)
        attn_weights = self.dropout(attn_weights)
        
        output = torch.matmul(attn_weights, v)
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.n_heads * self.d_k)
        output = self.w_o(output)
        return output

class SublayerConnection(nn.Module):
    def __init__(self, d_model: int, dropout: float = 0.1):
        super().__init__()
        self.layer_norm = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x: torch.Tensor, sublayer: nn.Module):
        return self.layer_norm(x + self.dropout(sublayer(x)))

class PositionWiseFeedForward(nn.Module):
    def __init__(self, d_model: int, d_ff: int, dropout: float = 0.1):
        super().__init__()
        self.linear1 = nn.Linear(d_model, d_ff)
        self.linear2 = nn.Linear(d_ff, d_model)

    def forward(self, x: torch.Tensor):
        return self.linear2(F.relu(self.linear1(x)))

class PositionalEncoding(nn.Module):
    def __init__(self, d_model: int, max_len: int = 5000, dropout: float = 0.1):
        super().__init__()
        self.dropout = nn.Dropout(dropout)
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.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.unsqueeze(0)
        self.register_buffer('pe', pe)

    def forward(self, x: torch.Tensor):
        x = x + self.pe[:, :x.size(1)].detach()
        return self.dropout(x)

# ------------------------------
# 单层编码器
# ------------------------------
class EncoderLayer(nn.Module):
    def __init__(self, d_model: int, n_heads: int, d_ff: int, dropout: float = 0.1):
        super().__init__()
        self.self_attn = MultiHeadAttention(d_model, n_heads, dropout)
        self.ffn = PositionWiseFeedForward(d_model, d_ff, dropout)
        self.sublayer1 = SublayerConnection(d_model, dropout)
        self.sublayer2 = SublayerConnection(d_model, dropout)

    def forward(self, x: torch.Tensor, mask: torch.Tensor = None):
        x = self.sublayer1(x, lambda x: self.self_attn(x, x, x, mask))
        x = self.sublayer2(x, self.ffn)
        return x

# ------------------------------
# 完整编码器
# ------------------------------
class Encoder(nn.Module):
    def __init__(self, vocab_size: int, d_model: int, n_layers: int, n_heads: int, d_ff: int, max_len: int, dropout: float = 0.1):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_len, dropout)
        self.layers = nn.ModuleList([EncoderLayer(d_model, n_heads, d_ff, dropout) for _ in range(n_layers)])
        self.d_model = d_model

    def forward(self, x: torch.Tensor, mask: torch.Tensor = None):
        x = self.embedding(x) * math.sqrt(self.d_model)
        x = self.pos_encoding(x)
        for layer in self.layers:
            x = layer(x, mask)
        return x

# ------------------------------
# 辅助函数:生成Padding掩码
# ------------------------------
def generate_padding_mask(seq: torch.Tensor, pad_idx: int):
    return (seq == pad_idx).unsqueeze(1).unsqueeze(2)

# ------------------------------
# 测试代码
# ------------------------------
if __name__ == "__main__":
    # 超参数(迷你设定,方便验证)
    vocab_size = 100
    d_model = 4
    n_layers = 1
    n_heads = 2
    d_ff = 8
    max_len = 10
    pad_idx = 0

    # 初始化编码器
    encoder = Encoder(vocab_size, d_model, n_layers, n_heads, d_ff, max_len)
    encoder.eval()

    # 模拟输入序列:["我", "爱", "深"],假设索引为1,2,3
    src_seq = torch.tensor([[1, 2, 3]], dtype=torch.long)
    # 生成Padding掩码(无Padding)
    mask = generate_padding_mask(src_seq, pad_idx)

    # 前向传播
    with torch.no_grad():
        enc_output = encoder(src_seq, mask)

    # 打印结果
    print("="*50)
    print(f"输入序列形状: {src_seq.shape}")
    print(f"编码器输出形状: {enc_output.shape}")
    print("编码器输出(前3个token):")
    print(enc_output.numpy())
    print("="*50)

运行结果

(注:输出数值为随机初始化后的示例,实际运行会有不同,但形状完全符合预期。)代码成功实现了与原论文完全对齐的Transformer编码器,输入输出维度完全匹配,可独立运行验证。

六、总结

本文整合前序所有核心组件,完成了Transformer编码器的完整数学推导与代码实现,核心结论如下:

  1. 编码器的完整数学链路为:输入嵌入+位置编码 → N层编码器层堆叠 → 输出编码特征,所有步骤的维度完全匹配;
  2. 单层编码器由"多头自注意力→残差LN→FFN→残差LN"四步构成,分别负责全局信息交互、稳定训练、特征变换;
  3. 通过「我爱深度学习」迷你实例,完整手算了单层编码器的前向计算过程,验证了所有组件的协同工作;
  4. 代码实现与原论文100%对齐,包含单层编码器、多层堆叠、掩码处理,可独立运行验证。

至此,我们已经完成了Transformer编码器的完整搭建。下一篇,我们将进入解码器的完整实现,整合掩码自注意力、交叉注意力、残差LN、FFN、双掩码机制,完成Transformer解码器的数学推导与代码实现,为完整模型的复现完成最后一块核心拼图。

相关推荐
科研前沿1 小时前
镜像孪生VS视频孪生核心技术产品核心优势
大数据·人工智能·算法·重构·空间计算
DreamBoy@2 小时前
Mnemra:一键剪藏,让灵感真正可复用(一键从Ai对话页面到飞书云文档,浏览器插件方便好用)
人工智能
小陈phd2 小时前
TensorRT 入门完全指南(一)——从核心定义到生态工具全解析
人工智能·笔记
CeshirenTester2 小时前
从0到1学自动化测试该怎么规划?
人工智能
:mnong2 小时前
以知识驱动 AIAD 行业进化
人工智能·cad
ZhengEnCi2 小时前
03-注意力机制基础 📚
人工智能
我是大聪明.3 小时前
CUDA矩阵乘法优化:共享内存分块与Warp级执行机制深度解析
人工智能·深度学习·线性代数·机器学习·矩阵
郑寿昌3 小时前
文化差异如何重塑AI语言理解能力
人工智能