Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
140 changes: 140 additions & 0 deletions app/docs/ai/MoE/MOE-intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
title: "MOE 浅谈"
description: "混合专家(Mixture of Experts, MoE)架构的简要介绍"
tags: ["MoE", "AI"]
---

# 混合专家(Mixture of Experts, MoE)架构

为了在不显著增加计算需求的情况下有效扩展模型参数规模,MoE 架构已经成为一种可行的解决方案。MoE 利用一组专门化的子模型和一个门控机制,动态地选择合适的“专家网络”来处理给定输入。这使得模型能够根据需求分配计算资源,这一概念被称为 **条件计算(conditional computation)**。

MoE 架构已经被广泛应用到大语言模型(LLMs)中,使这些模型能够在参数规模显著扩大的同时,获得相应的能力提升。
例如,Mixtral AI 提出的 **Mixtral-8x7B** 管实际激活的参数量仅有 130 亿,**在多个基准测试上表现优于或相当于 Llama-2-70B 和 GPT-3.5**。

---

## 传统 MoE 架构

自 MoE 最早被引入 Transformer 架构以来,MoE 主要作为 **前馈网络 (FFN)** 的替代模块使用。通常情况下,MoE 层中的每个专家都直接复制了其所替换的 FFN 结构。然后配备有一个 Router 来训练具体交给哪个专家处理。

![](./MOE-intro.assets/img-20250920112106486.png)

MoE 主要应用于 FFN 层,而不是自注意力层,原因在于:

- **注意力层**:稀疏性较低,更适用于全局交互。
- **FFN 层**:稀疏性较高,更具有领域特性。
其中 DS-MoE 使用 Wikitext 作为任务时,发现:FFN 层的专家仅有 **20%** 被激活
而注意力层激活率高达 **80%**。这种高利用率表明注意力层的核心通讯机制不适用于特异化的专家。反之具有稀疏特性的 FFN 层,具有完整多专家特异化的潜力。

![](./MOE-intro.assets/img-20250920112106518.png)

---

## Routing 机制:Dense MoE 与 Sparse MoE

![](./MOE-intro.assets/img-20250920112106554.png)

- **Dense MoE**
- gate 对于输入 token 使用 **softmax** 路由机制,传递给每个专家一定权重。
- 优点:训练稳定。
- 缺点:每次都要计算所有专家,计算成本高。

- **Sparse MoE**
- 使用 **Top-K** 路由机制,仅激活前 K 个权重最大的专家。
- 优点:极大减少计算量,这是目前主流模型(如 GShard、Switch Transformer、Mixtral、DeepSeek-MoE)的策略。
- 缺点:Router 训练变复杂,容易出现「热门专家被频繁使用,冷门专家学不到东西」的问题 → **路由坍塌**。
- 解决办法:训练中需要引入额外的 **负载均衡损失**。

---

## 专家个数选择

**GLaM (Google, 2021)** 在实验中探索了不同专家数量与 gating 策略的组合:
发现 **64 个专家(per layer)+ Top-2 gating** 在性能和计算效率之间达到了最佳平衡。
Top-2 gating 能显著提升效果,相比单一专家更稳定。并且 64 专家的配置在 **zero-shot、one-shot、few-shot** 场景下均表现优异。 所以后续的很多 MoE 工作(如 Mixtral, DBRX, DeepSeekMoE)也基本采用 ≤64 专家的规模,这个设计在实际应用中也具有参考价值。

---

## MoE 与 PEFT

