终于把 Transformer 算法搞懂了!
终于把 Transformer 算法搞懂了!!
今天给大家分享一个强大的算法模型,Transformer
Transformer 是一种基于自注意力机制的深度学习架构,由 Vaswani 等人在 2017 年的论文《Attention Is All You Need》中提出。
它在自然语言处理(NLP)领域取得了巨大成功,并逐渐扩展到计算机视觉(CV)等其他领域。

程序员学长
关注推荐系统、计算广告、大数据技术领域,专注个人能力提升
589篇原创内容
公众号
与传统的循环神经网络(RNN)和卷积神经网络(CNN)不同,Transformer 彻底抛弃了循环和卷积的结构,完全依靠自注意力机制(Self-Attention)来捕捉输入序列中的依赖关系。这使得 Transformer 能够实现并行计算,大大提高了训练效率,并能更好地处理长距离依赖问题。

Transformer 的架构
Transformer 由两个主要部分组成
-
编码器(Encoder)
-
解码器(Decoder)

编码器
编码器负责将输入序列转换成一系列的上下文相关的表示。它由 N 个相同的编码器层堆叠而成。
每个编码器层包含两个子层
-
多头自注意力机制(Multi-Head Attention)
负责计算输入序列中每个词与其他词之间的关联程度。
-
前馈神经网络(Feed-Forward Neural Network)
对自注意力机制的输出进行非线性变换。
每个子层都使用了残差连接和层归一化。
解码器
解码器负责将编码器输出的上下文表示,结合已生成的输出序列,逐步生成新的输出序列(如翻译后的句子)。
它也由 N 个相同的解码器层堆叠而成。
每个解码器层包含三个子层:
-
掩蔽多头自注意力机制(Masked Multi-Head Attention)
与编码器中的自注意力类似,但加入了掩码机制,确保在生成当前词时只能关注到已经生成的词,避免“作弊”。
-
编码器-解码器注意力(Encoder-Decoder Attention)
它使得解码器在生成输出时能够关注编码器输出的上下文信息。
-
前馈神经网络(Feed-Forward Neural Network)
与编码器中的前馈网络类似。
同样,每个子层都使用了残差连接和层归一化。
核心组件
1.输入嵌入
Transformer 处理的是序列数据,最初输入是离散的词(Token)。输入嵌入就是把这些离散的词转换成连续的向量表示,以便神经网络处理。
给定输入序列 ,每个 是词表中的一个词。
使用嵌入矩阵 ( 是词表大小, 是嵌入维度):
输出嵌入序列为

2.位置编码
由于 Transformer 完全依赖自注意力机制,没有像 RNN 那样的循环结构来感知顺序。
因此需要通过位置编码来显式地注入位置信息,使模型能感知序列中单词的顺序。
位置编码的计算公式如下
其中, 是词的位置, 是维度, 是嵌入维度的大小。
最终的输入向量是词嵌入向量和位置编码的和。

3.自注意力机制
自注意力机制是 Transformer 的核心。它允许模型在处理序列中的每个词时,能够 “关注” 到序列中的其他所有词,并计算它们对当前词的重要性,从而捕捉序列中的全局依赖关系。

具体来说,给定一个输入序列 ,自注意力机制的目标是通过计算每个单词与其他单词的相关性来加权更新每个单词的表示。
-
线性变换
对于输入序列中的每个词,自注意力机制会生成三个向量
这些向量通过线性变换从输入向量 得到
其中,、、 为可学习的权重矩阵。
-
查询(Query,Q):表示当前词的信息,用于查询其他词。
-
键(Key, K):表示其他词的信息,用于被查询。
-
值(Value, V):表示其他词的实际内容,用于加权求和。
-
-
计算注意力分数
通过查询 Q 和键 K 的点积来衡量它们之间的相似度。点积后通常会进行缩放(Scaling),以防止点积结果过大导致 softmax 函数进入梯度饱和区。
-
计算注意力权重
对注意力分数应用 Softmax 函数,将其转换为概率分布,得到注意力权重。
这些权重表示了序列中每个词对当前词的重要性。
具体的计算公式为
-
加权求和
最后,将注意力权重与值向量 V 进行加权求和,得到每个输入元素的输出表示
4.多头自注意力机制
为了让模型能够从不同的子空间中学习到不同的注意力模式,Transformer 引入了多头自注意力机制。

