Transformers documentation
Contribuir
Contribuir
Transformers admite muchos métodos de cuantización, como QLoRA, GPTQ, LLM.int8 y AWQ. Sin embargo, aún existen muchos más enfoques de cuantización que no se han integrado todavía. Para facilitar la adición y el uso de estos métodos de cuantización con Transformers, utilice la clase HfQuantizer. HfQuantizer está diseñada para ser una clase auxiliar interna para agregar un método de cuantización, en lugar de algo que se aplique a cada módulo de PyTorch.
Esta guía le mostrará cómo integrar un nuevo método de cuantización con HfQuantizer.
Requisitos
Antes de integrar un nuevo método de cuantización en Transformers, asegúrese de que el método cumpla con los siguientes requisitos. Solo se admiten los métodos de cuantización que pueden ejecutarse con módulos de PyTorch.
El método de cuantización está disponible a través de un paquete de Python que se puede instalar con pip (también está bien si solo puedes instalar el paquete desde el código fuente). Idealmente, el paquete de pip incluye kernels precompilados.
El método puede ejecutarse en hardware de uso común (CPU, GPU, etc.).
El método está envuelto en un nn.Module (
~bitsandbytes.nn.Linear8bitLt,~bitsandbytes.nn.Linear4bit), y la capa lineal cuantizada debe tener la siguiente definición.class Linear4bit(nn.Module): def __init__(self, ...): ... def forward(self, x): return my_4bit_kernel(x, self.weight, self.bias)De esta manera, los modelos de Transformers se cuantizan fácilmente reemplazando las instancias de nn.Linear por una clase objetivo.
El método de cuantización debe ser serializable. Puede guardar los pesos cuantizados localmente o subirlos al Hub.
Asegúrese de que el paquete que contiene los kernels/primitivas de cuantización sea estable (sin cambios frecuentes que rompan la compatibilidad).
Algunos métodos de cuantización pueden requerir “pre-cuantizar” el modelo mediante calibración de datos (AWQ). En este caso, preferimos admitir solo la inferencia en Transformers y dejar que la biblioteca de terceros mantenida por la comunidad de ML se encargue de la cuantización del modelo.
Crear la nueva clase HFQuantizer
El mejor punto de partida sería echar un vistazo a otro método de cuantización, como Finegrained Fp8. Tendrá que actualizar o crear un total de tres archivos: el archivo de configuración, el archivo de integración y el archivo del cuantizador.
Cree una nueva clase de configuración de cuantización dentro de src/transformers/utils/quantization_config.py. Añada la nueva configuración de cuantización a _import_structure dentro del archivo src/transformers/__init__.py de Transformers.
Cree un nuevo archivo dentro de src/transformers/quantizers/ llamado
quantizer_your_method.pyy haga que herede de [`~quantizers.HfQuantizer`]. Asegúrese de agregar el nuevo cuantizador y la configuración de cuantización en el mapeo automático de cuantización en src/transformers/quantizers/auto.py.Defina los siguientes atributos de clase y métodos de propiedad para su método de cuantización:
requires_calibration: Indica si el método de cuantización requiere un proceso de calibración de datos. Si se establece enTrue, solo se puede admitir la inferencia (con pesos cuantizados) y no la inferencia y la cuantización.is_serializable: un método de propiedad para determinar si el método es serializable o no.is_trainable: un método de propiedad para determinar si se pueden ajustar modelos sobre el método de cuantización (con o sin enfoques PEFT).
Escribe los métodos
validate_environmentyupdate_dtype. Estos métodos se llaman antes de crear el modelo cuantizado para asegurarse de que los usuarios utilicen la configuración correcta. Consulta otros cuantizadores para ver un ejemplo de cómo se implementan.Escriba el método
_process_model_before_weight_loading. En Transformers, los modelos cuantizados se inicializan primero en el dispositivo"meta"antes de cargar los pesos. Esto significa que el método_process_model_before_weight_loadingse encarga de manipular el esqueleto del modelo para reemplazar algunos módulos (nn.Linear) con los módulos objetivo (módulos de cuantización).
Puede definir la lógica de reemplazo de módulos o cualquier otro método de utilidad creando un nuevo archivo en transformers/src/integrations/ y exponiendo los métodos relevantes en el archivo __init__.py de esa carpeta.
Agregue el método
get_quantize_opsa la clase cuantizadora si la cuantización admite la cuantización sobre la marcha. En transformers, materializamos cada tensor y aplicamos una secuencia de operaciones diferentes sobre él. En nuestro caso, la operación de cuantización ocurre al final. Debe crear unXXXQuantize, una subclase deConversionOps, y agregar un métodoconvert. En el métodoconvert, debe cuantizar los pesos y devolver un diccionario de parámetros cuantizados.Agregue el método
get_weight_conversionsa la clase cuantizador si la cuantización admite la carga de pesos precuantizados. En transformers, podemos recopilar varios tensores y aplicar operaciones sobre ellos. Esto resulta especialmente útil cuando tenemos tensores en el checkpoint que deben reagruparse para recrear los tensores cuantizados.Escriba el método
_process_model_after_weight_loadingsi es necesario. Este método permite implementar funciones adicionales que requieran manipular el modelo después de cargar los pesos.¡Documenta todo! Asegúrate de que tu método de cuantización esté documentado añadiendo un nuevo archivo bajo
docs/source/en/quantization.Deberías añadir pruebas incluyendo el paquete en nuestro Dockerfile de pruebas nocturnas dentro de
docker/transformers-quantization-latest-gpuy luego añadiendo un nuevo archivo de pruebas entests/quantization/xxx. Puedes consultar los métodos de cuantización existentes para ver cómo se implementa.
Resumen de archivos
| Archivo | Propósito |
|---|---|
utils/quantization_config.py | Defina YourMethodConfig heredando de QuantizationConfigMixin |
quantizers/quantizer_your_method.py | Implementa YourMethodHfQuantizer heredando de HfQuantizer |
integrations/your_method.py | Implementa subclases de ConversionOps y funciones auxiliares |
quantizers/auto.py | Registra el cuantizador y la configuración en AUTO_QUANTIZER_MAPPING y AUTO_QUANTIZATION_CONFIG_MAPPING |
docs/source/en/quantization/your_method.md | Documentar el uso para los usuarios |
tests/quantization/your_method/ | Agregar pruebas de integración |
Comprender get_quantize_ops frente a get_weight_conversions
Estos dos métodos gestionan diferentes escenarios para la carga de pesos. Comprender cuándo usar cada uno es esencial.
get_quantize_ops — Cuantización en tiempo real
Utilice esto al cargar un punto de control no cuantizado (p. ej., pesos float16/bfloat16) y cuantizar durante la carga.
Checkpoint: model.safetensors (float16 weights for example)
↓
get_quantize_ops → YourQuantize.convert()
↓
Result: Quantized weights in memoryEl método convert recibe un tensor a la vez, lo cuantiza y puede devolver un diccionario de parámetros cuantizados, por ejemplo:
class YourQuantize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, missing_keys, **kwargs):
# input_dict = {"layer.weight": <float16 tensor>}
value = list(input_dict.values())[0]
module, tensor_name = get_module_from_name(model, full_layer_name)
# Quantize and assign
quantized, scale, zero_point = your_quantize_fn(value)
return {full_layer_name: quantized, full_layer_name + ".scale": scale, full_layer_name + ".zero_point": zero_point}get_weight_conversions — Cargar puntos de control pre-cuantizados
Utilice esto al cargar un punto de control pre-cuantizado en el que los pesos cuantizados se guardan como varios componentes separados (como datos, escala y punto cero) y que deben combinarse en un solo tensor durante la carga. No todos los métodos de cuantización requieren esta etapa de reconstrucción: por ejemplo, algunos métodos como FP8 simplemente cargan los pesos y las escalas tal como están, sin combinarlos. Otros, como torchao, sí requieren reensamblar el tensor cuantizado a partir de sus múltiples componentes guardados.
Checkpoint: model.safetensors (quantized components)
- layer._weight_qdata
- layer._weight_scale
- layer._weight_zero_point
↓
get_weight_conversions → WeightConverter + YourDeserialize.convert()
↓
Result: Reconstructed quantized tensor → layer.weightEl WeightConverter recopila los tensores relacionados en función de source_patterns y luego los pasa a su método convert:
def get_weight_conversions(self):
if self.pre_quantized:
return [
WeightConverter(
source_patterns=["_weight_qdata", "_weight_scale", "_weight_zero_point"],
target_patterns="weight",
operations=[YourDeserialize(self)],
),
]
return []
class YourDeserialize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, **kwargs):
# input_dict contains all collected tensors
# Reconstruct the quantized tensor from components
reconstructed_tensor = reconstruct_from_components(input_dict)
return {full_layer_name: reconstructed_tensor}