GPT-QModel lazy-load smoke testing
This skill describes how to exercise the lazy checkpoint path on CPU and verify that the first decoder layer is correctly materialized during StageInputsCapture.cache_inputs.
When to use
- A PR touches
gptqmodel/looper/module_looper.py,gptqmodel/looper/stage_inputs_capture.py,gptqmodel/models/base.py, orgptqmodel/utils/structure.py. - You need to verify that
shell_module_materializereceives a dottedmodule_pathsuch asmodel.layers.0instead ofNoneor a class name. - You want to confirm that
LazyTurtle.materialize_submoduleloads real parameters/buffers (notmeta) and that forward/generate runs withoutAttributeErrororNaN.
Devin Secrets Needed
None for CPU-only smoke testing. If GPU testing is required, set CUDA_VISIBLE_DEVICES as appropriate and use device="cuda".
Environment prerequisites
- Install system development headers; otherwise torch inductor /
cpp_extensionJIT builds forpack_block_cpufail withPython.h: No such file or directory:sudo apt-get update -qq && sudo apt-get install -y -qq python3-dev python3.10-dev - Install the CPU torch stack and project dependencies:
pip install -U pip pip install --index-url https://download.pytorch.org/whl/cpu torch torchvision pip install -r requirements.txt pip install -e . --no-build-isolation --no-deps - Verify
gptqmodelis importable from the repo root:python -c "import gptqmodel; print(gptqmodel.__version__)"
Minimal fixture
Build a tiny LlamaForCausalLM and save it to a temp directory. The fixture should be small enough to quantize in seconds on CPU:
from transformers import LlamaConfig, LlamaForCausalLM, PreTrainedTokenizerFast
from tokenizers import Tokenizer, models, pre_tokenizers, trainers
import torch, os, tempfile
config = LlamaConfig(
vocab_size=128,
hidden_size=64,
intermediate_size=96,
num_hidden_layers=1,
num_attention_heads=4,
max_position_embeddings=128,
)
model = LlamaForCausalLM(config)
tok = Tokenizer(models.WordLevel(unk_token="<unk>"))
tok.pre_tokenizer = pre_tokenizers.Whitespace()
tok.add_special_tokens(["<s>", "</s>", "<unk>", "<pad>"])
tok_trainer = trainers.WordLevelTrainer(
special_tokens=["<s>", "</s>", "<unk>", "<pad>"], vocab_size=128
)
tok.train_from_iterator(
["the quick brown fox", "lorem ipsum dolor", "hello world"],
trainer=tok_trainer,
)
hf_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tok, pad_token="<pad>")
tmp = tempfile.mkdtemp()
model.save_pretrained(tmp)
hf_tokenizer.save_pretrained(tmp)
Lazy-load + input-capture test
from gptqmodel import GPTQModel, BACKEND
from gptqmodel.models.base import QUANT_CONFIG_NAME
from gptqmodel.quantization.config import QuantizeConfig
calibration = [
{"text": "the quick brown fox jumps over the lazy dog"},
{"text": "lorem ipsum dolor sit amet"},
{"text": "hello world this is a test"},
]
qcfg = QuantizeConfig(
bits=4,
group_size=32,
desc_act=False,
device="cpu",
)
model = GPTQModel.load(
tmp,
quantize_config=qcfg,
backend=BACKEND.TORCH,
)
assert model.turtle_model is not None
Capture the materialization path
Wrap model.shell_module_materialize to record the module_path passed during cache_inputs:
calls = []
orig = model.shell_module_materialize
def capture(*args, **kwargs):
calls.append((args, kwargs))
return orig(*args, **kwargs)
model.shell_module_materialize = capture
model.quantize(
calibration,
batch_size=1,
backend=BACKEND.GPTQ_TORCH,
calibration_data_min_length=1,
)
first_call_args, first_call_kwargs = calls[0]
module_path = first_call_kwargs.get("module_path")
assert module_path == "model.layers.0", module_path
Verify first-layer materialization
After model.quantize reaches cache_inputs, inspect the first decoder layer:
first_layer = model.model.model.layers[0]
devs = {p.device.type for p in first_layer.parameters()}
assert "meta" not in devs, f"first layer still has meta parameters: {devs}"
assert not any(torch.isnan(p).any() for p in first_layer.parameters())
Save, reload, and generate
quantized_dir = os.path.join(tmp, "quantized")
model.save(quantized_dir)
qmodel = GPTQModel.load(
quantized_dir,
backend=BACKEND.GPTQ_TORCH,
device="cpu",
)
in_ids = torch.tensor([[2, 5, 11]])
out = qmodel.generate(
input_ids=in_ids,
attention_mask=torch.ones_like(in_ids),
max_new_tokens=4,
do_sample=False,
)
assert out.shape == (1, in_ids.shape[1] + 4)
assert not torch.isnan(out).any()
Expected log signals
INFO Loader: using checkpoint-backed lazy turtle source for /tmp/...INFO ModuleLooper: capturing layer inputs from N calibration batches[test] first materialized module path: 'model.layers.0'[test] generate output shape: torch.Size([1, 6])[test] PASS
Common issues
Python.h: No such file or directoryduringTorchLinearforward: installpython3-dev/python3.10-devand rerun.torchaoextension load warnings (_C_cutlass_90a.so,_C_mxfp8...so) are non-fatal on CPU.Calibration dataset size should be more than 256warnings are expected for tiny smoke fixtures.- If
module_pathisNone, the new resolution logic instage_inputs_capture.pywas not reached orlayer_nameswas not propagated frommodule_looper.py.
Regression test reference
tests/test_stage_inputs_capture.pycovers themodule_pathresolution paths.- For end-to-end validation, run
smoke_lazy_load.pyfrom the repo root.