Transformers documentation
Ekspor kuantisasi
Ekspor kuantisasi
Setiap konfigurasi export dapat menerima quantizer, yang melakukan kuantisasi model selama proses export. Quantizer tersebut berada di transformers.exporters.quantizers, dan masing-masing dijalankan pada titik tetap dari export: pada grafik FX torch.export, sebelum konversi apa pun, atau pada model yang dikonversi oleh backend.
| Quantizer | Mengkuantisasi | Dynamo | ONNX | ExecuTorch | OpenVINO |
|---|---|---|---|---|---|
| PT2EQuantizer | graf FX, dengan kuantisasi PyTorch 2 Export (PT2E) | 🟢 | 🟢 | 🟢 | 🟢 |
| NNCFTorchFXQuantizer | graf FX, dengan NNCF | 🟢 | 🟢 | 🟢 (hanya-berat) | 🟢 |
| OnnxRuntimeQuantizer | model ONNX, dengan onnxruntime.quantization | 🔴 | 🟢 | 🔴 | 🔴 |
| NNCFOnnxQuantizer | model ONNX, dengan NNCF | 🔴 | 🟢 | 🔴 | 🔴 |
| NNCFOpenVINOQuantizer | model OpenVINO, dengan NNCF | 🔴 | 🔴 | 🔴 | 🟢 |
Ekspor memeriksa kuantizer terhadap backend dan paket yang terpasang sebelum pelacakan, sehingga ketidakcocokan akan gagal lebih awal. Sama seperti exporter, setiap kuantizer mencantumkan versi paket yang diujinya, dan memberikan peringatan jika versi Anda berbeda.
Contoh di bawah ini mengkuantisasi klasifikator sentimen ke int8 dengan ONNX Runtime, lalu menjalankannya.
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from transformers.exporters import OnnxConfig, OnnxExporter, OnnxRuntimeQuantizer
model_id = "distilbert/distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForSequenceClassification.from_pretrained(model_id)
texts = [
"A wonderful, heartfelt film.",
"The plot was dull and the acting worse.",
"I would watch it again tomorrow.",
"Two hours I will never get back.",
]
calibration_dataset = [tokenizer(text, return_tensors="pt") for text in texts]
inputs = tokenizer("An absolute delight from start to finish.", return_tensors="pt")
config = OnnxConfig(dynamic=True, quantizer=OnnxRuntimeQuantizer(calibration_dataset=calibration_dataset))
onnx_program = OnnxExporter().export(model, inputs, config)
logits = onnx_program(**inputs)[0]
print(model.config.id2label[int(logits.argmax())]) # POSITIVEPT2E
PT2EQuantizer membungkus kuantizer PT2E, baik dari torchao maupun dari runtime target, dan menjalankannya pada grafik FX (prepare_pt2e → kalibrasi → convert_pt2e), sehingga berfungsi dengan setiap backend. Setiap kuantizer PT2E menyuntikkan operasi quantize/dequantize-nya sendiri, jadi pilihlah yang didukung oleh runtime Anda:
| Di mana Anda akan menjalankan | Kuantizer PT2E | Impor dari |
|---|---|---|
| PyTorch inductor, ONNX Runtime (QDQ), OpenVINO | X86InductorQuantizer | torchao.quantization.pt2e.quantizer.x86_inductor_quantizer |
| Backend XNNPACK ExecuTorch | XNNPACKQuantizer | executorch.backends.xnnpack.quantizer.xnnpack_quantizer |
Untuk ExecuTorch, bungkus XNNPACKQuantizer milik ExecuTorch itu sendiri:
from executorch.backends.xnnpack.quantizer.xnnpack_quantizer import (
XNNPACKQuantizer,
get_symmetric_quantization_config,
)
from transformers.exporters import ExecutorchConfig, PT2EQuantizer
xnnpack = XNNPACKQuantizer().set_global(get_symmetric_quantization_config())
config = ExecutorchConfig(backend="xnnpack", quantizer=PT2EQuantizer(xnnpack, calibration_dataset=calibration_dataset))Kuantisasi model generatif melalui ~HfExporter.export_for_generation. Di sini, calibration_dataset berisi kwargs generate, seperti inputs, dan setiap komponen melakukan kalibrasi pada input yang ditangkap untuknya. Model teks saja memiliki komponen prefill dan decode; model multimodal memecah prefill-nya lebih lanjut, menjadi encoder modalitasnya (seperti image_encoder), projectornya, language_model-nya, dan lm_head-nya (lihat Cara kerja export_for_generation).
from torchao.quantization.pt2e.quantizer.x86_inductor_quantizer import (
X86InductorQuantizer,
get_default_x86_inductor_quantization_config,
)
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.exporters import DynamoConfig, DynamoExporter, PT2EQuantizer
model_id = "meta-llama/Llama-3.2-1B"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
prompts = ["The capital of France is", "Photosynthesis turns sunlight into", "The first moon landing was in"]
calibration_dataset = [tokenizer(prompt, return_tensors="pt") for prompt in prompts]
inputs = tokenizer("Once upon a time", return_tensors="pt")
x86 = X86InductorQuantizer().set_global(get_default_x86_inductor_quantization_config())
config = DynamoConfig(dynamic=True, quantizer=PT2EQuantizer(x86, calibration_dataset=calibration_dataset))
components = DynamoExporter().export_for_generation(model, inputs, config) # {"prefill": ..., "decode": ...}Pada OpenVINO, bobot PT2E tetap dalam presisi penuh di belakang pasangan quantize/dequantize, yang kemudian dikonversi oleh OpenVINO menjadi FakeQuantize dan dikompres menjadi int8 oleh OpenVINO itu sendiri.
ONNX Runtime
OnnxRuntimeQuantizer menjalankan quantize_static secara default (aktivasi dan bobot int8 QDQ,
dikalibrasi pada calibration_dataset), seperti pada contoh di atas, dengan argumen dari OnnxRuntimeStaticConfig. Dengan OnnxRuntimeDynamicConfig, ia menjalankan quantize_dynamic (bobot int8, aktivasi dikuantisasi saat runtime, tanpa kalibrasi).
from transformers.exporters import OnnxRuntimeDynamicConfig, OnnxRuntimeStaticConfig
config = OnnxConfig(
quantizer=OnnxRuntimeQuantizer(OnnxRuntimeStaticConfig(per_channel=True), calibration_dataset=calibration_dataset)
)
config = OnnxConfig(quantizer=OnnxRuntimeQuantizer(OnnxRuntimeDynamicConfig()))NNCF
Tiga kuantizer NNCF dalam tabel di atas menjalankan nncf.quantize secara default (aktivasi dan bobot int8, dikalibrasi pada calibration_dataset, dengan model_type=nncf.ModelType.TRANSFORMER kecuali Anda meneruskan nilai lain), dengan argumen dari NNCFQuantizationConfig. Dengan NNCFWeightCompressionConfig, mereka menjalankan nncf.compress_weights (hanya bobot int8 atau int4, dengan AWQ dan estimasi skala untuk int4, serta koreksi GPTQ dan LoRA pada OpenVINO). ExecuTorch hanya menurunkan hasil hanya-bobot dari NNCFTorchFXQuantizer.
import nncf
from transformers.exporters import (
DynamoConfig,
NNCFOnnxQuantizer,
NNCFOpenVINOQuantizer,
NNCFTorchFXQuantizer,
NNCFWeightCompressionConfig,
OnnxConfig,
OpenVINOConfig,
OpenVINOExporter,
)
int4 = NNCFWeightCompressionConfig(mode=nncf.CompressWeightsMode.INT4_SYM, group_size=128)
# OpenVINO: int8 activations and weights, or weight-only int4
openvino_int8 = OpenVINOConfig(quantizer=NNCFOpenVINOQuantizer(calibration_dataset=calibration_dataset))
openvino_int4 = OpenVINOConfig(quantizer=NNCFOpenVINOQuantizer(int4))
# ONNX: weight-only int4, as ONNX Runtime's `MatMulNBits`
onnx_int4 = OnnxConfig(quantizer=NNCFOnnxQuantizer(int4))
# Dynamo: int8 on the FX graph
dynamo_int8 = DynamoConfig(quantizer=NNCFTorchFXQuantizer(calibration_dataset=calibration_dataset))
ov_model = OpenVINOExporter().export(model, inputs, openvino_int4)Aktivasi Int8 menjalankan matmul int8, yang mengalami saturasi pada CPU tanpa VNNI (Intel hanya AVX2 dan AMD Zen 2 atau lebih lama), sehingga akurasi yang lebih rendah diharapkan di sana. Kompresi hanya bobot mempertahankan matmul dalam titik apung.
Kalibrasi
A quantizer’s calibration_dataset is an iterable of model inputs, such as a list of tokenizer outputs or a DataLoader whose batches collate to model inputs. It is a plain attribute, so you can also set it after creating
the quantizer (quantizer.calibration_dataset = samples). Omit it and a quantizer that needs data calibrates on the
export’s own sample inputs, with a warning, because one sample can skew the observed ranges. Quantizers that need no
data (dynamic ONNX Runtime quantization, int8 weight compression) never read it.
Resep yang berbeda untuk setiap komponen
Lewatkan dict {component: config} ke ~HfExporter.export_for_generation untuk mengkuantisasi setiap komponen secara terpisah. Untuk model di atas, gunakan static int8 pada prefill dan dynamic int8 yang lebih ringan pada decode:
dynamic_x86 = X86InductorQuantizer().set_global(get_default_x86_inductor_quantization_config(is_dynamic=True))
config = {
"prefill": DynamoConfig(dynamic=True, quantizer=PT2EQuantizer(x86)),
"decode": DynamoConfig(dynamic=True, quantizer=PT2EQuantizer(dynamic_x86)),
}
components = DynamoExporter().export_for_generation(model, inputs, config)Dict tersebut harus menamai setiap komponen yang dihasilkan oleh decompose_for_generation() (model multimodal menambahkan encoder-nya, dan dapat memisahkan language_model serta lm_head). Komponen yang konfigurasinya tidak mengatur quantizer tetap berada dalam presisi penuh. Dalam dict ini, calibration_dataset dari quantizer berisi kwargs forward komponen, bukan kwargs generate.
Tambahkan kuantizer
Quantizer berada di transformers.exporters.quantizers, satu kelas per toolchain dan representasi. Subclass ExportQuantizer dan deklarasikan:
quantizes_fx_graph:Trueuntuk grafik FXtorch.export, sebelum konversi apa pun (sehingga setiap backend mengambil hasilnya), atauFalse(default) untuk model yang dikonversi oleh backend (onnx_ir.Model,openvino.Model).supported_formats: format ekspor yang dikuantisasi. Ekspor menolak format lain sebelum pelacakan.required_packages, dan secara opsionalmin_versionsdantested_versions: apa yang diimpor. Ekspor memeriksa apakah paket tersebut terinstal sebelum pelacakan, memicu error jika versi di bawah minimum, dan memberikan peringatan jika versi berbeda dari versi yang diuji.
Lalu implementasikan quantize(model, sample_inputs, export_format). model adalah grafik FX atau model backend, dan sample_inputs adalah input dari export itu sendiri. Lakukan kalibrasi pada CalibrationSet: komponen ini membaca calibration_dataset dari quantizer (atau sample_inputs jika tidak ada) dan memetakan setiap sampel ke input model dengan umpan dari transformers.exporters.quantizers.utils (traced_inputs untuk grafik FX, onnx_feed untuk ONNX, openvino_feed untuk OpenVINO).
from transformers.exporters import ExportFormat
from transformers.exporters.quantizers import CalibrationSet, ExportQuantizer
from transformers.exporters.quantizers.utils import onnx_feed
class MyOnnxQuantizer(ExportQuantizer):
supported_formats = (ExportFormat.ONNX,)
required_packages = ("my_toolkit",)
tested_versions = {"my_toolkit": "1.0.0"}
def quantize(self, model, sample_inputs, export_format):
import my_toolkit
names = [graph_input.name for graph_input in model.graph.inputs]
calibration = CalibrationSet(self.calibration_dataset, sample_inputs, lambda sample: onnx_feed(names, sample))
return my_toolkit.quantize(model, calibration_feeds=list(calibration))