Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Half-Quadratic Quantization for LLMs without calibration data. Use when quantizing models to 4/3/2-bit precision without needing calibration datasets, for fast quantization workflows, or when deploying with vLLM or HuggingFace Transformers.
.claude/skills/openlair-hqq-quantization/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 75% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 99% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -2% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 131% | 0% |
Fast, calibration-free weight quantization supporting 8/4/3/2/1-bit precision with multiple optimized backends.
Use HQQ when:
Key advantages:
Use alternatives instead:
bashpip install hqq # With specific backend pip install hqq[torch] # PyTorch backend pip install hqq[torchao] # TorchAO int4 backend pip install hqq[bitblas] # BitBlas backend pip install hqq[marlin] # Marlin backend
pythonfrom hqq.core.quantize import BaseQuantizeConfig, HQQLinear import torch.nn as nn # Configure quantization config = BaseQuantizeConfig( nbits=4, # 4-bit quantization group_size=64, # Group size for quantization axis=1 # Quantize along output dimension ) # Quantize a linear layer linear = nn.Linear(4096, 4096) hqq_linear = HQQLinear(linear, config) # Use normally output = hqq_linear(input_tensor)
pythonfrom transformers import AutoModelForCausalLM, HqqConfig # Configure HQQ quantization_config = HqqConfig( nbits=4, group_size=64, axis=1 ) # Load and quantize model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=quantization_config, device_map="auto" ) # Model is quantized and ready to use
HQQ uses BaseQuantizeConfig to define quantization parameters:
pythonfrom hqq.core.quantize import BaseQuantizeConfig # Standard 4-bit config config_4bit = BaseQuantizeConfig( nbits=4, # Bits per weight (1-8) group_size=64, # Weights per quantization group axis=1 # 0=input dim, 1=output dim ) # Aggressive 2-bit config config_2bit = BaseQuantizeConfig( nbits=2, group_size=16, # Smaller groups for low-bit axis=1 ) # Mixed precision per layer type layer_configs = { "self_attn.q_proj": BaseQuantizeConfig(nbits=4, group_size=64), "self_attn.k_proj": BaseQuantizeConfig(nbits=4, group_size=64), "self_attn.v_proj": BaseQuantizeConfig(nbits=4, group_size=64), "mlp.gate_proj": BaseQuantizeConfig(nbits=2, group_size=32), "mlp.up_proj": BaseQuantizeConfig(nbits=2, group_size=32), "mlp.down_proj": BaseQuantizeConfig(nbits=4, group_size=64), }
The core quantized layer that replaces nn.Linear:
pythonfrom hqq.core.quantize import HQQLinear import torch # Create quantized layer linear = torch.nn.Linear(4096, 4096) hqq_layer = HQQLinear(linear, config) # Access quantized weights W_q = hqq_layer.W_q # Quantized weights scale = hqq_layer.scale # Scale factors zero = hqq_layer.zero # Zero points # Dequantize for inspection W_dequant = hqq_layer.dequantize()
HQQ supports multiple inference backends for different hardware:
pythonfrom hqq.core.quantize import HQQLinear # Available backends backends = [ "pytorch", # Pure PyTorch (default) "pytorch_compile", # torch.compile optimized "aten", # Custom CUDA kernels "torchao_int4", # TorchAO int4 matmul "gemlite", # GemLite CUDA kernels "bitblas", # BitBlas optimized "marlin", # Marlin 4-bit kernels ] # Set backend globally HQQLinear.set_backend("torchao_int4") # Or per layer hqq_layer.set_backend("marlin")
Backend selection guide: | Backend | Best For | Requirements | |---------|----------|--------------| | pytorch | Compatibility | Any GPU | | pytorch_compile | Moderate speedup | torch>=2.0 | | aten | Good balance | CUDA GPU | | torchao_int4 | 4-bit inference | torchao installed | | marlin | Maximum 4-bit speed | Ampere+ GPU | | bitblas | Flexible bit-widths | bitblas installed |
pythonfrom transformers import AutoModelForCausalLM, AutoTokenizer # Load HQQ-quantized model from Hub model = AutoModelForCausalLM.from_pretrained( "mobiuslabsgmbh/Llama-3.1-8B-HQQ-4bit", device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B") # Use normally inputs = tokenizer("Hello, world!", return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_new_tokens=50)
pythonfrom transformers import AutoModelForCausalLM, HqqConfig # Quantize config = HqqConfig(nbits=4, group_size=64) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=config, device_map="auto" ) # Save quantized model model.save_pretrained("./llama-8b-hqq-4bit") # Push to Hub model.push_to_hub("my-org/Llama-3.1-8B-HQQ-4bit")
pythonfrom transformers import AutoModelForCausalLM, HqqConfig # Different precision per layer type config = HqqConfig( nbits=4, group_size=64, # Attention layers: higher precision # MLP layers: lower precision for memory savings dynamic_config={ "attn": {"nbits": 4, "group_size": 64}, "mlp": {"nbits": 2, "group_size": 32} } )
pythonfrom vllm import LLM, SamplingParams # Load HQQ-quantized model llm = LLM( model="mobiuslabsgmbh/Llama-3.1-8B-HQQ-4bit", quantization="hqq", dtype="float16" ) # Generate sampling_params = SamplingParams(temperature=0.7, max_tokens=100) outputs = llm.generate(["What is machine learning?"], sampling_params)
pythonfrom vllm import LLM llm = LLM( model="meta-llama/Llama-3.1-8B", quantization="hqq", quantization_config={ "nbits": 4, "group_size": 64 } )
pythonfrom transformers import AutoModelForCausalLM, HqqConfig from peft import LoraConfig, get_peft_model # Load quantized model quant_config = HqqConfig(nbits=4, group_size=64) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=quant_config, device_map="auto" ) # Apply LoRA lora_config = LoraConfig( r=16, lora_alpha=32, 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, lora_config) # Train normally with Trainer or custom loop
pythonfrom transformers import TrainingArguments, Trainer training_args = TrainingArguments( output_dir="./hqq-lora-output", per_device_train_batch_size=4, gradient_accumulation_steps=4, learning_rate=2e-4, num_train_epochs=3, fp16=True, logging_steps=10, save_strategy="epoch" ) trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, data_collator=data_collator ) trainer.train()
pythonfrom transformers import AutoModelForCausalLM, AutoTokenizer, HqqConfig # 1. Configure quantization config = HqqConfig(nbits=4, group_size=64) # 2. Load and quantize (no calibration needed!) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=config, device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B") # 3. Verify quality prompt = "The capital of France is" inputs = tokenizer(prompt, return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_new_tokens=20) print(tokenizer.decode(outputs[0])) # 4. Save model.save_pretrained("./llama-8b-hqq") tokenizer.save_pretrained("./llama-8b-hqq")
pythonfrom hqq.core.quantize import HQQLinear from transformers import AutoModelForCausalLM, HqqConfig # 1. Quantize with optimal backend config = HqqConfig(nbits=4, group_size=64) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=config, device_map="auto" ) # 2. Set fast backend HQQLinear.set_backend("marlin") # or "torchao_int4" # 3. Compile for additional speedup import torch model = torch.compile(model) # 4. Benchmark import time inputs = tokenizer("Hello", return_tensors="pt").to(model.device) start = time.time() for _ in range(10): model.generate(**inputs, max_new_tokens=100) print(f"Avg time: {(time.time() - start) / 10:.2f}s")
Out of memory during quantization:
python# Quantize layer-by-layer from hqq.models.hf.base import AutoHQQHFModel model = AutoHQQHFModel.from_pretrained( "meta-llama/Llama-3.1-8B", quantization_config=config, device_map="sequential" # Load layers sequentially )
Slow inference:
python# Switch to optimized backend from hqq.core.quantize import HQQLinear HQQLinear.set_backend("marlin") # Requires Ampere+ GPU # Or compile model = torch.compile(model, mode="reduce-overhead")
Poor quality at 2-bit:
python# Use smaller group size config = BaseQuantizeConfig( nbits=2, group_size=16, # Smaller groups help at low bits axis=1 )
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 13,529 | 6,600 | -51% | 1 | 1 | 0% | 2,766 | 4,836 | +75% | 0 | 0 | — |
case-02 | fail→pass | 13,801 | 8,024 | -42% | 1 | 1 | 0% | 2,601 | 5,177 | +99% | 0 | 0 | — |
case-03 | fail→pass | 13,964 | 9,361 | -33% | 1 | 1 | 0% | 3,065 | 5,730 | +87% | 0 | 0 | — |
case-04 | pass→pass | 17,944 | 10,156 | -43% | 1 | 1 | 0% | 3,168 | 5,381 | +70% | 0 | 0 | — |
case-05 | pass→pass | 18,293 | 7,158 | -61% | 1 | 1 | 0% | 3,243 | 4,709 | +45% | 0 | 0 | — |
case-06 | pass→pass | 6,426 | 5,542 | -14% | 1 | 1 | 0% | 1,368 | 4,552 | +233% | 0 | 0 | — |
case-07 | fail→pass | 23,285 | 5,389 | -77% | 1 | 1 | 0% | 4,687 | 4,587 | -2% | 0 | 0 | — |
case-08 | pass→pass | 17,332 | 9,169 | -47% | 1 | 1 | 0% | 2,985 | 5,284 | +77% | 0 | 0 | — |
case-09 | fail→pass | 8,986 | 3,990 | -56% | 1 | 1 | 0% | 1,840 | 4,255 | +131% | 0 | 0 | — |
case-10 | pass→pass | 16,059 | 8,887 | -45% | 1 | 1 | 0% | 3,215 | 5,387 | +68% | 0 | 0 | — |
case-11 | fail→pass | 9,000 | 4,691 | -48% | 1 | 1 | 0% | 1,928 | 4,483 | +133% | 0 | 0 | — |
case-12 | fail→pass | 15,541 | 5,734 | -63% | 1 | 1 | 0% | 3,176 | 4,776 | +50% | 0 | 0 | — |
case-13 | fail→pass | 16,090 | 3,909 | -76% | 1 | 1 | 0% | 3,246 | 4,226 | +30% | 0 | 0 | — |
case-14 | pass→pass | 7,809 | 4,397 | -44% | 1 | 1 | 0% | 1,553 | 4,381 | +182% | 0 | 0 | — |
case-15 | fail→pass | 10,344 | 2,972 | -71% | 1 | 1 | 0% | 2,033 | 4,012 | +97% | 0 | 0 | — |
case-16 | pass→pass | 13,687 | 10,884 | -20% | 1 | 1 | 0% | 2,903 | 5,916 | +104% | 0 | 0 | — |
case-17 | fail→fail | 12,140 | 9,935 | -18% | 1 | 1 | 0% | 2,360 | 5,459 | +131% | 0 | 0 | — |
case-18 | fail→pass | 10,041 | 6,205 | -38% | 1 | 1 | 0% | 1,896 | 4,640 | +145% | 0 | 0 | — |
case-19 | pass→pass | 10,980 | 5,409 | -51% | 1 | 1 | 0% | 2,304 | 4,567 | +98% | 0 | 0 | — |
case-20 | pass→pass | 10,327 | 5,181 | -50% | 1 | 1 | 0% | 1,932 | 4,516 | +134% | 0 | 0 | — |
case-21 | pass→pass | 8,643 | 2,798 | -68% | 1 | 1 | 0% | 1,555 | 3,922 | +152% | 0 | 0 | — |
case-22 | pass→pass | 10,829 | 5,591 | -48% | 1 | 1 | 0% | 1,920 | 4,511 | +135% | 0 | 0 | — |
case-23 | pass→pass | 14,904 | 9,256 | -38% | 1 | 1 | 0% | 2,853 | 5,220 | +83% | 0 | 0 | — |
case-24 | pass→pass | 4,278 | 1,692 | -60% | 1 | 1 | 0% | 714 | 3,741 | +424% | 0 | 0 | — |
case-25 | pass→pass | 4,519 | 1,262 | -72% | 1 | 1 | 0% | 718 | 3,640 | +407% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +40 percentage points is the difference between those two pass rates over the 25 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.