FSDP将模型参数、梯度和优化器状态在数据并行组间全部分片,每个GPU仅持有部分参数。前向计算时按需All-Gather恢复完整参数,反向传播后Reduce-Scatter同步梯度,显著降低单卡显存峰值,支持更大模型的训练。在数据驱动的AI系统中,该方案对保障数据质量和模型可靠性具有重要作用。

岗位关联

需要学习FSDP:PyTorch Fully Sharded Data Parallel、扁平参数分片、自动包装策略与通信优化,FSDP将模型参数、梯度和优化器状态在数据并行组间全部分片,每个GPU仅持有部分参数。在数据为中心AI范式 > 数据质量评估的学习路径中,FSDP:PyTorch Fully Sharded Data Parallel、扁平参数分片、自动包装策略与通信优化直接影响对深层原理的理解。

目录
  1. 可视化演示
  2. FSDP全分片数据并行的核心原理
  3. 扁平参数分片的实现机制
  4. 前向All-Gather与反向Reduce-Scatter通信
  5. 自动包装策略与手动包装选择
  6. 通信优化与预取计算重叠
  7. 混合精度CPU Offload与激活检查点
  8. FSDP与DDP和DeepSpeed ZeRO的对比选型
  9. AI 应用场景
  10. Python 演示
  11. 常见问答
  12. 常见误区
  13. 参考来源

可视化演示

展示FSDP将模型参数分片到多个GPU的过程,包括All-Gather前向恢复、Reduce-Scatter梯度同步及显存节省对比。

本节配有交互动效(进入视口后自动加载,约 3KB)。

FSDP全分片数据并行 All-Gather恢复参数 Reduce-Scatter同步梯度 VRAM=Total/N 单卡显存降至1/N,N为GPU数

FSDP全分片数据并行的核心原理

PyTorch FSDP(Fully Sharded Data Parallel)是专为超大模型训练设计的数据并行方案。要理解FSDP的价值,首先需要明确传统DDP(Distributed Data Parallel)的局限性:DDP只在数据维度切分,每个GPU持有完整的模型参数、梯度和优化器状态副本。当模型参数量达到数百亿甚至千亿级别时,单卡显存根本无法容纳完整的模型状态。

FSDP的核心突破在于'全分片'——将模型参数、梯度和优化器状态三部分全部在数据并行组内按维度切分。假设有N个GPU,每个GPU只持有1/N的参数、1/N的梯度和1/N的优化器状态。以700亿参数模型在8卡A100 80GB上训练为例:使用DDP时每卡需要约2800GB显存(远超单卡80GB),而FSDP将显存需求降至约350GB/卡,再配合混合精度即可在8卡上完成训练。

类比来说,FSDP就像把一本厚重的百科全书撕成N份分给N个人保管。每个人只需要背自己负责的那几页内容,需要查阅某个词条时大家临时凑在一起拼出完整页面,查阅完毕再各自收好自己的部分。这样每个人负担的重量只有原来的1/N,但所有人合在一起仍然能访问完整的知识。

从显存占用角度分析,训练一个大模型需要的显存主要包括四部分:参数(4字节×参数量)、梯度(4字节×参数量)、Adam优化器状态(8字节×参数量,存储一阶和二阶动量)以及激活值。DDP下前三项每卡都需要完整副本,而FSDP将它们全部除以N,单卡显存占用从O(model_size)降至O(model_size/N),这是数量级的改善。

python16 行
# DDP vs FSDP 显存占用对比def calc_memory(params_billion, n_gpus, mode='ddp'):    params = params_billion * 1e9    param_mem = params * 4 / 1e9    grad_mem = params * 4 / 1e9    optim_mem = params * 8 / 1e9    if mode == 'ddp':        total = param_mem + grad_mem + optim_mem    elif mode == 'fsdp':        total = (param_mem + grad_mem + optim_mem) / n_gpus    return total for params in [7, 13, 70]:    ddp = calc_memory(params, 8, 'ddp')    fsdp = calc_memory(params, 8, 'fsdp')    print(f'{params}B参数: DDP={ddp:.0f}GB, FSDP={fsdp:.0f}GB (8卡)')

扁平参数分片的实现机制

FSDP的分片并不是简单地按参数逐个分配,而是采用'扁平化分片'(Flat Param Sharding)策略。具体来说,FSDP首先将一个包装单元(通常是一个或多个Module)内的所有参数flatten成一个一维连续张量,然后按GPU数量均匀切分为N段,每个GPU持有其中一段。

