【速写】Transformer-encoder-decoder深度解析

news2025/4/19 13:18:38

文章目录

  • 一、理论分析
    • 1. Transformers概述
    • 2. Transformer的输入部分具体是如何构成?
      • 2.1 单词 Embedding
      • 2.2 位置 Embedding
    • 3 自注意力原理
      • 3.1 自注意力结构
      • 3.2 QKV的计算
      • 3.3 自注意力的输出
      • 3.4 多头注意力
    • 4 Encoder结构
      • 4.1 AddNorm
      • 4.2 前馈
      • 4.3 组成Encoder
  • 二、代码实现细节


一、理论分析

1. Transformers概述

在这里插入图片描述
Transformers由6个encoder和6个decoder组成:

在这里插入图片描述

工作流程:

  1. 获取输入句子的每一个单词的表示向量 X X X,由单词的embedding和位置编码相加得到:
    在这里插入图片描述

  2. 将嵌入矩阵 X ∈ R n × d X\in\R^{n\times d} XRn×d输入到Encoder中,经过6个encoder block后得到句子所有单词的编码信息矩阵 C C C,其中 n n n是句中单词数量, d d d是单词维度(论文中为 d = 512 d=512 d=512
    每一个encoderblock的输出矩阵与输入矩阵形状相同

    在这里插入图片描述

(细节:这里会按照词根来划分token,比如doing会被分成do和ing来编码)

  1. 将Encoder输出的编码矩阵 C C C传递到Decoder中,Decoder依次会根据当前翻译过的单词 1 , 2 , . . . , i 1,2,...,i 1,2,...,i来翻译下一个单词 i + 1 i+1 i+1

    • 实际使用中,翻译到第 i + 1 i+1 i+1个单词时需要通过Mask来遮盖住 i + 1 i+1 i+1之后的单词:

    在这里插入图片描述

    • Decoder接收了 C C C然后输出一个翻译开始符<Begin>,预测第一个单词 i i i
    • 然后输入<Begin> i,预测单词have,以此类推
    • 这是Transformer使用的大致流程

2. Transformer的输入部分具体是如何构成?

Transformer 中单词的输入表示 x由单词 Embedding 和位置 Embedding 相加得到。

2.1 单词 Embedding

  • 单词的 Embedding 有很多种方式可以获取,
  • 例如可以采用 Word2Vec、Glove 等算法预训练得到,也可以在 Transformer 中训练得到。

2.2 位置 Embedding

  • Transformer 中除了单词的 Embedding,还需要使用位置 Embedding 表示单词出现在句子中的位置。
  • 因为 Transformer 不采用 RNN 的结构,而是使用全局信息,不能利用单词的顺序信息,而这部分信息对于 NLP 来说非常重要。
  • 所以 Transformer 中使用位置 Embedding 保存单词在序列中的相对或绝对位置。
  • 位置 Embedding用 PE表示,PE的维度与单词 Embedding 是一样的。
  • PE 可以通过训练得到,也可以使用某种公式计算得到。在Transformer 中采用了后者,计算公式如下:

P E ( p o s , 2 i ) = sin ⁡ ( p o s / 1000 0 2 i / d ) P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s / 1000 0 2 i / d ) PE(pos, 2i) = \sin (pos / 10000^{2i/d})\\ PE(pos, 2i + 1) = \cos(pos / 10000^{2i/d}) PE(pos,2i)=sin(pos/100002i/d)PE(pos,2i+1)=cos(pos/100002i/d)

  • pos 表示单词在句子中的位置,d表示 PE的维度(与词 Embedding 一样)
  • 2i 表示偶数的维度,2i+1表示奇数维度 (即 2i < d, 2i + 1 < d)。

使用这种公式计算PE的好处:

  • 使 PE 能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20 个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以快速计算出第 21 位的 Embedding。
  • 可以让模型容易地计算出相对位置,对于固定长度的间距k,PE(poS+k)可以用 PE(poS)计算得到。因为:
Sin(A+B)=Sin(A)Cos(B)+Cos(A)Sin(B),
Cos(A+B)=Cos(A)Cos(B)-Sin(A)Sin(B)
  • 将单词的词 Embedding 和位置 Embedding相加,就可以得到单词的表示向量x,x就是 Transformer 的输入。

3 自注意力原理

在这里插入图片描述

  • 红色圈忠的部分是多头注意力,是由多个自注意力组成,可以看到:

    • Encoder包含一个多头注意力
    • Decoder包含两个多头注意力(其中一个用到Mask)
  • 多头注意力上方还包括一个AddNorm层,就是残差连接加层正则化(LayerNorm)

3.1 自注意力结构

在这里插入图片描述

  • 输入: Q , K , V Q,K,V Q,K,V
  • 实际操作忠,自注意力接收的是输入(单词的表示向量组成的矩阵 X X X)或者上一个Encoder block的输出
  • Q , K , V Q,K,V Q,K,V正是通过自注意力的输入进行线性变换得到

3.2 QKV的计算

自注意力的输入用矩阵 X X X表示,则可以使用线性变换矩阵 W Q , W K , W V W_Q,W_K,W_V WQ,WK,WV计算得到 Q , K , V Q,K,V Q,K,V,计算如下图所示,注意 X , Q , K , V X,Q,K,V X,Q,K,V的每一行都表示一个单词:

在这里插入图片描述

3.3 自注意力的输出

得到矩阵 Q , K , V Q,K,V Q,K,V之后就可以计算出自注意力的输出了:

A t t ( Q , K , V ) = s o f t m a x ( Q K ⊤ d ) V Att(Q,K,V)={\rm softmax}\left(\frac{QK^\top}{\sqrt{d}}\right)V Att(Q,K,V)=softmax(d QK)V

其中 d k d_k dk Q , K Q,K Q,K的列数,即向量维度,论文中 d = 512 d=512 d=512

  • 公式中计算矩阵 Q Q Q K K K每一行向量的内积,为了防止内积过大,因此除以 d k d_k dk的平方根
  • Q Q Q乘以 K K K的转置后,得到的矩阵行列数都为 n n n n n n为句子单词数,这个矩阵可以表示单词之间的attention强度
  • 下图为 Q K ⊤ QK^\top QK,1234表示句子中的单词:

在这里插入图片描述

  • 得到 Q K ⊤ QK^\top QK之后,使用softmax计算每一个单词对于其他单词的attention系数
  • 公式中的softmax是对矩阵的每一行进行softmax,即每一行的和都变为1

