Transformer核心原理图解:从自注意力到多头注意力的完整拆解
2026/8/31 7:10:24 网站建设 项目流程

做算法开发这几年,Transformer 几乎是绕不开的一道门槛。不管你是做 NLP、CV,还是最近在折腾大模型微调,最终都会回到同一个问题上:Transformer 内部到底是怎么工作的?我刚开始接触时,也被 QKV、多头注意力、位置编码这些概念绕得头晕,网上的资料要么太偏数学,要么只有代码没有解释。这篇文章便是我自己的学习梳理笔记,用“图解 + 最小代码 + 工程经验”的方式,把 Transformer 讲清楚。文中会从循环神经网络并行化困境讲起,逐步拆解 Self-Attention、Multi-Head Attention、位置编码、Encoder-Decoder 结构,最后给出 PyTorch 手写核心模块和 Hugging Face 实际调用示例。新手可以把这篇文章当作第一份学习地图,有基础的开发者则可以直接跳到代码和排错部分。本文不追求论文级严谨,只追求“讲得明白、能跑起来、能用上”。

1. 为什么最后是 Transformer:从 RNN 到自注意力的演进

1.1 RNN / LSTM 的并行化困境

在 Transformer 出现之前,处理序列数据(如文本、语音、时间序列)的主流模型是 RNN(循环神经网络)和 LSTM(长短期记忆网络)。

RNN 的基本思路是:按时间步顺序读取序列,每一步把当前输入和历史隐藏状态融合,生成新的隐藏状态。

h_t = f(h_{t-1}, x_t)

这个结构有两个明显问题:

  • 无法并行。第 t 步必须等第 t-1 步算完,文本越长,算得越慢。GPU 虽然有很多计算单元,但 RNN 这种串行模式让 GPU 难以充分发挥算力。
  • 长距离依赖衰减。虽然 LSTM 通过门控机制缓解了梯度消失问题,但当序列长度达到几百甚至上千时,早期信息传递到后期仍然会大幅衰减。

1.2 Attention 带来的改变

Attention(注意力)机制最早被引入到 Seq2Seq 模型中,用来解决“编码器把整个源句子压缩成一个向量,信息损失严重”的问题。它的核心思想是:在解码时,不要只依赖一个固定向量,而是动态地查看原始输入的不同位置,并分配不同权重。

这给了我们一个重要启发:如果每个位置都能直接看到其他所有位置,那么长距离依赖问题可以被大幅缓解。2017 年,Google 在论文《Attention Is All You Need》中把这个思想推到极致——直接用 Attention 替代循环结构,这就是 Transformer。它的核心优势是:

  • 全局建模能力强。每个 token 都能直接与其他所有 token 交互。
  • 并行度高。矩阵运算可以由 GPU 高效并行执行。
  • 扩展性好。通过堆叠层数和扩大参数量,模型效果持续提升,这也是后来 BERT、GPT 等一系列大模型的基础架构。

1.3 Transformer 的定位

简单来说,Transformer 是一个基于自注意力机制的序列模型架构。它不再按顺序迭代,而是通过注意力矩阵来捕捉输入内部的关系。这样的设计让它在自然语言处理、图像分类、语音识别、推荐系统等场景中都能适用。

接下来我们进入核心部分:Transformer 的完整架构。

2. Transformer 整体架构图解

2.1 宏观视角:Encoder-Decoder 结构

Transformer 的原始版本采用 Encoder-Decoder 框架。左侧是 Encoder(编码器),右侧是 Decoder(解码器)。

输入序列: [我, 爱, 学习] │ ▼ ┌──────────────────────┐ │ Input Embedding │ 词向量嵌入 └──────────────────────┘ │ ┌──────────────────────┐ │ Positional Encoding│ 位置编码 └──────────────────────┘ │ ▼ ┌──────────────────────┐ │ Encoder Layer ×N │ 多头注意力 + 前馈网络 └──────────────────────┘ │ ▼ ┌──────────────────────┐ │ Encoder 输出 │ 即 KV 的来源 └──────────────────────┘ 输出侧流程类似: 输入序列: [<s>, 我, 爱] │ ▼ ┌──────────────────────┐ │ Output Embedding │ └──────────────────────┘ │ ▼ ┌──────────────────────┐ │ Positional Encoding │ └──────────────────────┘ │ ▼ ┌──────────────────────┐ │ Decoder Layer ×N │ │ Masked Self-Attention│ │ Cross-Attention │ │ Feed Forward │ └──────────────────────┘ │ ▼ ┌──────────────────────┐ │ Linear + Softmax │ → 预测下一个 token └──────────────────────┘

