8:Transformer
🎯 欢迎进入AI的”核心反应堆”!
Section titled “🎯 欢迎进入AI的”核心反应堆”!”恭喜你!🎉 经过前面所有题目的历练,你已经从AI小白成功进阶。现在,是时候挑战现代AI的核心引擎——Transformer了!
这不仅仅是一道题目,更是一次从入门到精通的华丽蜕变!从GPT到ChatGPT,从BERT到Stable Diffusion,几乎所有震撼世界的AI模型都离不开这个神奇的架构。
🚀 激动人心的事实: 你即将亲手实现支撑整个大语言模型时代的核心技术!
📚 学习目标
Section titled “📚 学习目标”✅ 深入理解 Transformer架构的设计哲学 ✅ 掌握注意力机制的数学原理 ✅ MiniGPT实战:理论转化为代码能力 ✅ 培养独立研究论文的能力
💡 学习建议
Section titled “💡 学习建议”-
理论先行: 在写代码之前,确保脑海中有清晰的架构图
-
循序渐进: 从单头注意力到多头,从简单到复杂
-
善用调试: 每一个tensor的shape变化都要心中有数
-
对比分析: 调参数,看变化,做一个”超参数猎人”
-
延伸思考: 想想如何让你的模型更强更快
⚠️ 重要提醒: 虽然这题很硬核,但完成后你将从入门直达精通!这可能是你编程生涯中最有成就感的时刻之一!同时也是面试中的重点题目喔~
🔥 第一部分:理论基础问答
Section titled “🔥 第一部分:理论基础问答”Attention is all you need!
Section titled “Attention is all you need!”在深入代码之前,让我们先”拷问”一下Transformer的灵魂!
** 必答题清单:**
-
Transformer的特点是什么?主要解决什么问题?缺点又是什么?
- 🔍 任务: 在原论文中找到对应位置并标注
-
Layer Norm vs Batch Norm
- 🤔 这两个”标准化兄弟”有什么恩怨情仇?
-
位置编码 (Positional Encoding)
-
深度解析: 什么是位置编码?
-
Transformer用了怎样的位置编码?
-
这种设计的优势在哪里?
-
-
Encoder & Decoder 架构解析
-
画图 + 文字: 详细说明两个模块的结构
-
数据是如何在其中流动的?
-
🎯 面试重点: 务必搞懂每个细节!
-
-
注意力机制核心问题
-
K, Q, V分别代表什么?如何变化?
-
Q×K^T的数学内涵是什么?
-
Scaled Dot-Product Attention vs Additive Attention
-
-
自注意力机制的”自”
- 这个”自”字体现在哪里?为什么这么设计?
-
可学习参数分析
-
注意力机制中有需要学习的参数吗?
-
多头注意力中呢?
-
我们希望这些参数学到什么?
-
-
数据流动全解析
-
文本输入后,各个维度是如何变化的?
-
从token到embedding到输出的完整过程
-
-
BLEU评估指标
- BLEU是什么?在NLP中扮演什么角色?
第二部分:MiniGPT实战挑战
Section titled “第二部分:MiniGPT实战挑战”“纸上得来终觉浅,绝知此事要躬行”
准备好撸起袖子,手搓一个迷你版GPT了吗?
🎮 实战环境准备
Section titled “🎮 实战环境准备”硬件需求: 强烈建议使用云端GPU(参考第0题白嫖攻略)
工具: Jupyter Lab
1️⃣ 数据集获取
Section titled “1️⃣ 数据集获取”tinyshakespeare数据集:
wget https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt💡 偷懒指南: 数据集很小,直接复制粘贴到txt文件也OK!
2️⃣ 超参数配置
Section titled “2️⃣ 超参数配置”import torchimport torch.nn as nnfrom torch.nn import functional as Fimport matplotlib.pyplot as plt
## 超参设置(每个参数都有讲究!)batch_size = 16 # 批处理大小block_size = 32 # 上下文长度max_iters = 5000 # 训练轮数learning_rate = 1e-3 # 学习率device = 'cuda' if torch.cuda.is_available() else 'cpu'n_embd = 64 # embedding维度n_head = 4 # 多头注意力头数n_layer = 4 # transformer层数dropout = 0.0 # dropout率torch.manual_seed(42) # 随机种子,保证可复现3️⃣ 数据预处理
Section titled “3️⃣ 数据预处理”# 读取莎士比亚文本with open('input.txt', 'r', encoding='utf-8') as f: text = f.read()
print(f"数据集总字符数: {len(text):,}")print(f"前300个字符预览:\n{text[:300]}")
# 构建词汇表chars = sorted(list(set(text)))vocab_size = len(chars)print(f"词汇表: {''.join(chars)}")print(f"词汇表大小: {vocab_size}")
# 简单tokenizer实现stoi = {ch: i for i, ch in enumerate(chars)}itos = {i: ch for i, ch in enumerate(chars)}encode = lambda s: [stoi[c] for c in s]decode = lambda l: ''.join([itos[i] for i in l])
# 测试编解码print(f"编码测试: {encode('Hello World!')}")print(f"解码测试: {decode(encode('Hello World!'))}")4️⃣ 数据分批处理
Section titled “4️⃣ 数据分批处理”def get_batch(split): """ 生成训练批次数据
你需要实现: 1. 从训练/验证集中随机采样 2. 生成输入序列x和目标序列y 3. 返回正确维度的tensor """ ################### # 你的代码在这里 ################### pass5️⃣ 模型架构实现
Section titled “5️⃣ 模型架构实现”🔥 这是整个项目的核心!必须手工实现!
class Head(nn.Module): """单头自注意力"""
def __init__(self, head_size): super().__init__() # QKV投影矩阵 self.key = nn.Linear(n_embd, head_size, bias=False) self.query = nn.Linear(n_embd, head_size, bias=False) self.value = nn.Linear(n_embd, head_size, bias=False)
# 下三角mask矩阵(防止看到未来) self.register_buffer('tril', torch.tril(torch.ones(block_size, block_size))) self.dropout = nn.Dropout(dropout)
def forward(self, x): B, T, C = x.shape ################### # 注意力计算逻辑 # 1. 计算Q, K, V # 2. 计算注意力分数 # 3. 应用mask # 4. 加权求和 ################### pass
class MultiHeadAttention(nn.Module): """多头注意力:并行处理多个注意力头"""
def __init__(self, num_heads, head_size): super().__init__() self.heads = nn.ModuleList([Head(head_size) for _ in range(num_heads)]) self.proj = nn.Linear(n_embd, n_embd) self.dropout = nn.Dropout(dropout)
def forward(self, x): ################### # 多头并行计算与合并 ################### pass
class FeedForward(nn.Module): """前馈神经网络:简单而强大""" ################### # 实现两层线性变换+激活 ################### pass
class Block(nn.Module): """Transformer Block:communication + computation""" ################### # 组装完整的transformer块 # LayerNorm + MultiHeadAttention + LayerNorm + FeedForward ################### pass
class BigramLanguageModel(nn.Module): """完整的语言模型"""
def __init__(self): super().__init__() # embedding表 self.token_embedding_table = nn.Embedding(vocab_size, n_embd) self.position_embedding_table = nn.Embedding(block_size, n_embd)
# 堆叠transformer块 self.blocks = nn.Sequential(*[Block(n_embd, n_head=n_head) for _ in range(n_layer)]) self.ln_f = nn.LayerNorm(n_embd) self.lm_head = nn.Linear(n_embd, vocab_size)
def forward(self, idx, targets=None): ################### # 完整前向传播 # 1. token + position embedding # 2. 通过transformer块 # 3. 输出预测 # 4. 计算损失(如果有target) ################### pass
def generate(self, idx, max_new_tokens): """文本生成:让AI说话!""" for _ in range(max_new_tokens): # 裁剪到block_size idx_cond = idx[:, -block_size:] # 预测下一个token logits, _ = self(idx_cond) logits = logits[:, -1, :] # 只要最后一个时间步 probs = F.softmax(logits, dim=-1) # 采样下一个token idx_next = torch.multinomial(probs, num_samples=1) idx = torch.cat((idx, idx_next), dim=1) return idx6️⃣ 模型评估 📊
Section titled “6️⃣ 模型评估 📊”@torch.no_grad()def estimate_loss(): """评估训练和验证损失""" out = {} model.eval() ################### # 计算平均损失 ################### model.train() return out7️⃣ 模型训练
Section titled “7️⃣ 模型训练”# 实例化模型model = BigramLanguageModel().to(device)print(f"模型参数量: {sum(p.numel() for p in model.parameters())/1e6:.2f}M")
# 训练循环optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate)train_losses, val_losses = [], []
for iter in range(max_iters): ################### # 训练循环实现 # 1. 获取batch # 2. 前向传播 # 3. 计算损失 # 4. 反向传播 # 5. 参数更新 # 6. 定期评估 ################### pass
# 绘制损失曲线plt.figure(figsize=(10, 5))plt.plot(train_losses, label='Train Loss', color='#FF6B6B')plt.plot(val_losses, label='Validation Loss', color='#4ECDC4')plt.xlabel('Iteration')plt.ylabel('Loss')plt.title('Training Progress: Loss Curves')plt.legend()plt.grid(True, alpha=0.3)plt.savefig('loss_plot.png', dpi=300, bbox_inches='tight')
# 生成莎士比亚风格文本print("AI莎士比亚开始创作...")context = torch.zeros((1, 1), dtype=torch.long, device=device)generated_text = decode(model.generate(context, max_new_tokens=2000)[0].tolist())print(generated_text)8️⃣ 结果分析
Section titled “8️⃣ 结果分析”回答以下问题:
-
Validation Loss收敛值是多少?
-
MiniGPT参数量统计(应该<1M)
-
显存占用情况(应该<1G)
9️⃣ 挑战性进阶问题
Section titled “9️⃣ 挑战性进阶问题”-
RoPE vs 正弦位置编码
-
为什么现代GPT使用Rotary Position Embedding?
-
尝试在MiniGPT中实现RoPE并对比性能!
-
-
LayerNorm位置之争
-
Pre-LN vs Post-LN:为什么前者更稳定?
-
修改代码实现Pre-LN架构并分析训练稳定性!
-
-
计算复杂度分析
-
当block_size增加到128时会发生什么?
-
尝试**梯度检查点(Gradient Checkpointing)**减少显存占用!
-
-
FlashAttention算法
- 了解这个让Transformer飞起来的神奇算法!
⚠️ 重要提醒
Section titled “⚠️ 重要提醒”AI工具使用: 本题强烈建议纯手工实现!这可能是你最后一次有机会完全从零手撸这么核心的算法了,好好珍惜这个过程吧!
-
代码文件: ml-8-姓名-学号.py
-
理论答案: ml-8-姓名-学号.md
-
压缩包提交
-
邮箱: gimmerml401@163.com
-
主题: 8-姓名-学号
出题人:百事可乐
QQ:2465800571