扁平化设计的好处有三:第一,连续内存在GPU间传输时可以利用完整的显存带宽,避免碎片化传输的效率损失;第二,均匀切分保证各GPU的分片大小严格一致,不存在负载不均衡问题;第三,扁平张量只需一次All-Gather即可恢复完整参数,比逐个参数通信更高效。

类比来说,扁平化分片就像把一摞散落的扑克牌先铺成一条直线再均分成N段,每个人拿一段。这比一张张分发更高效且分得更均匀,避免某些人拿太多某些人拿太少的情况。

在实现层面,FSDP会在初始化时为每个包装单元创建一个flat_param属性,原始参数通过view操作映射到扁平张量的对应区段。前向计算时通过All-Gather恢复完整的扁平张量,再view回各个原始参数的形状供计算使用。计算完毕后完整张量立即释放,只保留本卡的分片。这种'按需组装、用完即拆'的策略是FSDP显存效率的关键。

python23 行
import torchclass FlatParamShard:    def __init__(self, params, world_size, rank):        flat = torch.cat([p.data.flatten() for p in params])        self.total_size = flat.numel()        self.shard_size = self.total_size // world_size        if self.total_size % world_size != 0:            pad = world_size - (self.total_size % world_size)            flat = torch.nn.functional.pad(flat, (0, pad))            self.total_size = flat.numel()            self.shard_size = self.total_size // world_size        start = rank * self.shard_size        self.shard = flat[start:start + self.shard_size].clone()    def all_gather(self, shards_list):        return torch.cat(shards_list) params = [torch.randn(100), torch.randn(200), torch.randn(300)]shard_0 = FlatParamShard(params, world_size=2, rank=0)shard_1 = FlatParamShard(params, world_size=2, rank=1)print(f'总参数量: {shard_0.total_size}')print(f'GPU0分片: {shard_0.shard.numel()}, GPU1分片: {shard_1.shard.numel()}')full = shard_0.all_gather([shard_0.shard, shard_1.shard])print(f'All-Gather恢复: {full.numel()} 个参数')

前向All-Gather与反向Reduce-Scatter通信

FSDP的通信模式是其性能的核心。前向传播时,当计算到达某个FSDP单元,系统先在该单元涉及的所有GPU间执行All-Gather操作,收集该单元的完整参数。计算完成后立即释放完整参数,只保留本卡的分片。这意味着完整参数只在计算的瞬间存在于显存中,不会持续占用。

反向传播时的通信更为复杂:首先同样需要All-Gather恢复完整参数以计算梯度,然后通过Reduce-Scatter操作将各卡计算出的梯度进行聚合并按分片方式分配——每个GPU最终只保留自己分片对应的那部分梯度。Reduce-Scatter本质上是Reduce(梯度求和)和Scatter(结果分发)的组合操作,比先Reduce再Broadcast更高效。

类比来说,这就像拼图游戏中每个人先拿出自己手里的碎片凑在一起拼出完整图案(All-Gather),计算完毕后再把拼图拆开各自收好碎片(释放)。反向时再拼一次(All-Gather),算完梯度后各自只带走属于自己那部分的拼图碎片(Reduce-Scatter)。

通信量的分析也很关键。对于参数量为P的模型,每个FSDP单元在前向和反向各需要一次All-Gather和一次Reduce-Scatter,通信总量为4P(与模型大小成正比),但与GPU数量无关——这是FSDP相比朴素分片方案的重要优势,通信效率不随GPU数量增加而恶化。

python27 行
import torchclass FSDPCommunicationSim:    def __init__(self, param_size, world_size, rank):        self.param_size = param_size        self.world_size = world_size        self.rank = rank        self.shard_size = param_size // world_size        self.param_shard = torch.randn(self.shard_size)        self.grad_shard = torch.zeros(self.shard_size)    def forward_step(self):        full_param = self.param_shard.repeat(self.world_size)        print(f'GPU{self.rank} 前向All-Gather: 获取{full_param.numel()}个参数')        output = full_param.sum()        del full_param        print(f'GPU{self.rank} 释放完整参数,保留{self.shard_size}个分片')        return output    def backward_step(self):        full_param = self.param_shard.repeat(self.world_size)        full_grad = torch.ones_like(full_param)        print(f'GPU{self.rank} 反向All-Gather: 计算完整梯度')        self.grad_shard = full_grad[self.rank*self.shard_size:(self.rank+1)*self.shard_size]        del full_param, full_grad        print(f'GPU{self.rank} Reduce-Scatter: 保留{self.grad_shard.numel()}个梯度分片') sim = FSDPCommunicationSim(param_size=1000, world_size=4, rank=0)sim.forward_step()sim.backward_step()

