Accelerate documentation
FSDP vs DeepSpeed
FSDP vs DeepSpeed
O Accelerate oferece flexibilidade em frameworks de treinamento, ao integrar duas ferramentas extremamente poderosas para treinamento distribuído, a saber, Pytorch FSDP e Microsoft DeepSpeed. O objetivo deste tutorial é traçar paralelos, bem como destacar possíveis diferenças, para capacitar o usuário a alternar sem problemas entre esses dois frameworks.
Para alternar entre os frameworks, recomendamos executar o código
accelerate launchpassando o arquivo de configuração correto com--config_file, ou passando diretamente os argumentos respectivos para FSDP e DeepSpeed .Exemplos de configurações do Accelerate podem ser encontrados aqui para DeepSpeed e FSDP, ou no example zoo sob “Launch Configurations”
Este tutorial é apenas para cenários de nó único, multi-GPU.
Configurando Funcionalidades
Os tensores do modelo são divididos em diferentes GPUs em uma tentativa de escalar os tamanhos dos modelos; isso é chamado de sharding no FSDP e de partitioning no DeepSpeed. O sharding do FSDP e os estágios do DeepSpeed ZeRO (partitioning) são configurados por --fsdp_sharding_strategy e --zero_stage, respectivamente. Em particular, o FULL_SHARD do FSDP corresponde ao estágio 3 do DeepSpeed ZeRO; veja este mapeamento abrangente entre as configurações de sharding do FSDP e do DeepSpeed ZeRO. A tabela abaixo resume e agrupa configurações semelhantes:
| Grupo | Framework | Configuração | Exemplo | Restrições (se houver) |
|---|---|---|---|---|
| sharding / particionamento | FSDP DeepSpeed | --fsdp_sharding_strategy--zero_stage | 1 (FULL_SHARD) 3 | |
| offload | FSDP DeepSpeed | --fsdp_offload_params--offload_param_device--offload_optimizer_device | truecpucpu | tudo ou nada |
| carregamento de modelo | FSDP DeepSpeed | --fsdp_cpu_ram_efficient_loading--zero3_init_flag | truetrue | somente ZeRO 3 |
| checkpointing eficiente | FSDP DeepSpeed | --fsdp_state_dict_type--zero3_save_16bit_model | SHARDED_STATE_DICTtrue | somente ZeRO 3 |
| pré-carregamento de pesos | FSDP DeepSpeed | --fsdp_forward_prefetch--fsdp_backward_prefetchNenhuma | trueBACKWARD_PRE | |
| model | FSDP DeepSpeed | --fsdp_auto_wrap_policy--fsdp_transformer_layer_cls_to_wrapNenhum | TRANSFORMER_BASED_WRAP<Classe de Camada> | Normalmente não é necessário Transparente para o usuário. |
| parâmetros de invocação | FSDP DeepSpeed | --fsdp_use_orig_paramsNenhum | true | necessário para torch.compileTransparente para o usuário |
| sincronização de parâmetros | FSDP DeepSpeed | --fsdp_sync_module_statesNenhum | true | |
| treinamento | FSDP DeepSpeed | Nenhum--gradient_accumulation_steps--gradient_clipping | autoauto | Transparente para o usuário |
Para descrições detalhadas do acima, consulte a documentação de lançamento do Accelerate.
Para acessar outras configurações do DeepSpeed, como as configurações de precisão mista, você precisa passar um
--deepspeed_config_file, consulte a documentação.O DeepSpeed também pode ser configurado via DeepSpeedPlugin, por exemplo,
DeepSpeedPlugin.zero_stageé equivalente a--zero_stage, eDeepSpeedPlugin.hf_ds_configpode ser usado para passar--deepeed_config_file.
O FSDP também pode ser configurado via FullyShardedDataParallelPlugin, por exemplo,
FullyShardedDataParallelPlugin.sharding_strategyé equivalente a--fsdp_sharding_strategy.
Checkpointing
Observe que, embora o FSDP possa ser configurado via --fsdp_state_dict_type para salvar checkpoints completos / fragmentados.
Para o DeepSpeed Zero3, é possível passar
--zero3_save_16bit_model true, o que consolida convenientemente o modelo em um único rank e salva; isso é o equivalente no FSDP defsdp_state_dict_type: FULL_STATE_DICT.
Para modelos grandes, consolidar o modelo em um único rank pode ser muito lento.
Para checkpoints mais rápidos, para FSDP use
fsdp_state_dict_type: SHARDED_STATE_DICT, e para DeepSpeed Zero3 use o scriptzero_to_fp32.pypara converter checkpoints fragmentados posteriormente.
Offloading
O FSDP permite apenas offload all-or-nothing (ou seja, ou offload parâmetros, gradientes e otimizador, ou mantém todos na GPU), mas o DeepSpeed pode offload parâmetros e otimizador de forma diferente. Além disso, o DeepSpeed também suporta offloading para NVME.
Pré-carregamento
O FSDP permite duas configurações de prefetching, --fsdp_forward_prefetch e --fsdp_backward_prefetch, para melhorar a sobreposição de comunicações e computação, a um custo de memória extra, consulte a documentação do FSDP.
Para o DeepSpeed, o prefetching será ativado quando necessário, e sua ativação depende de certos hiperparâmetros, como stage3_param_persistence_threshold, stage3_max_reuse_distance, etc., que podem ser configurados para o Zero3; o accelerate pode definir esses hiperparâmetros automaticamente se você não os definir explicitamente no arquivo de configuração do deepspeed.
Para o FSDP, defina
fsdp_backward_prefetch: BACKWARD_PREpara melhorar o throughput, caso a memória permita.
Carregamento de Modelos
Embora o FSDP exija um --fsdp_cpu_ram_efficient_loading true explícito para ativar o carregamento eficiente do modelo, o transformers ativará o recurso semelhante sempre que o DeepSpeed Zero3 for usado.
Para o FSDP, sempre que
--fsdp_cpu_ram_efficient_loading truefor definido, oacceleratedefinirá automaticamentesync_module_statescomo true. Para o carregamento eficiente de RAM, os pesos serão carregados apenas em um único rank, e, portanto, é necessário quesync_module_statesseja usado para transmitir os pesos para os outros ranks.
Model
O FSDP requer um --fsdp_auto_wrap_policy explícito para que o algoritmo decida como agendar as operações de all-gather e reduce-scatter. Mas, para o DeepSpeed, isso é transparente para o usuário.
Para o FSDP, basta definir
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP. Nas versões mais recentes dotransformers, fazemos o possível para determinar ofsdp_transformer_layer_cls_to_wrapadequado para os modelos de transformers do HF. No entanto, se você receber um erro relacionado a isso, especifique-o.
Parâmetros de Invocação
O FSDP requer a flag explícita --fsdp_use_orig_params ao usar torch.compile, consulte a documentação do PyTorch. Para o DeepSpeed, isso é transparente para o usuário.
Para o FSDP, ao usar
torch.compile, definafsdp_use_orig_params: True.
Treinamento
Deepspeed requer as flags explícitas --gradient_accumulation_steps e --gradient_clipping. Para o FSDP, isso é transparente para o usuário.
Ao usar o DeepSpeed, defina
gradient_accumulation_steps: "auto"egradient_clipping: "auto"para recuperar automaticamente os valores definidos no Accelerator ou noTrainingArguments(se estiver usando otransformers).
Sobre as diferenças no tratamento da precisão dos dados
Para discutir como a precisão dos dados é tratada no FSDP e no DeepSpeed, é instrutivo primeiro apresentar uma visão geral de como os parâmetros do modelo são processados nesses frameworks. Antes que os parâmetros do modelo/otimizador sejam distribuídos entre as GPUs, a preparação dos parâmetros envolve primeiro “achatar” (flatten) os parâmetros em torch.Tensor unidimensionais. A implementação do FSDP/DeepSpeed difere em relação ao dtype no qual esses parâmetros “achatados” são armazenados, e isso tem implicações para a forma como o torch.Optimizer aloca seus dtypes. A tabela abaixo descreve os processos de ambos os frameworks; a coluna “Local” indica o processo que ocorre em nível de GPU individual, portanto, qualquer sobrecarga de memória causada pelo upcasting deve ser entendida como amortizada pelo número de GPUs utilizadas.
Como regra geral, para um treinamento estável com precisão mista automática, todos os parâmetros treináveis devem estar em
torch.float32.
| Processo | Local | Framework | Detalhes |
|---|---|---|---|
Carregamento, ou seja, AutoModel.from_pretrained(..., torch_dtype=torch_dtype) | |||
| Preparação, ou seja, criação dos “flat params” | ✅ | FSDP DeepSpeed | criado em torch_dtype.ignora torch_dtype, criado em float32. |
| Inicialização do otimizador | ✅ | FSDP DeepSpeed | cria parâmetros em torch_dtypecria parâmetros em float32 |
| Etapa de treinamento, ou seja, forward, backward, redução | FSDP DeepSpeed | segue MixedPrecisionsegue as configurações de precisão mista do deepspeed_config_file. | |
| Otimizador (Pré-Passo) | ✅ | FSDP DeepSpeed | upcasting (se houver) para torch_dtypeupcasted para float32 |
| Otimizador (Passo Real) | ✅ | FSDP DeepSpeed | ocorre em torch_dtype ocorre em float32. |
Portanto, ao usar o DeepSpeed com um pequeno número de GPUs, esteja ciente de possíveis sobrecargas de memória significativas devido ao upcasting durante a preparação.
Com o FSDP, na ausência de precisão mista, é possível operar o
torch.Optimizerem baixa precisãotorch_dtype, o que pode ser útil ao usar um pequeno número de GPUs.
Com precisão mista, FSDP e DeepSpeed farão o upcast na etapa de preparação do modelo (cf. tabela acima). Mas observe que o FSDP salvará os checkpoints na precisão upcasted; o DeepSpeed ainda pode salvar checkpoints de baixa precisão se
--zero3_save_16bit_modelfor especificado.
Para esclarecer a tabela acima, considere os exemplos concretos abaixo; o passo prévio e o passo real do otimizador foram combinados para brevidade. Com FSDP, é possível operar nos dois modos mostrados abaixo, mas o DeepSpeed só pode operar em um.
| Framework | Carregamento de modelos (torch_dtype) | Precisão Mista | Preparação (Local) | Treinamento | Otimizador (Local) |
|---|---|---|---|---|---|
| FSDP | bf16 | padrão (nenhum) | bf16 | bf16 | bf16 |
| FSDP | bf16 | bf16 | fp32 | bf16 | fp32 |
| DeepSpeed | bf16 | bf16 | fp32 | bf16 | fp32 |