Qwen3-VL-32B H3 Generation Tail β NVFP4
Decoder layers 50β63, the final norm, and the LM head of Qwen/Qwen3-VL-32B-Instruct, quantized to NVFP4 for use as a generation tail on top of MiniMax H3's conditioning text encoder.
This is not a standalone model. It has no token embeddings, no vision tower, and no layers 0β49. It is useless on its own.
Why this exists
MiniMax H3 ships its Qwen3-VL-32B text encoder truncated to the first 50 of 64 layers, with no final norm and no LM head β enough to condition the video model, not enough to generate text. If you want to use that same encoder as a prompt enhancer, you need the missing tail.
Loading a second complete 32B model just to generate a prompt is wasteful. This file is only the missing piece, so it can be loaded temporarily alongside the encoder you already have resident and unloaded afterwards.
Contents
156 tensors, ComfyUI naming:
| Key | Precision | Notes |
|---|---|---|
model.layers.50-63.* |
NVFP4 | 154 tensors; linears quantized, norms kept bf16 |
model.norm.weight |
bf16 | final RMS norm |
model.lm_head.weight |
bf16 | 151936 Γ 5120, deliberately not quantized |
The LM head is left at full precision on purpose. It is the projection to 151936 logits, so quantization error there lands directly in sampling. It is also the single largest tensor, which is why the file is bigger than a naive "4-bit" estimate.
Requirements
- Base layers 0β49 from a MiniMax H3 Qwen3-VL-32B conditioning encoder. This tail supplies nothing else.
- Blackwell GPU (SM β₯ 10.0/12.0) for NVFP4 inference.
Usage (ComfyUI)
Place in models/text_encoders/. With
boo-textgen, connect
BOO MiniMax H3 Generation Tail Loader β the clip_tail input of
BOO Generate MiniMax H3 Prompt, with your normal 50-layer H3 CLIP on clip.
The tail is loaded for the duration of generation and unloaded immediately after.
Provenance
Extracted directly from Qwen/Qwen3-VL-32B-Instruct (shards 11β14 of 14) and
remapped to ComfyUI key naming:
model.language_model.layers.{50..63}.* -> model.layers.{50..63}.*
model.language_model.norm.weight -> model.norm.weight
lm_head.weight -> model.lm_head.weight
On matching MiniMax H3: MiniMax did not fine-tune the tail. model.norm.weight
(complete tensor) and the leading 64 KiB of model.lm_head.weight are byte-identical
between MiniMaxAI/MiniMax-H3 and stock Qwen3-VL-32B-Instruct. Note this was
verified on the unquantized tensors only β the 14 decoder layers could not be
compared directly, as the available MiniMax-derived tail was already quantized.
How it was quantized
Using convert_to_quant
(branch feature/layer-config-convrot-plus-int4):
ctq -i tail_quant_src.safetensors -o tail_nvfp4.safetensors \
--nvfp4 --comfy_quant --save-quant-metadata --full_precision_matrix_mult
The LM head was held out of this step and merged back afterwards at bf16, because
ctq quantizes every 2D *.weight it is given.
Default learned-rounding (AdaRound/Prodigy) was used rather than --simple.
No AWQ smoothing was applied β see below.
File
qwen3vl_32b_h3_generation_tail_50_63_nvfp4.safetensors |
5.03 GiB, 450 tensors |
| sha256 | 3f897b316986c5d4fc854f1ea9e5037bd1591048161d8f372d1c44015a10ccde |
Roughly 3.6 GiB of NVFP4 layers plus a 1.5 GiB bf16 LM head.
Verification
All 156 source tensors confirmed finite before quantization.
All 98 FP8 E4M3 block-scale tensors in the output confirmed finite β zero NaN, and zero non-finite values anywhere in the file.
Reconstruction error, dequantizing through ComfyUI's own
TensorCoreNVFP4Layoutand comparing against the bf16 source:tensor shape rel. error layers.50.self_attn.q_proj(8192, 5120) 0.0948 layers.50.mlp.down_proj(5120, 25600) 0.0948 layers.56.self_attn.o_proj(5120, 8192) 0.0952 layers.56.mlp.gate_proj(25600, 5120) 0.0951 layers.63.self_attn.v_proj(1024, 5120) 0.0946 layers.63.mlp.up_proj(25600, 5120) 0.0947 ~9.5% relative error is the expected band for 4-bit E2M1 with per-16 block scales (about 20 dB SNR). The tight spread across projection types and across layers 50, 56 and 63 indicates no tensor degenerated.
Why no AWQ
An existing NVFP4 AWQ build of this same tail is defective: 46 of its
float8_e4m3 block scales are NaN, spread across 13 tensors and exclusively
in o_proj and down_proj β precisely the two projections carrying AWQ
pre_quant_scale. Its finite scales saturate at 448.0, the maximum finite value
of E4M3. AWQ smoothing inflates weight magnitudes; when a block's required scale
exceeded 448 the exporter emitted NaN instead of clamping. Because
model.layers.50 is affected, NaN enters on the very first token and every logit
becomes NaN, tripping a CUDA device-side assert in multinomial that aborts the
whole process.
ComfyUI treats pre_quant_scale as optional (weight_scale and weight_scale_2
are the only mandatory NVFP4 tensors), so AWQ was skipped here entirely. That
gives up some accuracy relative to a correct AWQ build, in exchange for
removing the mechanism that produced the failure.
If you are evaluating any NVFP4 quant, it is worth checking:
import torch
from safetensors import safe_open
with safe_open("model.safetensors", framework="pt", device="cpu") as f:
for k in f.keys():
t = f.get_tensor(k)
if t.dtype == torch.float8_e4m3fn and torch.isnan(t.float()).any():
print("NaN block scales in", k)
License
Apache 2.0, inherited from Qwen3-VL-32B-Instruct. See LICENSE and NOTICE.
Model tree for rockerBOO/qwen3-vl-32b-h3-tail-nvfp4
Base model
Qwen/Qwen3-VL-32B-Instruct