qpatch
Automatic fixes for quantized model fine-tuning.
qpatch monkey-patches known incompatibilities when training 4-bit/8-bit quantized models with LoRA adapters — especially on models with custom CUDA kernels (Mamba, MoE, RWKV, xLSTM).
The Problem
QLoRA training fails on many non-standard architectures with cryptic errors:
AttributeError: 'NoneType' object has no attribute 'get' # safetensors metadata
RuntimeError: expected mat1 and mat2 to have the same dtype # uint8 vs float16
RuntimeError: mat1 and mat2 shapes cannot be multiplied # fused kernels + 4-bit
RuntimeError: index_add_(): self (BFloat16) and source (Float) # MoE dtype mismatch
RuntimeError: "fused_dropout" not implemented for 'Byte' # dropout on uint8
The Fix
import qpatch
qpatch.patch_all()
# That's it. Now train normally.
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
model = AutoModelForCausalLM.from_pretrained(
"nvidia/Nemotron-3-Nano-30B",
quantization_config=BitsAndBytesConfig(load_in_4bit=True),
device_map="auto",
trust_remote_code=True,
)
model = get_peft_model(model, LoraConfig(r=32, target_modules=["up_proj", "down_proj"]))
trainer.train() # Just works
What It Fixes
| Issue | Error | Affected Models |
|---|---|---|
| Safetensors metadata | 'NoneType' has no attribute 'get' |
Any model with metadata-less safetensors |
| LoRA dtype cast | unsigned char != c10::Half |
Any 4-bit model with LoRA |
| MoE dtype mismatch | index_add_(): BFloat16 and Float |
Nemotron, Mixtral, any MoE |
| Fused kernel bypass | shapes cannot be multiplied |
Mamba, Nemotron-H, hybrid architectures |
Install
pip install qpatch
Individual Patches
Apply only what you need:
import qpatch
qpatch.patch_safetensors_metadata() # Fix None metadata in safetensors
qpatch.patch_lora_dtype_cast() # Cast uint8 inputs to float16
qpatch.patch_moe_dtype_mismatch() # Auto-cast MoE index_add_ dtypes
qpatch.patch_fused_kernel_bypass() # Skip fused kernels for quantized models
GPU Architecture Notes
- Volta (V100, GV100): Use
qpatch.patch_all(compute_dtype=torch.float16)— Volta does not support bf16 - Ampere+ (A100, H100): Use
qpatch.patch_all(compute_dtype=torch.bfloat16)
How It Works
qpatch applies targeted monkey-patches at import time:
patch_safetensors_metadata— Wrapstransformers.modeling_utils.load_state_dictto detect None metadata and fall back tosafetensors.torch.load_filepatch_lora_dtype_cast— Wrapspeft.tuners.lora.bnb.Linear4bit.forwardto cast uint8 inputs to the compute dtypepatch_moe_dtype_mismatch— Wrapstorch.Tensor.index_add_to auto-cast source tensors when dtypes mismatchpatch_fused_kernel_bypass— Scans HuggingFace's cached model code and replaces fused-path conditions withif False:to force the quantization-safe slow path
All patches are idempotent — calling patch_all() multiple times is safe.
Tested With
- Nemotron-3-Nano-30B (Mamba hybrid)
- Transformers 4.46–5.3
- PEFT 0.12–0.18
- bitsandbytes 0.42–0.49
- PyTorch 2.5–2.10
- CUDA 12.2–12.8
- Volta (GV100), Pascal (P100), Ampere (A100)
License
MIT
Citation
@software{bond2026qpatch,
author = {Bond, Andrew H.},
title = {qpatch: Automatic fixes for quantized model fine-tuning},
year = {2026},
url = {https://github.com/ahb-sjsu/qpatch},
}
Metadata
Release files for qpatch 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| qpatch-0.2.0.tar.gz | 15.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qpatch-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.6 kB
Release files / qpatch-0.2.0.tar.gz
| Download URL | qpatch-0.2.0.tar.gz |
|---|---|
| Size | 15.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d25d7ff1ce6df31967d7398038156dfae8d33126b0e2a518891ad3b0144d56c5
|
|
BLAKE2b-256 checksum How to use checksums |
b8208cd3ac2b83fc45fcb040c131d6ac6a9899df4aac185fa15e4af459769def
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.2
|
Release files / qpatch-0.2.0-py3-none-any.whl
| Download URL | qpatch-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c3ae6e9eda4701444c814f19e24580d6a5a3802274b7b073898305d58072ee31
|
|
BLAKE2b-256 checksum How to use checksums |
9f78dedf6710167ff5816f791488aa0d7ee90179a0e50a2ede0c3a7647141ed1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.2
|
Security for qpatch 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.