近期仍有不少工作专注于 PEFT(参数高效微调)。
论文 [_Pushing Mixture of Experts to the Limit: Extremely Parameter Efficient MoE for Instruction Tuning_](https://arxiv.org/abs/2309.05444) 首次提出将 **LoRA 类型的 PEFT 方法和 MoE 框架结合**。
其主要理念为,不直接在整个大模型上加 LoRA,而是专门在 MoE 的 expert 模块里应用 LoRA。因为 MoE 的每个专家就是 FFN(MLP),它们是知识写入的关键位置。这样每次只动一小部分 LoRA experts,并且大大增强了这种架构的易扩展性。

![](./MOE-intro.assets/img-20250920112106588.png)

该方法的核心思想是利用 **低秩近似更新** 来避免高级算力的微调。

1. **输入 (Input → Embedding)**
- 输入 token(字或子词)先经过 Embedding。
- 这部分和普通 Transformer 一样。

2. **Multi-Head Attention**
- 输入 embedding 进入多头注意力模块。
- 在这里,Q、K、V 一切正常,完全没被 LoRAMoE 改动。
- 输出再走 **Add & Norm**,结果传给 FFN。

3. **FFN → MoE (Expert 路由)**
- 普通 Transformer 的 FFN 被换成 **LoRA + MoE 专家网络**。
- Router 根据输入选择若干专家,每个专家是 **LoRA 化(低秩适配)的模块**,而不是全量可训练的 FFN。
- 冻结的部分(❄️)是预训练的大模型主干。
- 火花(🔥)表示 LoRA Adapter(可训练参数,低秩矩阵)。
- Router 输出的加权组合:

$$
y = \sum_i \alpha_i \cdot Expert_i(x)
$$

其中 $\alpha_i$ 是 Router 根据输入算出来的权重。

4. **输出 (Add & Norm → Residual)**
- Router 混合后的专家输出,和残差连接一起进入 Add & Norm,继续往后层传。

---

#### LoRA 拆解

LoRA(Low-Rank Adaptation)的核心思想:

对一个大的线性层权重 $W \in \mathbb{R}^{d_{out} \times d_{in}}$,不去训练整个矩阵,而是加上一个低秩近似更新:

$$
W' = W + \Delta W, \quad \Delta W = BA
$$

- $A \in \mathbb{R}^{r \times d_{in}}, B \in \mathbb{R}^{d_{out} \times r}$
- 秩 $r \ll d_{in}, d_{out}$,通常只取个位数到几十
- $W$:冻结(❄️,预训练参数)
- $A, B$:可训练(🔥,参数量大幅减少)

这样,一个输入向量 $x$ 经过 LoRA 线性层时:

$$
Wx + BAx
$$

等于 **原始主干输出 + 一个小的低秩修正**。

回到该图,我们可以发现每个专家 $Expert_i$ 不是全新的大 FFN,而是 **一个 FFN 的 LoRA adapter 组合**:

$$
Expert_i(x) = B_i A_i x
$$

- Router 对输入 hidden state 计算一个分布 $\alpha$,然后加权组合:

$$
y = \sum_i \alpha_i \cdot Expert_i(x)
$$

- 最终结果再加上主干(冻结的 FFN 权重输出):

$$
y_{final} = W_{FFN}x + \sum_i \alpha_i \cdot B_i A_i x
$$

---

作者:**Yang Lewis**
非商业转载请标明出处。
商业转载请联系作者:**840691168ly@gmail.com**
193 changes: 193 additions & 0 deletions app/docs/ai/compute-platforms/model-compuational-resource-demand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
---
title: "算力需求指南"
description: "如何计算训练大模型所需显存大小"
date: "2025-09-20"
tags:
- compute-platforms
---

# 大模型多卡训练笔记

## 1. 单位说明

1 GB = 1024 MB = 1024×1024 KB = 1024×1024×1024 Byte(字节) = 1024×1024×1024×8 Bit

**参数类型与大小:**

| 参数类型 | 字节数 (Byte) |
| ----------- | ------------- |
| FP32 | 4 |
| FP16 / BF16 | 2 |
| INT8 | 1 |
| INT4 | 0.5 |

---

## 2. 大模型训练显存计算

单卡哪怕有 80 GB 显存,也扛不住数十亿、上百亿参数的大模型全量训练。
权重只是一部分,梯度、优化器状态、激活都需要显存。

假设模型有 **N 参数量**(例如 2B = 20 亿):

1. **权重 W**
- 存储方式:BF16 (2 Byte)
- 显存:$W = N \times 2$ Byte
- 例:2B 参数 → ≈ 4 GB

2. **梯度 G**
- 存储方式:BF16 (2 Byte)
- 显存:$G = N \times 2$ Byte
- 例:2B 参数 → ≈ 4 GB

3. **优化器状态(Adam)**
- 包含动量项 V、平方梯度 S,各自 FP32 (4 Byte)
- 每份 ≈ 8 GB,合计 ≈ 16 GB
其中:优化器显存还需要的开销(权重梯度在训练中可能会复制很多份儿)
1. **权重 W**
- 模型本身的参数,BF16/FP16 存 2 Byte。

2. **梯度 G**
- 反向传播临时存储,BF16/FP16 2 Byte。

3. **优化器状态**(不同优化器差别大):
- **SGD**:通常只需要梯度本身,**0份复制**。
- **SGDM(带动量的 SGD)**:需要一个动量向量(FP32,4 Byte)。**一份复制**
- **Adam/AdamW**:
- **一阶动量 (V)**:FP32(4 Byte)。
- **二阶动量 (S)**:FP32(4 Byte)。
- 所以是 **2 份状态**。

4. **Master 权重 ($W^A$)**
- 混合精度训练时常见:虽然前向/反向用 BF16,但优化器更新需要 FP32 精度 → 所以再存一份 FP32 权重。

4. **Activations**
- 依赖 batch size、seq_len、实现细节
- 粗略估计:≈ 0.7–1.0 × 权重大小

---

## 3. 公式总表

- **普通 Adam 模式:**

$W + G + W^A + V + S + 0.7W ≈ 24.8$ GB (以 2B 参数为例)

- **DeepSpeed ZeRO-3 模式:**

$W + G + W^A + G^A + V + S + 0.7W ≈ 32.8$ GB

说明:ZeRO-3 显存更省,但通信和 I/O 开销更大。

---

## 4. 实际案例:Mixtral-8×7B

### 设定与常数

- 架构:`d_model ≈ 4096`,`ffn_dim ≈ 14336`,每层 **8 个专家**,**32 层**,SwiGLU(gate/up/down 三个线性层)。
- 单个专家参数量:
$4096×14336×2 + 14336×4096 = 176,160,768$ ≈ **1.76×10^8**
→ BF16 权重 ≈ **352 MB/专家**。
- 一层 8 专家 ≈ **2.82 GB/层**
- 32 层合计 ≈ **90 GB(仅专家权重)**
→ 全专家全参训练在 **44 GB 显存**上不可能。

---

### 案例 A:Router-only

- 路由器参数:`d_model × n_experts ≈ 4k × 8 = 32k`
- 全 32 层 ≈ **百万级参数**
- 开销极小(MB 级),显存主要花在 **激活**
- 在 44 GB 上完全可行,但改进有限

---

### 案例 B:部分层 × 部分专家

例:只训底部 **6 层**,每层 **2 专家**,同时训路由。

- 可训练参数数:
$6 × 2 × 176,160,768 = 2.114B$
- 权重(BF16):≈ 4.23 GB
- 梯度(BF16):≈ 4.23 GB
- Adam 状态(V+S,FP32):≈ 16.9 GB
- Master 权重(FP32):≈ 8.46 GB
- **合计(持久内存 + 梯度)**:≈ 33.8 GB
- 再加冻结权重占位、激活开销,44 GB 卡上需:
- `batch=1–2`
- `seq_len ≤ 1024`
- `use_cache=False`
- `gradient_checkpointing=True`
- 可行,但需要严格控制。

---

### 案例 C:4-bit 全模型 + LoRA

在专家 / 路由上挂 LoRA(r=16)。

- 单专家 LoRA 参数:
$r × (4096+14336 + 4096+14336 + 14336+4096) = r × 55296$
→ r=16 → 0.885M/专家
- 每层 8 专家:7.08M
- 32 层:226.6M LoRA 参数
- 显存开销:
- 权重 ≈ 0.45 GB
- 梯度 ≈ 0.45 GB
- Adam + Master ≈ 2.72 GB
- 合计 ≈ 3.6 GB
- 远低于 44 GB 显存

---

## 5. 并行方式

### 数据并行 (DP)

- 各 GPU 拷贝全模型,喂不同 batch,梯度汇总
- 优点:简单
- 缺点:显存浪费大

### 分布式数据并行 (DDP)

- 一卡一进程,梯度分桶同步
- 优点:主流、稳定
- 缺点:依然每卡全模型

### ZeRO 优化 (DeepSpeed)

- ZeRO-1:拆优化器状态
- ZeRO-2:再拆梯度
- ZeRO-3:连参数也拆
- 优点:显存省
- 缺点:通信复杂

### 模型并行

- **张量并行 (TP)**:矩阵切块
- **流水并行 (PP)**:层切片,像传送带
- **MoE 并行**:专家分散在不同卡,token 激活部分专家

---

## 6. 踩坑经验

- 显存碎片化:
`PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True`
(需在 `import torch` 前设置)
- 通信库:
NCCL > Gloo > MPI(除非特殊环境)
- DDP:必须同步 random seed
- eval:
- eval_mb_size 可大
- 训练 batch 小 + 梯度累积
- 关掉 `model.config.use_cache`
- device = "auto": HF 会自动根据你机器的显存大小,把模型的不同部分切片分布,对于大模型,比如 7B,在单卡 44 GB 上:通常 attention + embedding + 部分 FFN 会放 GPU,冻结的模块、或者用不到的专家 (MoE inactive experts) 可以被放到 CPU。这个参数对推理来说自动分配还是很好的,但是训练的话**需要梯度的参数**必须常驻 GPU,否则每次 forward/backward 都要把参数搬上来,通信成本爆炸。所以,**device_map=auto 对训练不总是安全**,因为它可能把你要训练的层塞到 CPU 去,导致速度慢甚至无法训练。

---

作者:**Yang Lewis**
非商业转载请标明出处。
商业转载请联系作者:**840691168ly@gmail.com**