Skip to content

Commit 092e01e

Browse files
lmxyykungtalon
andauthored
fix: close the NVFP4 performance gap between the Python backend and C backend
Co-authored-by: Kung Talon <31659820+kungtalon@users.noreply.github.com>
1 parent 7fcce6f commit 092e01e

5 files changed

Lines changed: 32 additions & 13 deletions

File tree

app/flux.1/t2i/latency.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
def get_args() -> argparse.Namespace:
1111
parser = argparse.ArgumentParser()
1212
parser.add_argument(
13-
"-m", "--model", type=str, default="schnell", choices=["schnell", "dev"], help="Which FLUX.1 model to use"
13+
"-m",
14+
"--model",
15+
type=str,
16+
default="schnell",
17+
choices=["schnell", "schnell_v2", "dev"],
18+
help="Which FLUX.1 model to use",
1419
)
1520
parser.add_argument(
1621
"-p", "--precision", type=str, default="int4", choices=["int4", "fp4", "bf16"], help="Which precision to use"

app/flux.1/t2i/utils.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,20 @@ def get_pipeline(
3030
assert torch.device(device).type == "cuda", "int4 only supported on CUDA devices"
3131
if precision == "int4":
3232
transformer = NunchakuFluxTransformer2dModel.from_pretrained(
33-
"mit-han-lab/nunchaku-flux.1-schnell/svdq-int4_r32-flux.1-schnell.safetensors"
33+
"nunchaku-tech/nunchaku-flux.1-schnell/svdq-int4_r32-flux.1-schnell.safetensors"
3434
)
3535
else:
3636
assert precision == "fp4"
3737
transformer = NunchakuFluxTransformer2dModel.from_pretrained(
38-
"mit-han-lab/nunchaku-flux.1-schnell/svdq-fp4_r32-flux.1-schnell.safetensors", precision="fp4"
38+
"nunchaku-tech/nunchaku-flux.1-schnell/svdq-fp4_r32-flux.1-schnell.safetensors", precision="fp4"
3939
)
40+
transformer.set_attention_impl("nunchaku-fp16")
4041
pipeline_init_kwargs["transformer"] = transformer
4142
if use_qencoder:
4243
from nunchaku.models.text_encoders.t5_encoder import NunchakuT5EncoderModel
4344

4445
text_encoder_2 = NunchakuT5EncoderModel.from_pretrained(
45-
"mit-han-lab/nunchaku-t5/awq-int4-flux.1-t5xxl.safetensors"
46+
"nunchaku-tech/nunchaku-t5/awq-int4-flux.1-t5xxl.safetensors"
4647
)
4748
pipeline_init_kwargs["text_encoder_2"] = text_encoder_2
4849
else:
@@ -52,7 +53,7 @@ def get_pipeline(
5253
)
5354
elif model_name == "schnell_v2":
5455
transformer = NunchakuFluxTransformer2DModelV2.from_pretrained(
55-
f"mit-han-lab/nunchaku-flux.1-schnell/svdq-{precision}_r32-flux.1-schnell.safetensors"
56+
f"nunchaku-tech/nunchaku-flux.1-schnell/svdq-{precision}_r32-flux.1-schnell.safetensors"
5657
)
5758
pipeline = FluxPipeline.from_pretrained(
5859
"black-forest-labs/FLUX.1-schnell",
@@ -63,7 +64,7 @@ def get_pipeline(
6364
elif model_name == "dev":
6465
if precision == "int4":
6566
transformer = NunchakuFluxTransformer2dModel.from_pretrained(
66-
"mit-han-lab/nunchaku-flux.1-dev/svdq-int4_r32-flux.1-dev.safetensors"
67+
"nunchaku-tech/nunchaku-flux.1-dev/svdq-int4_r32-flux.1-dev.safetensors"
6768
)
6869
if lora_name not in ["All", "None"]:
6970
transformer.update_lora_params(SVDQ_LORA_PATHS[lora_name])
@@ -73,7 +74,7 @@ def get_pipeline(
7374
from nunchaku.models.text_encoders.t5_encoder import NunchakuT5EncoderModel
7475

7576
text_encoder_2 = NunchakuT5EncoderModel.from_pretrained(
76-
"mit-han-lab/nunchaku-t5/awq-int4-flux.1-t5xxl.safetensors"
77+
"nunchaku-tech/nunchaku-t5/awq-int4-flux.1-t5xxl.safetensors"
7778
)
7879
pipeline_init_kwargs["text_encoder_2"] = text_encoder_2
7980
pipeline = FluxPipeline.from_pretrained(

nunchaku/models/linear.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ def __init__(
6464
self.proj_down = nn.Parameter(torch.empty(in_features, rank, dtype=torch_dtype, device=device))
6565
self.proj_up = nn.Parameter(torch.empty(out_features, rank, dtype=torch_dtype, device=device))
6666

67-
self.wtscale = None
68-
self.wcscales = None
6967
if precision == "nvfp4":
70-
self.wtscale = nn.Parameter(torch.ones(1, dtype=torch_dtype, device=device), requires_grad=False)
7168
self.wcscales = nn.Parameter(
7269
torch.ones(out_features, dtype=torch_dtype, device=device), requires_grad=False
7370
)
71+
self.wtscale = 1.0
72+
else:
73+
self.wtscale = None
74+
self.wcscales = None
7475

7576
self.act_unsigned = act_unsigned
7677

nunchaku/models/transformers/transformer_flux_v2.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828
class NunchakuFluxAttention(NunchakuBaseAttention):
29-
def __init__(self, other: FluxAttention, processor: str = "flashattn2", **kwargs):
29+
def __init__(self, other: FluxAttention, processor: str = "nunchaku-fp16", **kwargs):
3030
super(NunchakuFluxAttention, self).__init__(processor)
3131

3232
self.head_dim = other.head_dim
@@ -263,11 +263,17 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str],
263263

264264
for k in state_dict.keys():
265265
if k not in converted_state_dict:
266-
assert ".wtscale" in k or ".wcscales" in k
266+
assert ".wcscales" in k
267267
converted_state_dict[k] = torch.ones_like(state_dict[k])
268268
else:
269269
assert state_dict[k].dtype == converted_state_dict[k].dtype
270270

271+
# load the wtscale from the converted state dict
272+
for n, m in transformer.named_modules():
273+
if isinstance(m, SVDQW4A4Linear):
274+
if m.wtscale is not None:
275+
m.wtscale = converted_state_dict.pop(f"{n}.wtscale", 1.0)
276+
271277
transformer.load_state_dict(converted_state_dict)
272278

273279
return transformer

nunchaku/models/transformers/transformer_qwenimage.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,16 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str],
248248
state_dict = transformer.state_dict()
249249
for k in state_dict.keys():
250250
if k not in model_state_dict:
251-
assert ".wtscale" in k or ".wcscales" in k
251+
assert ".wcscales" in k
252252
model_state_dict[k] = torch.ones_like(state_dict[k])
253253
else:
254254
assert state_dict[k].dtype == model_state_dict[k].dtype
255+
256+
# load the wtscale from the state dict, as it is a float on CPU
257+
for n, m in transformer.named_modules():
258+
if isinstance(m, SVDQW4A4Linear):
259+
if m.wtscale is not None:
260+
m.wtscale = model_state_dict.pop(f"{n}.wtscale", 1.0)
255261
transformer.load_state_dict(model_state_dict)
256262

257263
return transformer

0 commit comments

Comments
 (0)