·2506 words·6 mins
最近学习 MIT 6.S191 Lecture 9,陆续把 DDP、ZeRO、FSDP2、Tensor Parallelism、Pipeline Parallelism、Sequence Parallelism、Context Parallelism,以及 Expert Parallelism 过了一遍。
·9000 words·18 mins
上一篇把单个 MoE Layer 的执行流走了一遍:Router 选 Expert、Token Dispatch 按 Expert 重排、Grouped GEMM 统一调度、Combine 加权合回原始 Token 顺序。整条链路假设所有 Expert 都在同一张 GPU 上。
·5127 words·11 mins
上一篇 MoE 笔记把架构家族理了一遍——稀疏、稠密、Soft MoE,gate 在前还是在后,决定了算力形态和适用场景。
但那篇有一段伪代码一直让我不太舒服:
1for prob, idx in zip(topk_probs.unbind(1), topk_idx.unbind(1)): 2 out += prob.unsqueeze(1) * self.experts[idx](x) 逻辑上没问题。但想象一下真实场景:一个 batch 有几千个 token,每个 token 选 2 个 expert,就是上万个 token-expert 计算任务。用 Python for loop 逐个调 expert 的 forward,GPU 利用率会低得离谱。
·5497 words·11 mins
前两篇写 Bid-Ask Spread 和 Adverse Selection 以及执行感知回测的时候,讨论的核心问题是"预测对了方向,为什么交易还可能亏钱"。结论是执行成本、成交概率和 Adverse Selection 都会侵蚀预测收益。
·5188 words·11 mins
上一篇 TP 写完之后,我对 Megatron 的 Column Parallel + Row Parallel 已经比较清楚了:前一层按输出特征切分,后一层按输入特征切分,两层之间不需要 AllGather,只在最后做一次 AllReduce 把部分和加起来。
·4700 words·10 mins
最近在看 MIT 6.S191 Lecture 9 讲 Context Parallelism 的时候,碰到了一个词:Causal Attention。
我对 Self-Attention 的公式并不陌生——之前那篇已经把 QKV 和 routing score table 拆得比较清楚了。但 Causal Attention 这个概念我一直没有认真想过。回头看,我写 Attention 公式、写 Multi-Head、写 FlashAttention 的时候,脑子里跑的都是"所有 token 都能看到所有 token"的 Full Self-Attention。
·5020 words·11 mins
起因 # 最近在过 MIT 6.S191 和分布式训练相关的材料,各种 Norm 反复出现。LayerNorm 在写 Transformer Block 那篇时已经接触过,BatchNorm 在做 CV 的那几年天天调,RMSNorm 在看 LLM 代码时到处都是。单独看每个都不算陌生。
·5564 words·12 mins
上一篇写到,预测对价格方向,不等于交易能赚钱。主动成交要付执行成本,挂单等成交又可能筛出对自己不利的行情。
顺着这个问题往下想,我还有一个疑问:如果把手续费算进去,回测里也只让一部分挂单成交,是不是就离真实收益很近了?
·5810 words·12 mins
之前写 order book 和价格形成那篇时,花了不少篇幅搞清楚 bid/ask、maker/taker、以及成交量和价格之间的关系。写完之后我觉得这些概念已经理顺了,但最近在看加密货币量化执行的材料时,碰到了一个更尖锐的问题:
·2441 words·5 mins
前几天在电脑上登 ChatGPT,登录页面多了个"使用通行密钥(Passkey)“的选项。以前一直用邮箱加密码,看到这个就顺手点了一下,想试试传说中的免密登录。
·5896 words·12 mins
最近在系统地补加密货币衍生品的知识。之前写过期权,那篇关注的是"方向对了也能亏钱"的多维度约束。这次想理清的是另一组概念:Basis Trade(基差交易)、永续合约(Perpetual Futures)和 Funding Rate(资金费率)。
·4193 words·9 mins
一道我答错的题 # 最近做了一个 Modern C++ 水平测试,碰到这样一道题:
1#include <utility> 2 3struct Widget { 4 Widget() = default; 5 Widget(const Widget&) = delete; 6 Widget(Widget&&) = delete; 7}; 8 9Widget createA() { return Widget{}; } 10 11Widget createB() { 12 Widget w; 13 return w; 14} 15 16Widget createC() { 17 Widget w; 18 return std::move(w); 19} 问:在 C++17 下,哪些函数能通过编译?
·4614 words·10 mins
起因 # 上一篇搞清楚了 Pipeline Parallelism 的调度机制:GPipe 先 Forward 后 Backward,1F1B 通过交替调度降低 Activation 暂存压力,但理想条件下 Bubble Time 相同。
·5476 words·11 mins
起因 # 上一篇把 ZeRO 的三个 Stage 走了一遍之后,我以为关于参数分片这件事已经想得差不多了——ZeRO-3 / FSDP 把参数、梯度和 Optimizer States 全部分片存储到多张 GPU 上,单卡 Model States 从 112 GB 降到约 28 GB,问题解决。
·5007 words·10 mins
起因 # 上一篇 Tensor Parallelism 写完之后,我对 TP 的基本原理有了底:把单个算子内部的矩阵乘法拆到多张 GPU 上执行,每张卡只算部分输出,最后通过 AllReduce 聚合。TP 分片的是计算本身。
·7498 words·15 mins
起因 # 上一篇搞清楚了 AllReduce、ReduceScatter 和 AllGather 三种通信原语,末尾提到 DDP 和 ZeRO Stage 2 选择了不同的通信原语组合,根本原因是参数更新的责任分配不同。
·4919 words·10 mins
起因 # 之前几篇文章从模型显存组成一路算到 7B 模型的训练账本,结论很直接:BF16 mixed precision + AdamW 的 Model States 就有 112 GB,一张 80 GB A100 连放都放不下。Checkpointing + Offloading 两个一起用可以勉强塞进去,但训练速度要被 PCIe 传输和额外重计算拖累。
·6738 words·14 mins
起因 # 上一篇讨论完 Checkpointing 和 Offloading 之后,结尾留了一句:单卡优化的代价已经不可接受时,下一步自然是考虑让多张 GPU 分担训练状态。
于是我开始看 DDP(DistributedDataParallel)。一开始觉得 DDP 的核心思想很直白——每张卡各算各的梯度,然后 All-Reduce 同步一下,用平均梯度更新参数。看起来最朴素的做法就是把所有梯度打包成一个大 tensor 做一次 All-Reduce,简单干净。
·5977 words·12 mins
起因 # 上一篇算完了 7B 模型的训练显存账本。结论很直接:BF16 mixed precision + AdamW 的 Model States 就有 112 GB,加上 30 GB 的 Activations,单卡至少需要 145 GB——一张 80 GB 的 A100 连 Model States 都放不下。
·4077 words·9 mins
起因 # 之前分别写了推理和训练的显存心智模型和混合精度训练中的显存组成,反复出现一个粗估:BF16 mixed precision + AdamW 大约 16 bytes/parameter。但这个数字每次都只是"1B × 16 = 16 GB"的单位换算,没有真正对着一个具体的 Transformer 架构把账从头到尾算一遍。