PEFT documentation
DeepSpeed
DeepSpeed
DeepSpeed là một thư viện được thiết kế cho tốc độ và quy mô trong huấn luyện phân tán các mô hình lớn có hàng tỷ tham số. Nền tảng cốt lõi của nó là Zero Redundancy Optimizer (ZeRO), vốn chia nhỏ trạng thái optimizer (ZeRO-1), gradient (ZeRO-2) và tham số (ZeRO-3) trên các tiến trình song song dữ liệu. Điều này giảm đáng kể lượng bộ nhớ sử dụng, cho phép bạn mở rộng huấn luyện lên các mô hình có hàng tỷ tham số. Để đạt hiệu quả bộ nhớ cao hơn nữa, ZeRO-Offload giảm tính toán và bộ nhớ GPU bằng cách tận dụng tài nguyên CPU trong quá trình tối ưu hóa.
Cả hai tính năng này đều được hỗ trợ trong 🤗 Accelerate, và bạn có thể sử dụng chúng với 🤗 PEFT.
Tương thích với lượng tử hóa bitsandbytes + LoRA
Dưới đây là bảng tóm tắt tính tương thích giữa LoRA của PEFT, thư viện bitsandbytes và các giai đoạn Zero của DeepSpeed đối với việc fine-tuning. DeepSpeed Zero-1 và 2 sẽ không có tác dụng khi suy luận vì giai đoạn 1 chia nhỏ trạng thái optimizer và giai đoạn 2 chia nhỏ trạng thái optimizer và gradient:
| Giai đoạn DeepSpeed | Có tương thích không? |
|---|---|
| Zero-1 | 🟢 |
| Zero-2 | 🟢 |
| Zero-3 | 🟢 |
Đối với DeepSpeed Stage 3 + QLoRA, vui lòng tham khảo phần Sử dụng PEFT QLoRA và DeepSpeed với ZeRO3 để tinh chỉnh các mô hình lớn trên nhiều GPU bên dưới.
Để xác nhận những quan sát này, chúng tôi đã chạy các script ví dụ chính thức của thư viện Transformers Reinforcement Learning (TRL) cho SFT (Supervised Fine-tuning) bằng cách sử dụng QLoRA + PEFT và các cấu hình accelerate có sẵn tại đây. Chúng tôi đã chạy các thí nghiệm này trên 2 GPU NVIDIA T4.
Sử dụng PEFT và DeepSpeed với ZeRO3 để tinh chỉnh các mô hình lớn trên nhiều thiết bị và nhiều nút
Phần này của hướng dẫn sẽ giúp bạn học cách sử dụng script huấn luyện DeepSpeed của chúng ta để thực hiện SFT. Bạn sẽ cấu hình script để thực hiện SFT (fine-tuning có giám sát) cho mô hình Llama-70B với LoRA và ZeRO-3 trên 8 GPU H100 80GB trên một máy duy nhất. Bạn có thể cấu hình để mở rộng sang nhiều máy bằng cách thay đổi accelerate config.
Cấu hình
Bắt đầu bằng cách chạy lệnh sau để tạo tệp cấu hình DeepSpeed bằng 🤗 Accelerate. Cờ --config_file cho phép bạn lưu tệp cấu hình vào một vị trí cụ thể, nếu không nó sẽ được lưu dưới dạng tệp default_config.yaml trong bộ nhớ đệm của 🤗 Accelerate.
File cấu hình được sử dụng để thiết lập các tùy chọn mặc định khi bạn khởi chạy script huấn luyện.
accelerate config --config_file deepspeed_config.yaml
Bạn sẽ được hỏi một vài câu hỏi về cấu hình của mình và thiết lập các đối số sau. Trong ví dụ này, bạn sẽ sử dụng ZeRO-3 nên hãy đảm bảo chọn các tùy chọn tương ứng.
`zero_stage`: [0] Disabled, [1] optimizer state partitioning, [2] optimizer+gradient state partitioning and [3] optimizer+gradient+parameter partitioning
`gradient_accumulation_steps`: Number of training steps to accumulate gradients before averaging and applying them. Pass the same value as you would pass via cmd argument else you will encounter mismatch error.
`gradient_clipping`: Enable gradient clipping with value. Don't set this as you will be passing it via cmd arguments.
`offload_optimizer_device`: [none] Disable optimizer offloading, [cpu] offload optimizer to CPU, [nvme] offload optimizer to NVMe SSD. Only applicable with ZeRO >= Stage-2. Set this as `none` as don't want to enable offloading.
`offload_param_device`: [none] Disable parameter offloading, [cpu] offload parameters to CPU, [nvme] offload parameters to NVMe SSD. Only applicable with ZeRO Stage-3. Set this as `none` as don't want to enable offloading.
`zero3_init_flag`: Decides whether to enable `deepspeed.zero.Init` for constructing massive models. Only applicable with ZeRO Stage-3. Set this to `True`.
`zero3_save_16bit_model`: Decides whether to save 16-bit model weights when using ZeRO Stage-3. Set this to `True`.
`mixed_precision`: `no` for FP32 training, `fp16` for FP16 mixed-precision training and `bf16` for BF16 mixed-precision training. Set this to `True`.Sau khi hoàn tất, cấu hình tương ứng sẽ có dạng như bên dưới và bạn có thể tìm thấy nó trong thư mục config tại deepspeed_config.yaml:
compute_environment: LOCAL_MACHINE
debug: false
deepspeed_config:
deepspeed_multinode_launcher: standard
gradient_accumulation_steps: 4
offload_optimizer_device: none
offload_param_device: none
zero3_init_flag: true
zero3_save_16bit_model: true
zero_stage: 3
distributed_type: DEEPSPEED
downcast_bf16: 'no'
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: falseLệnh khởi động
Lệnh khởi động có sẵn tại run_peft_deepspeed.sh và cũng được hiển thị bên dưới:
accelerate launch --config_file "configs/deepspeed_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-deepspeed" \
--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 FalseLưu ý rằng chúng ta đang sử dụng LoRA với rank=8, alpha=16 và nhắm vào tất cả các lớp tuyến tính. Chúng ta đang truyền tệp cấu hình deepspeed và tinh chỉnh mô hình Llama 70B trên một tập con của bộ dữ liệu ultrachat.
Các phần quan trọng
Hãy cùng tìm hiểu sâu hơn về script để bạn có thể thấy những gì đang diễn ra và hiểu cách nó hoạt động.
Điều đầu tiên cần biết là script sử dụng DeepSpeed cho huấn luyện phân tán vì cấu hình DeepSpeed đã được truyền vào. Lớp SFTTrainer xử lý toàn bộ công việc tạo mô hình PEFT bằng cách sử dụng cấu hình peft được truyền vào. Sau đó, khi bạn gọi trainer.train(), SFTTrainer bên trong sẽ sử dụng 🤗 Accelerate để chuẩn bị mô hình, optimizer và trainer bằng cách sử dụng cấu hình DeepSpeed để tạo DeepSpeed engine, sau đó tiến hành huấn luyện. Đoạn mã chính được trình bày bên dưới:
# 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}")
# 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
trainer.save_model()Lượng bộ nhớ sử dụng
Trong ví dụ trên, bộ nhớ tiêu thụ trên mỗi GPU là 64 GB (80%) như được thấy trong ảnh chụp màn hình bên dưới:

Tài nguyên bổ sung
Bạn cũng có thể tham khảo bài viết trên blog Falcon 180B Finetuning using 🤗 PEFT and DeepSpeed về cách finetune mô hình Falcon 180B trên 16 GPU A100 ở 2 máy.
Sử dụng PEFT QLoRA và DeepSpeed với ZeRO3 để tinh chỉnh các mô hình lớn trên nhiều GPU
Trong phần này, chúng ta sẽ xem xét cách sử dụng QLoRA và DeepSpeed Stage-3 để tinh chỉnh mô hình llama 70B trên 2 GPU 40GB.
Để làm điều này, trước tiên chúng ta cần bitsandbytes>=0.43.3, accelerate>=1.0.1, transformers>4.44.2, trl>0.11.4 và peft>0.13.0. Chúng ta cần đặt zero3_init_flag thành true khi sử dụng cấu hình Accelerate. Dưới đây là cấu hình có thể tìm thấy tại deepspeed_config_z3_qlora.yaml:
compute_environment: LOCAL_MACHINE
debug: false
deepspeed_config:
deepspeed_multinode_launcher: standard
offload_optimizer_device: none
offload_param_device: none
zero3_init_flag: true
zero3_save_16bit_model: true
zero_stage: 3
distributed_type: DEEPSPEED
downcast_bf16: 'no'
machine_rank: 0
main_training_function: main
mixed_precision: bf16
num_machines: 1
num_processes: 2
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: falseLệnh khởi động được cho bên dưới, có sẵn tại run_peft_qlora_deepspeed_stage3.sh:
accelerate launch --config_file "configs/deepspeed_config_z3_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-dsz3" \
--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"Lưu ý đối số mới được truyền vào bnb_4bit_quant_storage_dtype, dùng để chỉ định kiểu dữ liệu cho việc đóng gói các tham số 4-bit. Ví dụ, khi được đặt thành bfloat16, 32/4 = 8 tham số 4-bit sẽ được đóng gói cùng nhau sau khi lượng tử hóa.
Về mã huấn luyện, các thay đổi mã quan trọng là:
...
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,
)Lưu ý rằng dtype của AutoModelForCausalLM giống với kiểu dữ liệu bnb_4bit_quant_storage. Đó là tất cả. Mọi thứ còn lại được xử lý bởi Trainer và TRL.
Lượng bộ nhớ sử dụng
Trong ví dụ trên, bộ nhớ tiêu thụ trên mỗi GPU là 36.6 GB. Do đó, việc trước đây cần 8 GPU 80GB với DeepSpeed Stage 3+LoRA và một vài GPU 80GB với DDP+QLoRA giờ chỉ cần 2 GPU 40GB. Điều này giúp việc tinh chỉnh các mô hình lớn trở nên dễ tiếp cận hơn.
Sử dụng PEFT và DeepSpeed với ZeRO3 và CPU Offloading để tinh chỉnh các mô hình lớn trên một GPU
Phần này của hướng dẫn sẽ giúp bạn học cách sử dụng script huấn luyện DeepSpeed của chúng tôi. Bạn sẽ cấu hình script để huấn luyện một mô hình lớn cho việc sinh có điều kiện với ZeRO-3 và CPU Offload.
💡 Để giúp bạn bắt đầu, hãy xem các script huấn luyện mẫu của chúng tôi cho causal language modeling và conditional generation. Bạn có thể điều chỉnh các script này cho ứng dụng của riêng mình hoặc thậm chí sử dụng chúng ngay lập tức nếu tác vụ của bạn tương tự như trong các script.
Cấu hình
Bắt đầu bằng cách chạy lệnh sau để tạo tệp cấu hình DeepSpeed bằng 🤗 Accelerate. Cờ --config_file cho phép bạn lưu tệp cấu hình vào một vị trí cụ thể, nếu không nó sẽ được lưu dưới dạng tệp default_config.yaml trong bộ nhớ đệm của 🤗 Accelerate.
File cấu hình được sử dụng để thiết lập các tùy chọn mặc định khi bạn khởi chạy script huấn luyện.
accelerate config --config_file ds_zero3_cpu.yaml
Bạn sẽ được hỏi một vài câu hỏi về cấu hình của mình và thiết lập các đối số sau. Trong ví dụ này, bạn sẽ sử dụng ZeRO-3 cùng với CPU-Offload nên hãy đảm bảo chọn các tùy chọn đó.
`zero_stage`: [0] Disabled, [1] optimizer state partitioning, [2] optimizer+gradient state partitioning and [3] optimizer+gradient+parameter partitioning
`gradient_accumulation_steps`: Number of training steps to accumulate gradients before averaging and applying them.
`gradient_clipping`: Enable gradient clipping with value.
`offload_optimizer_device`: [none] Disable optimizer offloading, [cpu] offload optimizer to CPU, [nvme] offload optimizer to NVMe SSD. Only applicable with ZeRO >= Stage-2.
`offload_param_device`: [none] Disable parameter offloading, [cpu] offload parameters to CPU, [nvme] offload parameters to NVMe SSD. Only applicable with ZeRO Stage-3.
`zero3_init_flag`: Decides whether to enable `deepspeed.zero.Init` for constructing massive models. Only applicable with ZeRO Stage-3.
`zero3_save_16bit_model`: Decides whether to save 16-bit model weights when using ZeRO Stage-3.
`mixed_precision`: `no` for FP32 training, `fp16` for FP16 mixed-precision training and `bf16` for BF16 mixed-precision training. Một tệp cấu hình mẫu có thể trông như sau. Điều quan trọng nhất cần lưu ý là zero_stage được đặt thành 3, và offload_optimizer_device cùng offload_param_device được đặt thành cpu.
compute_environment: LOCAL_MACHINE
deepspeed_config:
gradient_accumulation_steps: 1
gradient_clipping: 1.0
offload_optimizer_device: cpu
offload_param_device: cpu
zero3_init_flag: true
zero3_save_16bit_model: true
zero_stage: 3
distributed_type: DEEPSPEED
downcast_bf16: 'no'
dynamo_backend: 'NO'
fsdp_config: {}
machine_rank: 0
main_training_function: main
megatron_lm_config: {}
mixed_precision: 'no'
num_machines: 1
num_processes: 1
rdzv_backend: static
same_network: true
use_cpu: falseCác phần quan trọng
Hãy cùng tìm hiểu sâu hơn về script để bạn có thể thấy những gì đang diễn ra và hiểu cách nó hoạt động.
Trong hàm main, script tạo một lớp Accelerator để khởi tạo tất cả các yêu cầu cần thiết cho huấn luyện phân tán.
💡 Bạn có thể tự do thay đổi model và dataset bên trong hàm
main. Nếu định dạng dataset của bạn khác với định dạng trong script, bạn cũng có thể cần viết hàm tiền xử lý của riêng mình.
Script cũng tạo ra một cấu hình cho phương pháp 🤗 PEFT bạn đang sử dụng, trong trường hợp này là LoRA. LoraConfig xác định loại tác vụ và các tham số quan trọng như chiều của các ma trận hạng thấp, hệ số tỷ lệ của các ma trận, và xác suất dropout của các lớp LoRA. Nếu bạn muốn sử dụng một phương pháp 🤗 PEFT khác, hãy đảm bảo thay thế LoraConfig bằng class phù hợp.
def main():
+ accelerator = Accelerator()
model_name_or_path = "facebook/bart-large"
dataset_name = "twitter_complaints"
+ peft_config = LoraConfig(
task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
)Trong suốt script, bạn sẽ thấy các hàm main_process_first và wait_for_everyone giúp kiểm soát và đồng bộ hóa thời điểm các tiến trình được thực thi.
Hàm get_peft_model() nhận một mô hình cơ sở và peft_config mà bạn đã chuẩn bị trước đó để tạo ra một PeftModel:
model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
+ model = get_peft_model(model, peft_config)Truyền tất cả các đối tượng huấn luyện liên quan vào prepare của 🤗 Accelerate để đảm bảo mọi thứ đã sẵn sàng cho việc huấn luyện:
model, train_dataloader, eval_dataloader, test_dataloader, optimizer, lr_scheduler = accelerator.prepare(
model, train_dataloader, eval_dataloader, test_dataloader, optimizer, lr_scheduler
)Đoạn mã tiếp theo kiểm tra xem plugin DeepSpeed có được sử dụng trong Accelerator hay không, và nếu plugin tồn tại, chúng ta sẽ kiểm tra xem có đang sử dụng ZeRO-3 hay không. Cờ điều kiện này được dùng khi gọi hàm generate trong quá trình suy luận để đồng bộ hóa các GPU khi các tham số của mô hình được chia nhỏ:
is_ds_zero_3 = False
if getattr(accelerator.state, "deepspeed_plugin", None):
is_ds_zero_3 = accelerator.state.deepspeed_plugin.zero_stage == 3Bên trong vòng lặp huấn luyện, lệnh loss.backward() thông thường được thay thế bằng backward của 🤗 Accelerate, sử dụng phương thức backward() phù hợp dựa trên cấu hình của bạn:
for epoch in range(num_epochs):
with TorchTracemalloc() as tracemalloc:
model.train()
total_loss = 0
for step, batch in enumerate(tqdm(train_dataloader)):
outputs = model(**batch)
loss = outputs.loss
total_loss += loss.detach().float()
+ accelerator.backward(loss)
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()Đó là tất cả! Phần còn lại của script xử lý vòng lặp huấn luyện, đánh giá và thậm chí đẩy lên Hub cho bạn.
Huấn luyện
Chạy lệnh sau để khởi chạy script huấn luyện. Trước đó, bạn đã lưu tệp cấu hình vào ds_zero3_cpu.yaml, vì vậy bạn cần truyền đường dẫn đến launcher bằng đối số --config_file như sau:
accelerate launch --config_file ds_zero3_cpu.yaml examples/conditional_generation/peft_lora_seq2seq_accelerate_ds_zero3_offload.py
Bạn sẽ thấy một số nhật ký đầu theo dõi mức sử dụng bộ nhớ trong quá trình huấn luyện, và khi hoàn tất, script sẽ trả về độ chính xác và so sánh các dự đoán với nhãn:
GPU Memory before entering the train : 1916
GPU Memory consumed at the end of the train (end-begin): 66
GPU Peak Memory consumed during the train (max-begin): 7488
GPU Total Peak Memory consumed during the train (max): 9404
CPU Memory before entering the train : 19411
CPU Memory consumed at the end of the train (end-begin): 0
CPU Peak Memory consumed during the train (max-begin): 0
CPU Total Peak Memory consumed during the train (max): 19411
epoch=4: train_ppl=tensor(1.0705, device='cuda:0') train_epoch_loss=tensor(0.0681, device='cuda:0')
100%|████████████████████████████████████████████████████████████████████████████████████████████| 7/7 [00:27<00:00, 3.92s/it]
GPU Memory before entering the eval : 1982
GPU Memory consumed at the end of the eval (end-begin): -66
GPU Peak Memory consumed during the eval (max-begin): 672
GPU Total Peak Memory consumed during the eval (max): 2654
CPU Memory before entering the eval : 19411
CPU Memory consumed at the end of the eval (end-begin): 0
CPU Peak Memory consumed during the eval (max-begin): 0
CPU Total Peak Memory consumed during the eval (max): 19411
accuracy=100.0
eval_preds[:10]=['no complaint', 'no complaint', 'complaint', 'complaint', 'no complaint', 'no complaint', 'no complaint', 'complaint', 'complaint', 'no complaint']
dataset['train'][label_column][:10]=['no complaint', 'no complaint', 'complaint', 'complaint', 'no complaint', 'no complaint', 'no complaint', 'complaint', 'complaint', 'no complaint']Lưu ý
- Việc gộp (merging) khi sử dụng PEFT và DeepSpeed hiện chưa được hỗ trợ và sẽ gây ra lỗi.
- Khi sử dụng CPU offloading, lợi ích chính từ việc dùng PEFT để thu nhỏ optimizer states và gradients xuống bằng kích thước của adapter weights sẽ được thể hiện trên RAM của CPU và sẽ không có sự tiết kiệm nào đối với bộ nhớ GPU.
- Việc sử dụng DeepSpeed Stage 3 và qlora kết hợp với CPU offloading dẫn đến mức sử dụng bộ nhớ GPU cao hơn so với khi tắt CPU offloading.
Update on GitHub💡 Khi bạn có mã yêu cầu gộp (và tách) trọng số, hãy thử thu thập thủ công các tham số bằng DeepSpeed Zero-3 trước:
import deepspeed is_ds_zero_3 = ... # check if Zero-3 with deepspeed.zero.GatheredParameters(list(model.parameters()), enabled= is_ds_zero_3): model.merge_adapter() # do whatever is needed, then unmerge in the same context if unmerging is required ... model.unmerge_adapter()