feat(quantization): add calibration cache to quantize_static
Summary
- Add an optional
calibration_cache_pathparameter toquantize_static()so users can save and reload the calibration result (TensorsData) across runs. - Avoids re-running the expensive calibration inference pass when iterating on post-calibration options such as
nodes_to_exclude,activation_type, orweight_type. - Cache format is JSON, mirroring the encoder already used by
write_calibration_table— no new serialization surface area.
Motivation
Fixes #21908. Users commonly re-run quantize_static multiple times on the same model and calibration dataset while varying the set of excluded nodes or the quant types, to trade off accuracy vs. speed. Today, every call repeats the full calibration inference loop even though the calibration result is identical, which is costly on large calibration datasets. There was no supported way to persist the computed tensor ranges — write_calibration_table writes a lossy table (drops histogram data) and has no paired reader. This PR closes that gap.
Changes
python/tools/quantization/calibrate.py:- Add
TensorData.from_dictandTensorsData.from_dictclassmethods (inverse of existingto_dict). - Add module-level
_CalibrationCacheEncoder(json.JSONEncoder),save_tensors_data(tensors, path), andload_tensors_data(path). The encoder handlesTensorData/TensorsData/np.ndarray/CalibrationMethod/numpy scalars. Writes are atomic (tmp file +os.replace) and auto-create parent directories.
- Add
python/tools/quantization/quantize.py:quantize_staticgainscalibration_cache_path: str | Path | None = None. If the path exists, calibration is skipped and ranges are loaded from the cache. If the path is new, calibration runs and the result is saved. RaisesValueErrorif the cachedcalibration_methoddoes not match the caller'scalibrate_method.calibration_data_readerbecomes optional; at least one of it or an existing cache must be provided, elseValueError.
python/tools/quantization/__init__.py: exportTensorData,TensorsData,save_tensors_data,load_tensors_data.- Tests: new
TestCalibrationCacheintest/python/quantization/test_calibration.pycovering MinMax roundtrip, Entropy roundtrip (with histogram), missing-path error, parent-dir auto-creation, numpy scalarbinshandling, method-mismatch guard, end-to-endquantize_staticcache hit/miss, andValueErrorwhen neither reader nor cache is provided.
Test Plan
python -m pytest onnxruntime/test/python/quantization/test_calibration.py::TestCalibrationCache -vpython -m pytest onnxruntime/test/python/quantization/test_calibration.py::TestCalibrateMinMaxCalibrator -v(regression)lintrunner -aon changed files: clean.
Backward Compatibility
calibration_data_reader changes from required-positional to optional-keyword. Existing call sites — whether positional or keyword — continue to work unchanged. The new behavior is only engaged when calibration_cache_path is provided.