自动包装策略与手动包装选择

FSDP的包装(wrap)决定了哪些子模块作为一个分片单元。包装粒度的选择直接影响通信次数和显存峰值:粒度过大(如整个模型作为一个单元),All-Gather时显存峰值接近DDP水平,失去分片优势;粒度过小(如每个Linear层一个单元),通信次数激增,通信开销超过显存收益。

PyTorch提供了两种自动包装策略。size_based_auto_wrap_policy按参数量阈值自动包装——当子模块参数量超过设定阈值(如1000万参数)时自动包装为FSDP单元。type_based_auto_wrap_policy按模块类型包装——将指定类型(如nn.TransformerDecoderLayer)的每个实例包装为独立单元,这是Transformer模型最常用的策略。

类比来说,自动包装策略就像快递公司按重量或体积自动决定哪些物品打包成一件。超过阈值的子模块自动作为一个分片单元,无需人工逐件打包分组。

对于手动包装,开发者可以用transformer_auto_wrap_policy或自定义wrap函数精确控制包装边界。常见做法是:Transformer的每个Decoder层作为一个FSDP单元(兼顾通信与显存平衡),Embedding层单独包装(参数量大且访问模式不同),最后的LM Head单独包装。手动包装适合对模型结构非常熟悉、需要精细调优的场景。

python21 行
import torchimport torch.nn as nnfrom torch.distributed.fsdp.wrap import ModuleWrapPolicy class SimpleTransformer(nn.Module):    def __init__(self, vocab_size, d_model, n_layers):        super().__init__()        self.embedding = nn.Embedding(vocab_size, d_model)        self.layers = nn.ModuleList([            nn.TransformerDecoderLayer(d_model, nhead=8)            for _ in range(n_layers)        ])        self.lm_head = nn.Linear(d_model, vocab_size) model = SimpleTransformer(vocab_size=50000, d_model=1024, n_layers=12)wrap_policy = ModuleWrapPolicy({nn.TransformerDecoderLayer})print(f'模型总参数量: {sum(p.numel() for p in model.parameters())/1e6:.1f}M')for name, module in model.named_modules():    n_params = sum(p.numel() for p in module.parameters(recurse=False))    if n_params > 0:        print(f'  {name}: {n_params/1e6:.1f}M params')

通信优化与预取计算重叠

FSDP的通信开销是训练吞吐的主要瓶颈之一。为了隐藏通信延迟,FSDP采用预取(prefetching)机制:在执行当前FSDP单元的前向/反向计算时,提前在另一个CUDA stream上发起下一个单元的All-Gather请求。这样通信和计算可以并行执行,有效隐藏网络延迟。

预取深度的控制通过prefetch_limit参数实现。预取太深会导致多个单元的完整参数同时存在于显存中,增加显存峰值;预取太浅则无法充分隐藏通信延迟。通常设置prefetch_limit=1或2即可取得良好效果。

limit_all_gathers是另一个重要的安全参数。当设置为True时,FSDP会限制同时处于All-Gather状态的单元数量,防止多个单元同时恢复完整参数导致OOM。这在显存紧张的场景下尤为关键,是以微小的性能损失换取显存安全性。

在带宽受限的集群上(如节点间通过以太网而非InfiniBand连接),通信优化尤为重要。可以通过增大batch size摊薄通信占比、使用梯度累积减少通信频率、或在节点内使用NVLink节点间使用RDMA等硬件优化来提升通信效率。软件层面还可以使用bucket化将多个小单元的通信合并为一次大通信,减少启动开销。

python21 行
class PrefetchSimulator:    def __init__(self, n_units, compute_time=0.1, comm_time=0.08):        self.n_units = n_units        self.compute_time = compute_time        self.comm_time = comm_time    def run_without_prefetch(self):        total = 0        for i in range(self.n_units):            total += self.comm_time + self.compute_time        return total    def run_with_prefetch(self):        total = self.comm_time + self.compute_time        for i in range(1, self.n_units):            step_time = max(self.comm_time, self.compute_time)            total += step_time        return total sim = PrefetchSimulator(n_units=12)t_no = sim.run_without_prefetch()t_yes = sim.run_with_prefetch()print(f'无预取: {t_no:.2f}s, 有预取: {t_yes:.2f}s, 加速比: {t_no/t_yes:.2f}x')