在这里插入图片描述

  • 得到softmax矩阵后可以和 V V V相乘,得到最终输出 Z Z Z

在这里插入图片描述

  • 上图中Softmax矩阵的第一行表示单词1和其他所有单词的attention系数
  • 最终单词1和输出 Z 1 Z_1 Z1等于所有单词 i i i的值 V i V_i Vi根据attention系数的比例加在一起得到,如下图所示:

在这里插入图片描述

3.4 多头注意力

在这里插入图片描述

  1. 首先将输入 X X X分别传递到 h h h个不同的自注意力中,计算得到 h h h个输出矩阵 Z Z Z,论文中 h = 8 h=8 h=8,即得到8个输出矩阵 Z Z Z
    在这里插入图片描述

  2. 得到 Z 1 Z_1 Z1 Z 8 Z_8 Z8之后,多头就是直接拼接,然后传入到Linear层,得到多头注意力最终输出 Z \bf Z Z,这里 Z \bf Z Z其实和那个是一个形状的。

在这里插入图片描述


4 Encoder结构

编码器由多头注意力残差连接+正则(ADD&NORM)前馈和**残差连接+正则(ADD&NORM)**组成

4.1 AddNorm

L a y e r N o r m ( X + M u l t i H e a d A t t ( X ) ) L a y e r N o r m ( X + F e e d F o r w a r d ( X ) ) LayerNorm(X+MultiHeadAtt(X))\\ LayerNorm(X+FeedForward(X)) LayerNorm(X+MultiHeadAtt(X))LayerNorm(X+FeedForward(X))

4.2 前馈

两层的全连接层,第一层激活用ReLU,第二层不用激活:

max ⁡ ( 0 , X W 1 + b 1 ) W 2 + b 2 \max(0, XW_1+b_1)W_2+b_2 max(0,XW1+b1)W2+b2

4.3 组成Encoder

Encoder block接收输入矩阵 X ∈ R n × d X\in\R^{n\times d} XRn×d,输出 O ∈ R n × d O\in\R^{n\times d} ORn×d,通过多个Encoder block叠加得到Encoder

  • 第一个Encoder的输入是句子单词的表示向量矩阵
  • 后续Encoder的输入是前一个Encoder的输出
  • 最后一个Encoder的输出就是编码信息矩阵 C C C

在这里插入图片描述


二、代码实现细节

video

import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from IPython.display import Image
# default: 100
mpl.rcParams['figure.dpi'] = 150

torch.manual_seed(42)

在这里插入图片描述

  • pytorch transformer (seq modeling) => transformers (hf, focus on language models) => LLM
  • pytorch
    • nn.TransformerEncoderLayer => nn.TransformerEncoder
      • TransformerEncoder is a stack of N encoder layers.
      • BERT
    • nn.TransformerDecoderLayer => nn.TransformerDecoder
      • TransformerDecoder is a stack of N decoder layers.
      • GPT
  • decoder 与 encoder 相比,有两个特殊的 attention sublayers
    • masked multi-head (self) attention
    • encoder-decoder (cross) attention
      • (k, v) from encoder (memory, last encoder layer)
      • q:decoder input
      • multihead_attn(x, mem, mem) from TransformerDecoderLayer
    • 两者权值不共享

(masked) multi-head attention

