Commit 5f88cf2
feat(export): export each decoder layer as layerwise calibration finishes it
A PTQ run that outlasts its GPU session loses every calibrated layer, and a
completed one still pays for a second whole-model export pass over a
full-precision intermediate checkpoint.
Add layerwise.export_dir: each decoder layer's final quantized tensors are
flushed to their own shard the moment calibration finishes with it, so the shards
double as the resume artifact. Combined with layerwise.checkpoint_dir a restarted
run skips layers already on disk instead of recalibrating them, and the per-layer
weights.pt / quantizer_buffers.pt files are no longer written. When the last layer
lands the directory is already a complete, loadable checkpoint, so
export_hf_checkpoint() is skipped. Setting the field is the whole switch;
hf_ptq.py rewrites it to --export_path, as it already does for checkpoint_dir.
One layer per shard is what makes that work: a shard is only ever written whole,
its name derives from the layer index, and the index is rebuilt at the end from
the shards on disk. A crash can lose the layer in flight but never corrupt an
earlier one, and a re-run overwrites in place rather than appending duplicates.
Resident modules have no materialization window to discard export's damage, so
transient_module_state snapshots the layer subtree's _parameters/_buffers/_modules
and restores them, leaving calibration free to run every later layer through it.
Tied-weight dedup is off here for the reason registry.py already turns it off for
offload: data_ptr() cannot identify a tensor across an export that keeps rolling
packed weights back. Weight-tied quantized modules are refused up front anyway.
NVFP4 works because export_layer rediscovers the scale-fusion groups itself: the
groups _fuse_shared_input_modules operates on -- q/k/v behind input_layernorm,
gate/up behind post_attention_layernorm -- never cross a layer boundary, so a
probe forward over one layer finds them. The probe uses that layer's real cached
activations rather than the synthetic input the whole-model pass builds.
Scope is resident, single-process models. AWQ and SVDQuant additionally need
requantize_resmooth_fused_llm_layers' pre-quant-scale steps, which are still
whole-model, so they stay refused along with accelerate offload, multi-process
jobs, weight-tied quantized modules,
multimodal models, MTP models and speculative decoding are refused with
NotImplementedError before calibration starts; each would otherwise produce a
silently different checkpoint rather than fail. A resumed run never recalibrates
the layers it skipped, so the in-memory model is not valid for inference and
layerwise.export_dir implies --skip_generate.
Two pieces move out of this path to avoid duplicating what already exists:
save_non_weight_artifacts() is extracted from the streaming exporter's tail, and
FUSION_FREE_FORMATS moves to model_config.py, where _fuse_shared_input_modules
had held the same set inline as a literal list.
Verified byte-identical to export_hf_checkpoint on Qwen3.6-35B-A3B (text-only,
FP8, 256 experts per layer): 93,273 tensors, 0 mismatched, and identical again
after a simulated mid-model resume. NVFP4 equivalence is covered by a GPU test.
The NVFP4 test leaves o_proj unquantized: layerwise calibration leaves its input
amax at 0 on every layer but the last, which no export path can write. That is a
pre-existing bug, unrelated to per-layer export.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Fridah-nv <201670829+Fridah-nv@users.noreply.github.com>1 parent dc5a47c commit 5f88cf2
14 files changed
Lines changed: 999 additions & 56 deletions
File tree
- examples/hf_ptq
- modelopt_recipes/general/ptq
- modelopt/torch
- export
- quantization
- utils
- tests
- gpu/torch/export
- unit/torch/quantization
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1166 | 1166 | | |
1167 | 1167 | | |
1168 | 1168 | | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
1169 | 1181 | | |
1170 | 1182 | | |
1171 | 1183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
814 | 815 | | |
815 | 816 | | |
816 | 817 | | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
817 | 865 | | |
818 | 866 | | |
819 | 867 | | |
| |||
915 | 963 | | |
916 | 964 | | |
917 | 965 | | |
918 | | - | |
919 | | - | |
920 | | - | |
921 | | - | |
922 | | - | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
923 | 982 | | |
924 | 983 | | |
925 | 984 | | |
| |||
1200 | 1259 | | |
1201 | 1260 | | |
1202 | 1261 | | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
1203 | 1270 | | |
1204 | 1271 | | |
1205 | 1272 | | |
| |||
1332 | 1399 | | |
1333 | 1400 | | |
1334 | 1401 | | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
1335 | 1407 | | |
1336 | 1408 | | |
1337 | 1409 | | |
| |||
0 commit comments