Skip to content

[Coverage] Direct unit-test suites for five untested core modules (conversion, core_utils, tensor_quantizer, model_calib, export/postprocess) — plus bugs found along the way #1902

Description

@arham766

Summary

While auditing test coverage, we found that several load-bearing modules have no direct unit-test file — they are exercised only incidentally through higher-level flows. We wrote hermetic, CPU-only unit suites (per CONTRIBUTING's tests/unit rules: fast, no network, no GPU) for five of them, adversarially reviewed and mutation-checked each suite, and will attach one PR per module so each is reviewable in isolation:

Module Suite Tests
torch/quantization/conversion.py test_conversion.py 63
torch/quantization/utils/core_utils.py test_core_utils.py 128
torch/quantization/nn/modules/tensor_quantizer.py test_tensor_quantizer.py 90 (incl. hand-computed INT8/FP8/block fake-quant values)
torch/quantization/model_calib.py test_model_calib.py 42
torch/export/postprocess.py test_postprocess.py 74 (TP/PP split layouts, padding math)

397 tests, ~4.2k lines, total runtime ~5s. Each suite was verified to kill seeded mutations of its target (wrong scale direction, flipped split axes, broken running-max, etc.), so this is regression-detection capacity, not line-count.

Bugs found while writing these (documented in-test with NOTE: documents current behavior comments; happy to file/fix separately as preferred)

  1. _normalize_fused_experts_quantizer_name collides with SequentialQuantizer child names (introduced in [NVBug 6108145] Fix PTQ calibration and export for fused-experts MoE (Qwen3.5-MoE VLM) #1340: the singular weight_quantizer.<N> pattern matches sequential children). Two consequences, both reproduced: (a) applying the same list-of-configs twice via set_quantizer_attributes_full nests SequentialQuantizers inside sub-slots (non-idempotent, corrupt state); (b) set_quantizer_attributes_partial with a list and a *weight_quantizer wildcard now raises ValueError mid-iteration for targets that are already sequential — a regression against its own docstring. Suggested fix: skip normalization when the matched quantizer's parent is a SequentialQuantizer.
  2. awq() silently no-ops on an unknown algorithm string (public __all__ API; only the mtq.quantize config layer validates the literal). One-line raise ValueError in an else would match the module's fail-fast style.
  3. TensorQuantizer.extra_repr dead code: the disabled branch builds a detailed string, then returns the literal "disabled", discarding it.
  4. update_lm_head_quantization warns "Enable lm_head quantization" even when quantizers are already disabled, and its sole call site (model_config_export.py:323) appears to pass inference_pipeline_parallel into the inference_tensor_parallel parameter.
  5. Minor exception-safety inconsistencies: replace_function/calibrate_with_adapters/enable_fake_quant yield without try/finally (unlike export_torch_mode et al.), so an exception mid-context leaks the patched state.

The behavior-documenting tests are written to fail-and-force-update when these are fixed.

PRs

Will be linked below, one per module, each self-contained.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions