Instructions to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4
- SGLang
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with Docker Model Runner:
docker model run hf.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4
Download runtime/COMPAT_NOTES.md from gitcommit90/SenseNova-Loop-9B-Preview-NVFP4: direct link, hf CLI and curl.
- Browser
- Download file 12 kB
-
https://huggingface.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4/resolve/main/runtime/COMPAT_NOTES.md
- Command line
-
hf download hf://gitcommit90/SenseNova-Loop-9B-Preview-NVFP4/runtime/COMPAT_NOTES.md
-
curl -L -o COMPAT_NOTES.md https://huggingface.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4/resolve/main/runtime/COMPAT_NOTES.md
SenseNova-Loop-9B NVFP4 + MTP on GB10 (sm_121): compatibility scout, 2026-10-30
Labels: [V] verified here (code read at a pinned SHA, or a command run on tux). [I] inferred, not yet run. Top criterion (added by the user): MTP speculative decoding plus an NVFP4 target in one runtime.
Ranking
| # | Path | GEMM | MTP | Status |
|---|---|---|---|---|
| 1 | SGLang PR #47281 overlay + 2 small patches on lmsysorg/sglang:nightly-dev-cu13-20261029-c10e0e17 |
W4A4 flashinfer mm_fp4 (cutlass/cudnn) |
NEXTN via the stock Qwen3_5ForCausalLMMTP, BF16 draft (needs patch 2) |
best; patches untested end-to-end |
| 2 | Same as #1 with --fp4-gemm-backend marlin |
W4A16 Marlin NVFP4 | same | fallback if W4A4 accuracy or kernels misbehave |
| 3 | vLLM 0.27.1 (local image) + out-of-tree sensenova_loop | W4A4 CUTLASS works on sm121 [V] | must port loop and wire MTP | big effort |
| 4 | LightLLM main |
no NVFP4/ModelOpt (awq/w8a8/fp8 only) [V] | has sensenova_loop + MTP (eagle_with_att) [V] |
BF16/FP8 reference only; fa3 defaults are Hopper-only |
| 5 | HF transformers + custom NVFP4 Linear | W4A4 torch._scaled_mm fp4 or flashinfer [V] |
none: we would write draft+verify ourselves | correctness oracle only |
1. SGLang PR #47281 [V]
- Open, unmerged, CI red. Fork
WANDY666/sglangbranchfeat/sensenova-loop. Head336c54ac1e721197806d94b6929f567446a59693. Merge basec10e0e17735f7981c7cc46891eed6908b7701e58, which is exactly the commit of nightlynightly-dev-cu13-20261029-c10e0e17, so the overlay is exact. Validated by the author on H800 BF16 only (logit cosine 0.984 to 0.9999 vs HF). No MTP and no quantized test. - Overlay = 7 runtime files (in
overlay/python/sglang/):srt/models/sensenova_loop.py(new),srt/configs/sensenova_loop.py(new),srt/configs/{__init__,model_config}.py,srt/layers/rotary_embedding/mrope_rope_index.py,srt/multimodal/processors/qwen_vl.py,srt/utils/hf_transformers/common.py. They need the very newlayer_boundary.MHCState,sglang.kernels.ops.layernorm.mhc, andruntime_context, so don't overlay onto release images ≤ v0.5.22. - Loop: the config expands to 56 execution layers (0..3, 4..27×2, 28..31). The KV and GDN pools are per execution layer. Re-visits are
copy.copyof the physical layer with new RadixAttention/RadixLinearAttention objects (layer_id = execution index) and shared params.load_weightsremapsmodel.language_model.layers.{phys}.<any suffix>to the first execution index, so weight_scale, weight_scale_2 and input_scale need no extra mapping. mHC routers are raw FP32 Parameters with F.linear and are never quantized. - Patch 1,
patches/sensenova_loop_quant.patch(required for NVFP4):get_layer()builds decoder layers withoutquant_config, so every decoder Linear would be BF16 and packed uint8 weights fail to load. Passquant_config=quant_config. Also build the physical layer with prefix...layers.{physical_id}, because ModelOptexclude_modulesuses physical names and layers 28..31 run at execution ids 52..55 (otherwise theirin_proj_a/bwould not be excluded). Alternative: rewrite exclude_modules to globs (*linear_attn.in_proj_a*,*linear_attn.in_proj_b*,lm_head,*visual*,mtp*). - Base code that already handles NVFP4 [V]: the GDN packed loaders cover weight/weight_scale/input_scale. Scalar
weight_scale_2with a tuple shard is broadcast byMergedColumnParallelLinear.weight_loader_v2. The BF16 fused in_proj fast-path turns itself off when quantized. - FP4 backend:
initialize_fp4_gemm_config()picksauto, which resolves to cutedsl on sm100, marlin on 8.0 ≤ cc < 10, andflashinfer_cutlassotherwise (sm121).
2. MTP (top criterion)
- (a) The PR does not implement MTP. The draft-arch rewrite in
configs/model_config.py(Qwen3.5 list, ~L1169) does not includeSenseNovaLoopForConditionalGeneration, so a NEXTN draft would instantiate the whole loop model [V]. Even with the arch added,SenseNovaLoopTextConfig.layers_block_typefollowslayer_types(56 entries, [0] = linear_attention), so the single MTP layer would be built as GDN instead of full attention [V, code]. Patch 2,patches/model_config_mtp_draft.patch: for draft + SenseNovaLoop, deep-copy the config, setnum_hidden_layers=1,layer_types=["full_attention"],full_attention_interval=1,execution_plan=(0,),mhc=None,num_nextn_predict_layers=1, and archQwen3_5ForCausalLMMTP. This mirrors the existing Qwen4Exp block. [Patch written, not run.] - Draft class
Qwen3_5ForCausalLMMTP(models/qwen3_5_mtp.py) loads namesmtp.*(fc, pre_fc_norm_embedding/hidden, layers.0.{self_attn,mlp,norms}, norm). Upstreammtp.safetensorshas exactly these 15 BF16 tensors [V], andembed_tokensandlm_headare shared from the target viaget_embed_and_head. The draft takes the target's final-norm hidden state. The PR's loop forward returnsfinal_norm(...), the same as Qwen3.5 [V code]. Whether SenseNova trained MTP on that same tensor is [I] (the README says MTP is "Available"). - Flags [I, standard SGLang]:
--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4(the draft model path defaults to the target). GDN spec-verify state is per layer_id, so visits are distinct [I]. - (b) NVFP4 target + BF16 draft:
_mtp_quant_config()returns None formodelopt_fp4with a serialized NVFP4 checkpoint, so the draft is built BF16 with no patch [V]. A draft-vs-main quantization mismatch is auto-resolved for draft models [V]. Keepmtp*in exclude_modules regardless. - Checkpoint layout SGLang expects:
mtp.*keys must be listed inmodel.safetensors.index.json. The loader iterates the index. The "add unindexed mtp.safetensors" hack is GLM-only. Upstream already indexes them intomtp.safetensors(871 keys) [V]. ModelOptexport_hf_checkpointcarries unplaced weights such as MTP heads into the export and adds them to exclusions [V code]. After export, verify thatmtp.*(15 keys) is in the new index. If not, copymtp.safetensorsand add its keys to the index. - (c) LightLLM: has
lightllm/models/sensenova_loopandtest/start_scripts/sensenova_loop/sensenova_loop_mtp.sh(--mtp_mode eagle_with_att --mtp_step 3 --mtp_draft_model_dir <separate dir>, fa3 attention) at mainccf4e33d0ce9…, but there is no FP4 quantization module inlightllm/common/quantization, so it does not meet the NVFP4 requirement. Useful as an MTP acceptance-rate reference on another GPU. - (d) The HF runtime cannot use
mtp.*(ignored keys), so draft and verify would have to be written by hand. It ranks last.
3. Images [V]
- Local:
vllm/vllm-openai:v0.27.1-aarch64and...-dflash2-nvfp4-hotfix-aarch64(vllm 0.27.1, torch 2.13.0+cu130, flashinfer 0.6.16.post3, transformers 5.15.0). No local SGLang image or venv (~/sglang-cacheholds only JIT caches;~/venvsholds vllm025 and vllm-026). - Pulled (the 1 allowed pull, since it is the exact PR base):
lmsysorg/sglang:nightly-dev-cu13-20261029-c10e0e17, indexsha256:78142f9f4b7fb3ee27f59065615dc7bb263f643ed256c9299c3861086ade4d47, arm64sha256:5efa08069f2822f313fc3e5764ce72238f72cb9ca8744e9fa0f46358fd2dd643(15.7 GB). Its pyproject pins flashinfer 0.7.2.
4. vLLM 0.27.1 [V facts / I effort]
Has Qwen3_5ForConditionalGeneration and Qwen3_5MTP, plus the NVFP4 linear kernels cutlass (works on sm121), marlin and emulation (flashinfer cutedsl is sm10x only).
A loop port must give each visit distinct Attention/GDN instances (vLLM keys KV and mamba state by layer prefix) and make Qwen3_5MTP see
the loop's output. That is about 1 to 2 days with CUDA-graph and prefix-cache risk. Not recommended while SGLang is viable.
5. Kernel smoke tests on GB10 [V]
docker run --rm --gpus all -v $PWD:/w:ro --entrypoint python3 vllm/vllm-openai:v0.27.1-aarch64 /w/smoke_fp4.py (and smoke_fp4_b.py).
Peak GPU memory 141 MB. N = K = 4096, ModelOpt scale convention (gs = 448·6/amax, alpha = 1/(gx·gw)).
flashinfer mm_fp4: cutlass OK, cudnn OK, auto OK; trtllm & cute-dsl -> BackendSupportedError (capability 121)
kernel vs emulated-FP4 reference rel_err 0.00166 (cutlass & cudnn) [FP4 vs BF16 noise on random data: 0.134]
M=128 : cutlass 44us (98 TFLOPS) cudnn 73us
M=2048: cutlass 225us (306 TFLOPS) cudnn 221us | bf16 torch 779us
M=1 : cutlass 1066us (!) cudnn 63us -> decode: prefer --fp4-gemm-backend flashinfer_cudnn (or autotune)
vllm ops.cutlass_scaled_fp4_mm OK; torch._scaled_mm(float4_e2m1fn_x2, e4m3 swizzled scales) OK (identical results)
flashinfer mm_bf16_fp4 (W4A16): unsupported on cc121 (cutlass/trtllm); cudnn path needs cuDNN >= 9.23.1 (image 9.20)
SGLang-image checks (PR unit tests with overlay, flashinfer 0.7.2 mm_fp4, Marlin W4A16, config expansion): ./run_sglang_smoke.sh.
NOT YET RUN: the image pull was still in progress at hand-off (pull.log; pid of docker pull still alive). Run the script once it finishes.
6. ModelOpt [V unless marked]
- PyPI stable 0.47.0 pins
transformers<5.15and is incompatible with 5.18.0. 0.48.0rc1 (2026-10-19) pins>=5.5,<5.19, so use it in a fresh venv. default_disabled_quantizers.yamldisables*linear_attn.in_proj_a*,*linear_attn.in_proj_b*,*linear_attn.conv1d*,*lm_head*,*visual*,*vision_tower*,mtp.*,*router*,*mlp.gate.*, and Embedding. GDN-state quantizers are off by default.NVFP4_DEFAULT_CFG= max calibration with w4a4_nvfp4_nvfp4. mhc_* are not nn.Linear, so they are not wrapped.- Modules visited twice: quantizers are per module, and max calibration takes the running max over all calls, so both visits are covered [I]. Export walks each physical module once.
- Remote code:
hf_model_typeis only a key for MoE specs and special cases, and the dense path is generic. It copies*.py. The resmooth step doesmodel(torch.ones(1,2))[I: fine, text-only]. - Output:
hf_quant_config.json{"producer":{"name":"modelopt",...},"quantization":{"quant_algo":"NVFP4","group_size":16, "kv_cache_quant_algo":null,"exclude_modules":[prefix-wildcards, physical names]}}, plus config.jsonquantization_config.quant_method="modelopt". Tensors:weightuint8 [N,K/2],weight_scalee4m3 [N,K/16],weight_scale_2fp32,input_scalefp32. - NVIDIA playbook (build.nvidia.com/station/nvfp4-quantization): Spark uses
nvcr.io/nvidia/tensorrt-llm/release:spark-single-gpu-devwith ModelOpt 0.41.0 (examples/llm_ptq/scripts/huggingface_example.sh --quant nvfp4 --tasks quant) andtrtllm-serve. Station uses vllm 25.12.post1 with ModelOpt 0.47.0. Both are too old for transformers 5.18, so use them only as a pattern.
7. Serve command (recipe, [I])
docker run --rm --gpus all --ipc=host -p 30000:30000 -v $OUT:/model:ro <7 overlay -v mounts, see run_sglang_smoke.sh> \
lmsysorg/sglang:nightly-dev-cu13-20261029-c10e0e17 python3 -m sglang.launch_server --model-path /model \
--quantization modelopt_fp4 --fp4-gemm-backend flashinfer_cudnn --mem-fraction-static 0.5 --port 30000 \
--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4
Port 30000 avoids 8000/3000/18080-18105.
8. Risks
- The PR is unmerged with CI red and BF16-only validation. Patches 1 and 2 are new and unrun against real weights. MTP on the loop model in SGLang is untested by anyone [I].
- The physical-prefix change only renames layers 28..31. Anything that parses the layer id from the prefix would see the physical id [I].
- GDN triton/fla kernels and spec-decode GDN state tracking on sm121 have not been exercised. M=1 cutlass mm_fp4 is slow, so benchmark cudnn.
- Looping doubles the use of every quantized weight. Keep mHC, in_proj_a/b, lm_head, vision and MTP in BF16, and evaluate against BF16 (and measure MTP acceptance against BF16).