TRL documentation
LoRA Không Cần Hối Hận
LoRA Không Cần Hối Hận
Nghiên cứu gần đây từ nhóm tại Thinking Machines Lab (Schulman et al., 2025) cho thấy LoRA có thể đạt hiệu suất tương đương fine-tuning đầy đủ khi được cấu hình đúng cách, trong khi chỉ sử dụng khoảng 67% tài nguyên tính toán. Những phát hiện này rất đáng khích lệ cho người dùng TRL vì chúng dễ triển khai và có thể cải thiện hiệu suất mô hình với ngân sách nhỏ hơn.
Hướng dẫn này cung cấp các bước đơn giản để tái tạo kết quả của bài đăng trên blog trong TRL.
Khuyến nghị đọc bài đăng trên blog trước khi làm theo hướng dẫn này, hoặc tham khảo cả hai nguồn tài liệu song song để đạt kết quả tốt nhất.
Lợi ích của LoRA so với tinh chỉnh đầy đủ
Trước hết, hãy cùng nhắc lại những lợi ích của LoRA so với fine-tuning toàn bộ.
LoRA thêm các lớp adapter lên trên mô hình cơ sở, trong đó chứa số lượng tham số ít hơn đáng kể so với chính mô hình cơ sở. Thiết kế này làm giảm yêu cầu về bộ nhớ GPU và cho phép huấn luyện hiệu quả hơn. Như đã mô tả trong blog, cách tiếp cận này ban đầu được cho là có sự đánh đổi về hiệu suất, mặc dù việc cấu hình cẩn thận có thể khắc phục sự đánh đổi này và đạt được hiệu suất tương đương với việc tinh chỉnh toàn bộ.
Ví dụ với TRL
Hãy triển khai và huấn luyện các adapter LoRA trong các script của TRL dựa trên những phát hiện cốt lõi của bài đăng trên blog. Sau đó, chúng ta sẽ xem xét lại từng phát hiện dưới ánh sáng của kết quả từ TRL.
Tinh chỉnh có giám sát (SFT)
Bài viết trên blog thực hiện SFT trên một loạt các mô hình và bộ dữ liệu từ Hub, và chúng ta có thể tái tạo lại trong TRL.
Chúng ta có thể tích hợp những phát hiện này với API Python của TRL như sau:
from datasets import load_dataset
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig
dataset = load_dataset("open-thoughts/OpenThoughts-114k", split="train")
peft_config = LoraConfig(r=256, lora_alpha=16, target_modules="all-linear")
training_args = SFTConfig(
learning_rate=2e-4,
per_device_train_batch_size=1,
gradient_accumulation_steps=4,
num_train_epochs=1,
report_to=["trackio"],
)
trainer = SFTTrainer(
model="Qwen/Qwen2.5-3B-Instruct",
train_dataset=dataset,
peft_config=peft_config,
args=training_args,
)
trainer.train()
hf jobs uv run \
--flavor a100-large \
--timeout 8h \
--secrets HF_TOKEN \
"https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py" \
--model_name_or_path Qwen/Qwen2.5-3B-Instruct \
--dataset_name open-thoughts/OpenThoughts-114k \
--learning_rate 2.0e-5 \
--num_train_epochs 1 \
--packing \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 16 \
--use_peft \
--lora_r 256 \
--lora_alpha 16 \
--lora_target_modules all-linear \
--output_dir Qwen2.5-3B-OpenThoughts-LoRA \
--report_to trackio \
--push_to_hub
Để sử dụng Hugging Face Jobs, hãy đăng nhập vào Hub (hf auth login) và có số dư tín dụng dương. Xem tài liệu về Jobs để biết thêm chi tiết.
uv run "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py" \
--model_name_or_path Qwen/Qwen2.5-3B-Instruct \
--dataset_name open-thoughts/OpenThoughts-114k \
--learning_rate 2.0e-5 \
--num_train_epochs 1 \
--packing \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 16 \
--eval_strategy no \
--use_peft \
--lora_r 256 \
--lora_alpha 16 \
--lora_target_modules all-linear \
--output_dir Qwen2.5-3B-OpenThoughts-LoRA \
--report_to trackio \
--push_to_hub
Để chạy script cục bộ, bạn cần cài đặt uv. Xem tài liệu uv để biết thêm chi tiết.
Khi quá trình huấn luyện bắt đầu, bạn có thể theo dõi tiến độ trên Trackio, nơi sẽ ghi lại URL.
Học tăng cường (GRPO)
Bài viết trên blog thực hiện GRPO trên một loạt các mô hình và bộ dữ liệu từ Hub, và một lần nữa chúng ta có thể tái tạo kết quả trong TRL.
| Mô hình | Bộ dữ liệu |
|---|---|
| Llama-3.1-8B-Base | GSM8k |
| Llama-3.1-8B-Base | DeepMath-103K |
| Qwen3-8b-base | DeepMath-103K |
Đối với học tăng cường, blog sử dụng một tác vụ suy luận toán học mà chúng ta có thể tái tạo dưới dạng một hàm Python.
Chúng ta có thể triển khai các khuyến nghị này bằng API Python của TRL như sau:
from datasets import load_dataset
from peft import LoraConfig
from trl import GRPOConfig, GRPOTrainer
from trl.rewards import reasoning_accuracy_reward
dataset = load_dataset("HuggingFaceH4/OpenR1-Math-220k-default-verified", split="train")
peft_config = LoraConfig(
r=1,
lora_alpha=32,
target_modules="all-linear"
)
training_args = GRPOConfig(
learning_rate=5e-5,
per_device_train_batch_size=1,
gradient_accumulation_steps=4,
num_train_epochs=1,
num_generations=8,
generation_batch_size=8,
report_to=["trackio"],
)
trainer = GRPOTrainer(
model="Qwen/Qwen3-0.6B",
reward_funcs=reasoning_accuracy_reward,
args=training_args,
train_dataset=dataset,
peft_config=peft_config,
)
trainer.train()
Đoạn mã này bỏ qua hàm phần thưởng đã được định nghĩa ở trên để giữ cho ví dụ ngắn gọn.
hf jobs uv run \
--flavor a100-large \
--timeout 4h \
--secrets HF_TOKEN \
--env PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
"https://huggingface.co/datasets/burtenshaw/lora-without-regrets/resolve/main/grpo.py" \
--model_name_or_path Qwen/Qwen3-0.6B \
--dataset_name HuggingFaceH4/OpenR1-Math-220k-default-verified \
--output_dir grpo-full-qwen3-0.6b \
--learning_rate 1.0e-6 \
--lr_scheduler_type cosine \
--warmup_steps 0.0 \
--max_grad_norm 1.0 \
--beta 0.0 \
--max_completion_length 4096 \
--num_generations 16 \
--generation_batch_size 16 \
--gradient_accumulation_steps 8 \
--per_device_train_batch_size 1 \
--num_train_epochs 1 \
--lora_r 1 \
--lora_alpha 32 \
--lora_dropout 0.0 \
--lora_target_modules all-linear \
--vllm_mode colocate \
--save_strategy steps \
--save_steps 50 \
--save_total_limit 1 \
--logging_steps 1 \
--max_steps 200 \
--report_to trackioĐể sử dụng Hugging Face Jobs, hãy đăng nhập vào Hub (hf auth login) và có số dư tín dụng dương. Xem tài liệu về Jobs để biết thêm chi tiết.
uv run "https://huggingface.co/datasets/burtenshaw/lora-without-regrets/resolve/main/grpo.py" \
--model_name_or_path Qwen/Qwen3-0.6B \
--dataset_name HuggingFaceH4/OpenR1-Math-220k-default-verified \
--output_dir grpo-full-qwen3-0.6b \
--learning_rate 1.0e-6 \
--lr_scheduler_type cosine \
--warmup_steps 0.0 \
--max_grad_norm 1.0 \
--beta 0.0 \
--max_completion_length 4096 \
--num_generations 16 \
--generation_batch_size 16 \
--gradient_accumulation_steps 8 \
--per_device_train_batch_size 1 \
--num_train_epochs 1 \
--lora_r 1 \
--lora_alpha 32 \
--lora_dropout 0.0 \
--lora_target_modules all-linear \
--vllm_mode colocate \
--save_strategy steps \
--save_steps 50 \
--save_total_limit 1 \
--logging_steps 1 \
--max_steps 200 \
--report_to trackioĐể chạy script cục bộ, bạn cần cài đặt uv. Xem tài liệu uv để biết thêm chi tiết.
Script học tăng cường với GRPO được triển khai dưới dạng script tùy chỉnh trong TRL, sử dụng hàm phần thưởng được nêu ở trên. Bạn có thể xem tại grpo.py - Thực hành tốt nhất cho học tăng cường với LoRA
Những phát hiện chính trong việc tối ưu hóa LoRA
Các tác giả khuyến nghị áp dụng LoRA cho tất cả các ma trận trọng số thay vì giới hạn ở các lớp attention, vì việc tăng rank không bù đắp được cho sự hạn chế này. Trong TRL, điều này có thể được cấu hình bằng cách sử dụng --lora_target_modules all-linear để áp dụng LoRA cho tất cả các ma trận trọng số.
Chúng tôi đã tái tạo được kết quả của bài đăng trên blog bằng cách sử dụng TRL và mô hình SmolLM3. Chúng tôi huấn luyện mô hình trong 500 bước trên dataset Math 220k với hàm thưởng và cấu hình như trên. Như bạn có thể thấy trong hình bên dưới, đường cong thưởng trung bình trong quá trình huấn luyện của mô hình LoRA khớp với đường cong của việc fine-tuning toàn bộ.

