核心内容摘要
老旧设备复活指南:3步解锁你的Mac升级潜力
本文面向想转行AI的软件工程师从工程视角讲解Transformer与注意力机制的核心原理。
通过代码搜索比喻解释Self-Attention的Q/K/V机制详述Multi-Head Attention、位置编码及编码器层结构并提供可运行的极简版PyTorch实现。
文章对比了BERT与GPT的结构差异给出了工程实践建议帮助读者真正理解大模型底层原理为后续学习LLM打下坚实基础。
面向想转行 AI 的软件工程师这一期我们从工程师视角把注意力机制和 Transformer 讲清楚再用一段可运行的 PyTorch 代码手写一个极简版 Transformer。
看完跟敲一遍你就能真正明白大模型底层到底在做什么。
为什么学完 CNN / LSTM还要补上 Transformer前面几篇文章已经讲过多层感知机MLP、CNN适合图像和 RNN / LSTM适合序列。
那为什么现在还要多学一个看起来更复杂的 Transformer从 2017 年《Attention Is All You Need》之后NLP 乃至深度学习几乎被 Transformer 一统江湖核心原因大致有三点并行计算更友好RNN / LSTM必须按时间顺序依次计算第 1 个 token、第 2 个 token……难以充分利用 GPU 并行Transformer一整句可以“同时算”Self-Attention 的计算天然适合并行。
更擅长捕捉长距离依赖RNN信息要一层层沿时间传递句子一长前面的信息就容易“衰减”掉TransformerSelf-Attention 让任意两个 token 之间可以“一跳直达”前后位置可以直接建立联系。
特别适合“堆大”只要把模型的层数、宽度、训练数据量往上堆性能就能稳定提升这就是今天各种 GPT、LLaMA、国产大模型背后的 scaling law 思路。
对工程师来说还有三个非常现实的理由几乎所有主流 LLMGPT、LLaMA、GLM…底层都是 Transformer 或它的变体做 RAG、Agent、本地微调开源模型时你真正接触和调整的就是 Transformer 权重面试里问「Q/K/V、Self-Attention、Multi-Head」已经是常规项目。
本期目标你能用自己的话说清 Self-Attention 的原理并且能看懂 / 改写一个极简 Transformer 的实现。
先打个比方把 Self-Attention 想象成“代码搜索”想象一个经典开发场景你打开一个 300 行的函数想弄明白变量user_info到底干嘛用。
通常你会在 IDE 里搜索user_info的所有使用位置对每个位置做判断这个上下文对理解user_info有多重要最后在脑子里把这些关键位置的信息综合起来形成一个对user_info的整体认识。
Self-Attention 本质上也是在做类似的事情对于序列里的每一个 token都“搜索”整个序列看其他哪些 token 跟它相关然后按重要程度把这些信息汇总进来。
这里有三个核心角色Query、Key、ValueQueryQ当前这个 token 想“问”的问题 —— 我要关注谁KeyK每个 token 对外公开的“名片 / 索引”ValueV每个 token 真正要传递的内容。
计算过程可以理解为用当前 token 的 Query 和所有 token 的 Key 去算相似度分数相关性评分对这些分数做 softmax变成一组“注意力权重”用这些权重对所有 token 的 Value 做加权和得到当前 token 的新表示。
一句话
总结每个 token 在全序列范围内“给别人打分”再把自己觉得重要的信息“抄过来”。
Q / K / V 到底长什么样假设一句话有seq_len个 token每个 token 的隐向量维度是d_model输入Xshape [seq_len, d_model]用三套权重矩阵把X映射到 Q / K / V 空间Q X * W_Q # [seq_len, d_k] K X * W_K # [seq_len, d_k] V X * W_V # [seq_len, d_v]然后#
相似度注意力得分 scores Q K.T # [seq_len, seq_len] #
缩放 softmax weights softmax(scores / sqrt(d_k), dim-
#
加权和 output weights V # [seq_len, d_v]几条必须记住的“工程直觉”scores[i, j]表示第 i 个 token 对第 j 个 token 的注意力打分weights[i]是第 i 个 token 对整个序列的“注意力分布”output[i]是第 i 个 token 汇总其他 token 信息后的新表示。
Multi-Head Attention让“多个视角”一起工作单头注意力相当于一个“通才型专家”在看问题。
Multi-Head Attention 则是把问题拆给多个“专业小组”每个 head 有自己的一套 Q / K / V 投影矩阵有的 head 更擅长捕捉局部语法有的 head 擅长实体指代有的关注长距离依赖最后把所有 head 的输出 concat 在一起再做一次线性变换形成综合表示。
在 PyTorch 里你可以直接用内置模块self.self_attn nn.MultiheadAttention(d_model, nhead, dropoutdropout)d_model总特征维度如
128、
1024nhead注意力头数如
4、
16内部会自动切分为d_head d_model / nhead。
可以这样理解Multi-Head 多个子空间里的 Self-Attention 并行运行最后把它们的结论拼起来。
位置编码Positional Encoding告诉模型“顺序很重要”Self-Attention 本身只关心 token 向量之间的相似度对“顺序”是天然不敏感的。
但在自然语言和时间序列里位置与顺序非常关键“我爱你”和“你爱我”顺序一换意思完全不同时间序列中先后顺序会直接影响预测。
因此需要把位置信息注入到每个 token 的向量中x embedding(tokens) # [B, L, d_model] x x positional_encoding[:L] # 加上位置编码经典的一种做法是正弦 / 余弦位置编码。
下面是一个可直接用的实现注意这里采用[batch_size, seq_len, d_model]形式import math import torch import torch.nn as nn class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len
: super().__init__() pe torch.zeros(max_len, d_model) # [max_len, d_model] position torch.arange(0, max_len, dtypetorch.float).unsqueeze(
# 频率因子 div_term torch.exp( torch.arange(0, d_model,
.float() * (-math.log(
10000.
/ d_model) ) pe[:, 0::2] torch.sin(position * div_term) # 偶数维用 sin pe[:, 1::2] torch.cos(position * div_term) # 奇数维用 cos pe pe.unsqueeze(
# [1, max_len, d_model] self.register_buffer(pe, pe) def forward(self, x): # x: [batch_size, seq_len, d_model] return x self.pe[:, :x.size(
]
一个编码器层长什么样残差连接 LayerNorm一个典型的 Transformer Encoder Layer 结构如下输入 x ↓ Multi-Head Self-Attention 残差x x Attn(x) LayerNorm ↓ 前馈网络 FFN两层全连接 激活 残差x x FFN(x) LayerNorm 输出 x对应 PyTorch 的简化实现如下采用官方推荐的[seq_len, batch_size, d_model]形式import torch.nn.functional as F class TransformerEncoderLayer(nn.Module): def __init__(self, d_model, nhead, dim_feedforward512, dropout
0.
: super().__init__() self.self_attn nn.MultiheadAttention(d_model, nhead, dropoutdropout) self.linear1 nn.Linear(d_model, dim_feedforward) self.dropout nn.Dropout(dropout) self.linear2 nn.Linear(dim_feedforward, d_model) self.norm1 nn.LayerNorm(d_model) self.norm2 nn.LayerNorm(d_model) self.dropout1 nn.Dropout(dropout) self.dropout2 nn.Dropout(dropout) def forward(self, src): src: [seq_len, batch_size, d_model] # Self-Attention src2 self.self_attn(src, src, src, need_weightsFalse)[0] src src self.dropout1(src
# 残差 src self.norm1(src) # LayerNorm # 前馈网络 FFN src2 self.linear2(self.dropout(F.relu(self.linear1(src)))) src src self.dropout2(src
# 残差 src self.norm2(src) return src残差连接 LayerNorm的好处避免在深层网络中梯度消失每一层只需要学习“增量”而不是从零构造新表示训练更稳定尤其是当你堆了很多层时尤为重要。
极简 Transformer从零写一个可跑的小模型下面实现一个可直接运行的极简 Transformer 编码器用来做简化版“语言建模”每个位置预测一个 token。
模型定义这里我们统一采用 PyTorch Transformer 常用的 shape中间层使用[seq_len, batch_size, d_model]输入输出对用户保持[batch_size, seq_len, ...]。
import torch import torch.nn as nn import torch.nn.functional as F import math # ---------- 位置编码 ---------- class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len
: super().__init__() pe torch.zeros(max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(
div_term torch.exp( torch.arange(0, d_model,
.float() * (-math.log(
10000.
/ d_model) ) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(
# [max_len, 1, d_model]方便和 [L, B, d] 相加 self.register_buffer(pe, pe) def forward(self, x): x: [seq_len, batch_size, d_model] seq_len x.size(
return x self.pe[:seq_len] # [seq_len, 1, d_model] 自动广播到 batch 维 # ---------- 编码器层 ---------- class TransformerEncoderLayer(nn.Module): def __init__(self, d_model, nhead, dim_feedforward512, dropout
0.
: super().__init__() self.self_attn nn.MultiheadAttention(d_model, nhead, dropoutdropout) self.linear1 nn.Linear(d_model, dim_feedforward) self.dropout nn.Dropout(dropout) self.linear2 nn.Linear(dim_feedforward, d_model) self.norm1 nn.LayerNorm(d_model) self.norm2 nn.LayerNorm(d_model) self.dropout1 nn.Dropout(dropout) self.dropout2 nn.Dropout(dropout) def forward(self, src): src: [seq_len, batch_size, d_model] # Self-Attention src2 self.self_attn(src, src, src, need_weightsFalse)[0] src src self.dropout1(src
src self.norm1(src) # Feed Forward src2 self.linear2(self.dropout(F.relu(self.linear1(src)))) src src self.dropout2(src
src self.norm2(src) return src # ---------- 极简 Transformer 编码器 ---------- class SimpleTransformer(nn.Module): 极简 Transformer 编码器 语言建模头 def __init__(self, vocab_size, d_model128, nhead4, num_layers2, dim_feedforward512, dropout
0.
: super().__init__() self.embedding nn.Embedding(vocab_size, d_model) self.pos_encoder PositionalEncoding(d_model) self.layers nn.ModuleList([ TransformerEncoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_layers) ]) self.fc_out nn.Linear(d_model, vocab_size) self.d_model d_model self._reset_parameters() def _reset_parameters(self): for p in self.parameters(): if p.dim() 1: nn.init.xavier_uniform_(p) def forward(self, src): src: [batch_size, seq_len] return: [batch_size, seq_len, vocab_size] # [B, L] - [L, B] src src.transpose(0,
# 嵌入 缩放 src self.embedding(src) * math.sqrt(self.d_model) # [L, B, d_model] # 加位置编码 src self.pos_encoder(src) # [L, B, d_model] # 逐层 Encoder for layer in self.layers: src layer(src) # 输出到 vocab output self.fc_out(src) # [L, B, vocab_size] return output.transpose(0,
# [B, L, vocab_size]
测试模型输出形状def create_dummy_data(vocab_size50, seq_len8, batch_size
: src torch.randint(0, vocab_size, (batch_size, seq_len)) tgt torch.randint(0, vocab_size, (batch_size, seq_len)) return src, tgt model SimpleTransformer(vocab_size
src, tgt create_dummy_data(vocab_size100, seq_len10, batch_size
output model(src) print(Input shape:, src.shape) # torch.Size([2, 10]) print(Output shape:, output.shape) # torch.Size([2, 10, 100])只要看到输出形状是[batch_size, seq_len, vocab_size]就说明这个模型可以用来做“每个位置预测一个 token”这类任务即简化的语言建模。
简单训练循环示例def train_loop(model, optimizer, criterion, epochs5, vocab_size100, seq_len10, batch_size
: for epoch in range(1, epochs
: model.train() # 随机生成训练数据 src torch.randint(0, vocab_size, (batch_size, seq_len)) tgt src.clone() # 简化预测自己类似自编码 / 语言模型雏形 optimizer.zero_grad() output model(src) # [B, L, vocab_size] loss criterion(output.view(-1, vocab_size), tgt.view(-
) loss.backward() optimizer.step() print(fEpoch {epoch}, Loss: {loss.item():.4f}) model SimpleTransformer(vocab_size
optimizer torch.optim.Adam(model.parameters(), lr1e-
criterion nn.CrossEntropyLoss() train_loop(model, optimizer, criterion)你会看到 loss 逐步下降说明模型确实在学习“序列模式”哪怕这里只是用随机数据做演示。
Encoder vs DecoderBERT 和 GPT 的结构差异在理解了上面的 Encoder 结构之后你离 BERT / GPT 只差半步。
BERT纯 Encoder偏“理解型”结构堆叠多层 Encoder预训练目标Masked Language Model随机遮挡一些词让模型填空特点整体语义理解能力强适合分类、匹配、阅读理解、抽取式问答等任务。
GPT纯 Decoder偏“生成型”结构堆叠多层 Decoder常见实现可理解为“带 Mask 的 Self-Attention FFN”预训练目标给定前缀预测下一个 token自回归特点擅长续写、对话、代码生成等生成式任务。
核心区别在于注意力的“方向”BERT 的 Self-Attention 是双向的可以同时看到左边和右边GPT 的 Self-Attention 是单向的通过 Mask 限制只能看到左边不能偷看“未来”因此天然适合自回归生成。
工程视角你需要掌握到什么程度暂时不必从头手写 Multi-Head Attention 的全部矩阵推导搭一个完整的 Encoder-Decoder 机器翻译系统。
但至少应该做到概念上能画出整体流程图输入 → Embedding Positional Encoding → N 层 Encoder / Decoder → 输出能讲清楚Q / K / V、Self-Attention、Multi-Head、残差、LayerNorm 各自的作用。
代码上看懂 PyTorch 的nn.MultiheadAttention和nn.TransformerEncoderLayer主要参数能修改一个简单Transformer 的关键超参d_model,nhead,num_layers并观察损失与速度变化。
实战上能读懂并调整 HuggingFace 模型配置中的字段例如hidden_size对应d_model、num_attention_heads对应nhead、num_hidden_layers对应你代码里的层数面试时不再把“注意力机制”当黑盒而是能把主要计算过程和设计动机讲清楚。
文末小建议写一写改造极简 Transformer做一个“字符级语言模型”从一本英文小说如《Alice in Wonderland》中截取几千字符构建字符级 vocaba-z、空格、标点等用SimpleTransformer训练几轮实现一个简单的“给定前缀 → 逐字符生成后续文本”的小 Demo。
位置编码对比实验训练两版模型一版带位置编码一版去掉位置编码在相同数据集上对比 loss 或生成效果用一段话
总结位置编码到底带来了什么提升。
阅读一个开源模型的配置文件随便选一个小型开源模型如distilbert-base-uncased、tiny-gpt2打开它在 HuggingFace 上的 config用中文回答hidden_size 对应什么num_attention_heads 对应什么num_hidden_layers 对应你本期代码里的哪一部分AI大模型从0到精通全套学习大礼包我在一线互联网企业工作十余年里指导过不少同行后辈。
帮助很多人得到了学习和成长。
只要你是真心想学AI大模型我这份资料就可以无偿共享给你学习。
大模型行业确实也需要更多的有志之士加入进来我也真心希望帮助大家学好这门技术如果日后有什么学习上的问题欢迎找我交流有技术上面的问题我是很愿意去帮助大家的如果你也想通过学大模型技术去帮助就业和转行可以扫描下方链接大模型重磅福利入门进阶全套104G学习资源包免费分享
从入门到精通的全套视频教程包含提示词工程、RAG、Agent等技术点
AI大模型学习路线图还有视频解说全过程AI大模型学习路线
学习电子书籍和技术文档市面上的大模型书籍确实太多了这些是我精选出来的
大模型面试题目详解
这些资料真的有用吗?这份资料由我和鲁为民博士共同整理鲁为民博士先后获得了北京清华大学学士和美国加州理工学院博士学位在包括IEEE Transactions等学术期刊和诸多国际会议上发表了超过50篇学术论文、取得了多项美国和中国发明专利同时还斩获了吴文俊人工智能科学技术奖。
目前我正在和鲁博士共同进行人工智能的研究。
所有的视频由智泊AI老师录制且资料与智泊AI共享相互补充。
这份学习大礼包应该算是现在最全面的大模型学习资料了。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。
智泊AI始终秉持着“让每个人平等享受到优质教育资源”的育人理念通过动态追踪大模型开发、数据标注伦理等前沿技术趋势构建起前沿课程智能实训精准就业的高效培养体系。
课堂上不光教理论还带着学员做了十多个真实项目。
学员要亲自上手搞数据清洗、模型调优这些硬核操作把课本知识变成真本事如果说你是以下人群中的其中一类都可以来智泊AI学习人工智能找到高薪工作一次小小的“投资”换来的是终身受益应届毕业生无工作经验但想要系统学习AI大模型技术期待通过实战项目掌握核心技术。
零基础转型非技术背景但关注AI应用场景计划通过低代码工具实现“AI行业”跨界。
业务赋能 突破瓶颈传统开发者Java/前端等学习Transformer架构与LangChain框架向AI全栈工程师转型。
获取方式有需要的小伙伴可以保存图片到wx扫描二v码免费领取【保证100%免费】