原理
-
多头注意力将单头自注意力并行执行 h 次(h 是头数)。
-
在每个头中,输入 Q,K,V 会被线性投影到不同的子空间中(维度通常更低,例如 )。
-
每个头独立地计算自注意力,从而学习到不同类型的特征和依赖关系。
-
所有 h 个头的输出会被拼接起来,然后通过一个最终的线性变换将其投影回原始维度 。
数学公式为
对于第 i 个头
其中 是第 i 个注意力头的可学习权重矩阵。
最后,将所有头的输出拼接后进行线性变换
其中, 是输出的线性变换矩阵。
5.前馈神经网络
在每个自注意力层之后,Transformer 添加了一个简单的、全连接的前馈神经网络。它对自注意力机制的输出进行非线性变换,增加模型的表达能力。
原理
-
前馈神经网络通常由两个线性变换层组成,中间夹一个非线性激活函数(如 ReLU)。
-
它对每个位置的输出向量独立进行操作,即不共享参数。
-
可以看作是对自注意力层输出的进一步加工,提取更高层次的特征。
数学公式为
其中, 和 是权重矩阵, 和 是偏置项。
6.残差连接和层归一化
为缓解深层网络训练时梯度消失和收敛困难,Transformer 在每个子层后都使用了残差连接和层归一化
残差连接
残差连接的目的是为了避免在深层网络训练过程中梯度消失的问题,并帮助模型更容易地训练。
残差连接的数学公式为
其中 是输入, 是该层的输出。
层归一化
层归一化对每个样本的特征维度做归一化,稳定训练过程。与 BatchNorm 不同,LayerNorm 不依赖于批次大小。
数学公式为
其中, 是特征的均值, 是特征的标准差, 和 是学习的参数,用于缩放和平移归一化后的结果。
7.掩蔽多头自注意力机制
在解码器中,为了防止模型在预测当前词时“看到”未来的词,引入了掩码机制。
即在计算自注意力分数时,通过将未来位置的注意力分数设置为负无穷大(在 Softmax 后变为 0),强制模型只能关注当前位置及之前的位置。

其数学公式为
其中,M 是一个掩蔽矩阵
如果如果
掩蔽矩阵中的负无穷值在 softmax 操作后会变为零,从而确保当前位置只能关注当前和之前的词。
8.编码器-解码器注意力
解码器中的第二个多头注意力层是编码器-解码器注意力。
在这个层中,查询 Q 来自于前一个解码器层的输出,而键 K 和值 V 则来自于编码器的最终输出。
这使得解码器在生成输出序列时,能够有效利用编码器对输入序列提取的上下文信息。