https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html

  • Encoder Self-Attention:
    • No Masking:
      • Since attn_bias is zero, the attention weights depend solely on the scaled dot product:
        Scores encoder = Q K ⊤ d k \text{Scores}_{\text{encoder}} = \frac{Q K^\top}{\sqrt{d_k}} Scoresencoder=dk QK
        Attention encoder = softmax ( Scores encoder ) \text{Attention}_{\text{encoder}} = \text{softmax}(\text{Scores}_{\text{encoder}}) Attentionencoder=softmax(Scoresencoder)
      • Each token attends to all tokens, including future ones.
  • Decoder Masked Self-Attention:
    • Causal Masking:
      • The mask M is defined as:
        M i , j = { 0 if  j ≤ i − ∞ if  j > i M_{i,j} = \begin{cases} 0 & \text{if } j \leq i \\ -\infty & \text{if } j > i \end{cases} Mi,j={0if jiif j>i
      • The attention scores become:
        Scores decoder = Q K ⊤ d k + M \text{Scores}_{\text{decoder}} = \frac{Q K^\top}{\sqrt{d_k}} + M Scoresdecoder=dk QK+M
      • Applying softmax:
        Attention decoder = softmax ( Scores decoder ) \text{Attention}_{\text{decoder}} = \text{softmax}(\text{Scores}_{\text{decoder}}) Attentiondecoder=softmax(Scoresdecoder)
        • The -inf in M ensures that positions where ( j > i ) (future positions) have zero attention weight.

encoder layer & encoder

  • input: X ∈ R T × B × d model \mathbf{X} \in \mathbb{R}^{T \times B \times d_{\text{model}}} XRT×B×dmodel
    1. multihead selfattn
    • 线性变换(linear projection, 矩阵乘法)生成 Q、K、V矩阵
    • X flat = X . reshape ( T × B , d m o d e l ) X_{\text{flat}}=\mathbf X.\text{reshape}(T\times B,d_{model}) Xflat=X.reshape(T×B,dmodel)
    • Q K V = X W i n T + b i n \mathbf{QKV}=\mathbf X\mathbf W_{in}^T+\mathbf b_{in} QKV=XWinT+binencoder_layer.self_attn.in_proj_weight, encoder_layer.self_attn.in_proj_bias
      • W i n ∈ R 3 d model × d model \mathbf{W}_{in} \in \mathbb{R}^{3d_{\text{model}} \times d_{\text{model}}} WinR3dmodel×dmodel b i n ∈ R 3 d model \mathbf{b}_{in} \in \mathbb{R}^{3d_{\text{model}}} binR3dmodel
      • Q K V ∈ R T × B , 3 d m o d e l \mathbf{QKV}\in \mathbb R^{T\times B,3d_{model}} QKVRT×B,3dmodel
    • 拆分 Q , K , V \mathbf Q, \mathbf K,\mathbf V Q,K,V
      • Q , K , V = split ( Q K V , d m o d e l ) \mathbf Q, \mathbf K,\mathbf V=\text{split}(\mathbf{QKV},d_{model}) Q,K,V=split(QKV,dmodel)(按列进行拆分)
      • Q , K , V ∈ R T × B , d model \mathbf Q, \mathbf K,\mathbf V\in \mathbb R^{T \times B, d_{\text{model}}} Q,K,VRT×B,dmodel
    • 调整形状以适应多头注意力
      • d k = d model h d_k = \frac{d_{\text{model}}}h dk=hdmodel
      • reshape_for_heads
        Q heads = Q . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) K heads = K . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) V heads = V . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) \begin{align*} \mathbf{Q}_{\text{heads}} &= \mathbf{Q}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \\ \mathbf{K}_{\text{heads}} &= \mathbf{K}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \\ \mathbf{V}_{\text{heads}} &= \mathbf{V}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \end{align*} QheadsKheadsVheads=Q.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)=K.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)=V.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)
    • 计算注意力分数: Scores = Q heads K heads ⊤ d k \text{Scores} = \frac{\mathbf{Q}_{\text{heads}} \mathbf{K}_{\text{heads}}^\top}{\sqrt{d_k}} Scores=dk QheadsKheads
      • Q heads ∈ R ( B × h ) × T × d k \mathbf{Q}_{\text{heads}} \in \mathbb{R}^{(B \times h) \times T \times d_k} QheadsR(B×h)×T×dk K heads ⊤ ∈ R ( B × h ) × d k × T \mathbf{K}_{\text{heads}}^\top \in \mathbb{R}^{(B \times h) \times d_k \times T} KheadsR(B×h)×dk×T,因此 Scores ∈ R ( B × h ) × T × T \text{Scores} \in \mathbb{R}^{(B \times h) \times T \times T} ScoresR(B×h)×T×T
    • 计算注意力权重: AttentionWeights = softmax ( Scores ) \text{AttentionWeights}=\text{softmax}(\text{Scores}) AttentionWeights=softmax(Scores)
    • 计算注意力输出: AttentionOutput = AttentionWeights × V heads \text{AttentionOutput}=\text{AttentionWeights}\times{\mathbf V_\text{heads}} AttentionOutput=AttentionWeights×Vheads
      • V heads ∈ R ( B × h ) × T × d k \mathbf{V}_{\text{heads}} \in \mathbb{R}^{(B \times h) \times T \times d_k} VheadsR(B×h)×T×dk,因此 AttentionOutput ∈ R ( B × h ) × T × d k \text{AttentionOutput} \in \mathbb{R}^{(B \times h) \times T \times d_k} AttentionOutputR(B×h)×T×dk
    • 合并多头输出: AttentionOutput = AttentionOutput . reshape ( B , h , T , d k ) . permute ( 2 , 0 , 1 , 3 ) . reshape ( T , B , d model ) \text{AttentionOutput} = \text{AttentionOutput}.\text{reshape}(B, h, T, d_k).\text{permute}(2, 0, 1, 3).\text{reshape}(T, B, d_{\text{model}}) AttentionOutput=AttentionOutput.reshape(B,h,T,dk).permute(2,0,1,3).reshape(T,B,dmodel)
    • 输出线性变换: AttnOutputProjected = AttentionOutput W out ⊤ + b out \text{AttnOutputProjected} = \text{AttentionOutput} \mathbf{W}_{\text{out}}^\top + \mathbf{b}_{\text{out}} AttnOutputProjected=AttentionOutputWout+bout
      • W out ∈ R d model × d model \mathbf{W}_{\text{out}} \in \mathbb{R}^{d{_\text{model}} \times d_{\text{model}}} WoutRdmodel×dmodel b out ∈ R d model \mathbf{b}_{\text{out}} \in \mathbb{R}^{d_{\text{model}}} boutRdmodel,对应代码中的out_proj_weightout_proj_bias
    1. 残差连接和层归一化(第一层)
    • 残差连接: Residual1 = X + AttnOutputProjected \text{Residual1} = \mathbf{X} + \text{AttnOutputProjected} Residual1=X+AttnOutputProjected
    • 层归一化: Normalized1 = LayerNorm ( Residual1 , γ norm1 , β norm1 ) \text{Normalized1} = \text{LayerNorm}(\text{Residual1}, \gamma_{\text{norm1}}, \beta_{\text{norm1}}) Normalized1=LayerNorm(Residual1,γnorm1,βnorm1)
      • γ norm1 , β norm1 ∈ R d model \gamma_{\text{norm1}}, \beta_{\text{norm1}} \in \mathbb{R}^{d_{\text{model}}} γnorm1,βnorm1Rdmodel,对应代码中的norm1.weightnorm1.bias
    1. 前馈神经网络 (ffn)
    • 第一层线性变换和激活函数: FFNOutput1 = ReLU ( Normalized1 W 1 ⊤ + b 1 ) \text{FFNOutput1} = \text{ReLU}(\text{Normalized1} \mathbf{W}_1^\top + \mathbf{b}_1) FFNOutput1=ReLU(Normalized1W1+b1)
      • 其中, W 1 ∈ R d ff × d model \mathbf{W}_1 \in \mathbb{R}^{d_{\text{ff}} \times d_{\text{model}}} W1Rdff×dmodel b 1 ∈ R d ff \mathbf{b}_1 \in \mathbb{R}^{d_{\text{ff}}} b1Rdff,对应代码中的 linear1.weightlinear1.bias
    • 第二层线性变换: FFNOutput2 = FFNOutput1 W 2 ⊤ + b 2 \text{FFNOutput2} = \text{FFNOutput1} \mathbf{W}_2^\top + \mathbf{b}_2 FFNOutput2=FFNOutput1W2+b2
      • 其中, W 2 ∈ R d model × d ff \mathbf{W}_2 \in \mathbb{R}^{d_{\text{model}} \times d_{\text{ff}}} W2Rdmodel×dff b 2 ∈ R d model \mathbf{b}_2 \in \mathbb{R}^{d_{\text{model}}} b2Rdmodel,对应代码中的 linear2.weightlinear2.bias
    1. 残差连接和层归一化(第二层)
    • 残差连接: Residual2 = Normalized1 + FFNOutput2 \text{Residual2} = \text{Normalized1} + \text{FFNOutput2} Residual2=Normalized1+FFNOutput2
    • 层归一化: Output = LayerNorm ( Residual2 , γ norm2 , β norm2 ) \text{Output} = \text{LayerNorm}(\text{Residual2}, \gamma_{\text{norm2}}, \beta_{\text{norm2}}) Output=LayerNorm(Residual2,γnorm2,βnorm2)
      • 其中, γ norm2 , β norm2 ∈ R d model \gamma_{\text{norm2}}, \beta_{\text{norm2}} \in \mathbb{R}^{d_{\text{model}}} γnorm2,βnorm2Rdmodel,对应代码中的 norm2.weightnorm2.bias