在机器翻译、文本摘要、对话生成这类“输入一段文本,输出另一段文本”的任务中,Encoder 负责理解输入文本,Decoder 负责生成输出文本。

但很多人刚开始学习时会有一个困惑:现在流行的 GPT 模型好像只用 Decoder?BERT 好像只用 Encoder?没错,这是 Transformer 的发展分支:

  • Encoder-only:适合理解类任务,例如文本分类、命名实体识别、语义相似度。典型代表是 BERT。
  • Decoder-only:适合生成类任务,例如对话、续写、代码生成。典型代表是 GPT 系列。
  • Encoder-Decoder:适合序列到序列的转换任务,例如翻译、摘要。典型代表是 T5、BART。

2.2 每个子模块的作用

一个标准的 Transformer Block 内部包含以下组件:

组件作用
Embedding将 token 映射为稠密向量
Positional Encoding给模型提供 token 的顺序信息
Multi-Head Self-Attention捕捉 token 之间的依赖关系
Add & Norm残差连接 + 层归一化,帮助训练稳定
Feed-Forward Network每个 token 独立通过的全连接网络,增强非线性表达能力
Masked Multi-Head AttentionDecoder 中防止看到未来 token

下面我们从最核心的 Self-Attention 开始拆解。

3. 自注意力机制(Self-Attention)详解

3.1 从“查字典”理解 Q、K、V

Self-Attention 中最难理解的就是 Q(Query)、K(Key)、V(Value)这三个向量。其实可以类比一个检索场景:

  • 你脑子里有一个问题,这是 Query。
  • 你面前有多个知识点,每个知识点有标题,这是 Key。
  • 每个知识点正文内容,这是 Value。

你要做的,是用问题(Query)去和每个标题(Key)做匹配,得到一个相关度分数,然后按照相关度去加权提取正文内容(Value)。相关度越高的内容,在最终结果中占的比例越大。

在 Transformer 中,输入序列的每个 token 都会生成自己的 Q、K、V。具体做法是:

Q = X · W_Q K = X · W_K V = X · W_V

其中 X 是输入向量矩阵,W_Q、W_K、W_V 是可学习的权重矩阵。

3.2 注意力分数的计算

假设输入序列有 n 个 token,每个 token 的维度是 d_model。那么:

  • Q 的维度是 [n, d_k]
  • K 的维度是 [n, d_k]
  • V 的维度是 [n, d_v]

注意力分数的计算公式如下:

Attention(Q, K, V) = softmax( Q · K^T / sqrt(d_k) ) · V

这里每个步骤的含义是:

  1. 计算 Q 和所有 K 的点积,得到“每个 token 与其他 token 的关注度打分”。
  2. 除以 sqrt(d_k),防止点积数值过大导致 softmax 梯度消失。d_k 是 K 的维度。
  3. 用 softmax 归一化,让每个 token 对整句话的注意力权重之和为 1。
  4. 用权重对 V 加权求和,得到当前 token 的上下文表示。

3.3 一个手动计算的例子

为了看得更明白,我们设计一个极小的例子。假设只有两个 token,“我”和“爱”,每个 token 映射成 2 维向量:

“我”的向量: [1, 0] “爱”的向量: [0, 1]

为了方便展示,我们直接忽略 W_Q、W_K、W_V 的具体学习过程,假设:

Q = [[1, 0], [0, 1]] K = [[1, 0], [0, 1]] V = [[1, 0], [0, 1]]

第一步,计算 Q 和 K 的点积矩阵:

[1, 0] · [1, 0]^T = 1 [1, 0] · [0, 1]^T = 0 [0, 1] · [1, 0]^T = 0 [0, 1] · [0, 1]^T = 1 得分矩阵 = [[1, 0], [0, 1]]