数学公式为
Transformer 的优点
-
并行性:完全基于注意力机制,允许并行计算,大大加快了训练速度。
-
长距离依赖:自注意力机制能够直接建模序列中任意两个词之间的关系,无需像 RNN 那样通过长距离的传播来捕捉依赖,因此在处理长序列时效果更好。
-
可解释性:注意力权重可以直观地展示模型在生成某个词时关注了输入序列的哪些部分,提供了一定的可解释性。
-
可扩展性强:容易扩展到大规模模型,比如后来的 GPT、BERT 等都是基于 Transformer 架构。
-
通用性高:不仅限于 NLP,还拓展到图像处理、语音识别等领域。
案例分享
以下是一个简单的 Transformer 模型实现,使用 PyTorch 来演示 Transformer 中的核心组件。
import torch
import torch.nn as nn
import math
# 位置编码 Positional Encoding
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super().__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1).float()
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) # shape: (1, max_len, d_model)
self.register_buffer('pe', pe)
def forward(self, x):
# x shape: (batch_size, seq_len, d_model)
x = x + self.pe[:, :x.size(1)]
return x
# 单头注意力机制
def scaled_dot_product_attention(Q, K, V, mask=None):
d_k = Q.size(-1)
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn = torch.softmax(scores, dim=-1)
return torch.matmul(attn, V), attn
# 多头注意力
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0
self.d_k = d_model // num_heads
self.num_heads = num_heads
self.q_linear = nn.Linear(d_model, d_model)
self.k_linear = nn.Linear(d_model, d_model)
self.v_linear = nn.Linear(d_model, d_model)
self.out = nn.Linear(d_model, d_model)
def forward(self, q, k, v, mask=None):
bs = q.size(0)
# Linear projections
Q = self.q_linear(q).view(bs, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.k_linear(k).view(bs, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.v_linear(v).view(bs, -1, self.num_heads, self.d_k).transpose(1, 2)
scores, attn = scaled_dot_product_attention(Q, K, V, mask)
concat = scores.transpose(1, 2).contiguous().view(bs, -1, self.num_heads * self.d_k)
return self.out(concat)
# 前馈神经网络
class FeedForward(nn.Module):
def __init__(self, d_model, d_ff=2048, dropout=0.1):
super().__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.dropout = nn.Dropout(dropout)
self.linear2 = nn.Linear(d_ff, d_model)
def forward(self, x):
return self.linear2(self.dropout(torch.relu(self.linear1(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.ffn = FeedForward(d_model, d_ff, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask):
attn_output = self.self_attn(x, x, x, mask)
x = self.norm1(x + self.dropout(attn_output))
ffn_output = self.ffn(x)
return self.norm2(x + self.dropout(ffn_output))
# 解码器层
class DecoderLayer(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.cross_attn = MultiHeadAttention(d_model, num_heads)
self.ffn = FeedForward(d_model, d_ff, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, enc_output, tgt_mask, src_mask):
x = self.norm1(x + self.dropout(self.self_attn(x, x, x, tgt_mask)))
x = self.norm2(x + self.dropout(self.cross_attn(x, enc_output, enc_output, src_mask)))
return self.norm3(x + self.dropout(self.ffn(x)))
# 编码器
class Encoder(nn.Module):
def __init__(self, vocab_size, d_model, num_layers, num_heads, d_ff, max_len):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model, max_len)
self.layers = nn.ModuleList([
EncoderLayer(d_model, num_heads, d_ff) for _ in range(num_layers)
])
def forward(self, x, mask):
x = self.embedding(x)
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, mask)
return x
# 解码器
class Decoder(nn.Module):
def __init__(self, vocab_size, d_model, num_layers, num_heads, d_ff, max_len):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model, max_len)
self.layers = nn.ModuleList([
DecoderLayer(d_model, num_heads, d_ff) for _ in range(num_layers)
])
self.fc_out = nn.Linear(d_model, vocab_size)
def forward(self, x, enc_output, tgt_mask, src_mask):
x = self.embedding(x)
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, enc_output, tgt_mask, src_mask)
return self.fc_out(x)
# 完整 Transformer 模型
class Transformer(nn.Module):
def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, num_layers=6,
num_heads=8, d_ff=2048, max_len=512):
super().__init__()
self.encoder = Encoder(src_vocab_size, d_model, num_layers, num_heads, d_ff, max_len)
self.decoder = Decoder(tgt_vocab_size, d_model, num_layers, num_heads, d_ff, max_len)
def make_pad_mask(self, seq, pad_idx=0):
return (seq != pad_idx).unsqueeze(1).unsqueeze(2)
def make_subsequent_mask(self, size):
return torch.triu(torch.ones(size, size), diagonal=1).bool()
def forward(self, src, tgt, src_pad_idx=0, tgt_pad_idx=0):
src_mask = self.make_pad_mask(src, src_pad_idx)
tgt_mask = self.make_pad_mask(tgt, tgt_pad_idx) & ~self.make_subsequent_mask(tgt.size(1)).to(tgt.device)
enc_output = self.encoder(src, src_mask)
return self.decoder(tgt, enc_output, tgt_mask, src_mask)
src = torch.randint(1, 100, (2, 10)) # (batch_size, seq_len)
tgt = torch.randint(1, 100, (2, 10))
model = Transformer(src_vocab_size=100, tgt_vocab_size=100)
output = model(src, tgt)
print(output.shape) # 预测输出: (batch_size, seq_len, vocab_size)
如何学习AI大模型 ?
“最先掌握AI的人,将会晚掌握AI的人有竞争优势,晚掌握AI的人比完全不会AI的人竞争优势更大”。 在这个技术日新月异的时代,不会新技能或者说落后就要挨打。
老蓝我作为一名在一线互联网企业(保密不方便透露)工作十余年,指导过不少同行后辈。帮助很多人得到了学习和成长。
我是非常希望可以把知识和技术分享给大家,但苦于传播途径有限,很多互联网行业的朋友无法获得正确的籽料得到学习的提升,所以也是整理了一份AI大模型籽料包括:AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、落地项目实战等 免费分享出来。
AI大模型学习路线图
100套AI大模型商业化落地方案
100集大模型视频教程
200本大模型PDF书籍
LLM面试题合集
AI产品经理资源合集

大模型学习路线
想要学习一门新技术,你最先应该开始看的就是学习路线图,而下方这张超详细的学习路线图,按照这个路线进行学习,学完成为一名大模型算法工程师,拿个20k、15薪那是轻轻松松!

视频教程
首先是建议零基础的小伙伴通过视频教程来学习,其中这里给大家分享一份与上面成长路线&学习计划相对应的视频教程。文末有整合包的领取方式

技术书籍籽料
当然,当你入门之后,仅仅是视频教程已经不能满足你的需求了,这里也分享一份我学习期间整理的大模型入门书籍籽料。文末有整合包的领取方式

大模型实际应用报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。文末有整合包的领取方式

大模型落地应用案例PPT
光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。文末有整合包的领取方式

大模型面试题&答案
截至目前大模型已经超过200个,在大模型纵横的时代,不仅大模型技术越来越卷,就连大模型相关的岗位和面试也开始越来越卷了。为了让大家更容易上车大模型算法赛道,我总结了大模型常考的面试题。文末有整合包的领取方式

领取方式
这份完整版的 AI大模型学习籽料我已经上传CSDN,需要的同学可以微⭐扫描下方CSDN官方认证二维码免费领取! 
。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)