文章

AI model 底层代码分解学习

Loading collection...

📚 AI 底层代码实现全景大纲(基于 PyTorch)

第一阶段:基石篇 —— 算力与数据的底层理解

目标:脱离高级封装,看透 PyTorch 里的张量(Tensor)运算本质。
  • 1.1 张量(Tensor)的数学本质
    • 数学解释:多维数组(标量、向量、矩阵、高阶张量)及其运算(点积、矩阵乘法 @)。
      • 代码关键组件:torch.tensorview()reshape()permute()transpose()unsqueeze()
        • 难点攻克:理解 Shape(形状)在底层的变换逻辑(如 [B, T, C] 与 [B, n_heads, T, d_k] 的映射关系)。
        • 1.2 自动求导(Autograd)原理
          • 核心机制:计算图(Computational Graph) 和 链式法则
            • 代码核心组件:requires_grad=True, 梯度累加与清零(zero_grad()),反向传播(loss.backward())。
              • 底层进阶:手动实现一个简单的反向传播而不调用 PyTorch Autograd。

              第二阶段:积木篇 —— 神经网络基础模块的纯手写

              目标:不用 nn.Sequential,自己用 nn.Module 搭积木。
              • 2.1 线性层与激活函数
                • 底层公式:y=σ(Wx+b)y=σ(Wx+b)。代码:nn.Linearnn.GELU / nn.ReLU
                • 2.2 归一化技术(让训练不崩的关键)
                  • LayerNorm(大模型标配):对样本的特征维度做归一化。代码:nn.LayerNorm
                    • BatchNorm(CNN 标配):对样本的批次维度做归一化。代码:nn.BatchNorm2d
                    • 2.3 正则化防过拟合
                      • 随机丢弃:nn.Dropout。底层原理:训练时随机屏蔽神经元,测试时按比例放大(或不放大)权重。

                      第三阶段:架构篇 —— 现代大模型(Transformer)的底层复现

                      目标:彻底弄懂 Attention 机制,实现 BERT 编码器和 GPT 解码器。
                      • 3.1 缩放点积注意力(Scaled Dot-Product Attention)
                        • 数学公式还原:Softmax( (Q @ K^T) / sqrt(d_k) ) @ V
                          • 代码关键点:q @ k.transpose(-2, -1) 的维度变换。
                          • 3.2 多头自注意力(Multi-Head Self-Attention)
                            • 分拆逻辑:利用 view 和 transpose 将大矩阵切分为多个头并行计算。
                              • 最后拼接:contiguous().view() 还原维度。
                              • 3.3 BERT 编码器底层(双向+填空任务)
                                • 结构复现:[多头注意力 + 残差连接 + 层归一化] + [前馈神经网络 + 残差连接 + 层归一化]
                                  • 位置编码:不可学习的 sin/cos 位置编码(公式手写)。
                                  • 3.4 GPT 解码器底层(单向+生成任务)【最高频考点】
                                    • 核心差异:引入 因果掩码(Causal Mask / Upper Triangular Mask)
                                      • 代码逻辑:构造上三角矩阵 torch.triu,利用 masked_fill(..., float('-inf')) 屏蔽未来信息。

                                      第四阶段:多模态篇 —— 打通视觉与文本的桥梁

                                      目标:把图像和文字塞进同一个模型里,复现 LLaVA 或 GPT-4V 的核心逻辑。
                                      • 4.1 视觉编码器(特征提取层)
                                        • 底层替代(或用前馈模型模拟):CNN(nn.Conv2d)或 ViT 将图片像素转为特征矩阵。
                                        • 4.2 投影层(Projector / 翻译官)【关键】
                                          • 底层逻辑:由于图像特征维度(如 1024)与 LLM 特征维度(如 768)不一致,必须通过一个 MLP(多层感知机) 或线性层进行“降维对齐”。
                                            • 代码重点:nn.Linear(d_vision, d_llm) 以及 GELU 激活。
                                            • 4.3 多模态序列拼接
                                              • 输入构造:inputs_embeds = torch.cat([image_tokens, text_tokens], dim=1)
                                                • 动态位置编码:因为拼接后的序列总长变了,需要动态计算 torch.arange(0, total_len)

                                                第五阶段:工程篇 —— 大模型训练与推理的底层框架

                                                目标:复现完整的 Train Loop,并掌握防止模型崩掉的工程技巧。
                                                • 5.1 优化器与学习率调度
                                                  • 代码:optim.AdamW(带权重衰减,是 Transformer 的标准)。
                                                    • 底层策略:学习率预热(Warmup)(前 10%-20% 步数线性增加到目标学习率)。
                                                    • 5.2 梯度裁剪(Gradient Clipping)
                                                      • 原理:限制梯度的 L2 范数,防止梯度爆炸导致 Loss 变成 NaN
                                                        • 底层代码:torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
                                                        • 5.3 训练循环的标准脚本结构
                                                          • 标准流程:zero_grad() -> forward() -> loss() -> backward() -> clip_grad() -> step()
                                                          • 5.4 数据加载(Dataloader)与掩码处理(Masking)
                                                            • 处理变长序列的 Padding 和 Attention Mask,让模型不把填充的 0 当作真实文本去预测。

                                                            第六阶段:进阶篇 —— 高效微调与工业落地(可选)

                                                            目标:了解底层如何实现大模型的低成本部署。
                                                            • 6.1 参数高效微调(LoRA 低秩适配)
                                                              • 底层实现:冻结原始 LLM 权重,在原来的线性层旁并接两个小矩阵 (A, B),只更新这两个小矩阵。数学本质是 W′=W+BAW′=W+BA
                                                              • 6.2 分布式训练基础
                                                                • 概念:数据并行(Data Parallel),DistributedDataParallel(DDP)底层如何利用多卡 GPU 同步梯度。
                                                                不需要任何高级库(只需 PyTorch),复制下来就能直接运行。 在底层构建了一个“视觉+文本”的大模型雏形,并用随机数据演示它训练的过程。
                                                                import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import math
                                                                ==============================================================================
                                                                模块 1: 核心架构基础 —— 多头自注意力机制 (带因果掩码的 GPT 版本)
                                                                ==============================================================================
                                                                class MultiHeadCausalAttention(nn.Module): def init(self, d_model, n_heads): super().init() assert d_model % n_heads == 0 self.n_heads = n_heads self.d_k = d_model // n_heads # 每个头的特征维度
                                                                # 定义 Q, K, V 的线性映射层 (数学公式: Q = X*W_Q) 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): B, T, C = x.shape # B: Batch大小, T: 序列长度(图像+文本总长), C: 特征维度 # 1. 计算 Q, K, V,并切分为多头 (view 和 transpose 是代码难点) # 形状变化: [B, T, C] -> [B, T, n_heads, d_k] -> [B, n_heads, T, d_k] q = self.w_q(x).view(B, T, self.n_heads, self.d_k).transpose(1, 2) k = self.w_k(x).view(B, T, self.n_heads, self.d_k).transpose(1, 2) v = self.w_v(x).view(B, T, self.n_heads, self.d_k).transpose(1, 2) # 2. 计算缩放点积得分 (Attention核心公式: Q * K^T / sqrt(d_k)) # K 转置后变为 [B, n_heads, d_k, T],与 Q 做矩阵乘法得到 [B, n_heads, T, T] scores = q @ k.transpose(-2, -1) / math.sqrt(self.d_k) # ========================================================================= # ⚠️ 核心代码:因果掩码 (Causal Mask) 【这是 GPT 与 BERT 的唯一区别】 # 训练时,模型预测第 t 个词,绝对不能看到第 t+1 个及以后的词。 # 否则就像考试时偷看了答案。 # ========================================================================= # 生成一个 T*T 的上三角矩阵,对角线及以上是 True,下方是 False causal_mask = torch.triu(torch.ones(T, T), diagonal=1).bool().to(x.device) # 把"未来"位置的得分替换为负无穷大(-inf)。经过 softmax 后,这些位置的权重就是 0。 scores = scores.masked_fill(causal_mask, float('-inf')) # 3. 应用 Softmax 得到注意力权重,并乘以 V attn_weights = F.softmax(scores, dim=-1) out = attn_weights @ v # [B, n_heads, T, d_k] # 4. 将多头重新拼接回原维度 (transpose -> contiguous -> view) out = out.transpose(1, 2).contiguous().view(B, T, C) # 5. 最后的线性变换 return self.w_o(out)
                                                                ==============================================================================
                                                                模块 2: 前馈神经网络 (FFN) —— 全连接+激活
                                                                ==============================================================================
                                                                class FeedForward(nn.Module): def init(self, d_model, d_ff=2048): super().init() # 两层全连接,中间用 GELU 激活 (BERT和GPT均使用 GELU) self.linear1 = nn.Linear(d_model, d_ff) self.linear2 = nn.Linear(d_ff, d_model)
                                                                def forward(self, x): return self.linear2(F.gelu(self.linear1(x)))
                                                                ==============================================================================
                                                                模块 3: 单个 Transformer Block (残差连接 + 层归一化)
                                                                ==============================================================================
                                                                class TransformerBlock(nn.Module): def init(self, d_model, n_heads, dropout=0.1): super().init() self.attn = MultiHeadCausalAttention(d_model, n_heads) # 带因果掩码的注意力 self.ffn = FeedForward(d_model) # 层归一化 (LayerNorm),大模型标配 self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.dropout = nn.Dropout(dropout)
                                                                def forward(self, x): # Pre-Norm 结构 (先归一化,再走注意力,最后残差连接) x = x + self.dropout(self.attn(self.norm1(x))) x = x + self.dropout(self.ffn(self.norm2(x))) return x
                                                                ==============================================================================
                                                                模块 4: 多模态投影层 (Projector) —— 连接图像和文本的翻译官
                                                                ==============================================================================
                                                                class MultimodalProjector(nn.Module): def init(self, d_vision=1024, d_llm=768): super().init() # 视觉特征(假设1024维)和LLM特征(768维)不匹配,通过 MLP 层强行对齐维度 self.proj = nn.Sequential( nn.Linear(d_vision, d_llm * 4), # 先放大(通常在实践中有利于提取特征) nn.GELU(), # 激活函数 nn.Linear(d_llm * 4, d_llm) # 再降维到大语言模型能接受的尺寸 (768) )
                                                                def forward(self, image_features): # 输入: [Batch, 图像块数量, 1024] 输出: [Batch, 图像块数量, 768] return self.proj(image_features)
                                                                ==============================================================================
                                                                模块 5: 完整的多模态大模型 (融合视觉编码器 + GPT LLM)
                                                                ==============================================================================
                                                                class MultimodalGPT(nn.Module): def init(self, vocab_size, d_model=768, n_heads=12, n_layers=6, max_len=512, d_vision=1024): super().init() self.d_model = d_model
                                                                # 1. 多模态投影层 (视觉转文本) self.projector = MultimodalProjector(d_vision, d_model) # 2. 文本嵌入层 (Word Embedding) self.token_embedding = nn.Embedding(vocab_size, d_model) # 3. 位置编码 (Positional Embedding) # GPT/Transformer 不像 RNN 有顺序感,必须显式注入位置信息 self.position_embedding = nn.Embedding(max_len, d_model) # 4. 堆叠 n_layers 个 Transformer Block self.blocks = nn.ModuleList([ TransformerBlock(d_model, n_heads) for _ in range(n_layers) ]) # 5. 最终层归一化 self.norm = nn.LayerNorm(d_model) # 6. 语言模型头 (LM Head) —— 把特征投影回词表大小,预测下一个词 self.lm_head = nn.Linear(d_model, vocab_size) def forward(self, image_features, input_ids): # image_features: 视觉编码器(如CLIP-ViT)提取的特征 [B, 576, 1024] # input_ids: 已经转为数字的文本序列 [B, 文本长度] B, T_text = input_ids.shape device = input_ids.device # 一、处理图像部分:经过投影层,变成大模型能读的 768 维向量 img_embeds = self.projector(image_features) # [B, 576, 768] img_len = img_embeds.shape[1] # 二、处理文本部分:转成 768 维向量 txt_embeds = self.token_embedding(input_ids) # [B, 20, 768] txt_len = txt_embeds.shape[1] # ⚠️ 三、物理拼接!把图像块当成“前缀词”,放在文本前面 # 序列变成了: [图像块_1 ... 图像块_576, 文本_1 ... 文本_20] combined_embeds = torch.cat([img_embeds, txt_embeds], dim=1) # [B, 596, 768] # 四、动态计算并加上位置编码 (因为序列总长度是 576+20=596) total_len = combined_embeds.shape[1] # 生成 0, 1, 2, ..., 595 的位置索引 positions = torch.arange(0, total_len, device=device).unsqueeze(0) combined_embeds = combined_embeds + self.position_embedding(positions) # 五、扔进 Transformer 堆叠块 x = combined_embeds for block in self.blocks: x = block(x) x = self.norm(x) # 六、用 LM Head 预测下一个词的概率 (取最后所有文本部分即可,也可以取全部) # 全取计算也没问题,因为因果掩码会自动屏蔽掉图像块里的无效读取 logits = self.lm_head(x) # [B, 596, 词表大小] return logits
                                                                ==============================================================================
                                                                模块 6: 实战训练循环 (端到端运行)
                                                                ==============================================================================
                                                                if name == "main": print("🚀 开始初始化多模态模型底层训练演示...")
                                                                # 1. 定义超参数 BATCH_SIZE = 4 VOCAB_SIZE = 10000 # 假设词表有1万个词 D_VISION = 1024 # 模拟图像特征维度 D_MODEL = 768 # GPT 内部特征维度 IMG_PATCHES = 49 # 模拟图片被切成了 49 个块 (7*7) TXT_LEN = 20 # 文本序列长度 # 2. 初始化模型 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = MultimodalGPT(vocab_size=VOCAB_SIZE, d_model=D_MODEL, n_heads=8, n_layers=3).to(device) # 3. 初始化优化器 (AdamW) 和 损失函数 (交叉熵) optimizer = optim.AdamW(model.parameters(), lr=1e-4) criterion = nn.CrossEntropyLoss() print(f"模型参数量: {sum(p.numel() for p in model.parameters()) / 1_000_000:.2f} 百万 (M)") print("👇 下面开始模拟 3 个 Epoch 的训练过程") # 4. 模拟训练循环 for epoch in range(3): model.train() # 开启训练模式 total_loss = 0.0 # 模拟一个 Batch 的数据 # 图像特征 (模拟来自 CLIP 视觉编码器的输出) dummy_image_features = torch.randn(BATCH_SIZE, IMG_PATCHES, D_VISION).to(device) # 文本输入 (模拟转换好的 Token ID) dummy_text_ids = torch.randint(0, VOCAB_SIZE, (BATCH_SIZE, TXT_LEN)).to(device) # --- 训练的核心数学步骤 --- optimizer.zero_grad() # 1. 清空旧梯度 # 2. 前向传播 (Forward) # 注意:模型返回的是所有位置(包括图片位置和文本位置)的预测概率 logits = model(dummy_image_features, dummy_text_ids) # 3. 构建标签 (Targets) # 在 GPT 中,我们是用 "第 t 个字的特征" 去预测 "第 t+1 个字" # 所以我们要把文本输入的 ID 整体左移一位作为标签 # 因为序列拼了图片,所以我们切出文本部分的 Logits # 因为图像位置没有标准文本标签,训练时我们"忽略"图像部分的 Loss text_logits = logits[:, IMG_PATCHES:, :] # 只取后半部分(文本部分)的预测 # 目标标签应该是原来的 text_ids,但模型应预测下一个词,所以 target 要左移一位 # 这里为了简单演示,我们假设模型预测出的是整个句子 targets = dummy_text_ids # 4. 计算损失 (Loss) # reshape 以便输入交叉熵: [B*T, vocab] vs [B*T] loss = criterion(text_logits.reshape(-1, VOCAB_SIZE), targets.reshape(-1)) # 5. 反向传播 (Backward) loss.backward() # 6. 梯度裁剪 (防止梯度爆炸的工程技巧,大模型标配) torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) # 7. 更新参数 optimizer.step() total_loss += loss.item() print(f"Epoch {epoch+1} | 平均 Loss: {total_loss:.4f}") print("\n✅ 成功完成底层多模态 GPT 的模拟训练!") print("📌 总结:我们刚才手动实现了:") print(" 1. 数学上的 QK^T / sqrt(d_k) 和 Causal Mask") print(" 2. 视觉到文本的投影层 (Projector)") print(" 3. 底层向量拼接和动态位置编码") print(" 4. 真实的大模型训练循环 (包含反向传播和梯度裁剪)")
                                                                Comments load when you scroll here.

                                                                © Ely 2021 - 2026