第二步,假设 d_k = 2,那么 sqrt(2) ≈ 1.414。将得分除以 1.414 后做 softmax。

对第一行 [0.707, 0] 做 softmax:

softmax([0.707, 0]) ≈ [0.668, 0.332]

这里“我”对“我”自己的关注度约 0.668,对“爱”的关注度约 0.332。

第三步,用这个权重去加权 V:

0.668 × [1, 0] + 0.332 × [0, 1] = [0.668, 0.332]

这就是“我”经过自注意力机制后的新向量。新向量同时蕴含了“我”和“爱”的信息,具体比例由注意力权重决定。

3.4 为什么需要缩放

点积的数值会随向量维度增大而变大。当 d_k 很大时,点积结果分布会变得非常尖锐,softmax 之后绝大多数概率集中在一个位置上,其他位置梯度接近 0,这会导致训练困难。除以 sqrt(d_k) 可以把点积分布拉回到方差适中的区间,让梯度更稳定。

很多初学者容易忽略缩放这一步,甚至直接删掉,这在训练深层 Transformer 时往往会导致 loss 不降。

4. 多头注意力与残差连接

4.1 多头注意力的动机

只有一个注意力头时,模型只能从一种关系视角去看输入。但真实文本中,关系是多种多样的。比如句子:

“小狗追着猫跑,它跑得很快。”

“它”可能指“小狗”,也可能指“猫”,具体含义需要结合上下文判断。单头注意力可能只关注到一种语法关系,而多头注意力可以让模型同时从多个子空间去捕捉不同关系。

多头注意力的做法是:

  1. 把 Q、K、V 分成 h 组,每组维度为原维度的 1/h。
  2. 每组独立计算注意力。
  3. 把 h 个头的输出拼接起来,通过一个线性层压缩回原始维度。
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) · W_O head_i = Attention(Q·W_Q^i, K·W_K^i, V·W_V^i)

这里 W_Q^i、W_K^i、W_V^i 是第 i 个头独立的投影矩阵,W_O 是输出投影矩阵。

4.2 多头注意力的直观理解

可以这么想:一个注意力头相当于一个“专家”,关注某一类关系。一个头关注语法依赖,另一个头关注指代关系,还有一个头关注语义相似度。多头机制让模型能够并行地学习多种不同表示。

在 BERT-base 中,注意力头数为 12,每头维度是 64。在 GPT-3 中,注意力头数达到 96 个,模型容量大幅提升。但不是说头越多越好,实际工程中需要结合模型总参数量和训练数据量做权衡。

4.3 残差连接与 LayerNorm

在多头注意力后面,通常会接一个 Add & Norm 结构。

X = LayerNorm(X + Attention(X))

这个设计有两个作用:

  • 残差连接:让梯度可以跨层直接回传,缓解深层网络训练困难。即使某一层的输出变化很大,模型也可以选择让信息“直通”。
  • LayerNorm:对每个样本的所有特征维度做归一化,让数据分布更加稳定,加速训练收敛。

在原始论文中,LayerNorm 被放在残差之后的 Add & Norm。但在近期很多大模型实现中,更常用 Pre-LN(先归一化再计算),例如:

X = X + Attention(LayerNorm(X))

两种方式各有优劣。Post-LN 效果上限高但训练不稳定;Pre-LN 训练更稳,深层次数更多时更常用。工程上优先使用 Pre-LN,更省心。

5. 位置编码:Transformer 如何感知顺序

5.1 为什么需要位置编码

RNN 天然按顺序读取输入,所以序列顺序被编码在结构中。Transformer 不同,它一次性看到所有 token,自注意力计算本身不带顺序信息。如果只是把“我爱学习”变成“学习爱我”的向量输入,模型看到的特征完全相同。

因此必须在输入中额外加入位置信息,这就是位置编码(Positional Encoding)。

5.2 原始 Transformer 的正余弦编码

原始论文使用固定频率的正弦和余弦函数来生成位置编码:

PE(pos, 2i) = sin(pos / 10000^(2i / d_model)) PE(pos, 2i+1) = cos(pos / 10000^(2i / d_model))

其中 pos 是 token 在序列中的位置,i 是向量维度下标。

这个设计有两个特点:

  • 不同位置得到不同编码向量,且相邻位置的编码比较相似。
  • 这种函数形式让模型更容易学习到“相对位置”关系,因为任意两个位置之间的偏移可以通过某种线性变换表示。

5.3 可学习位置编码与相对位置编码

在 BERT 中,位置编码被改成可学习的 Embedding,效果和正余弦编码接近。后来很多模型又引入了更复杂的相对位置编码(如 RoPE、ALiBi),它们对长文本泛化更好。尤其是 RoPE(旋转位置编码)被 LLaMA、ChatGLM 等模型广泛采用。

工程上,如果你只是调用现成大模型,不需要手动实现位置编码。但如果要自己设计序列模型,需要记住:位置信息必须显式注入模型,否则序列顺序对模型而言是无效的。

6. Encoder 与 Decoder:从哪里生成到哪里预测

6.1 Encoder 的编码逻辑

Encoder 的核心任务是理解输入。每个 Encoder Layer 包含两个子层:

  1. Multi-Head Self-Attention:捕捉输入内部 token 之间的关系。
  2. Feed-Forward Network:对每个 token 表示逐位置做非线性变换。

Encoder 输出的是一组向量,每个向量对应输入中的一个 token,并且已经融合了全句上下文信息。这组向量被称为“编码表示”。

6.2 Decoder 的掩码自注意力

Decoder 的输入是“已经生成的 token 序列”。在生成第 t 个 token 时,模型不应该看到未来的 token。因此 Decoder 内部使用 Masked Self-Attention。

具体做法是:在计算注意力分数时,把未来位置的分数设为负无穷,这样 softmax 之后它们的权重为 0。

得分矩阵(3个token): [[0.7, -inf, -inf], [0.5, 0.8, -inf], [0.3, 0.6, 0.9]]

这样第 1 个 token 只能关注自己,第 2 个 token 只能关注前两个,第 3 个 token 能关注前三个。这个设计保证了模型的自回归特性:每一步生成都只依赖历史输出。

6.3 Cross-Attention:Encoder 与 Decoder 的桥

Decoder 中除了 Masked Self-Attention,还有一个 Cross-Attention(交叉注意力)。在这个子层中:

  • Query 来自 Decoder 当前层的输出。
  • Key 和 Value 来自 Encoder 最后一层的输出。

这样 Decoder 在生成每一个 token 时,都可以动态地“查阅”原始输入中它最关注的片段。这就是翻译模型能够根据源语言逐步生成目标语言的关键机制。

对于只用 Decoder 的 GPT 类模型,没有 Encoder 和 Cross-Attention,它们纯粹是自回归地生成文本。

7. 从原理到代码:手写核心模块与 Hugging Face 实战

7.1 用 PyTorch 实现多头注意力

下面给出一个最小化但结构完整的 PyTorch 实现。注意,这里重点演示原理,不追求与论文完全一致的最优实现。

import torch import torch.nn as nn import torch.nn.functional as F class MultiHeadAttention(nn.Module): def __init__(self, d_model, num_heads): super().__init__() assert d_model % num_heads == 0 self.d_model = d_model self.num_heads = num_heads self.d_k = d_model // num_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) def forward(self, x, mask=None): batch_size, seq_len, _ = x.size() Q = self.w_q(x) # [batch, seq, d_model] K = self.w_k(x) V = self.w_v(x) # 拆成多头 Q = Q.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) K = K.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) V = V.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) # 计算注意力分数 scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32)) # scores: [batch, num_heads, seq, seq] if mask is not None: scores = scores.masked_fill(mask == 0, float("-inf")) attn = F.softmax(scores, dim=-1) output = torch.matmul(attn, V) # [batch, num_heads, seq, d_k] output = output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.d_model) output = self.w_o(output) return output

这里的关键点:

  • 通过viewtranspose把 d_model 拆成 num_heads 个子空间。
  • scores除以 sqrt(d_k) 对应缩放点积注意力。
  • masked_fill对应 decoder 中的掩码操作。
  • 最终把多头结果拼接后经w_o输出。