d_model = 4  # 模型维度
nhead = 2    # 多头注意力中的头数
dim_feedforward = 8  # 前馈网络的维度
batch_size = 1
seq_len = 3

assert d_model % nhead == 0
encoder_input = torch.randn(seq_len, batch_size, d_model)  # [seq_len, batch_size, d_model]
# 禁用 droput
encoder_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead,
                                           dim_feedforward=dim_feedforward, dropout=0.0)
                                           memory = encoder_layer(encoder_input)  # 编码器输出
memory
"""
tensor([[[-1.0328, -0.9185,  0.6710,  1.2804]],
        [[-1.4175, -0.1948,  1.3775,  0.2347]],
        [[-1.0022, -0.8035,  0.3029,  1.5028]]],
       grad_fn=<NativeLayerNormBackward0>)
"""
encoder_input.shape, memory.shape # (torch.Size([3, 1, 4]), torch.Size([3, 1, 4]))

手写encoder

encoder_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead,
                                           dim_feedforward=dim_feedforward, dropout=0.0)

形如:

TransformerEncoderLayer(
  (self_attn): MultiheadAttention(
    (out_proj): NonDynamicallyQuantizableLinear(in_features=4, out_features=4, bias=True)
  )
  (linear1): Linear(in_features=4, out_features=8, bias=True)
  (dropout): Dropout(p=0.0, inplace=False)
  (linear2): Linear(in_features=8, out_features=4, bias=True)
  (norm1): LayerNorm((4,), eps=1e-05, elementwise_affine=True)
  (norm2): LayerNorm((4,), eps=1e-05, elementwise_affine=True)
  (dropout1): Dropout(p=0.0, inplace=False)
  (dropout2): Dropout(p=0.0, inplace=False)
)

调整模型输入的形状

X = encoder_input  # [3, 1, 4]
X_flat = X.contiguous().view(-1, d_model)  # [T * B, d_model] -> [3, 4]

多层注意力层

self_attn = encoder_layer.self_attn
# d_model = 4
# (3d_model, d_model), (3d_model)
self_attn.in_proj_weight.shape, self_attn.in_proj_bias.shape # (torch.Size([12, 4]), torch.Size([12]))
# d_model = 4
# (d_model, d_model), (d_model) 
self_attn.out_proj.weight.shape, self_attn.out_proj.bias.shape # (torch.Size([4, 4]), torch.Size([4]))

W_in = self_attn.in_proj_weight
b_in = self_attn.in_proj_bias

W_out = self_attn.out_proj.weight
b_out = self_attn.out_proj.bias

QKV = F.linear(X_flat, W_in, b_in)  # [3, 3*d_model]
QKV.shape # torch.Size([3, 12])

Q, K, V = QKV.split(d_model, dim=1)  # 每个维度为[3, d_model]
Q.shape, K.shape, V.shape # (torch.Size([3, 4]), torch.Size([3, 4]), torch.Size([3, 4]))

# 调整Q、K、V的形状以适应多头注意力
head_dim = d_model // nhead  # 每个头的维度
def reshape_for_heads(x):
    return x.contiguous().view(seq_len, batch_size, nhead, head_dim).permute(1, 2, 0, 3).reshape(batch_size * nhead, seq_len, head_dim)

Q = reshape_for_heads(Q)
K = reshape_for_heads(K)
V = reshape_for_heads(V)
# B*h, T, d_k
Q.shape, K.shape, V.shape # (torch.Size([2, 3, 2]), torch.Size([2, 3, 2]), torch.Size([2, 3, 2]))
# 计算注意力分数
scores = torch.bmm(Q, K.transpose(1, 2)) / (head_dim ** 0.5)  # [batch_size * nhead, seq_len, seq_len]

# 应用softmax
attn_weights = F.softmax(scores, dim=-1)  # [batch_size * nhead, seq_len, seq_len]

# 计算注意力输出
attn_output = torch.bmm(attn_weights, V)  # [batch_size * nhead, seq_len, head_dim]

# 调整形状以合并所有头的输出
attn_output = attn_output.view(batch_size, nhead, seq_len, head_dim).permute(2, 0, 1, 3).contiguous()
attn_output = attn_output.view(seq_len, batch_size, d_model)  # [seq_len, batch_size, d_model]

# 通过输出投影层
attn_output = F.linear(attn_output.view(-1, d_model), W_out, b_out)  # [seq_len * batch_size, d_model]
attn_output = attn_output.view(seq_len, batch_size, d_model)

这里我们看一下atten_weights.sum(dim=-1)

tensor([[1.0000, 1.0000, 1.0000],
        [1.0000, 1.0000, 1.0000]], grad_fn=<SumBackward1>)

即就是一个加权平均

残差连接和层归一化(第一层)

norm1 = encoder_layer.norm1
residual = X + attn_output  # [seq_len, batch_size, d_model]
normalized = F.layer_norm(residual, (d_model,), weight=norm1.weight, bias=norm1.bias)  # [seq_len, batch_size, d_model]

通过前馈神经网络:

W_1 = encoder_layer.linear1.weight
b_1 = encoder_layer.linear1.bias

W_2 = encoder_layer.linear2.weight
b_2 = encoder_layer.linear2.bias

norm2 = encoder_layer.norm2

ffn_output = F.linear(normalized.view(-1, d_model), W_1, b_1)  # [seq_len * batch_size, dim_feedforward]
ffn_output = F.relu(ffn_output)  # [seq_len * batch_size, dim_feedforward]

# 第二层线性变换
ffn_output = F.linear(ffn_output, W_2, b_2)  # [seq_len * batch_size, d_model]
ffn_output = ffn_output.view(seq_len, batch_size, d_model)  # [seq_len, batch_size, d_model]

# 残差连接和层归一化(第二层)
residual2 = normalized + ffn_output  # [seq_len, batch_size, d_model]
normalized2 = F.layer_norm(residual2, (d_model,), weight=norm2.weight, bias=norm2.bias)  # [seq_len, batch_size, d_model]
normalized2
"""
tensor([[[-1.0328, -0.9185,  0.6710,  1.2804]],

        [[-1.4175, -0.1948,  1.3775,  0.2347]],

        [[-1.0022, -0.8035,  0.3029,  1.5028]]],
       grad_fn=<NativeLayerNormBackward0>)
"""
torch.allclose(normalized2, memory) # True