混合精度CPU Offload与激活检查点

FSDP支持三种显存优化技术的叠加使用,使训练远超单卡显存容量的超大模型成为可能。第一种是混合精度训练:使用BF16或FP16存储参数和梯度的计算副本,将参数量和梯度量的显存占用减半。BF16相比FP16的优势在于动态范围更大,不需要loss scaling,训练更稳定。

第二种是CPU Offload:将不活跃的参数分片从GPU显存卸载到CPU内存。FSDP的CPU Offload策略是:前向计算完一个FSDP单元后,将其参数分片从GPU搬到CPU内存;下一个单元需要时再从CPU搬回GPU。这相当于用CPU内存作为GPU显存的扩展,代价是增加了PCIe传输延迟。

第三种是激活检查点(Activation Checkpointing):前向传播时不保存中间激活值,反向传播时重新计算。这用计算时间换显存空间,对于深层Transformer模型可以节省大量显存(激活值显存与层数和序列长度的平方成正比)。

三种技术叠加的效果是乘性的。以700亿参数模型在8卡A100 80GB上训练为例:FSDP分片将显存降至约35GB/卡,BF16混合精度再减半至约17.5GB/卡,激活检查点节省激活值显存约10-20GB,CPU Offload进一步释放5-10GB。最终单卡显存可控制在40GB以内,远低于80GB的显存上限,留出充足空间用于增大batch size提升训练效率。

python21 行
def estimate_memory(params_b, seq_len, n_layers, n_gpus,                    use_bf16=False, use_offload=False, use_ckpt=False):    params = params_b * 1e9    if use_bf16:        base = (params*2 + params*2 + params*4) / n_gpus / 1e9    else:        base = (params*4 + params*4 + params*8) / n_gpus / 1e9    d_model = 4096    activation = seq_len * d_model * n_layers * 4 * 2 / 1e9    if use_ckpt:        activation *= 0.1    offload_save = base * 0.3 if use_offload else 0    return base + activation - offload_save print('70B, seq=2048, 128层, 8卡A100:')for bf16 in [False, True]:    for offload in [False, True]:        for ckpt in [False, True]:            mem = estimate_memory(70, 2048, 128, 8, bf16, offload, ckpt)            cfg = f'BF16={bf16} Offload={offload} CKPT={ckpt}'            print(f'  {cfg}: {mem:.1f}GB [{"OK" if mem<80 else "OOM"}]')

FSDP与DDP和DeepSpeed ZeRO的对比选型

FSDP在分布式训练方案谱系中的定位很清晰:相比DDP,FSDP从'只切数据'升级为'全分片',显存效率提升N倍(N为GPU数量),代价是增加了All-Gather和Reduce-Scatter通信开销。DDP适合单卡能放下模型的场景,FSDP适合单卡放不下必须分片的场景。

FSDP与DeepSpeed ZeRO Stage 3在数学上等价——都是将参数、梯度和优化器状态全分片。区别在于工程实现:FSDP是PyTorch原生集成(torch.distributed.fsdp),无需额外安装依赖,与PyTorch生态(torch.compile、torch.profiler等)天然兼容;DeepSpeed作为独立引擎,在异构内存管理(NVMe Offload、ZeRO-Infinity)和Zero Bubble调度等方面更成熟。

选型建议:如果团队主要使用PyTorch生态且模型规模在数百亿参数以内,FSDP是首选——原生集成减少依赖复杂度,社区支持活跃。如果模型规模达到千亿级别需要极致的显存优化(如NVMe Offload),或者需要Pipeline Parallelism的深度优化,DeepSpeed可能更合适。两者也可以混合使用——例如用FSDP做节点内分片,DeepSpeed做跨节点调度。

值得注意的是,PyTorch 2.x引入了FSDP2(又称fully_shard),采用per-parameter sharding替代FSDP1的flat param方案,与torch.compile的兼容性更好,是未来的发展方向。新项目建议直接使用FSDP2 API。

