论文笔记 -《MegaBlocks- Efficient Sparse Training with Mixture-of-Experts》
MegaBlocks: 高效的稀疏MoE训练
1 Stanford University, Stanford, California, USA
2 Microsoft Research, Redmond, Washington, USA
3 Google Research, Mountain View, California, USA. Correspondence to: Trevor Galetgale@cs.stanford.edu.
1、MoE的潜力与挑战
- 潜力:用更少的计算获得更好的模型
- 混合专家模型 (Mixture-of-Experts, MoE) 是一种结构化稀疏模型。
- 通过动态路由,每个Token只被一小部分“专家”(小规模神经网络)处理。
- 效果:在参数量远
- 挑战:动态性和负载不均衡
- 动态路由:Token到专家的分配在每次前向传播时都可能变化。
- 负载不均衡:某些“热门”专家可能被分配到远超平均数量的Token。
- 现代硬件(GPU/TPU)为稠密、规则的计算而设计,难以高效处理这种动态和不均衡的计算。
2、现有方法(Token Dropping)的局限性
- 现有解决方案:Procrustean Formulation (削足适履)
- 为了适应硬件,现有框架(如GShard, Tutel)为每个专家设置一个固定的容量 (Capacity)。
- 负载不均衡导致的两难困境:
- Token Dropping:分配给某专家的Token数量超过其容量时,多余的Token被直接丢弃,不参与计算。
- Padding:分配的Token数量不足容量时,用0值进行填充以凑齐尺寸。
- 核心矛盾:模型质量 vs. 硬件效率
- 丢弃Token → 损害模型质量:丢失了信息,降低模型最终性能。
- 增加容量 → 浪费计算和内存:过多的Padding导致大量无效计算,并占用宝贵的GPU显存。
- 证据:容量因子 (Capacity Factor) 的影响
- Capacity Factor 是一个关键超参,决定了容量的大小。
- 实验证明(Figure 2):
- 提高容量因子(减少Token Dropping)可以显著降低模型Loss(提高质量)。
- 但这是以增加超过2倍的计算量为代价的。
- 最理想的情况是"max"容量,即不丢弃任何Token。
- 结论:我们需要一种既不丢弃Token,又高效的解决方案。
3、核心方法
3.1 块稀疏计算
- (A) 传统方法:批处理矩阵乘法 (Batched Matrix Multiplication)
- 将所有专家的计算看作是一批独立的、形状完全相同的矩阵乘法。
- 约束:所有专家的输入(Token数量)和权重矩阵必须大小一致。
- 这正是Padding的根源!
- (B) 等价视角:块对角矩阵 (Block Diagonal Matrix)
- 可以将上述批处理运算等价地看作一个大的块对角矩阵与一个向量的乘法。
- 每个对角块代表一个专家的权重。
- 目前为止,所有对角块的大小仍然是相同的(因为存在Padding)。
- © MegaBlocks的核心突破:块稀疏矩阵 (Block Sparse Matrix,无需Padding或Dropping)
- 如果我们接受负载不均衡,那么每个专家处理的Token数量就应该是可变的。
- 这在块对角矩阵的视角下,意味着每个对角块的行数(代表Token数)是可变的!
- 这种具有可变大小对角块的矩阵,其本质就是一个块稀疏矩阵。
- 结论:MoE的专家计算可以被完美地重塑 (reformulate) 为一系列的块稀疏矩阵运算。
3.2 Dropless MoE (dMoE) 的计算流程
- 基于块稀疏重塑后的MoE层(dMoE)
- 以一个标准的2层MLP专家为例:
- y = GeLU(x @ W1) @ W2
- 以一个标准的2层MLP专家为例:
- 计算流程(Figure 6伪代码)
- 路由 (Routing):同标准MoE,为每个Token找到目标专家。
- 构建稀疏拓扑 (Make Topology):根据路由结果,在逻辑上构建出Figure 3C中的块稀疏矩阵的结构信息。
- 置换 (Permutation & Padded Gather):将Token按专家分组,并对每个组进行少量填充,使其数量成为块大小(如128)的整数倍。
- 块稀疏计算 (Block-Sparse Computation):
- 第一层 (Up-projection): x = SDD(x, W1, topology)
- S (Sparse Output), D (Dense Input), D (Dense Weight)
- 第二层 (Down-projection): x = DSD(x, W2)
- D (Dense Output), S (Sparse Input), D (Dense Weight)
- 逆置换 (Un-permutation & Scatter):将计算结果放回原始Token顺序。
- 优势:整个流程没有丢弃任何Token,并且计算被映射到了高效的块稀疏原语上。
3.3 为何要自研算子?
- 目标:需要高效实现SDD、DSD等块稀疏矩阵乘法及其转置版本。
- 现有库的局限性 (Section 5.1.1)
- NVIDIA cuSPARSE:
- 不支持SDD操作。
- 其Blocked-ELL格式要求稀疏矩阵每行有相同数量的非零块,这违背了我们处理负载不均衡的初衷。
- Triton Blocksparse:
- 假定稀疏模式(Topology)在多次调用之间是静态不变的。
- 而MoE的路由结果每轮迭代都在动态变化,每次都重新计算其内部元数据会带来巨大开销。
- NVIDIA cuSPARSE:
- 结论:没有现成的轮子,必须从底层构建自己的高性能GPU算子来高效处理MoE的动态稀疏性。
- 实现基础:扩展NVIDIA CUTLASS库,选择128x128作为性能最佳的块大小 (Block Size)。
3.4 混合CSR-COO编码
- 挑战:如何设计一个既适合DSD又适合SDD的稀疏格式?
- CSR (Compressed Sparse Row):按行存储非零块。非常适合DSD(行优先访问)。
- CSR的困境:在计算SDD时,需要知道每个输出块的行索引,但在CSR中这需要进行搜索(因为仅有行信息是不够的),效率低下。
- MegaBlocks的解决方案:Hybrid Blocked-CSR-COO (Figure 5)
- 主体采用BCSR (Blocked-CSR):存储每个非零块的列索引(Column Indices)和行偏移量(Row Offsets)。这保证了DSD的高效性。
- 额外增加COO元数据:为每个非零块显式存储其行索引 (Row Indices)。
- 这样,在计算SDD时,GPU线程可以立即(O(1)复杂度)查到自己负责的输出块的完整坐标(行、列),无需搜索。
- 代价:存储了少量额外的元数据。
- 收益:对于128x128的大块,这点元数据存储和计算开销几乎可以忽略不计,但换来了SDD操作的巨大性能提升。
3.5 转置索引 (Transpose Indices)
- 挑战:反向传播需要计算转置矩阵的乘法(如DSD^T)。
- 方案1:显式转置矩阵:在运行时拷贝数据生成一个转置后的矩阵。开销巨大。
- 方案2:按转置顺序遍历:在CSR格式上实现列优先遍历。效率极低,因为内存访问不连续。
- MegaBlocks的解决方案:Transpose Indices (Figure 5)
- 思想:不移动数据,只创建一套新的索引。
- 实现:
- 数据(非零块的值)仍然按行(BCSR)顺序存储。
- 在预处理阶段,额外创建一个**“转置索引”数组 (Transpose Indices)**。
- 这个数组的顺序是按列优先的,其内容指向原始数据块在内存中的偏移量。
- 效果:当需要进行转置计算时,GPU线程按顺序遍历Transpose Indices数组,通过一层间接寻址 (indirection),即可访问到正确的数据块。
- 这就像为数据库的主键创建了一个二级索引,实现了对数据的另一种高效访问模式,而无需复制整个数据库。
4、实验与结果
- 对比场景:MegaBlocks (dMoE) vs. Tutel (dMoE, 即不丢弃Token的模式)。专家64选1
- 实验设置:在The Pile数据集上训练Transformer MoE模型,使用8张A100 GPU。
- 结果 (Figure 7):
- MegaBlocks实现了 1.38倍 至 4.35倍 的端到端训练加速。
- 加速效果随模型增大而愈发显著。
- 为什么这么快?—— 显存效率是关键!
- Tutel的Padding机制消耗了大量显存。
- (Table 3) 为了不爆显存,Tutel被迫使用更小的micro_batch_size(例如,Medium模型下Tutel为1,MegaBlocks为8)。
- 更小的batch size导致GPU硬件利用率下降,训练时间变长。
- MegaBlocks因无需Padding,显存占用更少,可以使用更大的batch size,充分发挥硬件性能。
4.1 与Token-Dropping MoE对比
- 对比场景:MegaBlocks (dMoE) vs. Tutel (标准Token-Dropping MoE,使用不同容量因子)。
- 目标:比较达到相同的模型质量(Validation Loss)所需的时间。
- 结果 (Figure 8):
- 即使与Tutel最优化容量因子后的模型相比,MegaBlocks仍然能将达到同等模型质量的训练时间缩短 1.18倍 至 1.38倍。
- 超越速度的优势:
- 简化工作流:MegaBlocks消除了capacity_factor这个棘手的超参数,用户无需再为不同模型和任务反复调参。
- 节省计算预算:节省下来的调参成本可以用于探索其他更有价值的模型设计。
4.2 算子性能基准测试
- 问题:我们自研的块稀疏算子本身性能如何?
- 对比对象:与理论上限——NVIDIA cuBLAS库中高度优化的批处理矩阵乘法(Batched GEMM)进行比较。
- 结果 (Figure 9):
- 在所有测试问题上,MegaBlocks的算子平均达到了cuBLAS 98.6% 的吞吐量。
- 在部分情况下甚至略微超过(104%)。
- 结论:我们的算子实现非常高效,由稀疏格式带来的额外开销极小。这证明了我们方法在底层的可行性和卓越性能。
5、总结与展望
5.1 总结与核心贡献
- 新的范式:首次将MoE计算重塑为块稀疏矩阵运算,从根本上解决了Token Dropping和Padding的权衡问题。
- 高效的实现:开发了基于混合CSR-COO编码和转置索引的高性能GPU算子,其性能逼近理论上限。
- 卓越的系统:MegaBlocks系统实现了
- 永不丢弃Token,保证模型质量。
- 显著的端到端加速(相对Tutel dMoE最高4.35x,相对稠密模型最高2.4x)。
- 更高的内存效率。
- 简化的超参调优。
5.2 未来工作与展望
- 可变大小的专家:当前方法在理论上支持不同专家有不同的大小(隐藏层维度),值得进一步探索。
- 结合更优的路由算法:可以与BASE Layers、Expert Choice等先进的路由算法结合,进一步提升性能。
- 结合更优的分布式策略:可以吸收FasterMoE等系统在通信优化上的技术,扩展到更大规模的集群训练。
6、Q&A
谢谢!欢迎提问