解码器部分

  • input: Y ∈ R T × B × d model \mathbf{Y} \in \mathbb{R}^{T \times B \times d_{\text{model}}} YRT×B×dmodel(解码器输入)

  • memory: M ∈ R T enc × B × d model \mathbf{M} \in \mathbb{R}^{T_{\text{enc}} \times B \times d_{\text{model}}} MRTenc×B×dmodel(编码器输出)

    1. Multi-head Self-Attention(解码器的多头自注意力)
    • 线性变换(linear projection,矩阵乘法)生成 Q self \mathbf{Q}_{\text{self}} Qself K self \mathbf{K}_{\text{self}} Kself V self \mathbf{V}_{\text{self}} Vself 矩阵
      • Y flat = Y . reshape ( T × B , d model ) Y_{\text{flat}} = \mathbf{Y}.\text{reshape}(T \times B, d_{\text{model}}) Yflat=Y.reshape(T×B,dmodel)
      • Q K V self = Y flat W in,self ⊤ + b in,self \mathbf{QKV}_{\text{self}} = Y_{\text{flat}} \mathbf{W}_{\text{in,self}}^\top + \mathbf{b}_{\text{in,self}} QKVself=YflatWin,self+bin,selfdecoder_layer.self_attn.in_proj_weightdecoder_layer.self_attn.in_proj_bias
        • W in,self ∈ R 3 d model × d model \mathbf{W}_{\text{in,self}} \in \mathbb{R}^{3d_{\text{model}} \times d_{\text{model}}} Win,selfR3dmodel×dmodel b in,self ∈ R 3 d model \mathbf{b}_{\text{in,self}} \in \mathbb{R}^{3d_{\text{model}}} bin,selfR3dmodel
        • Q K V self ∈ R T × B , 3 d model \mathbf{QKV}_{\text{self}} \in \mathbb{R}^{T \times B, 3d_{\text{model}}} QKVselfRT×B,3dmodel
      • 拆分 Q self \mathbf{Q}_{\text{self}} Qself K self \mathbf{K}_{\text{self}} Kself V self \mathbf{V}_{\text{self}} Vself
        • Q self \mathbf{Q}_{\text{self}} Qself, K self \mathbf{K}_{\text{self}} Kself, V self = split ( Q K V self , d model ) \mathbf{V}_{\text{self}} = \text{split}(\mathbf{QKV}_{\text{self}}, d_{\text{model}}) Vself=split(QKVself,dmodel)(按列进行拆分)
        • Q self \mathbf{Q}_{\text{self}} Qself, K self \mathbf{K}_{\text{self}} Kself, V self ∈ R T × B , d model \mathbf{V}_{\text{self}} \in \mathbb{R}^{T \times B, d_{\text{model}}} VselfRT×B,dmodel
    • 调整形状以适应多头注意力
      • d k = d model h d_k = \frac{d_{\text{model}}}{h} dk=hdmodel
      • reshape_for_heads
        Q heads,self = Q self . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) K heads,self = K self . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) V heads,self = V self . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) \begin{align*} \mathbf{Q}_{\text{heads,self}} &= \mathbf{Q}_{\text{self}}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \\ \mathbf{K}_{\text{heads,self}} &= \mathbf{K}_{\text{self}}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \\ \mathbf{V}_{\text{heads,self}} &= \mathbf{V}_{\text{self}}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \end{align*} Qheads,selfKheads,selfVheads,self=Qself.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)=Kself.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)=Vself.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)
    • 计算注意力分数: Scores self = Q heads,self K heads,self ⊤ d k \text{Scores}_{\text{self}} = \frac{\mathbf{Q}_{\text{heads,self}} \mathbf{K}_{\text{heads,self}}^\top}{\sqrt{d_k}} Scoresself=dk Qheads,selfKheads,self
      • Q heads,self ∈ R ( B × h ) × T × d k \mathbf{Q}_{\text{heads,self}} \in \mathbb{R}^{(B \times h) \times T \times d_k} Qheads,selfR(B×h)×T×dk K heads,self ⊤ ∈ R ( B × h ) × d k × T \mathbf{K}_{\text{heads,self}}^\top \in \mathbb{R}^{(B \times h) \times d_k \times T} Kheads,selfR(B×h)×dk×T,因此 Scores self ∈ R ( B × h ) × T × T \text{Scores}_{\text{self}} \in \mathbb{R}^{(B \times h) \times T \times T} ScoresselfR(B×h)×T×T
    • (可选)应用遮掩矩阵
      • 如果需要应用遮掩(例如防止解码器看到未来的信息),生成遮掩矩阵 Mask ∈ R T × T \text{Mask} \in \mathbb{R}^{T \times T} MaskRT×T
      • Scores self \text{Scores}_{\text{self}} Scoresself 应用遮掩: Scores self = Scores self + Mask \text{Scores}_{\text{self}} = \text{Scores}_{\text{self}} + \text{Mask} Scoresself=Scoresself+Mask
    • 计算注意力权重: AttentionWeights self = softmax ( Scores self ) \text{AttentionWeights}_{\text{self}} = \text{softmax}(\text{Scores}_{\text{self}}) AttentionWeightsself=softmax(Scoresself)
    • 计算注意力输出: AttentionOutput self = AttentionWeights self × V heads,self \text{AttentionOutput}_{\text{self}} = \text{AttentionWeights}_{\text{self}} \times \mathbf{V}_{\text{heads,self}} AttentionOutputself=AttentionWeightsself×Vheads,self
      • V heads,self ∈ R ( B × h ) × T × d k \mathbf{V}_{\text{heads,self}} \in \mathbb{R}^{(B \times h) \times T \times d_k} Vheads,selfR(B×h)×T×dk,因此 AttentionOutput self ∈ R ( B × h ) × T × d k \text{AttentionOutput}_{\text{self}} \in \mathbb{R}^{(B \times h) \times T \times d_k} AttentionOutputselfR(B×h)×T×dk
    • 合并多头输出: AttentionOutput self = AttentionOutput self . reshape ( B , h , T , d k ) . permute ( 2 , 0 , 1 , 3 ) . reshape ( T , B , d model ) \text{AttentionOutput}_{\text{self}} = \text{AttentionOutput}_{\text{self}}.\text{reshape}(B, h, T, d_k).\text{permute}(2, 0, 1, 3).\text{reshape}(T, B, d_{\text{model}}) AttentionOutputself=AttentionOutputself.reshape(B,h,T,dk).permute(2,0,1,3).reshape(T,B,dmodel)
    • 输出线性变换: AttnOutputProjected self = AttentionOutput self W out,self ⊤ + b out,self \text{AttnOutputProjected}_{\text{self}} = \text{AttentionOutput}_{\text{self}} \mathbf{W}_{\text{out,self}}^\top + \mathbf{b}_{\text{out,self}} AttnOutputProjectedself=AttentionOutputselfWout,self+bout,self
      • W out,self ∈ R d model × d model \mathbf{W}_{\text{out,self}} \in \mathbb{R}^{d_{\text{model}} \times d_{\text{model}}} Wout,selfRdmodel×dmodel b out,self ∈ R d model \mathbf{b}_{\text{out,self}} \in \mathbb{R}^{d_{\text{model}}} bout,selfRdmodel,对应代码中的 self_out_proj_weightself_out_proj_bias
    1. 残差连接和层归一化(第一层)
    • 残差连接: Residual1 = Y + AttnOutputProjected self \text{Residual1} = \mathbf{Y} + \text{AttnOutputProjected}_{\text{self}} Residual1=Y+AttnOutputProjectedself
    • 层归一化: Normalized1 = LayerNorm ( Residual1 , γ norm1 , β norm1 ) \text{Normalized1} = \text{LayerNorm}(\text{Residual1}, \gamma_{\text{norm1}}, \beta_{\text{norm1}}) Normalized1=LayerNorm(Residual1,γnorm1,βnorm1)
      • γ norm1 , β norm1 ∈ R d model \gamma_{\text{norm1}}, \beta_{\text{norm1}} \in \mathbb{R}^{d_{\text{model}}} γnorm1,βnorm1Rdmodel,对应代码中的 norm1.weightnorm1.bias
    1. Multi-head Encoder-Decoder Attention(交叉注意力)
    • 线性变换生成 Q cross \mathbf{Q}_{\text{cross}} Qcross K cross \mathbf{K}_{\text{cross}} Kcross V cross \mathbf{V}_{\text{cross}} Vcross 矩阵
      • 对于查询矩阵:
        • Q cross = Normalized1 flat W q,cross ⊤ + b q,cross \mathbf{Q}_{\text{cross}} = \text{Normalized1}_{\text{flat}} \mathbf{W}_{\text{q,cross}}^\top + \mathbf{b}_{\text{q,cross}} Qcross=Normalized1flatWq,cross+bq,cross
          • W q,cross ∈ R d model × d model \mathbf{W}_{\text{q,cross}} \in \mathbb{R}^{d_{\text{model}} \times d_{\text{model}}} Wq,crossRdmodel×dmodel b q,cross ∈ R d model \mathbf{b}_{\text{q,cross}} \in \mathbb{R}^{d_{\text{model}}} bq,crossRdmodel
      • 对于键和值矩阵:
        • K V cross = M flat W k,v,cross ⊤ + b k,v,cross \mathbf{KV}_{\text{cross}} = M_{\text{flat}} \mathbf{W}_{\text{k,v,cross}}^\top + \mathbf{b}_{\text{k,v,cross}} KVcross=MflatWk,v,cross+bk,v,cross
          • W k,v,cross ∈ R 2 d model × d model \mathbf{W}_{\text{k,v,cross}} \in \mathbb{R}^{2d_{\text{model}} \times d_{\text{model}}} Wk,v,crossR2dmodel×dmodel b k,v,cross ∈ R 2 d model \mathbf{b}_{\text{k,v,cross}} \in \mathbb{R}^{2d_{\text{model}}} bk,v,crossR2dmodel
        • 拆分 K cross \mathbf{K}_{\text{cross}} Kcross, V cross \mathbf{V}_{\text{cross}} Vcross
          • K cross \mathbf{K}_{\text{cross}} Kcross, V cross = split ( K V cross , d model ) \mathbf{V}_{\text{cross}} = \text{split}(\mathbf{KV}_{\text{cross}}, d_{\text{model}}) Vcross=split(KVcross,dmodel)
    • 调整形状以适应多头注意力
      • reshape_for_heads
        Q heads,cross = Q cross . reshape ( T , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T , d k ) K heads,cross = K cross . reshape ( T enc , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T enc , d k ) V heads,cross = V cross . reshape ( T enc , B , h , d k ) . permute ( 1 , 2 , 0 , 3 ) . reshape ( B × h , T enc , d k ) \begin{align*} \mathbf{Q}_{\text{heads,cross}} &= \mathbf{Q}_{\text{cross}}.\text{reshape}(T, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T, d_k) \\ \mathbf{K}_{\text{heads,cross}} &= \mathbf{K}_{\text{cross}}.\text{reshape}(T_{\text{enc}}, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T_{\text{enc}}, d_k) \\ \mathbf{V}_{\text{heads,cross}} &= \mathbf{V}_{\text{cross}}.\text{reshape}(T_{\text{enc}}, B, h, d_k).\text{permute}(1, 2, 0, 3).\text{reshape}(B \times h, T_{\text{enc}}, d_k) \end{align*} Qheads,crossKheads,crossVheads,cross=Qcross.reshape(T,B,h,dk).permute(1,2,0,3).reshape(B×h,T,dk)=Kcross.reshape(Tenc,B,h,dk).permute(1,2,0,3).reshape(B×h,Tenc,dk)=Vcross.reshape(Tenc,B,h,dk).permute(1,2,0,3).reshape(B×h,Tenc,dk)
      • 注意: T enc T_{\text{enc}} Tenc 是编码器输出的序列长度
    • 计算注意力分数: Scores cross = Q heads,cross K heads,cross ⊤ d k \text{Scores}_{\text{cross}} = \frac{\mathbf{Q}_{\text{heads,cross}} \mathbf{K}_{\text{heads,cross}}^\top}{\sqrt{d_k}} Scorescross=dk Qheads,crossKheads,cross
      • Scores cross ∈ R ( B × h ) × T × T enc \text{Scores}_{\text{cross}} \in \mathbb{R}^{(B \times h) \times T \times T_{\text{enc}}} ScorescrossR(B×h)×T×Tenc
    • 计算注意力权重: AttentionWeights cross = softmax ( Scores cross ) \text{AttentionWeights}_{\text{cross}} = \text{softmax}(\text{Scores}_{\text{cross}}) AttentionWeightscross=softmax(Scorescross)
    • 计算注意力输出: AttentionOutput cross = AttentionWeights cross × V heads,cross \text{AttentionOutput}_{\text{cross}} = \text{AttentionWeights}_{\text{cross}} \times \mathbf{V}_{\text{heads,cross}} AttentionOutputcross=AttentionWeightscross×Vheads,cross
      • AttentionOutput cross ∈ R ( B × h ) × T × d k \text{AttentionOutput}_{\text{cross}} \in \mathbb{R}^{(B \times h) \times T \times d_k} AttentionOutputcrossR(B×h)×T×dk
    • 合并多头输出: AttentionOutput cross = AttentionOutput cross . reshape ( B , h , T , d k ) . permute ( 2 , 0 , 1 , 3 ) . reshape ( T , B , d model ) \text{AttentionOutput}_{\text{cross}} = \text{AttentionOutput}_{\text{cross}}.\text{reshape}(B, h, T, d_k).\text{permute}(2, 0, 1, 3).\text{reshape}(T, B, d_{\text{model}}) AttentionOutputcross=AttentionOutputcross.reshape(B,h,T,dk).permute(2,0,1,3).reshape(T,B,dmodel)
    • 输出线性变换: AttnOutputProjected cross = AttentionOutput cross W out,cross ⊤ + b out,cross \text{AttnOutputProjected}_{\text{cross}} = \text{AttentionOutput}_{\text{cross}} \mathbf{W}_{\text{out,cross}}^\top + \mathbf{b}_{\text{out,cross}} AttnOutputProjectedcross=AttentionOutputcrossWout,cross+bout,cross
      • W out,cross ∈ R d model × d model \mathbf{W}_{\text{out,cross}} \in \mathbb{R}^{d_{\text{model}} \times d_{\text{model}}} Wout,crossRdmodel×dmodel b out,cross ∈ R d model \mathbf{b}_{\text{out,cross}} \in \mathbb{R}^{d_{\text{model}}} bout,crossRdmodel,对应代码中的 cross_out_proj_weightcross_out_proj_bias
    1. 残差连接和层归一化(第二层)
    • 残差连接: Residual2 = Normalized1 + AttnOutputProjected cross \text{Residual2} = \text{Normalized1} + \text{AttnOutputProjected}_{\text{cross}} Residual2=Normalized1+AttnOutputProjectedcross
    • 层归一化: Normalized2 = LayerNorm ( Residual2 , γ norm2 , β norm2 ) \text{Normalized2} = \text{LayerNorm}(\text{Residual2}, \gamma_{\text{norm2}}, \beta_{\text{norm2}}) Normalized2=LayerNorm(Residual2,γnorm2,βnorm2)
      • γ norm2 , β norm2 ∈ R d model \gamma_{\text{norm2}}, \beta_{\text{norm2}} \in \mathbb{R}^{d_{\text{model}}} γnorm2,βnorm2Rdmodel,对应代码中的 norm2.weightnorm2.bias
    1. 前馈神经网络(FFN)
    • 第一层线性变换和激活函数: FFNOutput1 = ReLU ( Normalized2 W 1 ⊤ + b 1 ) \text{FFNOutput1} = \text{ReLU}(\text{Normalized2} \mathbf{W}_1^\top + \mathbf{b}_1) FFNOutput1=ReLU(Normalized2W1+b1)
      • W 1 ∈ R d ff × d model \mathbf{W}_1 \in \mathbb{R}^{d_{\text{ff}} \times d_{\text{model}}} W1Rdff×dmodel b 1 ∈ R d ff \mathbf{b}_1 \in \mathbb{R}^{d_{\text{ff}}} b1Rdff,对应代码中的 linear1.weightlinear1.bias
    • 第二层线性变换: FFNOutput2 = FFNOutput1 W 2 ⊤ + b 2 \text{FFNOutput2} = \text{FFNOutput1} \mathbf{W}_2^\top + \mathbf{b}_2 FFNOutput2=FFNOutput1W2+b2
      • W 2 ∈ R d model × d ff \mathbf{W}_2 \in \mathbb{R}^{d_{\text{model}} \times d_{\text{ff}}} W2Rdmodel×dff b 2 ∈ R d model \mathbf{b}_2 \in \mathbb{R}^{d_{\text{model}}} b2Rdmodel,对应代码中的 linear2.weightlinear2.bias
    1. 残差连接和层归一化(第三层)
    • 残差连接: Residual3 = Normalized2 + FFNOutput2 \text{Residual3} = \text{Normalized2} + \text{FFNOutput2} Residual3=Normalized2+FFNOutput2
    • 层归一化: Output = LayerNorm ( Residual3 , γ norm3 , β norm3 ) \text{Output} = \text{LayerNorm}(\text{Residual3}, \gamma_{\text{norm3}}, \beta_{\text{norm3}}) Output=LayerNorm(Residual3,γnorm3,βnorm3)
      • γ norm3 , β norm3 ∈ R d model \gamma_{\text{norm3}}, \beta_{\text{norm3}} \in \mathbb{R}^{d_{\text{model}}} γnorm3,βnorm3Rdmodel,对应代码中的 norm3.weightnorm3.bias

解码器实现类似编码器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329242.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis八股文-执行流程、延迟加载、一级与二级缓存

(一)执行流程 mybatis-config.xml核心配置文件的作用&#xff1a; 在MyBatis框架的核心配置文件中需要去指定当前的环境配置、指定需要操作的是哪个数据库&#xff0c;并且输入当前的用户名与密码&#xff0c;只有配置了他才能真正操作数据库。同时还去加载了SQL映射文件&#…

基于Spark的哔哩哔哩舆情数据分析系统

【Spark】基于Spark的哔哩哔哩舆情数据分析系统 &#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 本项目基于Python和Django框架进行开发&#xff0c;为了便于广大用户针对舆情进行个性化分析处…

【Linux】日志模块实现详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…

Java基础:面向对象高级(四)

内部类&#xff08;类中五大成分之一&#xff09; 四种形式 成员内部类【了解】 静态内部类【了解】 局部内部类【了解】 匿名内部类【重点】 枚举 泛型 什么是泛型 泛型类-模拟ArrayList 泛型接口-操作学生&#xff0c;老师增删改查 泛型方法 泛型擦除和注意事项

easy-poi 一对多导出

1. 需求&#xff1a; 某一列上下两行单元格A,B值一样且这两个单元格&#xff0c; 前面所有列对应单元格值一样的话&#xff0c; 就对A,B 两个单元格进行纵向合并单元格 1. 核心思路&#xff1a; 先对数据集的国家&#xff0c;省份&#xff0c;城市...... id 身份证进行排序…