7.2 用 PyTorch 实现一个 Transformer 编码层

有了多头注意力,就可以组装一个完整的 Encoder Layer。

class FeedForward(nn.Module): def __init__(self, d_model, d_ff): super().__init__() self.fc1 = nn.Linear(d_model, d_ff) self.fc2 = nn.Linear(d_ff, d_model) self.relu = nn.ReLU() def forward(self, x): return self.fc2(self.relu(self.fc1(x))) class EncoderLayer(nn.Module): def __init__(self, d_model, num_heads, d_ff, dropout=0.1): super().__init__() self.self_attn = MultiHeadAttention(d_model, num_heads) self.feed_forward = FeedForward(d_model, d_ff) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.dropout = nn.Dropout(dropout) def forward(self, x, mask=None): # Pre-LN 结构 attn_output = self.self_attn(self.norm1(x), mask) x = x + self.dropout(attn_output) ff_output = self.feed_forward(self.norm2(x)) x = x + self.dropout(ff_output) return x

你可以用下面这段代码快速验证:

model = EncoderLayer(d_model=512, num_heads=8, d_ff=2048) x = torch.randn(2, 10, 512) # batch_size=2, seq_len=10, d_model=512 y = model(x) print(y.shape) # torch.Size([2, 10, 512])

7.3 使用 Hugging Face 加载预训练 Transformer

实际项目中基本不会从零训练 Transformer,而是加载预训练模型做微调。Hugging Face 的 Transformers 库是目前最常用的工具。以下示例演示加载一个 BERT 模型做文本分类。

pip install transformers torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch # 1. 加载分词器和预训练模型 tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese") model = AutoModelForSequenceClassification.from_pretrained("bert-base-chinese", num_labels=2) # 2. 对输入文本编码 texts = ["这个电影太棒了,剧情精彩,演员演技在线。", "电影很无聊,浪费时间。"] inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt") # 3. 前向推理 with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits predictions = torch.argmax(logits, dim=-1) print(predictions)

如果你想要一个 GPT 风格的续写示例,可以加载 GPT-2:

from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("gpt2") model = AutoModelForCausalLM.from_pretrained("gpt2") text = "Once upon a time" inputs = tokenizer(text, return_tensors="pt") outputs = model.generate(**inputs, max_length=50, do_sample=True, top_p=0.9) print(tokenizer.decode(outputs[0], skip_special_tokens=True))

这里需要说明:gpt2的官方权重主要针对英文训练,中文续写效果很一般。做中文生成任务建议使用bert-base-chinese配合分类任务,或者搜索中文本地化生成模型。版本方面,Transformers 4.x 和 PyTorch 2.x 是当前常见组合,具体版本以你的开发环境为准。

8. 常见问题与排查思路

8.1 问题汇总

问题现象常见原因解决思路
训练 loss 不下降学习率过大/过小;未做缩放;数据未归一化检查学习率,使用 warmup;确认注意力缩放;检查数据预处理
显存不足 OOM序列过长,注意力矩阵复杂度为 O(n²)缩短 max_length,使用梯度累积,或用长文本稀疏注意力方案
生成结果一直重复解码参数不恰当;训练数据存在重复模式调整 no_repeat_ngram_size,增大 top_p 或 temperature
加载模型报错模型权重与 Transformers 版本不匹配升级或回退 Transformers 版本,检查from_pretrained参数
序列长度超过模型限制BERT 一般限制 512,GPT 一般是 1024/2048对长文本切片、摘要,或选择支持长文本的模型
中文预测效果差使用了不支持中文的预训练模型换成bert-base-chinesechinese-roberta等中文预训练模型

8.2 排查清单

遇到 Transformer 相关问题时,可以按以下顺序排查:

  1. 确认输入张量形状是否正确,特别是 batch size 和 seq len 的维度。
  2. 确认注意力掩码是否有效。训练完看不到推理时是否传给模型。
  3. 打印 attention 最后一层的权重,确认模型是否关注到了合理位置。
  4. 检查 loss 曲线:如果出现 NaN,优先降低学习率并检查输入是否有异常值。
  5. 如果是 OOM,先减小 batch size,再考虑序列长度压缩。
  6. 如果是推理速度慢,先检查是否开启了torch.no_grad(),再考虑半精度。