Và quan trọng nhất, mô hình LoRA sử dụng bộ nhớ ít hơn đáng kể so với mô hình tinh chỉnh đầy đủ, như chúng ta có thể thấy trong hình bên dưới.

Dưới đây là các tham số chúng tôi đã sử dụng để huấn luyện các mô hình ở trên
| Tham số | LoRA | FT đầy đủ |
|---|---|---|
--model_name_or_path | HuggingFaceTB/SmolLM3-3B | HuggingFaceTB/SmolLM3-3B |
--dataset_name | HuggingFaceH4/OpenR1-Math-220k-default-verified | HuggingFaceH4/OpenR1-Math-220k-default-verified |
--learning_rate | 1.0e-5 | 1.0e-6 |
--max_completion_length | 4096 | 4096 |
--lora_r | 1 | - |
--lora_alpha | 32 | - |
--lora_dropout | 0.0 | - |
--lora_target_modules | all-linear | - |
Hãy cùng phân tích các phát hiện chính của bài đăng trên blog và cách chúng tôi đã tái hiện chúng.
1. LoRA hoạt động tốt hơn khi được áp dụng cho tất cả các ma trận trọng số
Các tác giả khuyến nghị áp dụng LoRA cho tất cả các ma trận trọng số thay vì giới hạn ở các lớp attention, vì việc tăng rank không bù đắp được cho sự hạn chế này.

