Runner¶
The Runner class is the main entry point for executing quantization pipelines in OneComp.
Runner ¶
Runner(model_config=None, quantizer=None, quantizers=None, calibration_config=None, qep=False, qep_config=None, lpcd=False, lpcd_config=None, multi_gpu=False, gpu_ids=None, post_processes=None, report_progress=True, moe_quant_experts=False)
Runner class for model quantization
Runner class for executing quantization. Supports quantization using calibration data and parallel quantization on multiple GPUs.
Examples:
Single GPU quantization (default):
>>> from onecomp import Runner, ModelConfig
>>> from onecomp.quantizer.gptq import GPTQ
>>> model_config = ModelConfig(model_id_or_path="meta-llama/Llama-2-7b-hf")
>>> quantizer = GPTQ(wbits=4, groupsize=128)
>>> runner = Runner(
... model_config=model_config,
... quantizer=quantizer,
... )
>>> runner.run()
Multi-GPU quantization (layer-wise parallel):
>>> from onecomp.quantizer.jointq import JointQ
>>> quantizer = JointQ(bits=4, group_size=128)
>>> # Use all available GPUs
>>> runner = Runner(
... model_config=model_config,
... quantizer=quantizer,
... multi_gpu=True,
... )
>>> runner.run()
>>> # Use specific GPUs (e.g., GPU 0, 2, 3)
>>> runner = Runner(
... model_config=model_config,
... quantizer=quantizer,
... multi_gpu=True,
... gpu_ids=[0, 2, 3],
... )
>>> runner.run()
init method
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_config
|
ModelConfig
|
Model configuration. Required. |
None
|
quantizer
|
Quantizer
|
The quantizer to use. Specify either |
None
|
quantizers
|
list[Quantizer]
|
Specify multiple quantizers. When used with
|
None
|
calibration_config
|
CalibrationConfig or None
|
Calibration data configuration. When See :class: |
None
|
qep
|
bool
|
Whether to use QEP. |
False
|
qep_config
|
QEPConfig or None
|
Configuration for QEP. If None and |
None
|
lpcd
|
bool
|
Whether to use LPCD. |
False
|
lpcd_config
|
LPCDConfig or None
|
Configuration for LPCD. If None and |
None
|
multi_gpu
|
bool
|
Whether to use multi-GPU for layer-wise parallel quantization. Default is False. |
False
|
gpu_ids
|
list[int]
|
List of GPU IDs to use for multi-GPU quantization. If None and multi_gpu is True, all available GPUs will be used. |
None
|
post_processes
|
list[PostQuantizationProcess] or None
|
Optional list of post-quantization processes to execute
after the main quantization step. Each process receives
a packed quantized model on CPU (built via
|
None
|
report_progress
|
bool
|
When |
True
|
moe_quant_experts
|
bool
|
When |
False
|
Note
For zero-config quantization (VRAM auto-estimation +
AutoBitQuantizer + QEP), use the class method
:meth:auto_run instead.
Examples:
Chunked calibration with GPTQ (large-scale calibration data):
>>> from onecomp import Runner, ModelConfig, CalibrationConfig
>>> from onecomp.quantizer.gptq import GPTQ
>>> model_config = ModelConfig(
... model_id_or_path="meta-llama/Llama-2-7b-hf"
... )
>>> quantizer = GPTQ(wbits=4, groupsize=128)
>>> calib_config = CalibrationConfig(
... max_length=2048,
... num_calibration_samples=1024,
... batch_size=128,
... )
>>> runner = Runner(
... model_config=model_config,
... quantizer=quantizer,
... calibration_config=calib_config,
... )
>>> runner.run()
With custom num_layers_per_group:
>>> calib_config = CalibrationConfig(
... max_length=2048,
... num_calibration_samples=1024,
... batch_size=128,
... num_layers_per_group=14,
... )
>>> runner = Runner(
... model_config=model_config,
... quantizer=quantizer,
... calibration_config=calib_config,
... )
>>> runner.run()
Multiple quantizers (benchmark comparison):
>>> from onecomp.quantizer.gptq import GPTQ
>>> from onecomp.quantizer.jointq import JointQ
>>> gptq = GPTQ(wbits=4, groupsize=128, calc_quant_error=True)
>>> jointq = JointQ(bits=4, group_size=128, calc_quant_error=True,
... device=torch.device(0))
>>> calib_config = CalibrationConfig(
... max_length=2048,
... num_calibration_samples=1024,
... batch_size=128,
... )
>>> runner = Runner(
... model_config=model_config,
... quantizers=[gptq, jointq],
... calibration_config=calib_config,
... )
>>> runner.run()
>>> # Results are stored in gptq.results and jointq.results respectively
auto_run
classmethod
¶
auto_run(model_id: str, wbits: Optional[float] = None, total_vram_gb: Optional[float] = None, groupsize: int = 128, device: str = 'cuda:0', qep: bool = True, evaluate: bool = True, eval_original_model: bool = False, save_dir: str = 'auto', **kwargs)
One-liner quantization with sensible defaults.
Sets up ModelConfig, AutoBitQuantizer (ILP-based mixed-precision),
and QEP, then runs quantization. When wbits is None,
the target bitwidth is estimated automatically from available VRAM.
Optionally evaluates perplexity and accuracy, and saves the
quantized model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_id
|
str
|
Hugging Face model ID or local path. |
required |
wbits
|
float or None
|
Target quantization bitwidth.
When |
None
|
total_vram_gb
|
float or None
|
Total VRAM budget in GB for
bitwidth estimation. Only used when |
None
|
groupsize
|
int
|
GPTQ group size (default: 128). Use -1 to disable grouping. |
128
|
device
|
str
|
Device to place the model on (default: "cuda:0"). |
'cuda:0'
|
qep
|
bool
|
Whether to use QEP (default: True). |
True
|
evaluate
|
bool
|
Whether to calculate perplexity and accuracy after quantization (default: True). |
True
|
eval_original_model
|
bool
|
Whether to also evaluate the original (unquantized) model (default: False). |
False
|
save_dir
|
str or None
|
Directory to save the quantized model.
|
'auto'
|
**kwargs
|
Additional keyword arguments forwarded to the
|
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
Runner |
The configured Runner instance (with quantization |
|
|
results accessible via |
Examples:
Minimal usage (QEP + GPTQ 4-bit, groupsize=128, auto-save):
>>> from onecomp import Runner
>>> runner = Runner.auto_run(
... model_id="TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T"
... )
Custom save directory:
>>> runner = Runner.auto_run(
... model_id="TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T",
... save_dir="./my_quantized_model",
... )
Skip saving:
>>> runner = Runner.auto_run(
... model_id="TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T",
... save_dir=None,
... )
Evaluate both original and quantized models:
run_post_processes ¶
Execute post-quantization processes.
Uses self.quantized_model when one has already been assigned;
otherwise builds a packed quantized model on CPU from
quantizer.results with
create_quantized_model(pack_weights=True, use_gemlite=False) by
default. The model is passed to each
:class:PostQuantizationProcess in order, and each process preserves
the incoming pack state (packed-in -> packed-out), so
self.quantized_model stays packed for memory-efficient eval reuse.
Processes that train (e.g. :class:PostProcessLoraSFT) unpack the base
weights internally for the duration of training and re-pack on exit.
use_gemlite=False is used because GemLite relies on fp16-only Triton
kernels that break when LoRA SFT runs with bfloat16 autocast; plain
buffers (qweight/scales) let training call base_layer.forward()
without dtype mismatch.
If an unpacked layout is required, explicitly build the model before
calling this method and assign it to runner.quantized_model::
runner.quantized_model, _ = runner.create_quantized_model(
pack_weights=False, use_gemlite=False)
Direct post_process.run(model, runner.model_config) execution can
use the same explicitly built model.
Each process records its own metadata in
model.config.quantization_config["onecomp_post_processes"] when it
finishes successfully, so direct process execution and Runner execution
share the same history path.
Raises:
| Type | Description |
|---|---|
ValueError
|
If neither |
check ¶
Check the settings
Performs the following checks:
model_configis aModelConfiginstance- Mutual exclusion check for
quantizerandquantizers(cannot specify both) - Type check for
quantizer/quantizers(must beQuantizerinstances) - At least one of them must be specified
- Parameter combination consistency check (see table below)
- When
multi_gpu=True,quantizer.flag_calibration=Truemust hold
Valid parameter combinations:
=========== ==== ========== ================================ quantizers qep multi_gpu calibration_config.batch_size =========== ==== ========== ================================ Specified False False Specified None True False None None False True None None False False Specified None False False None =========== ==== ========== ================================
Note
multi_gpu=True requires a quantizer with flag_calibration=True.
This method is intended to be called from the run() flow only.
It is not designed to be used in the
load_quantized_model() -> Runner.run_post_processes() flow, and
the checks here do not cover that use case.
Raises:
| Type | Description |
|---|---|
TypeError
|
Invalid type for |
ValueError
|
Invalid parameter combination |
calculate_perplexity ¶
calculate_perplexity(original_model=False, dequantized_model=False, quantized_model=True, dataset_name='wikitext', dataset_config='wikitext-2-raw-v1', split='test', max_samples=None, max_length=2048, stride=2048, quantizer=None)
Calculate the perplexity of the model
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_model
|
bool
|
Whether to calculate the perplexity of the original model. |
False
|
dequantized_model
|
bool
|
Whether to calculate the perplexity of the dequantized model. |
False
|
quantized_model
|
bool
|
Whether to calculate the perplexity of the quantized model. |
True
|
dataset_name
|
str
|
The name of the dataset to use for calculating perplexity. |
'wikitext'
|
dataset_config
|
str
|
The configuration of the dataset. |
'wikitext-2-raw-v1'
|
split
|
str
|
The split of the dataset to use. |
'test'
|
max_samples
|
int
|
The maximum number of samples to use. |
None
|
max_length
|
int
|
Maximum length of the sliding window. Uses model.config.max_position_embeddings if None. 2048 is recommended to match standard paper values. |
2048
|
stride
|
int
|
Stride of the sliding window. Same as max_length (no overlap) if None. |
2048
|
quantizer
|
Quantizer
|
The quantizer. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(original_ppl, dequantized_ppl, quantized_ppl) |
Note
Evaluating the original or dequantized model requires loading the full model on GPU.
Quantized-model evaluation (quantized_model=True) is
currently supported only for GPTQ and DBF quantizers.
Support for other quantization methods is planned.
Examples:
Single quantizer mode:
Multiple quantizers mode:
benchmark_perplexity ¶
benchmark_perplexity(original_model=True, dequantized_model=False, quantized_model=True, dataset_name='wikitext', dataset_config='wikitext-2-raw-v1', split='test', max_samples=None, max_length=2048, stride=2048, quantizers=None)
Calculate perplexity for all quantizers at once
Internally calls calculate_perplexity for each quantizer. The original model PPL is calculated only once (on the first iteration).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_model
|
bool
|
Whether to calculate the perplexity of the original model. |
True
|
dequantized_model
|
bool
|
Whether to calculate the perplexity of the dequantized model. |
False
|
quantized_model
|
bool
|
Whether to calculate the perplexity of the quantized model. |
True
|
dataset_name
|
str
|
The name of the dataset to use for calculating perplexity. |
'wikitext'
|
dataset_config
|
str
|
The configuration of the dataset. |
'wikitext-2-raw-v1'
|
split
|
str
|
The split of the dataset to use. |
'test'
|
max_samples
|
int
|
The maximum number of samples to use. |
None
|
max_length
|
int
|
Maximum length of the sliding window. Uses model.config.max_position_embeddings if None. |
2048
|
stride
|
int
|
Stride of the sliding window. Same as max_length (no overlap) if None. |
2048
|
quantizers
|
list[Quantizer]
|
List of quantizers. Uses self.quantizers or [self.quantizer] if None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dictionary of PPL values. Keys are as follows: |
|
|
||
|
||
|
Examples:
>>> runner.run()
>>> ppl_dict = runner.benchmark_perplexity()
>>> print(ppl_dict)
{'original': 5.47, 'GPTQ': 5.72, 'JointQ': 5.68}
Specify quantizers explicitly:
Include dequantized model PPL:
calculate_accuracy ¶
calculate_accuracy(original_model=False, dequantized_model=False, quantized_model=True, tasks=None, batch_size=8, num_fewshot=0, display_results=True, quantizer=None)
Calculate the zero-shot accuracy of the model
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_model
|
bool
|
Whether to calculate the accuracy of the original model. |
False
|
dequantized_model
|
bool
|
Whether to calculate the accuracy of the dequantized model. |
False
|
quantized_model
|
bool
|
Whether to calculate the accuracy of the quantized model. |
True
|
tasks
|
list
|
The list of tasks to evaluate. Default: ["arc_easy", "arc_challenge", "piqa", "winogrande"] |
None
|
batch_size
|
int
|
The batch size for evaluation. |
8
|
num_fewshot
|
int
|
The number of few-shot examples. |
0
|
display_results
|
bool
|
Whether to display the results. |
True
|
quantizer
|
Quantizer
|
The quantizer. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(original_acc, dequantized_acc, quantized_acc) |
Note
Evaluating the original or dequantized model requires loading the full model on GPU.
Quantized-model evaluation (quantized_model=True) is
currently supported only for GPTQ and DBF quantizers.
Support for other quantization methods is planned.
Examples:
Single quantizer mode:
Multiple quantizers mode:
benchmark_accuracy ¶
benchmark_accuracy(original_model=True, dequantized_model=False, quantized_model=True, tasks=None, batch_size=8, num_fewshot=0, display_results=False, quantizers=None)
Calculate accuracy for all quantizers at once
Internally calls calculate_accuracy for each quantizer. The original model accuracy is calculated only once (on the first iteration).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original_model
|
bool
|
Whether to calculate the accuracy of the original model. |
True
|
dequantized_model
|
bool
|
Whether to calculate the accuracy of the dequantized model. |
False
|
quantized_model
|
bool
|
Whether to calculate the accuracy of the quantized model. |
True
|
tasks
|
list
|
The list of tasks to evaluate. Default: ["arc_easy", "arc_challenge", "piqa", "winogrande"] |
None
|
batch_size
|
int
|
The batch size for evaluation. |
8
|
num_fewshot
|
int
|
The number of few-shot examples. |
0
|
display_results
|
bool
|
Whether to display the results. |
False
|
quantizers
|
list[Quantizer]
|
List of quantizers. Uses self.quantizers or [self.quantizer] if None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dictionary of accuracy values. Keys are as follows: |
|
|
||
|
||
|
Examples:
>>> runner.run()
>>> acc_dict = runner.benchmark_accuracy()
>>> print(acc_dict)
{'original': {...}, 'GPTQ': {...}, 'JointQ': {...}}
Specify quantizers explicitly:
Include dequantized model accuracy:
print_quantization_results ¶
Log quantization results.
Formats and logs the quantizer results. The following information is output for each layer:
- Quantization time (seconds)
- Output squared error (only if value exists)
- Mean output squared error (only if value exists)
- Weight squared error (only if value exists)
- Mean weight squared error (only if value exists)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quantizer
|
Quantizer
|
The quantizer. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Examples:
Single quantizer mode:
Multiple quantizers mode:
save_quantization_statistics ¶
Save the quantization statistics
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
File path to save to |
required |
quantizer
|
Quantizer
|
Quantizer whose statistics to save. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Examples:
Single quantizer mode:
Multiple quantizers mode:
save_quantization_results ¶
Save the quantization results to a file
Save quantization results (QuantizationResult objects) to a file. The saved data includes dequantized weights, scales, zero points, integer assignments, and other quantization parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
The path to save the quantization results. The .pt extension is recommended. |
required |
quantizer
|
Quantizer
|
Quantizer whose results to save. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Examples:
Single quantizer mode:
Multiple quantizers mode:
save_dequantized_model ¶
Save the dequantized model to the specified path
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
The path to save the dequantized model. |
required |
quantizer
|
Quantizer
|
The quantizer. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Examples:
Single quantizer mode:
Multiple quantizers mode:
save_quantized_model ¶
Save the quantized model to the specified directory
If self.quantized_model is already set (e.g. after
run_post_processes(), or after loading a checkpoint and assigning it
for a load -> post-process -> re-save flow), that in-place updated model
is saved as-is so post-process results are preserved: its
quantization_config is validated, any recorded
onecomp_post_processes history is persisted to config.json, and
model_config is required (for the tokenizer). Otherwise the base
quantized model is built from quantizer.results via
:meth:create_quantized_model. The result is saved in
HuggingFace-compatible safetensors format.
If the selected model contains LoRAGPTQLinear wrappers, this method
saves base weights with LoRA tensors excluded and additionally writes a
PEFT-compatible LoRA adapter sidecar
(lora_adapter/adapter_model.safetensors +
lora_adapter/adapter_config.json). The resulting directory can then
be loaded back with
:func:onecomp.load_quantized_model (which auto-detects the sidecar and
re-wraps the layers) or served by vLLM via enable_lora=True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_directory
|
str
|
The path to save the quantized model. |
required |
pack_weights
|
bool
|
Whether to pack quantized weights for a more
memory/storage-efficient representation. When building from
|
True
|
save_format
|
str
|
One of |
'auto'
|
Examples:
Single quantizer mode:
GPTQ + LoRA SFT:
create_quantized_model ¶
Create a quantized model from quantization results.
Loads the base model on CPU, replaces Linear layers with quantized
inference layers (e.g. GPTQLinear), and attaches quantization
config to model.config.
Must be called after run() (i.e., quantizer.results must
be populated).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pack_weights
|
bool
|
Whether to pack quantized weights for memory-efficient representation. Default is True. |
True
|
quantizer
|
Quantizer
|
The quantizer to use. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
use_gemlite
|
bool or None
|
Whether to use GemLite for inference layers. Set to False when saving to avoid extra params in safetensors. Default is None (uses quantizer default). |
None
|
Returns:
| Type | Description |
|---|---|
|
tuple[nn.Module, PreTrainedTokenizer]: (quantized_model, tokenizer) |
Examples:
With post-process (manual single-process run; run_post_processes()
builds the model with pack_weights=True by default). The same
packed model can be passed directly to post-processes that preserve
quantized layer structure, such as BlockWisePTQ or GlobalPTQ:
>>> model, tokenizer = runner.create_quantized_model()
>>> post_process = BlockWisePTQ()
>>> post_process.run(model, runner.model_config)
>>> post_process = GlobalPTQ()
>>> post_process.run(model, runner.model_config)
LoRA SFT also accepts the model directly. It introduces custom
wrapper modules (LoRAGPTQLinear), which save_quantized_model
handles by writing the base weights as safetensors plus a
PEFT-compatible adapter sidecar under lora_adapter/:
>>> model, tokenizer = runner.create_quantized_model(
... pack_weights=True,
... use_gemlite=False,
... )
>>> post_process = PostProcessLoraSFT(data_files="train.jsonl")
>>> post_process.run(model, runner.model_config)
>>> runner.quantized_model = model # so the LoRA model is the one saved
>>> runner.save_quantized_model("./quantized_model_lora")
Post-processes preserve the incoming pack state. If a workflow
requires unpacked quantized buffers (e.g. when intentionally
debugging an unpacked-buffer path), build the model explicitly with
pack_weights=False before direct execution:
save_quantized_model_pt ¶
Save the quantized model as a PyTorch .pt file.
This serializes the entire model object with torch.save,
preserving custom module types such as LoRAGPTQLinear. It is a
legacy/alternative to :meth:save_quantized_model, which is preferred
for all cases -- including LoRA post-processes, whose adapter is saved
as a PEFT-compatible safetensors sidecar and is loadable by
:func:onecomp.load_quantized_model and servable by vLLM. Use this
.pt method only when you specifically need a single serialized
model object; note that loading it requires
allow_unsafe_deserialization=True (see
:func:onecomp.load_quantized_model_pt).
The saved directory contains:
- model.pt: The model (torch.save)
- Tokenizer files (via save_pretrained)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_directory
|
str
|
The path to save the model. |
required |
See Also
:func:onecomp.load_quantized_model_pt to load models
saved by this method.
Examples:
analyze_cumulative_error ¶
analyze_cumulative_error(layer_keywords=None, plot_path=None, json_path=None, batch_keywords=False, quantizer=None)
Analyze cumulative quantization error for each linear layer.
Cumulative error: ||W_orig X_orig - W_quant X_quant||^2_F
Note
Must be used after calling the run() method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layer_keywords
|
List of keywords to filter layers. Each keyword is analyzed and plotted separately. Default: ["mlp.down_proj"] Example: ["q_proj", "k_proj"] |
None
|
|
plot_path
|
Base path to save plots. Keyword is inserted before extension. Example: "error.png" -> "error_mlp.down_proj.png" |
None
|
|
json_path
|
Path to save results as JSON file. Example: "cumulative_error.json" |
None
|
|
batch_keywords
|
If True, process all keywords in a single forward pass. This is faster but uses more CPU memory because all target layers' outputs are stored simultaneously. If False (default), process each keyword separately with model reload per keyword. This uses less CPU memory but incurs overhead from repeated model loading and forward passes. |
False
|
|
quantizer
|
Quantizer
|
The quantizer. Uses self.quantizer if None. Specify explicitly when using quantizers mode. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
keyword -> {layer_name -> cumulative squared error} |
Examples:
Single quantizer mode:
>>> results = runner.analyze_cumulative_error()
>>> results = runner.analyze_cumulative_error(plot_path="cumulative_error.png")
Multiple quantizers mode:
prepare_calibration_dataset ¶
Prepare calibration data for quantization methods such as GPTQ.
See calibration.calibration_data_loader.prepare_calibration_dataset for details.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device
|
device
|
Device to place tensors on (CPU or GPU) |
required |
model
|
Model instance (optional). Add model-specific fields |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Input dictionary for the model - "input_ids": tensor of shape (num_chunks, max_length) - "attention_mask": tensor of shape (num_chunks, max_length) |