PEFT documentation
Kuantisasi
Kuantisasi
Quantisasi merepresentasikan data dengan jumlah bit yang lebih sedikit, menjadikannya teknik yang berguna untuk mengurangi penggunaan memori dan mempercepat inferensi, terutama ketika berkaitan dengan model bahasa besar (LLM). Ada beberapa cara untuk mengkuantisasi model, termasuk:
- mengoptimalkan bobot model mana yang dikuantisasi dengan algoritma AWQ
- mengkuantisasi setiap baris dari matriks bobot secara independen dengan algoritma GPTQ
- kuantisasi ke presisi 8-bit dan 4-bit dengan pustaka bitsandbytes
- mengkuantisasi hingga presisi 2-bit dengan algoritma AQLM
Namun, setelah model dikuantisasi, model tersebut biasanya tidak dilatih lebih lanjut untuk tugas turunan karena pelatihan dapat menjadi tidak stabil akibat presisi yang lebih rendah pada bobot dan aktivasi. Tetapi karena metode PEFT hanya menambahkan parameter yang dapat dilatih ekstra, hal ini memungkinkan Anda untuk melatih model terkuantisasi dengan adapter PEFT di atasnya! Menggabungkan kuantisasi dengan PEFT dapat menjadi strategi yang baik untuk melatih bahkan model terbesar pada satu GPU. Sebagai contoh, QLoRA adalah metode yang mengkuantisasi model menjadi 4-bit dan kemudian melatihnya dengan LoRA. Metode ini memungkinkan Anda untuk melakukan penyesuaian halus (finetune) model dengan 65B parameter pada satu GPU 48GB!
Pada panduan ini, Anda akan melihat cara mengkuantisasi model ke 4-bit dan melatihnya dengan LoRA.
Kuantisasi model
bitsandbytes adalah pustaka kuantisasi dengan integrasi Transformers. Dengan integrasi ini, Anda dapat mengkuantisasi model menjadi 8 atau 4-bit dan mengaktifkan banyak opsi lain dengan mengonfigurasi kelas BitsAndBytesConfig. Misalnya, Anda dapat:
- set
load_in_4bit=Trueuntuk mengkuantisasi model menjadi 4-bit saat memuatnya - set
bnb_4bit_quant_type="nf4"untuk menggunakan tipe data 4-bit khusus untuk bobot yang diinisialisasi dari distribusi normal - set
bnb_4bit_use_double_quant=Trueuntuk menggunakan skema kuantisasi bersarang guna mengkuantisasi bobot yang sudah terkuantisasi - set
bnb_4bit_compute_dtype=torch.bfloat16untuk menggunakan bfloat16 agar komputasi lebih cepat
import torch
from transformers import BitsAndBytesConfig
config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16,
)Lewatkan config ke metode from_pretrained.
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)Selanjutnya, Anda harus memanggil fungsi prepare_model_for_kbit_training() untuk memproses model terkuantisasi sebelum pelatihan.
from peft import prepare_model_for_kbit_training
model = prepare_model_for_kbit_training(model)Sekarang model terkuantisasi sudah siap, mari kita atur konfigurasinya.
LoraConfig
Buat LoraConfig dengan parameter berikut (atau pilih parameter Anda sendiri):
from peft import LoraConfig
config = LoraConfig(
r=16,
lora_alpha=8,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)Lalu gunakan fungsi get_peft_model() untuk membuat PeftModel dari model terkuantisasi dan konfigurasinya.
from peft import get_peft_model
model = get_peft_model(model, config)Anda sudah siap untuk pelatihan dengan metode pelatihan apa pun yang Anda pilih!
Inisialisasi LoftQ
LoftQ menginisialisasi bobot LoRA sehingga error kuantisasi diminimalkan, dan dapat meningkatkan kinerja saat melatih model terkuantisasi. Untuk memulai, ikuti instruksi ini.
LoftQ hanya diterapkan pada lapisan linear, termasuk yang ditargetkan melalui target_parameters. Lapisan embedding dan konvolusional tidak didukung dan menggunakan inisialisasi LoRA default sebagai gantinya. Lapisan nn.MultiheadAttention tidak didukung dan akan memicu error.
Secara umum, agar LoftQ bekerja dengan optimal, disarankan untuk menargetkan sebanyak mungkin lapisan dengan LoRA, karena lapisan yang tidak ditargetkan tidak dapat menerapkan LoftQ. Artinya, meneruskan LoraConfig(..., target_modules="all-linear") kemungkinan besar akan memberikan hasil terbaik. Selain itu, Anda harus menggunakan nf4 sebagai tipe kuantisasi dalam konfigurasi kuantisasi Anda saat menggunakan kuantisasi 4bit, yaitu BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4").
Secara umum, agar LoftQ bekerja dengan optimal, disarankan untuk menargetkan sebanyak mungkin lapisan dengan LoRA, karena lapisan yang tidak ditargetkan tidak dapat menerapkan LoftQ. Artinya, meneruskan LoraConfig(..., target_modules="all-linear") kemungkinan besar akan memberikan hasil terbaik. Selain itu, Anda harus menggunakan nf4 sebagai tipe kuantisasi dalam konfigurasi kuantisasi Anda saat menggunakan kuantisasi 4bit, yaitu BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4").
Saat ini ada dua cara yang dimaksud untuk menerapkan LoftQ:
- muat model dasar non-kuantisasi, terapkan LoftQ dengan level kuantisasi yang Anda inginkan (misalnya,
bits=4untuk nf4) dan simpan adapter yang dihasilkan. Kemudian kuantisasi model dasar menggunakan, misalnya,BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")dan muat adapter yang diinisialisasi dengan LoftQ di atasnya - memuat model dasar terkuantisasi, menginisialisasi model PEFT dengan LoRA (tanpa loftq), dan menggunakan
replace_lora_weights_loftquntuk menerapkan inisialisasi LoftQ dengan streaming bobot referensi dari model dasar non-kuantisasi dari file bobot (dijelaskan lebih lanjut di bagian berikutnya)
Menggunakan replace_lora_weights_loftq untuk penerapan LoftQ secara langsung
Cara yang lebih mudah namun lebih terbatas untuk menerapkan inisialisasi LoftQ adalah dengan menggunakan fungsi kemudahan replace_lora_weights_loftq. Fungsi ini menerima model PEFT terkuantisasi sebagai input dan mengganti bobot LoRA secara in-place dengan padanannya yang telah diinisialisasi LoftQ.
from peft import replace_lora_weights_loftq
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="loftq" or loftq_config!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_loftq(peft_model)replace_lora_weights_loftq juga memungkinkan Anda untuk meneruskan argumen callback untuk memberikan kendali lebih besar atas lapisan mana yang harus dimodifikasi atau tidak, yang secara empiris dapat meningkatkan hasil cukup banyak. Untuk melihat contoh yang lebih rinci tentang hal ini, lihat notebook ini.
replace_lora_weights_loftq hanya mengimplementasikan satu langkah iterasi dari LoftQ. Artinya, hanya bobot LoRA yang diperbarui, bukan memperbarui bobot LoRA dan bobot model dasar yang dikuantisasi secara iteratif. Hal ini dapat menyebabkan penurunan performa, tetapi memiliki keunggulan bahwa kita dapat menggunakan bobot kuantisasi asli yang diturunkan dari model dasar, alih-alih harus menyimpan salinan tambahan dari bobot kuantisasi yang dimodifikasi. Apakah tradeoff ini sepadan bergantung pada kasus penggunaannya.
Saat ini, replace_lora_weights_loftq memiliki batasan tambahan berikut:
- File model harus disimpan sebagai file
safetensors. - Hanya kuantisasi 4 bit bitsandbytes yang didukung.
Inisialisasi PiSSA
PiSSA tidak dapat diterapkan pada bobot terkuantisasi. Biasanya, metode ini diterapkan pada model dasar yang tidak terkuantisasi, kemudian residual yang dihasilkan disimpan dan dimuat dengan kuantisasi, yang mengharuskan seluruh model non-kuantisasi muat ke dalam memori.
Sebagai alternatif, replace_lora_weights_pissa menerima model PEFT terkuantisasi dan mengalirkan bobot model non-kuantisasi dari file bobot, satu lapisan pada satu waktu. Bobot LoRA setiap lapisan diinisialisasi dengan PiSSA dan bobot dasarnya diganti dengan residual yang dikuantisasi ulang.
from peft import replace_lora_weights_pissa
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="pissa" here!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_pissa(peft_model, init_lora_weights="pissa_niter_4")Kedua "pissa" dan "pissa_niter_[number of iters]" didukung.
Karena bobot dasar dimodifikasi, menyimpan hanya adapter tidak cukup untuk memulihkan model. Seperti inisialisasi PiSSA lainnya, simpan juga model dasar atau konversi adapter yang telah dilatih menggunakan argumen path_initial_model_for_weight_conversion dari save_pretrained().
Saat ini, replace_lora_weights_pissa memiliki batasan tambahan berikut:
- File model harus disimpan sebagai file
safetensors. - Hanya kuantisasi 4 bit bitsandbytes yang didukung.
- Variasi LoRA seperti DoRA tidak didukung.
Pelatihan bergaya QLoRA
QLoRA menambahkan bobot yang dapat dilatih ke semua lapisan linear dalam arsitektur transformer. Karena nama atribut untuk lapisan linear ini dapat bervariasi di antara arsitektur, atur target_modules ke "all-linear" untuk menambahkan LoRA ke semua lapisan linear:
config = LoraConfig(target_modules="all-linear", ...)Kuantisasi GPTQ
Anda dapat mempelajari lebih lanjut tentang kuantisasi [2, 3, 4, 8] bit berbasis GPTQ di GPT-QModel dan dalam dokumentasi GPTQ Transformers. PEFT mendukung pelatihan pasca-GPTQ melalui GPT-QModel.
# GPT-QModel install
pip install "gptqmodel>=7.0.0"from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig
model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)
gptq_config = GPTQConfig(bits=4, group_size=128, dataset="wikitext2", tokenizer=tokenizer)
quantized_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)
# save quantized model
quantized_model.save_pretrained("./opt-125m-gptq")
tokenizer.save_pretrained("./opt-125m-gptq")Setelah dikuantisasi, Anda dapat melatih ulang model GPTQ dengan API PEFT.
Kuantisasi AQLM
Additive Quantization of Language Models (AQLM) adalah metode kompresi Large Language Models. Metode ini mengkuantisasi beberapa bobot secara bersama-sama dan memanfaatkan ketergantungan antar bobot tersebut. AQLM merepresentasikan kelompok 8-16 bobot sebagai jumlah dari beberapa kode vektor. Hal ini memungkinkan kompresi model hingga sedemikian rendah yaitu 2-bit dengan kerugian akurasi yang relatif rendah.
Karena proses kuantisasi AQLM sangat mahal secara komputasi, penggunaan model pre-kuantisasi sangat disarankan. Daftar parsial model yang tersedia dapat ditemukan di repository resmi aqlm.
Model-model ini mendukung penyetelan adapter LoRA. Untuk menyetel model yang dikuantisasi, Anda perlu menginstal pustaka inferensi aqlm: pip install aqlm>=1.0.2. Adapter LoRA yang telah disetel ulang harus disimpan secara terpisah, karena penggabungan dengan bobot terkuantisasi AQLM tidak memungkinkan.
quantized_model = AutoModelForCausalLM.from_pretrained(
"BlackSamorez/Mixtral-8x7b-AQLM-2Bit-1x16-hf-test-dispatch",
dtype="auto", device_map="auto", low_cpu_mem_usage=True,
)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)Anda dapat merujuk pada contoh Google Colab untuk gambaran umum finetuning AQLM+LoRA.
Kuantisasi EETQ
Anda juga dapat melakukan fine-tuning LoRA pada model yang dikuantisasi EETQ. Paket EETQ menawarkan cara yang sederhana dan efisien untuk melakukan kuantisasi 8-bit, yang diklaim lebih cepat daripada algoritma LLM.int8(). Pertama, pastikan Anda memiliki versi transformers yang kompatibel dengan EETQ (misalnya dengan menginstalnya dari pypi terbaru atau dari source).
import torch
from transformers import EetqConfig
config = EetqConfig("int8")Lewatkan config ke metode from_pretrained.
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)dan buat LoraConfig lalu teruskan ke get_peft_model:
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=16,
lora_alpha=8,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, config)Kuantisasi HQQ
Model yang dikuantisasi menggunakan Half-Quadratic Quantization of Large Machine Learning Models (HQQ) mendukung penyetelan adapter LoRA. Untuk menyetel model yang dikuantisasi, Anda perlu menginstal pustaka hqq dengan: pip install hqq.
from hqq.engine.hf import HQQModelForCausalLM
device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
quantized_model = HQQModelForCausalLM.from_quantized(save_dir_or_hfhub, device=device)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)Atau gunakan versi transformers yang kompatibel dengan HQQ (misalnya dengan menginstalnya dari pypi terbaru atau dari source).
from transformers import HqqConfig, AutoModelForCausalLM
quant_config = HqqConfig(nbits=4, group_size=64)
quantized_model = AutoModelForCausalLM.from_pretrained(save_dir_or_hfhub, device_map=device_map, quantization_config=quant_config)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)torchao (Optimasi Arsitektur PyTorch)
PEFT mendukung model yang dikuantisasi dengan torchao (“ao”) untuk kuantisasi int8.
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, TorchAoConfig
from torchao.quantization import Int8WeightOnlyConfig
model_id = ...
quantization_config = TorchAoConfig(quant_type=Int8WeightOnlyConfig())
base_model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)
peft_config = LoraConfig(...)
model = get_peft_model(base_model, peft_config)Catatan:
- Gunakan versi terbaru dari torchao (>= v0.4.0) dan transformers (> 4.42).
- Saat ini, hanya lapisan linear yang didukung.
quant_type = "int4_weight_only"saat ini tidak didukung.NF4belum diimplementasikan di transformers dan karenanya juga belum didukung.- Saat ini, DoRA hanya berfungsi dengan
quant_type = "int8_weight_only". - Terdapat dukungan eksplisit untuk torchao saat digunakan dengan LoRA. Namun, ketika torchao mengkuantisasi sebuah layer, kelasnya tidak berubah, hanya tipe tensor di baliknya yang berubah. Karena alasan ini, metode PEFT selain LoRA umumnya juga akan berfungsi dengan torchao, meskipun tidak didukung secara eksplisit. Perhatikan, bagaimanapun, bahwa merging hanya berfungsi dengan benar dengan LoRA dan dengan
quant_type = "int8_weight_only". Jika Anda menggunakan metode PEFT atau dtype yang berbeda, merging kemungkinan akan menghasilkan error, dan bahkan jika tidak, hasilnya tetap akan salah.
Kuantisasi INC
Intel Neural Compressor (INC) memungkinkan kuantisasi model untuk berbagai perangkat,
termasuk akselerator Intel Gaudi (juga dikenal sebagai perangkat HPU). Anda dapat melakukan fine-tuning LoRA pada model yang telah
dikuantisasi menggunakan INC. Untuk menggunakan INC dengan model PyTorch, instal pustakanya dengan: pip install neural-compressor[pt].
Kuantisasi model ke presisi FP8 untuk perangkat HPU dapat dilakukan dengan alur kerja kuantisasi satu langkah berikut:
import torch
from neural_compressor.torch.quantization import FP8Config, convert, finalize_calibration, prepare
quant_configs = {
...
}
config = FP8Config(**quant_configs)Lewatkan config ke metode prepare, jalankan inferensi untuk mengumpulkan statistik kalibrasi, dan panggil metode finalize_calibration dan convert untuk mengkuantisasi model ke presisi FP8:
model = prepare(model, config)
# Run inference to collect calibration statistics
...
# Finalize calibration and convert the model to FP8 precision
finalize_calibration(model)
model = convert(model)
# Load PEFT LoRA adapter as usual
...Contoh yang menunjukkan cara memuat adapter PEFT LoRA ke dalam model teks-ke-gambar FLUX yang dikuantisasi INC untuk perangkat HPU disediakan di sini.
Catatan:
- Metode
merge()danunmerge()saat ini tidak didukung untuk model yang dikuantisasi INC. - Saat ini, hanya lapisan INC-quantized Linear yang didukung saat memuat adapter PEFT.
Metode PEFT Lain yang Didukung
Selain LoRA, metode PEFT berikut juga mendukung kuantisasi:
- VeRA (mendukung kuantisasi bitsandbytes)
- AdaLoRA (mendukung kuantisasi bitsandbytes dan GPTQ)
- (IA)³ (mendukung kuantisasi bitsandbytes)
Transformer Engine (TE) LoRA
PEFT mendukung adapter LoRA di atas lapisan NVIDIA Transformer Engine (te.pytorch.Linear, te.pytorch.LayerNormLinear, dan te.pytorch.LayerNormMLP). Lapisan TE menggunakan FP8 dan kernel terpadu untuk mempercepat pelatihan transformer, dan pemasangan adapter LoRA memungkinkan Anda melakukan fine-tuning model yang dipercepat TE secara efisien parameter.
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_proj", "v_proj"],
task_type="TOKEN_CLS",
)
model = get_peft_model(te_model, config)Ketika Transformer Engine terpasang, PEFT secara otomatis mengalokasikan lapisan yang cocok ke adapter TeLinear — tidak diperlukan konfigurasi tambahan.
Catatan
merge()danunmerge()belum didukung untuk lapisan TE.- DoRA tidak didukung dengan lapisan TE.
Contoh klasifikasi token ESM2 lengkap tersedia di examples/lora_finetuning_transformer_engine/.
Menggabungkan adapter ke dalam bobot terkuantisasi
Untuk metode kuantisasi apa pun yang mendukungnya, merge_adapter() melakukan dekuantisasi pada bobot dasar, menambahkan bobot adapter, dan mengkuantisasi hasilnya kembali. unmerge_adapter() melakukan hal yang sama secara terbalik, sehingga tidak memulihkan bobot terkuantisasi asli, dan siklus merge dan unmerge yang berulang dapat mengakumulasi error pembulatan. Untuk mendapatkan kembali bobot asli, muat ulang model dasar. Untuk beralih antara model dasar dan adapter tanpa melakukan merge, gunakan context manager disable_adapter().
Langkah selanjutnya
Jika Anda tertarik untuk mempelajari lebih lanjut tentang kuantisasi, berikut ini mungkin dapat membantu:
- Pelajari lebih lanjut tentang QLoRA dan lihat beberapa benchmark mengenai dampaknya di blog post Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA.
- Baca lebih lanjut tentang skema kuantisasi yang berbeda dalam panduan Kuantisasi Transformers.