LoRA chỉ áp dụng cho Attention cho hiệu suất thấp hơn ngay cả khi sử dụng rank cao hơn để khớp số lượng tham số. Trong TRL, bạn có thể cấu hình điều này bằng cách sử dụng --lora_target_modules all-linear để áp dụng LoRA cho tất cả các ma trận trọng số. Trong Python, chúng ta có thể thực hiện như sau:
from peft import LoraConfig
peft_config = LoraConfig(target_modules="all-linear") 2. Adapter cần đủ sức chứa để học từ tập dữ liệu
Bài đăng trên blog khuyến nghị sử dụng rank LoRA đủ lớn để học từ bộ dữ liệu. Rank quyết định số lượng tham số có thể huấn luyện trong bộ thích ứng LoRA. Do đó, “Đối với các bộ dữ liệu vượt quá khả năng của LoRA, LoRA hoạt động kém hơn FullFT”.

Trong script TRL, chúng ta có thể sử dụng --lora_r để đặt rank và điều chỉnh nó dựa trên tác vụ và tập dữ liệu mà chúng ta đang huấn luyện. Bài viết trên blog khuyến nghị các rank sau dựa trên tác vụ và kích thước tập dữ liệu:
Các tác vụ học tăng cường thường yêu cầu dung lượng thấp hơn, do đó có thể sử dụng các bậc LoRA nhỏ hơn. Điều này là do các thuật toán gradient chính sách chỉ trích xuất khoảng ~1 bit thông tin mỗi tập, đòi hỏi dung lượng tham số tối thiểu.
Bài viết trên blog định nghĩa kích thước bộ dữ liệu lý tưởng cho LoRA để đạt hiệu quả tương đương với fine-tuning toàn bộ là “Post-training scale”. Chúng ta có thể sử dụng điều này để xác định rank được khuyến nghị cho LoRA trong SFT và RL như sau:
| Loại tác vụ | Kích thước bộ dữ liệu | Rank được khuyến nghị |
|---|---|---|
| SFT | Quy mô huấn luyện sau | 256 |
| RL | Bất kỳ kích thước nào | 1-32 |
3. “FullFT và LoRA bậc cao có đường cong học tập tương tự”
Trái với trực giác, bài viết trên blog khuyên nên sử dụng tốc độ học cao hơn so với fine-tuning toàn bộ. Trong bảng ở trên, chúng tôi đã sử dụng 1.0e-5 cho LoRA và 1.0e-6 cho fine-tuning toàn bộ. Trong script của TRL, chúng ta có thể sử dụng --learning_rate để đặt tốc độ học. Việc scaling trong LoRA làm cho tốc độ học tối ưu gần như độc lập với rank.

4. “Trong một số kịch bản, LoRA kém chịu đựng hơn so với fine-tuning toàn bộ khi kích thước batch lớn.”
Bài viết trên blog khuyến nghị sử dụng kích thước batch hiệu dụng < 32 vì các tác giả nhận thấy LoRA kém chịu đựng hơn với các kích thước batch lớn. Điều này không thể được khắc phục bằng cách tăng rank của LoRA. Trong script TRL, chúng ta có thể sử dụng --per_device_train_batch_size và --gradient_accumulation_steps để thiết lập kích thước batch.

Điểm chính
Sử dụng TRL, bạn có thể triển khai hiệu quả các adapter LoRA để đạt hiệu suất tương đương với fine-tuning toàn bộ, áp dụng các nguyên tắc cốt lõi (đích đến tất cả các ma trận trọng số, chọn rank phù hợp, và quản lý kích thước batch cùng tốc độ học) mà không cần chi phí tính toán nặng nề của FullFT.
Trích dẫn
@article{schulman2025lora,
title = {{LoRA Without Regret}},
author = {John Schulman and Thinking Machines Lab},
year = 2025,
journal = {Thinking Machines Lab: Connectionism},
doi = {10.64434/tml.20250929},
note = {https://thinkingmachines.ai/blog/lora/}
}