Transformers documentation
Xuất lượng tử hóa
Xuất lượng tử hóa
Mọi cấu hình export đều có thể nhận một quantizer, thực hiện lượng tử hóa mô hình trong quá trình export. Các quantizer nằm trong transformers.exporters.quantizers, và mỗi quantizer chạy tại một điểm cố định của quy trình export: trên đồ thị FX của torch.export, trước bất kỳ bước chuyển đổi nào, hoặc trên mô hình mà backend chuyển đổi nó thành.
| Bộ lượng tử hóa | Lượng tử hóa | Dynamo | ONNX | ExecuTorch | OpenVINO |
|---|---|---|---|---|---|
| PT2EQuantizer | đồ thị FX, với lượng tử hóa PyTorch 2 Export (PT2E) | 🟢 | 🟢 | 🟢 | 🟢 |
| NNCFTorchFXQuantizer | đồ thị FX, với NNCF | 🟢 | 🟢 | 🟢 (chỉ trọng số) | 🟢 |
| OnnxRuntimeQuantizer | mô hình ONNX, với onnxruntime.quantization | 🔴 | 🟢 | 🔴 | 🔴 |
| NNCFOnnxQuantizer | mô hình ONNX, với NNCF | 🔴 | 🟢 | 🔴 | 🔴 |
| NNCFOpenVINOQuantizer | mô hình OpenVINO, với NNCF | 🔴 | 🔴 | 🔴 | 🟢 |
Quá trình xuất kiểm tra bộ lượng tử hóa so với backend và các gói đã cài đặt trước khi thực hiện tracing, do đó sự không tương thích sẽ bị phát hiện sớm. Giống như các trình xuất, mỗi bộ lượng tử hóa liệt kê các phiên bản gói đã được kiểm thử và sẽ cảnh báo nếu phiên bản của bạn khác đi.
Ví dụ dưới đây lượng tử hóa một bộ phân loại cảm xúc sang int8 bằng ONNX Runtime, sau đó chạy nó.
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 bao bọc một bộ lượng tử hóa PT2E, từ torchao hoặc từ runtime đích, và chạy nó trên đồ thị FX (prepare_pt2e → hiệu chuẩn → convert_pt2e), do đó nó hoạt động với mọi backend. Mỗi bộ lượng tử hóa PT2E chèn các op lượng tử hóa/giải lượng tử hóa của riêng nó, vì vậy hãy chọn bộ lượng tử hóa mà runtime của bạn hỗ trợ:
| Nơi bạn sẽ chạy | Bộ lượng tử hóa PT2E | Nhập từ |
|---|---|---|
| PyTorch inductor, ONNX Runtime (QDQ), OpenVINO | X86InductorQuantizer | torchao.quantization.pt2e.quantizer.x86_inductor_quantizer |
| Backend XNNPACK của ExecuTorch | XNNPACKQuantizer | executorch.backends.xnnpack.quantizer.xnnpack_quantizer |
Đối với ExecuTorch, hãy bọc XNNPACKQuantizer của chính ExecuTorch:
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))Thực hiện lượng hóa các mô hình sinh thông qua ~HfExporter.export_for_generation. Ở đây, calibration_dataset chứa các tham số kwargs cho generate, chẳng hạn như inputs, và mỗi thành phần sẽ hiệu chuẩn trên các đầu vào được ghi nhận cho thành phần đó. Một mô hình chỉ xử lý văn bản có thành phần prefill và thành phần decode; một mô hình đa phương thức sẽ tách thêm phần prefill của nó thành các bộ mã hóa phương thức (chẳng hạn như image_encoder), bộ chiếu (projector), language_model và lm_head của nó (xem Cách export_for_generation hoạt động).
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": ...}Trên OpenVINO, trọng số PT2E được giữ ở độ chính xác đầy đủ phía sau các cặp quantize/dequantize, mà OpenVINO sẽ chuyển đổi thành FakeQuantize và tự nén xuống int8.
ONNX Runtime
OnnxRuntimeQuantizer chạy quantize_static theo mặc định (kích hoạt và trọng số int8 QDQ, được hiệu chuẩn trên calibration_dataset), như trong ví dụ ở trên, với các đối số của một OnnxRuntimeStaticConfig. Với một OnnxRuntimeDynamicConfig, nó chạy quantize_dynamic (trọng số int8, kích hoạt được lượng tử hóa tại thời điểm chạy, không cần hiệu chuẩn).
from transformers.exporters import OnnxRuntimeDynamicConfig, OnnxRuntimeStaticConfig
config = OnnxConfig(
quantizer=OnnxRuntimeQuantizer(OnnxRuntimeStaticConfig(per_channel=True), calibration_dataset=calibration_dataset)
)
config = OnnxConfig(quantizer=OnnxRuntimeQuantizer(OnnxRuntimeDynamicConfig()))NNCF
Ba bộ lượng tử hóa NNCF trong bảng ở trên chạy nncf.quantize theo mặc định (kích hoạt và trọng số int8, được hiệu chuẩn trên calibration_dataset, với model_type=nncf.ModelType.TRANSFORMER trừ khi bạn truyền một giá trị khác), với các đối số của NNCFQuantizationConfig. Khi dùng NNCFWeightCompressionConfig, chúng chạy nncf.compress_weights (chỉ trọng số int8 hoặc int4, kèm AWQ và ước lượng thang cho int4, cùng hiệu chỉnh GPTQ và LoRA trên OpenVINO). ExecuTorch chỉ hạ cấp kết quả chỉ trọng số của 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)Int8 activations chạy các phép nhân ma trận int8, bị bão hòa trên các CPU không có VNNI (chỉ có AVX2 trên Intel và AMD Zen 2 trở về trước), do đó hãy kỳ vọng độ chính xác thấp hơn ở đó. Nén chỉ trọng số giữ các phép nhân ma trận ở dạng số dấu phẩy động.
Hiệu chuẩn
calibration_dataset của một quantizer là một iterable gồm các đầu vào của model, chẳng hạn như một danh sách các đầu ra của tokenizer hoặc một DataLoader mà các batch của nó được collate thành các đầu vào của model. Đây là một thuộc tính thông thường, vì vậy bạn cũng có thể đặt nó sau khi tạo quantizer (quantizer.calibration_dataset = samples). Nếu bỏ qua thuộc tính này, một quantizer cần dữ liệu sẽ hiệu chuẩn trên chính các đầu vào mẫu của quá trình xuất, kèm theo một cảnh báo, vì một mẫu duy nhất có thể làm lệch các khoảng quan sát được. Các quantizer không cần dữ liệu (lượng tử hóa ONNX Runtime động, nén trọng số int8) sẽ không bao giờ đọc thuộc tính này.
Công thức riêng cho từng thành phần
Truyền dict {component: config} vào ~HfExporter.export_for_generation để lượng tử hóa từng thành phần theo các điều kiện riêng. Đối với mô hình ở trên, dùng static int8 cho prefill và dynamic int8 nhẹ hơn cho 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 phải đặt tên cho mọi thành phần mà decompose_for_generation() tạo ra (một model đa phương thức sẽ thêm các encoder của nó, và có thể tách riêng language_model và lm_head). Một thành phần có config không đặt quantizer nào sẽ giữ ở độ chính xác đầy đủ. Trong dict này, calibration_dataset của một quantizer chứa các kwargs forward của thành phần đó, không phải kwargs generate.
Thêm bộ lượng tử hóa
Quantizers nằm trong transformers.exporters.quantizers, mỗi class tương ứng với một toolchain và biểu diễn. Kế thừa ExportQuantizer và khai báo:
quantizes_fx_graph:Truecho đồ thị FX củatorch.export, trước bất kỳ bước chuyển đổi nào (để mọi backend đều nhận kết quả), hoặcFalse(mặc định) cho mô hình mà một backend chuyển đổi nó thành (onnx_ir.Model,openvino.Model).supported_formats: các định dạng xuất mà nó lượng tử hóa. Việc xuất sẽ từ chối mọi định dạng khác trước khi theo dõi (tracing).required_packages, và tùy chọnmin_versionsvàtested_versions: những gì được import. Việc xuất kiểm tra chúng đã được cài đặt trước khi trace, gây lỗi nếu thấp hơn phiên bản tối thiểu, và cảnh báo khi phiên bản khác với phiên bản đã kiểm thử.
Sau đó, triển khai quantize(model, sample_inputs, export_format). model là đồ thị FX hoặc mô hình backend, còn sample_inputs là các đầu vào của chính bản xuất. Hiệu chuẩn trên một CalibrationSet: nó đọc calibration_dataset của bộ lượng tử hóa (hoặc sample_inputs nếu không có) và ánh xạ mỗi mẫu vào các đầu vào của chính mô hình bằng một feed từ transformers.exporters.quantizers.utils (traced_inputs cho đồ thị FX, onnx_feed cho ONNX, openvino_feed cho 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))