Repository navigation
[OMNIML-6085] [21/21] Run expert-parallel PTQ from hf_ptq.py - #2754
Open
shengliangxu wants to merge 29 commits into
Open
shengliangxu wants to merge 29 commits into
shengliangxu wants to merge 29 commits into
Conversation
|
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. |
Contributor
shengliangxu
added this pull request to stack #2755
October 12, 2026 00:57
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 12, 2026 01:11
b298b8a to
9364c1b
Compare
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 12, 2026 02:44
9364c1b to
9d9b154
Compare
Contributor
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## shengliangx/hfep-11c-kimi-k3 #2754 +/- ##
===============================================================
Coverage ? 62.28%
===============================================================
Files ? 667
Lines ? 74107
Branches ? 0
===============================================================
Hits ? 46159
Misses ? 27948
Partials ? 0
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:
|
Collaborator
Author
|
/ok to test 9d9b154 |
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 12, 2026 08:39
9d9b154 to
487a8e8
Compare
Collaborator
Author
|
/ok to test 487a8e8 |
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 13, 2026 00:53
487a8e8 to
c8d0e4f
Compare
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 13, 2026 01:32
c8d0e4f to
22ac8fc
Compare
Collaborator
Author
|
/ok to test 22ac8fc |
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 13, 2026 17:41
22ac8fc to
d2b13df
Compare
shengliangxu
removed this pull request from stack #2755
October 13, 2026 17:42
shengliangxu
changed the base branch from
shengliangx/hfep-13-ep-export
to
shengliangx/hfep-13b-load-routing
October 13, 2026 17:42
shengliangxu
added this pull request to stack #2775
October 13, 2026 17:43
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 13, 2026 19:38
d2b13df to
f9293cd
Compare
Base automatically changed from
shengliangx/hfep-13b-load-routing
to
shengliangx/hfep-13-ep-export
October 13, 2026 19:38
shengliangxu
removed this pull request from stack #2775
October 13, 2026 19:38
shengliangxu
added this pull request to stack #2781
October 13, 2026 19:40
shengliangxu
force-pushed
the
shengliangx/hfep-14-hf-ptq
branch
from
October 13, 2026 21:12
f9293cd to
3be65ef
Compare
hf_ptq already had a distributed path, but only one: --use_fsdp2, which shards a dense model and replicates every expert of a MoE, so the documented CLI -- recipes, export formats, the flag deprecations -- did not reach an expert-parallel run. A distributed launch now runs inside a ModelOptSession, which owns the process group and is what the expert-parallel loader reads its rank and device from. args.dist_state becomes a view of that session rather than a second, independently derived one. load_model decides the plan after applying the model's spec -- for several models the spec is what supplies the base_model_ep_plan, so deciding first would see an expert-parallel-capable MoE as dense -- and gains an expert-parallel arm ahead of the FSDP2 one. It is an arm of the same chain rather than an early return, so the shared post-processing (tokenizer, VLM language-model extraction) still runs. --use_fsdp2 skips the decision entirely, so an explicit request for the FSDP2 loader is honored. MODELOPT_EP_DEGREE and MODELOPT_FSDP_SIZE override the automatic degrees. A model that CAN be expert-parallel but resolves to no sharding at all raises: that configuration runs and quietly replicates the whole MoE on every rank. Every distributed path calibrates on its own 1/world shard of the data, and through distributed_forward_loop, which re-plants the torch_a2a forward wrappers quantizer insertion clobbers on transformers >= 5.16 (without it the experts forward runs with no EP process group and raises at the first step). A dense model under torchrun is placed on this rank's GPU rather than by accelerate's "auto" heuristic, which picks the same card on every rank of an idle node and aborts the first collective with "Duplicate GPU detected". Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Rebasing onto a main that had opened a new release section left the entry where its context matched: in the Misc list of 0.47.0, a release that has already shipped. It belongs with the other new quantization features of 0.49.0, the section main opened for what merges after 0.48.0's cut. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Cover how hf_ptq.py runs under torchrun: - the MODELOPT_EP_DEGREE / MODELOPT_FSDP_SIZE knobs, read at call time; - applying a model's spec before the EP decision; - the decision itself: the auto degree, the knobs overriding it, --use_fsdp2 and single-process runs opting out, an unsharded MoE refused; - load_model handing an EP plan to load_and_prepare_ep and to no other loader; - each rank pinning a model to its own GPU; - dist_state following the torchrun session; - main() closing the session even when the run raises; - calibration on per-rank data through distributed_forward_loop. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Only the expert-parallel loader shards a dense part by itself. When the plan asked for dense sharding (MODELOPT_FSDP_SIZE, or "auto" finding the dense part too big for one GPU) but resolved to ep_size=1, the decision returned no plan without complaint, and load_model replicated the whole model -- MoE or dense -- on every rank. The error for an unsharded MoE even recommended MODELOPT_FSDP_SIZE=world, which only silenced it. Raise instead, pointing at --use_fsdp2 (and at MODELOPT_EP_DEGREE for an MoE), and drop the bad advice and the unreachable --use_fsdp2 check. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
get_model pinned every indexed device to that one GPU so that torchrun's ranks stop sharing a card, but it did so for a single process too: a run passing --device cuda:0 no longer spread a model too big for one GPU across the others, as it did before. Pin only when the run has more than one rank. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Say what running hf_ptq.py under torchrun does to an MoE, how to launch it on one node or several, what MODELOPT_EP_DEGREE and MODELOPT_FSDP_SIZE override, and which models it refuses. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Every distributed run calibrated through distributed_forward_loop, which moved --use_fsdp2 off main's create_forward_loop and with it the split-on-OOM retry and the encoder-decoder generate path. Only expert parallelism needs the distributed loop -- it re-plants the all-to-all forwards quantizer insertion clobbers -- so it is now chosen from the session's ep_mesh, which load_and_prepare_ep records, and FSDP2 keeps the plain loop. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
launch_memory_monitor checks that NVML can report memory before starting the monitor, so hosts where it cannot (#374) skip monitoring instead of crashing. But the probe ran before nvmlInit, which only GPUMemoryMonitor's constructor calls, so every NVML call in it raised NVMLError_Uninitialized: the monitor printed "Failed to get GPU memory info: Uninitialized" and never started on any host. hf_ptq.py launches it on every run, so no run has reported its per-GPU peak memory since. The probe now initializes NVML for itself and shuts it down afterwards, so the init count stays balanced with the monitor's own. Hosts where memory info is unsupported still skip the monitor. Unit tests run launch_memory_monitor against a fake, reference-counted NVML: the monitor starts when memory info is available (this fails on the old code), and is skipped with NVML left shut down when it is not. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
get_model now loads through load_pretrained(ckpt_path, auto_class, ...), which replaced example_utils' own recording loader. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The expert-parallel and --use_fsdp2 runs now load through load_pretrained, with the plan or "fsdp2", instead of calling load_and_prepare_ep and parallel_load_and_prepare_fsdp2 themselves, so they get its checks: the expert-parallel run now refuses a Nemotron-H MTP checkpoint it would have exported with the head unquantized. resolve_distribution_plan takes over the decision, including the refusal to replicate an expert-parallel MoE on every rank; this script keeps only its own rule that FSDP2 runs under --use_fsdp2. get_model and the low-memory load ask for "sequential": their run is already decided, and they place the model themselves. The tests of the decision itself moved with it to test_load_pretrained_distribution.py. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
hf_ptq's FSDP2 load now goes through load_pretrained, so the test that checks the MTP refusal comes before it stubs that instead of parallel_load_and_prepare_fsdp2, which hf_ptq no longer imports. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The plan is now decided through the session, whose decide is collective. These tests are about what gets decided, so each simulated rank acts as its group's first. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…EP mesh where needed main() runs inside distributed_run, which sets the process group up on a distributed launch and tears it down even when the run raises. The example's DistributedState reads rank and world from that group, the calibration data is sharded by it, and an expert-parallel model calibrates through distributed_forward_loop with the mesh its experts are sharded over (expert_parallel_mesh). Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…ibutes hf_ptq.py decides the plan up front with resolve_distribution_plan, --use_fsdp2 asking it for FSDP2 without expert parallelism, and loads every model by it through load_pretrained, get_model's whole-model loads and the low-memory load included. A plan that FSDP2-shards the whole model still needs --use_fsdp2, whose checks now run before anything is set up. Everything after reads the plan back from the model instead of the flag or the process group: the calibration device, the data sharding, the expert-parallel calibration loop, and get_model's pinning of each rank's whole model to its own GPU. The one-rank process group FSDP2 shards through is set up for the plan, right before the load, and torn down with the run; a distributed launch's group stays distributed_run's. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
hf_ptq built its DistributedState itself, in setup_distributed_args, from the process group distributed_run had just set up. distributed_run yields that state now, so main() hands it to the run, with --device for a single process, and the example's own class and setup are gone. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
hf_ptq set up the one-rank group FSDP2 needs in a single process and tore it down in its own finally. Both live in modelopt's distributed module now: load_model sets the group up with setup_fsdp2_process_group, keeping its two-hour collective timeout, and distributed_run destroys it with the run, as it does a launch's. The example's own helpers go. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
load_pretrained sets up the one-rank group its FSDP2 load shards through ([3/21]), and distributed_run destroys it with the run, so hf_ptq no longer sets it up before loading. The group keeps PyTorch's default collective timeout: on one rank no collective waits for a peer, which is what the two hours were for. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Each rank previews the first sample of its own calibration shard, so the ranks reach EOS at different steps. Under expert parallelism, or with the dense part FSDP2-sharded, every forward runs a collective (the experts' all-to-all, FSDP2's all-gathers), and a rank that stopped decoding left the others blocked in it: Qwen3-30B-A3B at NVFP4 and EP4 hung in the post-PTQ preview, while the same run with --skip_generate finished. The previews, Nemotron-VL's included, now generate with synced_gpus when the model's plan shards it, so every rank keeps stepping until all have finished. The preview tests' stand-in models are modules now, since the previews read their distribution plan. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…ge preview A one-rank FSDP2 plan needs no lockstep, but no case pinned it, so a check dropping world_size went unnoticed. The Nemotron-VL test stubbed vlm_utils whole, so nothing checked that the image preview merges the kwargs it is handed into the config its chat() gets. Both gaps found by the epdp port. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
A dense model under torchrun gets a replicated plan, and every rank then ran the export into the same directory, racing each other's files and the in-place config.json rewrite. Rank 0 alone writes a replicated model; a sharded one still needs every rank. The source config of a multimodal model is rank 0's in every plan: another rank's, written after rank 0's export, would replace the config.json carrying the quantization config. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
With fewer expert-parallel ranks than the world (the automatic degree when the world size does not divide the expert count), FSDP2 shards the dense part within each replica. The no-gather export cannot write that layout, and found out only after the load and the whole calibration. Refuse the plan up front and name the settings that avoid it. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…ches resolve_distribution_plan reads the checkpoint through the failure-carrying all_reduce, which gathers from every rank of a launch. The torchrun fixture answers that gather as it answers the plan's broadcast: every rank read the checkpoint as this one did. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Nothing ran examples/hf_ptq/hf_ptq.py expert-parallel: its wiring tests approximate a torchrun launch with stubbed collectives, loaders and forward loops. The new test launches it under torchrun on two GPUs with MODELOPT_EP_DEGREE=2 on a tiny Qwen3-MoE, calibrates FP8 on a local calibration file, and checks that every expert of every layer is exported FP8 with its scale: a rank whose share of the experts is lost, or written under the wrong expert index, fails it. It skips below two GPUs, so it runs on the multi-GPU runners. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
- The single-process and dense-under-torchrun plan tests go: the library's single-process tests and the get_model load test fail on the same regressions. - The EP and --use_fsdp2 load_pretrained-call tests become one table; the get_model test stays, a different loader and device placement. - The two calibration-loop tests become one parametrized test, its helper inlined. - The memory-monitor pair becomes one parametrized test. - Kept: the Nemotron-VL preview test's full plan table, whose cases are the only guard of the VL preview's own lockstep decision (a VL preview deciding by expert parallelism alone fails only [fsdp2], one ignoring the world size only [one_rank_fsdp2]); and the main-owns-the-process- group test, the only guard of main's collective timeout above NCCL's default, which the GPU smoke test runs too briefly to reach. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
That exporter reads the process count as Megatron's training tensor parallelism. Under torchrun with a replicated plan, rank 0 ran it alone and waited in its barrier for ranks that had already returned; run on every rank, it would merge whole replicas as if they were shards. hf_ptq now refuses an encoder-decoder, sparsity or int8_smoothquant export with more than one process before it loads the model. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
hf_ptq picked the VLM calibration loop for image calibration before it checked for expert parallelism, so an expert-parallel run with images never re-planted the all-to-all forwards that quantizer insertion drops. On transformers 5.16 and later, the first routed forward then raised for want of the EP process group. Nemotron-H Omni, which has an EP spec and calibrates on images by default, hit this with default flags. distributed_forward_loop now takes an optional per-batch forward, and the VLM loop's per-batch call is factored out as create_vlm_calibration_forward. An expert-parallel image run calibrates through distributed_forward_loop with that forward on the whole VLM. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
resolve_distribution_plan now hands ensure_local_checkpoint token, cache_dir and local_files_only. The stub these tests put in its place took only the path and the group, so every test that reached the plan's checkpoint read failed with an unexpected keyword. (Found by the epdp port.) Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…s preview On a GPU, Transformers' generate runs the experts of a grouped_mm MoE on batched_mm for the decoding stage and switches them back (_optimize_model_for_decode, Transformers 5.0 and later). Two things follow. An FSDP2-wrapped model, whose class is a subclass built outside its modeling module, is refused the switch. A Qwen3-30B-A3B run under --use_fsdp2 on 4 GPUs failed in the pre-quantization preview with "FSDPQwen3MoeForCausalLM does not support setting experts implementation" (Transformers 5.13). And ModelOpt's quantizers sit on the eager, grouped_mm and torch_a2a forwards, which batched_mm bypasses, so the preview after PTQ of any grouped_mm MoE on a GPU decoded on unquantized experts. That predates the FSDP2 and expert-parallel work. The pre- and post-quantization previews and the Nemotron VL preview now run inside a context manager that keeps generate's hook off the model and puts it back. A model without the hook is left alone. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…FSDP2 The two-GPU hf_ptq test skipped generation, so no test reached a sharded preview. A real Qwen3-30B-A3B run did: under FSDP2 Transformers refused the experts switch generate makes for an FSDP2-wrapped class, after the previews of an earlier round had hung ranks that finished decoding at different steps. The test now runs both plans, expert parallelism and FSDP2, with the previews on, on a tiny Qwen3-MoE. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Collaborator
Author
|
/ok to test fb135b1 |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Type of change: New feature
hf_ptq.pyhad one distributed path,--use_fsdp2, which shards a dense model and replicates every expert of an MoE. This PR wires the expert-parallel path ([1/21]-[20/21]) into it, so the documented CLI reaches an expert-parallel run: recipes, export formats, deprecations.main()runs insidedistributed_run([4/21]), which owns the process group on a distributed launch. The run takes this process'sDistributedState(rank, size, device) from it, with--devicefor a single process. FSDP2 on one rank still shards through a process group, of one, which the load sets up ([6/21]) anddistributed_rundestroys with the run. The example's ownDistributedState,setup_distributed_argsand process-group helpers are gone.load_modeldecides the plan once, withresolve_distribution_plan([5/21], [12/21], [13/21]), and loads every model by it throughload_pretrained([6/21]): expert-parallel, FSDP2,get_model's whole-model loads and the low-memory load. Everything after reads the plan back from the model, not the flag or the process group: the calibration device, the data sharding, the calibration loop, andget_model's GPU placement.MODELOPT_EP_DEGREEandMODELOPT_FSDP_SIZEoverride the automatic choices.--use_fsdp2asks the decision for FSDP2 and no expert parallelism.--use_fsdp2, the flag this script's FSDP2 checks hang on, which now run before anything is set up.resolve_distribution_planrefuses a plan that would quietly replicate an expert-parallel-capable MoE, and a model whose spec refuses expert parallelism (GPT-OSS, Llama-4, [13/21]) raises unless--use_fsdp2rules expert parallelism out. A plan that FSDP2-shards the dense part within several expert-parallel groups (the automatic degree when the world size does not divide the expert count), which the export cannot write yet, raises before loading and names the settings that avoid it.config.json. A multimodal model's source config is rank 0's in every plan.Every distributed run calibrates on its own 1/world shard of the data ([8/21]).
Expert-parallel runs go through
distributed_forward_loop, which re-plants the all-to-all forwards that quantizer insertion clobbers on transformers 5.16 and later.FSDP2 keeps main's plain loop, with its split-on-OOM retry.
The calibration algorithms under a plan that spans several ranks:
max(amax all-reduced over the data-, expert- and tensor-parallel groups),mse(searches the weights max leaves identical on every rank)gptq(Hessians merged across each module's data-parallel replicas),smoothquant(scales from max's synced amax),nvfp4_act_headroom(activation scales MAX-reduced over data parallelism)awq_lite,awq_clip,awq_full,svdquant,local_hessian,imatrix, andmaxormsewithdistributed_syncoff, also as another algorithm's weight or scale algorithm: each keeps its statistics on its rank, so the ranks' copies of a weight would come out differentlsq's learnable scales (its first scale calibration follows the rows above)synced_gpuswhen the model's plan shards it.launch_memory_monitorprobed NVML before initializing it. Every probe raisedUninitialized, so the per-GPU peak-memory report never started on any host where nothing else had initialized NVML. The probe now initializes NVML itself.Usage
# One node, 8 GPUs: the experts shard over all 8 ranks, each calibrating its own data. torchrun --nproc_per_node 8 examples/hf_ptq/hf_ptq.py \ --pyt_ckpt_path Qwen/Qwen3-30B-A3B --qformat nvfp4 --export_path /out/qwen3-30b-a3b-nvfp4Testing
tests/examples/hf_ptq/test_hf_ptq_expert_parallel.py(31 cases; the decision itself is tested in [5/21], [12/21] and [13/21]):--use_fsdp2, and FSDP2 sharding refused unless--use_fsdp2;load_modelloading by the plan: an EP plan and--use_fsdp2throughload_pretrainedand no other loader, a data-parallel one throughget_model;main()running insidedistributed_run, which it leaves even when the run raises, and handing the run the statedistributed_runyields, with--devicefor a single process;synced_gpusexactly when the plan shards the model (EP or FSDP2 over several ranks);test_ptq_qwen3_moe_expert_parallel(tests/examples/hf_ptq/test_llm_ptq.py):torchrun --nproc_per_node 2 hf_ptq.pywithMODELOPT_EP_DEGREE=2on a tiny Qwen3-MoE and the FP8 recipe. It checks that every expert of both ranks is exported FP8 with its weight scale, and that the config names FP8. It is the tests' one real expert-parallel run of the script; the file above covers the wiring with stand-ins. It passed on 2 GB200s in 29.5 s at f4bb395488 (2026-10-16), which carries this test on a revision before the latest loader and calibration fixes ([7/21], [8/21]). It skips on CI's 1-GPU PR runner and runs on 2-GPU runners.tests/examples/hf_ptq/test_hf_ptq_model_type.py(main's): the preview tests' stand-in models are modules now, since the previews read their distribution plan.tests/unit/torch/utils/test_memory_monitor.py, against a fake reference-counted NVML: the monitor starts when NVML can report memory (this fails on the old code), and is skipped with NVML shut down when it cannot.get_model's tests cover are dropped, and the load-call, calibration-loop and memory-monitor pairs are one parametrized test each. Each drop is checked by mutation.load_pretrained([6/21], [12/21]); this revision's GPU tests run in CI only. The series' GPU tests on this branch: 19 passed on a 4-GPU node. On 1 GPU, CI's PR runner, 6 passed and 13 skipped. They cover:nox -s gpu(all oftests/gpu, 1 GPU, CI's PR-runner shape): every test failing on this branch also fails at the base, and the only new tests are the series' own.tests/examples/hf_ptq, TensorRT-LLM image, 1 GPU): no outcome changes on the 296 shared tests. The series' 30 pass, except 2 that need transformers 5.7.tests/gpu_megatron(2 GPUs): no outcome changes over the 311 tests both runs reached. The rest time out identically at the base in that image.Qwen3-30B-A3B at EP16 over 4 nodes, NVFP4 and FP8: the exports with the dense part FSDP-sharded over the world and with it replicated have byte-identical weights and weight scales; only calibration-derived input scales differ. Every dense FP8 weight is FP8 with its scale, and no NVFP4 weight has the all-zero high nibbles of a lost pack shift.
Qwen3-VL-30B and MiniMax-M3: tensor counts match single-GPU exports, and every expert weight is packed.
MiniMax-M2.7 (block-FP8 source) at EP16 over 4 nodes, NVFP4: every exported weight name is the source checkpoint's, and routed experts are
block_sparse_moe.experts.N.w1/w2/w3. Served by vLLM (0.30 dev build, TP4), it scores 0.94 / 0.93 on gsm8k (5-shot, 100 samples, flexible / strict), against the FP8 source's 0.93 / 0.95.DeepSeek-V3 and GLM: on an earlier revision.
Kimi-K3 NVFP4 at EP64 over 16 GB200 nodes, in 10 minutes (peak 155 GiB per GPU on an earlier build of this series), checked against the source checkpoint:
The same checks flag the export made before this series' fixes. vLLM 0.28 loads the export and starts serving, but it cannot serve a Kimi-K3 NVFP4 export with an FP8 KV cache: its FP8-KV path needs an FP8 prefill query, which its NVFP4 linears reject. TBD: generation and gsm8k from the checkpoint-mirror recipe
models/moonshotai/Kimi-K3/ptq/nvfp4_experts-fp8_pb_attentionon this series' code with the [3/21] fix.Before your PR is "Ready for review"
--use_fsdp2runs behave as before. A torchrun launch without--use_fsdp2now runs an MoE expert-parallel.CONTRIBUTING.md: N/AAdditional Information
Part 21 of 21 of expert-parallel PTQ for Hugging Face MoE models; merges after [20/21].
Summary by CodeRabbit