python通过调用海康SDK打开工业相机(全流程)

首先打开海康机器人-机器视觉-下载中心 下载最新版的 MVS 安装后打开目录找到 ...\MVS\Development\Samples\Python 将MvImport内所有文件拷贝至工作目录 然后到 C:\Program Files (x86)\Common Files\MVS\Runtime 找到适合自己系统的版本&#xff0c;将整个文件夹拷贝至工…

manim,制作专业的数学公式动画

manim是一个Python第三方库,全称是mathematical animation engine(数学动画引擎)。manim用于解说线性代数、微积分、神经网络、黎曼猜想、傅里叶变换以及四元数等数学概念。 manim使你能够以编程的方式创建精确的数学图形、动画和场景。与传统的几何画板等绘图软件不同,man…

小刚说C语言刷题——第15讲 多分支结构

1.多分支结构 所谓多分支结构是指在选择的时候有多种选择。根据条件满足哪个分支&#xff0c;就走对应分支的语句。 2.语法格式 if(条件1) 语句1; else if(条件2) 语句2; else if(条件3) 语句3; ....... else 语句n; 3.示例代码 从键盘输入三条边的长度&#xff0c;…

[ctfshow web入门] web6

前置知识 入口点(目录)爆破 还记得之前说过网站的入口的吗&#xff0c;我们输入url/xxx&#xff0c;其中如果url/xxx存在&#xff0c;那么访问成功&#xff0c;证明存在这样一个入口点&#xff1b;如果访问失败则证明不存在此入口点。所以我们可以通过遍历url/xxx&#xff0c;…