9. 最佳实践与工程建议

9.1 数据与 Tokenizer 规范

文本输入前必须走同一个 tokenizer 流程。训练和推理时使用的 tokenizer 必须是同一个版本,否则会出现 token id 无法对齐的问题。中文文本建议直接使用中文预训练模型的专门 tokenizer,不要用英文 tokenizer 处理中文。

9.2 输入长度与注意力复杂度

Transformer 的标准注意力复杂度是 O(n²),也就是说,序列长度翻倍,计算量变成原来的 4 倍。这在实际工程中很容易成为瓶颈。

应对方案:

  • 能截断就截断,先保证输入长度在模型支持范围内。
  • 使用长文本模型(如 Longformer、BigBird、或者带 RoPE 的 LLaMA)处理超长文本。
  • 对文档类任务,先做段落拆分,再按段落处理,最后聚合结果。

9.3 训练稳定性

训练 Transformer 时,最忌讳直接全量微调。推荐顺序是:

  1. 冻结大部分底层参数,只训练顶层。
  2. 确认 loss 下降后,再逐步解冻更多层。
  3. 使用 warmup 学习率策略,前几步让学习率从小慢慢升到目标值。
  4. 如果显存允许,使用 AdamW 优化器并设置正确的权重衰减。

9.4 推理性能优化

对生产环境,常见的推理加速手段包括:

  • 使用半精度(FP16)或 INT8 量化,减少显存占用。
  • 使用批处理(batch inference),一次推理多条请求。
  • 对 Decoder 模型使用 KV Cache,避免重复计算已经生成的历史 token。
  • 通过 ONNX Runtime、TensorRT 等推理加速框架部署。

9.5 数据偏差与公平性

Transformer 训练过程会继承训练数据中的偏见。如果训练语料本身有性别、地域、职业上的偏向,模型输出也可能带有这种偏向。在模型上线前,应该做一定程度上的偏差测试,尤其是面向 C 端用户的产品。这个环节不决定模型效果上限,但决定产品能不能稳定落地。

9.6 成本与 Token 计量

大模型训练和推理的成本往往和 Token 数量直接挂钩。Token 是模型处理文本的基本单位,一个中文汉字可能对应一个或多个 Token,具体要看 tokenizer 切词方式。在生产环境中,建议在调用日志中统计 Token 消耗,用于成本核算和异常流量检测。做计费系统时,要明确“输入 Token”和“输出 Token”是否分别计量,以及上下文字符串如何计算。这个细节在规模化运营时非常重要。

10. 总结与下一步学习路线

Transformer 是当前人工智能大模型的基础架构。本文从 RNN 的并行化瓶颈出发,逐步拆解了 Self-Attention 的 QKV 计算过程、多头注意力的作用、位置编码的必要性,以及 Encoder 和 Decoder 的分工差异。通过手写最小多头注意力实现,又通过 Hugging Face 加载预训练模型,相信你对 Transformer 已经有了一个“既能看懂理论、也能跑通代码”的认识。

接下来你可以从几个方向继续深入:

  • 阅读源码:去看 PyTorch 的nn.Transformer模块,或者 Hugging Face 里的BertSelfAttention源码,代码会比你手写的版本更工程化。
  • 动手微调:用一个小规模的中文数据集做一次文本分类或者文本生成微调,亲手踩一遍过拟合、显存不足、loss 不降这些坑。
  • 关注大模型架构演进:新一代模型(如 LLaMA、ChatGLM、Qwen)在原始 Transformer 上做了哪些改动?为什么说 RoPE 重要?为什么 GQA 能节省显存?这些问题都可以顺着这次的基础继续探索。
  • 回看 Transformer 与 CNN/RNN 的对比:理解为什么在图像任务上 Vision Transformer 也能奏效,核心原因就是自注意力机制本身不依赖输入是文本还是图像。

学习 Transformer 不要等到把所有数学公式都搞懂才开始动手,先跑通一个最小示例,再慢慢完善认知,这条路是最快的。希望这篇文章能帮你省下一些探路时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询