python13 行
def compare_frameworks():    features = {        '特性': ['参数分片','梯度分片','优化器分片','原生PyTorch集成','CPU/NVMe Offload','与torch.compile兼容','Pipeline Parallel'],        'DDP': ['否','否','否','是','否','是','需手动'],        'FSDP': ['是','是','是','是','CPU Offload','FSDP2支持','需组合'],        'DeepSpeed ZeRO-3': ['是','是','是','否','CPU+NVMe','部分支持','原生支持']    }    header = f"{'特性':<24} {'DDP':<10} {'FSDP':<16} {'DeepSpeed ZeRO-3':<16}"    print(header)    print('-'*70)    for i in range(len(features['特性'])):        print(f"{features['特性'][i]:<24} {features['DDP'][i]:<10} {features['FSDP'][i]:<16} {features['DeepSpeed ZeRO-3'][i]:<16}")compare_frameworks()

AI 应用场景

大语言模型预训练的显存优化

阶段:模型训练

解决的问题:解决百亿到千亿参数大模型在有限GPU资源下的显存瓶颈问题

具体案例:在8张A100 80GB上预训练一个130亿参数的LLM,使用FSDP将参数、梯度、Adam优化器状态全分片到8卡,单卡显存从约520GB降至约65GB,配合BF16混合精度和激活检查点进一步降到40GB以内,使原本需要64卡才能训练的模型在8卡上即可启动,训练吞吐量相比DDP场景下OOM无法训练实现了从0到1的突破。

多模态大模型的分布式微调

阶段:模型训练

解决的问题:解决多模态大模型在保持视觉编码器与语言解码器联合训练时的显存与通信瓶颈

具体案例:对一个视觉语言大模型进行SFT微调,视觉编码器和语言模型分别用不同的auto_wrap_policy包装,视觉Transformer按块包装降低单次All-Gather显存峰值,语言模型按Decoder层包装提升overlap机会,配合CPU Offload把不活跃层的参数分片卸载到CPU,使单卡80GB显存即可微调700亿参数的多模态模型,相比纯DDP显存占用降低75%。

Python 演示

python52 行
import torchimport torch.nn as nn class TransformerBlock(nn.Module):    def __init__(self, d_model, nhead, dim_ff):        super().__init__()        self.attn = nn.MultiheadAttention(d_model, nhead)        self.ffn = nn.Sequential(nn.Linear(d_model, dim_ff), nn.GELU(), nn.Linear(dim_ff, d_model))        self.norm1 = nn.LayerNorm(d_model)        self.norm2 = nn.LayerNorm(d_model)    def forward(self, x):        h = self.norm1(x)        h = x + self.attn(h, h, h)[0]        h = self.norm2(h)        h = h + self.ffn(h)        return h class LargeLM(nn.Module):    def __init__(self, vocab_size, d_model, n_layers, nhead, dim_ff):        super().__init__()        self.embedding = nn.Embedding(vocab_size, d_model)        self.layers = nn.ModuleList([TransformerBlock(d_model, nhead, dim_ff) for _ in range(n_layers)])        self.lm_head = nn.Linear(d_model, vocab_size)    def forward(self, input_ids):        h = self.embedding(input_ids)        for layer in self.layers:            h = layer(h)        return self.lm_head(h) def analyze_memory(model, n_gpus, mode='fsdp', use_bf16=False):    params = sum(p.numel() for p in model.parameters())    bpp = 2 if use_bf16 else 4    param_mem = params * bpp / 1e9    grad_mem = params * bpp / 1e9    optim_mem = params * 8 / 1e9    if mode == 'ddp':        return param_mem + grad_mem + optim_mem    elif mode == 'fsdp':        return (param_mem + grad_mem + optim_mem) / n_gpus model = LargeLM(vocab_size=50000, d_model=4096, n_layers=32, nhead=32, dim_ff=16384)print(f'参数量: {sum(p.numel() for p in model.parameters())/1e9:.2f}B')for n in [8, 16, 32]:    print(f'{n}卡: DDP={analyze_memory(model,n,"ddp"):.1f}GB FSDP={analyze_memory(model,n,"fsdp"):.1f}GB FSDP+BF16={analyze_memory(model,n,"fsdp",True):.1f}GB') print('\n--- 扁平参数分片 ---')block = model.layers[0]flat = torch.cat([p.data.flatten() for p in block.parameters()])print(f'TransformerBlock参数: {flat.numel()/1e6:.1f}M')for r in range(4):    s = flat.numel() // 4    print(f'  GPU{r}: {s/1e6:.1f}M params')
目的:演示FSDP核心机制:Transformer模型构建、显存分析对比和扁平参数分片过程
  1. class TransformerBlock(nn.Module):定义Transformer基本单元,作为FSDP的包装粒度
  2. self.attn = nn.MultiheadAttention(d_model, nhead)多头注意力层,参数量最大的子模块
  3. class LargeLM(nn.Module):大语言模型结构,包含Embedding、多层Transformer和LM Head
  4. self.layers = nn.ModuleList([TransformerBlock(d_model, nhead, dim_ff) for _ in range(n_layers)])Transformer层列表,每层将作为一个FSDP包装单元
  5. def analyze_memory(model, n_gpus, mode='fsdp', use_bf16=False):显存分析函数,对比DDP和FSDP在不同配置下的单卡显存占用
  6. return (param_mem + grad_mem + optim_mem) / n_gpusFSDP模式下参数+梯度+优化器状态全部除以GPU数量
  7. flat = torch.cat([p.data.flatten() for p in block.parameters()])将TransformerBlock的所有参数flatten并拼接为一维连续张量
  8. s = flat.numel() // 4均匀切分扁平张量,每个GPU获得等大的参数分片

常见问答

FSDP和DDP的本质区别是什么?
DDP只在数据维度切分,每个GPU持有完整的模型参数、梯度和优化器状态副本;FSDP将这三部分全部在数据并行组内按维度分片,每个GPU只持有1/N的参数、梯度和优化器状态。显存占用差异可达N倍。
FSDP的扁平参数分片为什么要先flatten再切分?
扁平化有三个好处:一是连续内存传输可以利用完整的显存带宽,避免碎片化传输的效率损失;二是均匀切分保证各GPU分片大小一致,不存在负载不均衡;三是一次All-Gather即可恢复完整参数,比逐个参数通信更高效。
FSDP前向计算后为什么要立即释放完整参数?
因为反向传播时还需要再次All-Gather恢复参数。如果前向计算后不释放,完整参数会一直占用显存直到反向结束,显存峰值接近DDP水平,失去分片优势。按需恢复、用完即拆是FSDP显存效率的关键。
FSDP和DeepSpeed ZeRO Stage 3应该如何选择?
两者在数学上等价,都是参数梯度优化器全分片。FSDP是PyTorch原生集成,与torch.compile等生态天然兼容,适合数百亿参数模型。DeepSpeed在NVMe Offload和Zero Bubble调度上更成熟,适合千亿参数极致优化。新项目建议用FSDP2(fully_shard API)。

常见误区

误区认为FSDP就是把数据切分到多卡的数据并行,和DDP没有本质区别

正解FSDP不仅切分数据,更关键的是把模型参数、梯度和优化器状态在数据并行组间全部按维度分片,每个GPU只持有1/N的参数,而DDP每个GPU持有完整参数副本,两者显存占用差异可达N倍。

为何常见:两者名字都含Data Parallel,且都通过集合通信同步梯度,让学习者误以为内部机制完全相同。

误区认为FSDP包装粒度越小越好,可以最大化显存节省

正解包装粒度过小会导致All-Gather通信次数激增,通信开销超过显存收益,反而降低训练吞吐。最优粒度需在显存峰值和通信次数间权衡,通常按Decoder层或参数量阈值自动包装。

为何常见:学习者直觉认为切得越碎省得越多,忽视通信次数与包装粒度成反比的关系。

误区认为FSDP的前向All-Gather会一直持有完整参数直到训练结束

正解FSDP采用按需恢复策略,前向计算完一个FSDP单元后立即释放其完整参数只保留分片,反向传播时再次All-Gather恢复,完整参数只在计算瞬间存在,不会持续占用显存。

为何常见:习惯了DDP参数常驻显存的模式,学习者容易假设FSDP也是参数常驻不释放。

误区认为FSDP和DeepSpeed ZeRO Stage 3是两套完全不同的机制需要二选一

正解FSDP的参数梯度优化器全分片机制在数学上等价于ZeRO Stage 3,区别在于FSDP是PyTorch原生集成无需额外引擎,DeepSpeed在异构内存Offload和Zero Bubble调度上更成熟,二者可按生态需求选型而非互斥。

为何常见:两者分属不同项目且文档各自独立,学习者容易误以为是技术路线对立关系。

参考来源