简单程序语言理论与编译技术·22 实现一个从AST到RISCV的编译器

本文是记录专业课“程序语言理论与编译技术”的部分笔记。 LECTURE 22&#xff08;实现一个从AST到RISCV的编译器&#xff09; 一、问题分析 1、完整的编译器&#xff08;如LLVM&#xff09;需先完成AST到IR的转换&#xff0c;并进行代码优化&#xff0c;再到汇编&#xff0…

lua和C的交互

1.C调用lua例子 #include <iostream> #include <lua.hpp>int main() {//用于创建一个新的lua虚拟机lua_State* L luaL_newstate();luaL_openlibs(L);//打开标准库/*if (luaL_dofile(L, "test.lua") ! LUA_OK) {std::cerr << "Lua error: &…

Css:如何解决绝对定位子元素内容被父级元素overflow:hidden属性剪裁

一、问题描述 今天小伙伴提了一个bug&#xff0c;在点击列表项的“…”按钮应该出现的悬浮菜单显示不完整&#xff1a; 二、问题排查 一般这种问题&#xff0c;是由于悬浮菜单采用的是绝对定位&#xff0c;而父级采用了overflow:hidden属性。但需要注意的是&#xff0c;这里的…

RoMo: Robust Motion Segmentation Improves Structure from Motion

前言 看起来像是一篇投稿CVPR的文章&#xff0c;不知道被哪个瞎眼审稿人拒了。同期还有一篇CVPR被接收的工作Segment Any Motion in Videos&#xff0c;看起来不如这篇直白&#xff08;也可能是因为我先看过spotlesssplats的缘故&#xff09;&#xff0c;后面也应该一并介绍了…

MCP 极简入门 - 三分钟 Cline + Smithery 运行 time 服务

文章目录 一、&#x1f680; 初识Smithery&#xff1a;AI服务的新大陆找到心仪的服务 二、Cline 编辑配置文件&#x1f527;1、打开配置文件2. 添加Time Server配置3. 验证配置效果 三、&#x1f4ac; 实战对话&#xff1a;让AI告诉你时间四、服务管理小技巧&#x1f504;&…

基本机动飞行性能

机动飞行时描述飞机在给定构型和发动机工作状态下改变飞行速度、飞行高度和飞行方向的能力 1. 水平加&#xff08;减&#xff09;速 水平加&#xff08;减&#xff09;速性能反映飞机在水平面内改变直线飞行速度的能力。描述水平加&#xff08;减&#xff09;速性能的参数包括…

【Linux】进程间通信、匿名管道、进程池

一.什么是通信 进程间通信(Inter-Process Communication&#xff0c;IPC),是指在操作系统中&#xff0c;不同进程之间进行数据交换和同步的机制。由于每个进程通常拥有独立的内存空间&#xff0c;进程间无法直接访问对方的内存&#xff0c;因此需要通过特定的机制来实现通信和…

【MATLAB定位例程】TDOA(到达时间差)的chan-tylor,三维环境,附完整代码

该代码实现了基于三维空间的动态目标TDOA定位,结合了Chan算法(解析解)与Taylor级数展开法(迭代优化)的双重优势。 文章目录 运行结果MATLAB代码代码讲解代码功能概述核心算法原理代码结构解析可视化与结果分析运行结果 定位示意图: 三轴状态曲线: 三轴误差曲线: MA…

数字化转型中的开源AI智能客服与S2B2C商城小程序的融合创新

摘要 数字经济时代&#xff0c;企业需通过技术重构用户交互与供应链体系。本文以“开源AI智能客服”“AI智能名片”及“S2B2C商城小程序”为核心&#xff0c;研究三者如何通过技术协同与场景化应用实现企业营销、客户服务与供应链管理的智能化升级。通过案例分析、技术架构设…

重生之我是去噪高手——diffusion model

diffusion model是如何运作的&#xff1f; 想象一下&#xff0c;你有一张清晰的图片。扩散模型的核心思想分为两个过程&#xff1a; 前向过程&#xff08;Forward Process / Diffusion Process&#xff09;&#xff1a;逐步加噪反向过程&#xff08;Reverse Process / Denois…

【C#】.net core 6.0 依赖注入常见问题之一,在构造函数使用的类,都需要注入到容器里,否则会提示如下报错,让DeepSeek找找原因,看看效果

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…