Add optional MLflow tracking to hf_ptq.py - #2023
Conversation
Records a PTQ run on an MLflow server so it can be reproduced from its MLflow entry alone. Enabled by --mlflow <tracking-uri>; without the flag nothing changes. The run is opened before the model loads, so an unreachable server or a bad URI fails in seconds rather than after hours of calibration. The invocation and the recipe are uploaded at that point too, which keeps a crashed run useful: it is still recorded, with status FAILED and its log attached. Uploads command.txt, recipe/resolved_recipe.yaml, logs/hf_ptq.log and the quantization summaries, plus the model / format / calibration settings as searchable params. The recipe is uploaded resolved rather than verbatim because a recipe may be a directory or use $imports -- for the Qwen3.6 MoE AutoQuantize recipe the source file is 2.2 KB against 7.6 KB resolved, so only the resolved form describes what actually ran. hf_ptq.py has no logging framework, so the log is produced by teeing stdout/stderr. Handlers that libraries bound to sys.stderr at import time are re-pointed at the tee for the duration, otherwise transformers and huggingface_hub warnings reach the console but never the log. Experiment defaults to $USER/hf_ptq/<checkpoint basename>-<recipe name, or --qformat when no recipe>; run name defaults to the UTC start time. Only the main rank uploads. MLflow failures never fail the quantization. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Chenjie Luo <chenjiel@nvidia.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2023 +/- ##
==========================================
- Coverage 66.83% 66.82% -0.02%
==========================================
Files 519 519
Lines 58916 58916
==========================================
- Hits 39376 39370 -6
- Misses 19540 19546 +6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Promotes the tracking helper from examples/hf_ptq to modelopt.torch.utils.mlflow so other example scripts can record runs the same way. The move required decoupling it from hf_ptq: MlflowRunLogger took an argparse Namespace and read ten PTQ-specific attributes off it, which no other caller could supply. It now takes a tracking URI, an experiment name and an explicit enabled flag, with params, tags and artifacts passed in; default_experiment_name takes (tool, model, variant) rather than inspecting args. hf_ptq keeps the PTQ-specific parts in two small helpers. Uploading the recipe moved to the caller as part of that, which also drops the modelopt.recipe import from the library module -- keeping it would have risked a modelopt.torch.utils -> modelopt.recipe -> modelopt.torch.quantization -> modelopt.torch.utils cycle. The captured log now takes its name from sys.argv[0] instead of hardcoding hf_ptq. Also uploads the ModelOpt version as version.txt. It stays a tag as well: the tag is what makes runs filterable, the artifact is what travels with a downloaded run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Chenjie Luo <chenjiel@nvidia.com>
|
What does this PR do?
Type of change: new feature
Adds
modelopt.torch.utils.mlflow.MlflowRunLogger, a reusable helper for recording a script run on an MLflow tracking server, and wiresexamples/hf_ptq/hf_ptq.pyup to it via--mlflow <tracking-uri>so a PTQ run can be reproduced from its MLflow entry alone. Without the flag, behavior is unchanged — every hook is gated on it.The logger lives in the library rather than the example so other scripts can record runs the same way: it takes a tracking URI, an experiment name and an explicit
enabledflag, with params, tags and artifacts passed in.hf_ptq.pysupplies only the PTQ-specific pieces (its params, the resolved recipe, the quantization summaries).mlflowis an optional dependency, imported only once tracking is enabled, so it is not a new requirement for the library.The run is opened before the model loads, so a bad URI or an unreachable server fails in seconds rather than after hours of calibration. The invocation and the recipe are uploaded at that point too, which keeps a crashed run useful: it is still recorded, with status
FAILEDand its log attached.Uploaded artifacts:
command.txtversion.txtrecipe/resolved_recipe.yaml--recipewith$imports expandedlogs/hf_ptq.logsummary/quant_summary.txt--no-verbose)summary/moe.htmlPlus model / format / calibration settings as searchable params, and
user/hostname/modelopt_version/git_shatags.Three design points worth review:
$imports, so the source file is not self-contained. Forhuggingface/qwen3_6_moe/auto_quantize/w4a16_nvfp4_fp8_at_6p0bits-active_moethe source is 2,230 B / 58 lines against 7,563 B / 308 lines resolved — the raw file records under 30% of what actually ran.hf_ptq.pyhas no logging framework (bareprint()), so the log is produced by teeing stdout/stderr. Handlers that libraries bound tosys.stderrat import time are re-pointed at the tee for the run's duration and handed back afterwards; without that,transformers/huggingface_hubwarnings reach the console but never the log. Native (C-level) output is still not captured — documented in the README.modelopt.recipeout ofmodelopt.torch.utils, which would otherwise risk amodelopt.torch.utils→modelopt.recipe→modelopt.torch.quantization→modelopt.torch.utilsimport cycle.Only the main rank uploads, so
--use_fsdp2runs produce a single run.Usage
--mlflow_experimentand--mlflow_run_nameoverride the defaults ($USER/hf_ptq/<basename>-<recipe name or --qformat>, and the UTC start time). Passing--mlflowwith no value uses$MLFLOW_TRACKING_URI. Authentication uses MLflow's own env vars.Testing
Unit — 26 tests in
tests/unit/torch/utils/test_mlflow.pyfor the library, plus 8 intests/examples/hf_ptq/test_hf_ptq_args.pyfor the hf_ptq wiring. CPU-only, no network and nomlflowdependency (driven against a stub module). Covers experiment-name derivation and sanitization, URI accept/reject, tee pass-through, the pre-bound-handler redirect, artifact renaming, skipping absent optional outputs, the disabled path, andversion.txt. 56 tests pass together with the existingtest_hf_ptq_args.py/test_example_utils.py.Hardware — real PTQ runs against a live MLflow server:
FINISHED, all artifacts, sane post-quant generationsw4a16_nvfp4_fp8_at_6p0bits-active_moe, 2×B200FINISHEDin 63 min, search hiteffective bits: 6.00; 106 KB log capturing every per-layer decision, 4.4 MB quant summaryFINISHEDFINISHED, all five artifacts includingversion.txtFAILEDrecorded with log + traceback attached, summaries correctly absentargparsewith aDid you mean https://…?hint--mlflowCoverage gap, stated plainly:
summary/moe.htmlis verified only against a synthetic file (unit test + a real upload). It could not be produced naturally —expert_token_countbuffers live on_QuantSparseSequentialMoe, while Qwen3.5/3.6 experts take the fused_QuantFusedExpertspath, so no such file is written for these models regardless of--moe_calib_experts_ratio. The uploader's conditional is correct; the branch simply had no natural input available here.Before your PR is "Ready for review"
--mlflowmeans no behavior change.CONTRIBUTING.md: ✅ — addsmlflowtoexamples/hf_ptq/requirements.txt. Apache-2.0 (permissive). No code copied from other sources.Additional Information
Draft: the
summary/moe.htmlpath would benefit from one run on a sparse-sequential MoE model before this is marked ready.🤖 Generated with Claude Code