# Tamamen Parçalı Veri Paralelliği

[Fully sharded data parallel](https://pytorch.org/docs/stable/fsdp.html) (FSDP), 1T parametreye kadar büyük ön eğitilmiş modellerin dağıtık eğitimi için geliştirilmiştir. FSDP, model parametrelerini, gradyanları ve optimizör durumlarını veri paralel süreçler arasında dilimleyerek (sharding) bunu başarır ve dilimlenmiş model parametrelerini bir CPU'ya aktarabilir (offload). FSDP'nin sağladığı bellek verimliliği, eğitimi daha büyük batch veya model boyutlarına ölçeklendirmenizi sağlar.

Her iki özellik de 🤗 Accelerate tarafından desteklenmektedir ve 🤗 PEFT ile birlikte kullanabilirsiniz.

# PEFT ve FSDP kullanın
Bu kılavuz bölümü, SFT (denetimli ince ayar) işlemi için [eğitim betiğimizi](https://github.com/huggingface/peft/blob/main/examples/sft/train.py) nasıl kullanacağınızı öğrenmenize yardımcı olacaktır. Betiği, tek bir makinede 8xH100 80GB GPU'larda Llama-70B modelini LoRA ve FSDP ile SFT yapmak üzere yapılandıracaksınız. accelerate yapılandırmasını değiştirerek birden fazla makineye ölçeklendirmek üzere yapılandırabilirsiniz.

## Yapılandırma

🤗 Accelerate ile [FSDP yapılandırma dosyası oluşturmak](https://huggingface.co/docs/accelerate/quicktour#launching-your-distributed-script) için aşağıdaki komutu çalıştırarak başlayın. `--config_file` bayrağı, yapılandırma dosyasını belirli bir konuma kaydetmenizi sağlar; aksi takdirde dosya, 🤗 Accelerate önbelleğinde `default_config.yaml` adıyla kaydedilir.

Yapılandırma dosyası, eğitim betiğini başlattığınızda varsayılan seçenekleri ayarlamak için kullanılır.

```bash
accelerate config --config_file fsdp_config.yaml
```

Kurulumunuzla ilgili birkaç soru sorulacak ve aşağıdaki argümanları yapılandıracaksınız. Bu örnekte, aşağıdaki görüntüde gösterildiği gibi anketi yanıtlayacaksınız.

    

FSDP kullanmak için Accelerate yapılandırmasını oluşturma

Bu işlem tamamlandıktan sonra, ilgili yapılandırma aşağıdaki gibi görünmeli ve [fsdp_config.yaml](https://github.com/huggingface/peft/blob/main/examples/sft/configs/fsdp_config.yaml) dosyası config klasöründe bulunabilir:

```yml
compute_environment: LOCAL_MACHINE
debug: false
distributed_type: FSDP
downcast_bf16: 'no'
fsdp_config:
  fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
  fsdp_backward_prefetch: BACKWARD_PRE
  fsdp_cpu_ram_efficient_loading: true
  fsdp_forward_prefetch: false
  fsdp_offload_params: false
  fsdp_sharding_strategy: FULL_SHARD
  fsdp_state_dict_type: SHARDED_STATE_DICT
  fsdp_sync_module_states: true
  fsdp_use_orig_params: false
machine_rank: 0
main_training_function: main
mixed_precision: bf16
num_machines: 1
num_processes: 8
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false
```

## Başlatma komutu

Başlatma komutu [run_peft_fsdp.sh](https://github.com/huggingface/peft/blob/main/examples/sft/run_peft_fsdp.sh) adresinde mevcuttur ve aşağıda da gösterilmektedir:
```bash
accelerate launch --config_file "configs/fsdp_config.yaml"  train.py \
--seed 100 \
--model_name_or_path "meta-llama/Llama-2-70b-hf" \
--dataset_name "smangrul/ultrachat-10k-chatml" \
--chat_template_format "chatml" \
--add_special_tokens False \
--append_concat_token False \
--splits "train,test" \
--max_seq_len 2048 \
--num_train_epochs 1 \
--logging_steps 5 \
--log_level "info" \
--logging_strategy "steps" \
--eval_strategy "epoch" \
--save_strategy "epoch" \
--push_to_hub \
--hub_private_repo True \
--hub_strategy "every_save" \
--bf16 True \
--packing True \
--learning_rate 1e-4 \
--lr_scheduler_type "cosine" \
--weight_decay 1e-4 \
--warmup_steps 0 \
--max_grad_norm 1.0 \
--output_dir "llama-sft-lora-fsdp" \
--per_device_train_batch_size 8 \
--per_device_eval_batch_size 8 \
--gradient_accumulation_steps 4 \
--gradient_checkpointing True \
--use_reentrant False \
--dataset_text_field "content" \
--use_flash_attn True \
--use_peft_lora True \
--lora_r 8 \
--lora_alpha 16 \
--lora_dropout 0.1 \
--lora_target_modules "all-linear" \
--use_4bit_quantization False
```

LoRA'nın rank=8, alpha=16 parametreleriyle ve tüm lineer katmanları hedef alacak şekilde kullanıldığını fark edin. FSDP yapılandırma dosyasını geçiriyor ve 70B Llama modelini [ultrachat veri setinin](https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k) bir alt kümesi üzerinde ince ayarlıyoruz.

## Önemli kısımlar

Betik biraz daha derinlemesine inceleyelim, böylece neler olduğunu görebilir ve nasıl çalıştığını anlayabilirsiniz.

Bilmeniz gereken ilk şey, FSDP yapılandırmasının iletildiği için script'in dağıtık eğitimde FSDP kullandığıdır. [SFTTrainer](https://huggingface.co/docs/trl/main/en/sft_trainer#trl.SFTTrainer) sınıfı, iletilen peft yapılandırmasını kullanarak PEFT modelini oluşturma işinin tamamını üstlenir. Ardından `trainer.train()` çağrıldığında, Trainer, FSDP yapılandırmasını kullanarak model, optimizer ve trainer'ı hazırlamak için içsel olarak 🤗 Accelerate'ı kullanır; bu sayede oluşturulan FSDP sarmalı model eğitilir. Ana kod parçası aşağıdadır:

```python
# trainer
trainer = SFTTrainer(
    model=model,
    processing_class=tokenizer,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    peft_config=peft_config,
)
trainer.accelerator.print(f"{trainer.model}")
if model_args.use_peft_lora:
    # handle PEFT+FSDP case
    trainer.model.print_healthcheck()
    if getattr(trainer.accelerator.state, "fsdp_plugin", None):
        from peft.utils.other import fsdp_auto_wrap_policy

        fsdp_plugin = trainer.accelerator.state.fsdp_plugin
        fsdp_plugin.auto_wrap_policy = fsdp_auto_wrap_policy(trainer.model)

# train
checkpoint = None
if training_args.resume_from_checkpoint is not None:
    checkpoint = training_args.resume_from_checkpoint
trainer.train(resume_from_checkpoint=checkpoint)

# saving final model
if trainer.is_fsdp_enabled:
    trainer.accelerator.state.fsdp_plugin.set_state_dict_type("FULL_STATE_DICT")
trainer.save_model()
```

Burada, FSDP'yi PEFT ile kullanırken şu anda dikkat edilmesi gereken ana nokta, GPU bellek tasarrufunu gerçekleştirmek için `use_orig_params`'in `False` olması gerektiğidir. `use_orig_params=False` nedeniyle, FSDP için otomatik sarma politikası, eğitilebilir ve eğitilemez parametrelerin ayrı ayrı sarılacak şekilde değiştirilmelidir. Bu, aşağıdaki kod parçasında PEFT'den `fsdp_auto_wrap_policy` yardımcı işlevini kullanarak yapılır:

```
if getattr(trainer.accelerator.state, "fsdp_plugin", None):
    from peft.utils.other import fsdp_auto_wrap_policy

    fsdp_plugin = trainer.accelerator.state.fsdp_plugin
    fsdp_plugin.auto_wrap_policy = fsdp_auto_wrap_policy(trainer.model)
```

## Bellek kullanımı

Yukarıdaki örnekte, aşağıdaki ekran görüntüsünde de görüldüğü üzere GPU başına tüketilen bellek 72-80 GB (%90-98) civarındadır. Son kısımdaki hafif GPU bellek artışı, modelin çıkarım sırasında `from_pretrained` yöntemiyle normal şekilde yüklenebilecek adaptör ağırlıklarına sahip olması için `SHARDED_STATE_DICT` yerine `FULL_STATE_DICT` state dict türü kullanılarak kaydedilmesi sırasında gerçekleşir:

    

Eğitim çalışması için GPU bellek kullanımı

# Büyük modelleri birden fazla GPU üzerinde ince ayarlamak için PEFT QLoRA ve FSDP kullanın

Bu bölümde, 70B llama modelini 2X24GB GPU'larda ince ayar yapmak için QLoRA ve FSDP'nin nasıl kullanılacağına bakacağız. [Answer.AI](https://www.answer.ai/), bitsandbytes ve Hugging Face 🤗 ile iş birliği içinde, FSDP+QLoRA kullanımını mümkün kılan kodu açık kaynak olarak yayımlamış ve tüm süreci içgörülü blog yazılarında [You can now train a 70b language model at home](https://www.answer.ai/posts/2024-03-06-fsdp-qlora.html) açıkladı. Bu özellik artık Hugging Face ekosistemine entegre edildi.

Bunun için öncelikle `bitsandbytes>=0.43.3`, `accelerate>=1.0.1`, `transformers>4.44.2`, `trl>0.11.4` ve `peft>0.13.0` gereklidir. Accelerate yapılandırması kullanıldığında `fsdp_cpu_ram_efficient_loading=true`, `fsdp_use_orig_params=false` ve `fsdp_offload_params=true` (cpu offloading) değerlerini ayarlamamız gerekir. accelerate launcher kullanılmadığında, alternatif olarak `export FSDP_CPU_RAM_EFFICIENT_LOADING=true` ortam değişkenini ayarlayabilirsiniz. Burada accelerate config kullanacağız ve [fsdp_config_qlora.yaml](https://github.com/huggingface/peft/blob/main/examples/sft/configs/fsdp_config_qlora.yaml) adresinde bulunabilen yapılandırma aşağıdaki gibidir:

```yml
compute_environment: LOCAL_MACHINE                                                                                                                                           
debug: false                                                                                                                                                                 
distributed_type: FSDP
downcast_bf16: 'no'
fsdp_config:
  fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
  fsdp_backward_prefetch: BACKWARD_PRE
  fsdp_cpu_ram_efficient_loading: true
  fsdp_forward_prefetch: false
  fsdp_offload_params: true
  fsdp_sharding_strategy: FULL_SHARD
  fsdp_state_dict_type: SHARDED_STATE_DICT
  fsdp_sync_module_states: true
  fsdp_use_orig_params: false
machine_rank: 0
main_training_function: main
mixed_precision: 'no'
num_machines: 1
num_processes: 2
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false
```

Başlatma komutu, [run_peft_qlora_fsdp.sh](https://github.com/huggingface/peft/blob/main/examples/sft/run_peft_qlora_fsdp.sh) adresinde bulunan aşağıdaki gibidir:
```
accelerate launch --config_file "configs/fsdp_config_qlora.yaml"  train.py \
--seed 100 \
--model_name_or_path "meta-llama/Llama-2-70b-hf" \
--dataset_name "smangrul/ultrachat-10k-chatml" \
--chat_template_format "chatml" \
--add_special_tokens False \
--append_concat_token False \
--splits "train,test" \
--max_seq_len 2048 \
--num_train_epochs 1 \
--logging_steps 5 \
--log_level "info" \
--logging_strategy "steps" \
--eval_strategy "epoch" \
--save_strategy "epoch" \
--push_to_hub \
--hub_private_repo True \
--hub_strategy "every_save" \
--bf16 True \
--packing True \
--learning_rate 1e-4 \
--lr_scheduler_type "cosine" \
--weight_decay 1e-4 \
--warmup_steps 0 \
--max_grad_norm 1.0 \
--output_dir "llama-sft-qlora-fsdp" \
--per_device_train_batch_size 2 \
--per_device_eval_batch_size 2 \
--gradient_accumulation_steps 2 \
--gradient_checkpointing True \
--use_reentrant True \
--dataset_text_field "content" \
--use_flash_attn True \
--use_peft_lora True \
--lora_r 8 \
--lora_alpha 16 \
--lora_dropout 0.1 \
--lora_target_modules "all-linear" \
--use_4bit_quantization True \
--use_nested_quant True \
--bnb_4bit_compute_dtype "bfloat16" \
--bnb_4bit_quant_storage_dtype "bfloat16"
```

Geçirilen yeni argümanı, 4 bit parametrelerin paketlenmesi için veri türünü belirten `bnb_4bit_quant_storage_dtype` argümanını fark edin. Örneğin, `bfloat16` olarak ayarlandığında, **16/4 = 4** adet 4 bit parametre, kuantizasyon sonrası birlikte paketlenir. `bfloat16` ile karma hassasiyetli eğitim kullanıldığında, `bnb_4bit_quant_storage_dtype` saf `bfloat16` ince ayarı için `bfloat16` veya otomatik karma hassasiyet için (bu daha fazla GPU belleği tüketir) `float32` olabilir. `float16` ile karma hassasiyetli eğitim kullanıldığında, `bnb_4bit_quant_storage_dtype` kararlı otomatik karma hassasiyetli eğitim için `float32` olarak ayarlanmalıdır.

Eğitim kodu açısından önemli kod değişiklikleri şunlardır:

```diff
...

bnb_config = BitsAndBytesConfig(
    load_in_4bit=args.use_4bit_quantization,
    bnb_4bit_quant_type=args.bnb_4bit_quant_type,
    bnb_4bit_compute_dtype=compute_dtype,
    bnb_4bit_use_double_quant=args.use_nested_quant,
+   bnb_4bit_quant_storage=quant_storage_dtype,
)

...

model = AutoModelForCausalLM.from_pretrained(
    args.model_name_or_path,
    quantization_config=bnb_config,
    trust_remote_code=True,
    attn_implementation="flash_attention_2" if args.use_flash_attn else "eager",
+   dtype=quant_storage_dtype or torch.float32,
)
```

`AutoModelForCausalLM` için `dtype`'nin, `bnb_4bit_quant_storage` veri tipiyle aynı olduğunu fark edin. Bu kadar. Geri kalan her şey Trainer ve TRL tarafından ele alınır.

## Bellek kullanımı

Yukarıdaki örnekte, GPU başına tüketilen bellek **19.6 GB** iken CPU RAM kullanımı yaklaşık **107 GB**'dir. CPU offloading devre dışı bırakıldığında, GPU bellek kullanımı **35.6 GB/ GPU** olur. Dolayısıyla, tam finetuning için 16X80GB GPU, FSDP+LoRA ile 8X80GB GPU ve DDP+QLoRA ile birkaç 80GB GPU gerektiren işlem, artık 2X24GB GPU ile yapılabilir. Bu, büyük modellerin finetuning'ini daha erişilebilir hale getirir.

## Daha fazla kaynak
FSDP ve PEFT kullanarak ince ayar yapma konusunda [llama-recipes](https://github.com/facebookresearch/llama-recipes/?tab=readme-ov-file#fine-tuning) deposuna ve [Getting started with Llama](https://llama.meta.com/get-started/#fine-tuning) kılavuzuna da başvurabilirsiniz.

## Dikkat Edilmesi Gerekenler
1. PEFT ve FSDP kullanırken birleştirme (merging) şu anda desteklenmemektedir ve hata oluşturacaktır.
2. `modules_to_save` yapılandırma parametresinin geçirilmesi şu anda test edilmemiştir.
3. CPU Offloading kullanılırken GPU bellek tasarrufu şu anda test edilmemiştir.
4. FSDP+QLoRA kullanıldığında, `paged_adamw_8bit` şu anda bir kontrol noktası (checkpoint) kaydedilirken hata vermektedir.
5. FSDP ile DoRA eğitimi çalışmalıdır (LoRA'ya kıyasla daha düşük hızda). bitsandbytes ile birleştirildiğinde (QDoRA), 4-bit kuantizasyon da çalışmalıdır, ancak 8-bit kuantizasyonun bilinen sorunları vardır ve önerilmez.
6. FSDP2 ile `set_adapter()` ve `set_requires_grad()`, `requires_grad` değişikliklerinin parçalara ayrılmış parametrelere ulaşabilmesi için [PeftModel](/docs/peft/main/tr/package_reference/peft_model#peft.PeftModel) içindeki FSDP2 modüllerini, `PeftModel` dahil olmak üzere yeniden parçalar (reshard). `disable_adapter()` içinden çıkış, yalnızca FSDP2'nin içinde kayıtlı parametre nesnelerini değiştirmesi (parçalara ayrılmış parametrelerle bir ileri geçişin yaptığı gibi) veya yeniden etkinleştirmenin `requires_grad` değerini girişteki durumundan değiştirmesi durumunda bunu yapar. Birleştirilmiş bir adaptör katmanının parametrelerini parçalara ayıran FSDP2 modülleri yeniden parçalanmaz; bu nedenle bu yöntemleri çağırmadan önce birleştirmeyi geri alın (unmerge). `reshard_after_forward=False` kullanıldığında veya kök modül için varsayılan `None` durumunda, sonraki ileri geçiş yeniden tüm toplama (all-gather) işlemini yapar. `PeftModel`'i saran FSDP2 modülleri yeniden parçalanmaz; bu yöntemleri çağırmadan önce bunlarda `reshard()` çağrın. Bu çağrılar temel ağırlıkları parçalara ayrılmış bırakabileceğinden, hemen ardından birleştirme işlemi doğru çalışmaz (bkz. 1). Prompt öğrenme yöntemleri ve adaption prompt henüz kapsam dışıdır.

