diffsynth 2.1.2__py3-none-any.whl → 2.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffsynth/configs/model_configs.py +90 -7
- diffsynth/configs/vram_management_module_maps.py +27 -1
- diffsynth/core/attention/attention.py +33 -7
- diffsynth/core/data/operators.py +2 -2
- diffsynth/core/device/npu_compatible_device.py +9 -9
- diffsynth/core/loader/file.py +17 -1
- diffsynth/core/loader/model.py +2 -3
- diffsynth/core/quant/__init__.py +1 -1
- diffsynth/core/quant/backends/__init__.py +28 -1
- diffsynth/core/quant/backends/bitsandbytes.py +42 -39
- diffsynth/core/quant/backends/comfy_kitchen.py +318 -0
- diffsynth/core/quant/backends/torchao.py +76 -52
- diffsynth/core/quant/base.py +27 -25
- diffsynth/core/quant/config.py +106 -53
- diffsynth/core/vram/disk_map.py +1 -1
- diffsynth/core/vram/layers.py +4 -2
- diffsynth/diffusion/flow_match.py +10 -2
- diffsynth/diffusion/logger.py +26 -0
- diffsynth/diffusion/parsers.py +6 -0
- diffsynth/diffusion/training_module.py +42 -5
- diffsynth/models/flux_redux.py +13 -0
- diffsynth/models/ideogram4_dit.py +7 -6
- diffsynth/models/{minimax_h3_dit_comfy_pruned.py → minimax_h3_dit_comfy.py} +10 -4
- diffsynth/models/minimax_h3_video_vae.py +69 -0
- diffsynth/models/minimax_music3_condition_encoder.py +48 -0
- diffsynth/models/minimax_music3_dit.py +159 -0
- diffsynth/models/minimax_music3_rvq_depth_decoder.py +92 -0
- diffsynth/models/minimax_music3_text_encoder.py +57 -0
- diffsynth/models/minimax_music3_vocoder.py +119 -0
- diffsynth/models/model_loader.py +11 -8
- diffsynth/models/qwen_image_dit.py +18 -0
- diffsynth/pipelines/flux2_image.py +3 -1
- diffsynth/pipelines/flux_image.py +300 -4
- diffsynth/pipelines/ltx2_audio_video.py +1 -1
- diffsynth/pipelines/minimax_music3.py +351 -0
- diffsynth/pipelines/qwen_image.py +7 -0
- diffsynth/utils/state_dict_converters/flux_ipadapter.py +9 -1
- diffsynth/utils/state_dict_converters/minimax_h3_text_encoder.py +18 -0
- diffsynth/utils/state_dict_converters/minimax_music3_text_encoder.py +2 -0
- diffsynth/utils/xfuser/xdit_context_parallel.py +1 -1
- diffsynth/version.py +1 -1
- diffsynth-2.1.4.dist-info/METADATA +819 -0
- {diffsynth-2.1.2.dist-info → diffsynth-2.1.4.dist-info}/RECORD +46 -37
- diffsynth-2.1.2.dist-info/METADATA +0 -51
- {diffsynth-2.1.2.dist-info → diffsynth-2.1.4.dist-info}/WHEEL +0 -0
- {diffsynth-2.1.2.dist-info → diffsynth-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {diffsynth-2.1.2.dist-info → diffsynth-2.1.4.dist-info}/top_level.txt +0 -0
|
@@ -339,6 +339,14 @@ flux_series = [
|
|
|
339
339
|
"model_class": "diffsynth.models.flux_dit.FluxDiT",
|
|
340
340
|
"state_dict_converter": "diffsynth.utils.state_dict_converters.flux_dit.FluxDiTStateDictConverterFromDiffusers",
|
|
341
341
|
},
|
|
342
|
+
{
|
|
343
|
+
# Example: ModelConfig(model_id="black-forest-labs/FLUX.1-Fill-dev", origin_file_pattern="flux1-fill-dev.safetensors")
|
|
344
|
+
"model_hash": "f876d2a6fb247fb7da0f84fc7fb8a823",
|
|
345
|
+
"model_name": "flux_dit",
|
|
346
|
+
"model_class": "diffsynth.models.flux_dit.FluxDiT",
|
|
347
|
+
"extra_kwargs": {"input_dim": 384},
|
|
348
|
+
"state_dict_converter": "diffsynth.utils.state_dict_converters.flux_dit.FluxDiTStateDictConverter",
|
|
349
|
+
},
|
|
342
350
|
{
|
|
343
351
|
# Example: ModelConfig(model_id="black-forest-labs/FLUX.1-dev", origin_file_pattern="text_encoder/model.safetensors")
|
|
344
352
|
"model_hash": "94eefa3dac9cec93cb1ebaf1747d7b78",
|
|
@@ -481,6 +489,21 @@ flux_series = [
|
|
|
481
489
|
"model_class": "diffsynth.models.flux_ipadapter.SiglipVisionModelSO400M",
|
|
482
490
|
"state_dict_converter": "diffsynth.utils.state_dict_converters.flux_ipadapter.SiglipStateDictConverter",
|
|
483
491
|
},
|
|
492
|
+
{
|
|
493
|
+
# Example: ModelConfig(model_id="black-forest-labs/FLUX.1-Redux-dev", origin_file_pattern="image_encoder/model.safetensors")
|
|
494
|
+
"model_hash": "6bd5343828144a2135d783519c665e2c",
|
|
495
|
+
"model_name": "flux_redux_image_encoder",
|
|
496
|
+
"model_class": "diffsynth.models.flux_ipadapter.SiglipVisionModelSO400M",
|
|
497
|
+
"state_dict_converter": "diffsynth.utils.state_dict_converters.flux_ipadapter.SiglipReduxStateDictConverter",
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
# Example: ModelConfig(model_id="black-forest-labs/FLUX.1-Redux-dev", origin_file_pattern="image_embedder/diffusion_pytorch_model.safetensors")
|
|
501
|
+
# 2-layer MLP projecting SigLIP tokens (1152) to the 4096-dim FLUX text
|
|
502
|
+
# space; keys already match FluxReduxImageEncoder, so no converter needed.
|
|
503
|
+
"model_hash": "d8ea4618391460bc831fddaae5fb5288",
|
|
504
|
+
"model_name": "flux_redux_image_embedder",
|
|
505
|
+
"model_class": "diffsynth.models.flux_redux.FluxReduxImageEncoder",
|
|
506
|
+
},
|
|
484
507
|
{
|
|
485
508
|
# Example: ModelConfig(model_id="stepfun-ai/Step1X-Edit", origin_file_pattern="step1x-edit-i1258.safetensors"),
|
|
486
509
|
"model_hash": "d30fb9e02b1dbf4e509142f05cf7dd50",
|
|
@@ -1394,18 +1417,46 @@ minimax_h3_series = [
|
|
|
1394
1417
|
"state_dict_converter": "diffsynth.utils.state_dict_converters.minimax_h3_text_encoder.MiniMaxH3TextEncoderStateDictConverter",
|
|
1395
1418
|
"quant_config": {"method": "bitsandbytes_nf4", "load_prequantized": True, "exclude_modules": ["qkv", "proj", "linear_fc1", "linear_fc2"]},
|
|
1396
1419
|
},
|
|
1420
|
+
{
|
|
1421
|
+
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="text_encoders/qwen3vl_32b_minimax_h3_int8_convrot.safetensors")
|
|
1422
|
+
"model_hash": "d6473c909b72b73afc4fa00c273d1da2",
|
|
1423
|
+
"model_name": "minimax_h3_text_encoder",
|
|
1424
|
+
"model_class": "diffsynth.models.minimax_h3_text_encoder.MiniMaxH3TextEncoder",
|
|
1425
|
+
"state_dict_converter": "diffsynth.utils.state_dict_converters.minimax_h3_text_encoder.MiniMaxH3TextEncoderComfyOrgStateDictConverter",
|
|
1426
|
+
"quant_config": {"method": "comfy_kitchen_int8_w8a8", "load_prequantized": True, "exclude_modules": ["qkv", "proj", "linear_fc1", "linear_fc2"]},
|
|
1427
|
+
},
|
|
1397
1428
|
{
|
|
1398
1429
|
# Example: ModelConfig(model_id="MiniMax/MiniMax-H3", origin_file_pattern="FL2VA/transformer/model*.safetensors")
|
|
1399
1430
|
"model_hash": "db0197b6919425a5c7102c54e73affc1",
|
|
1400
1431
|
"model_name": "minimax_h3_dit",
|
|
1401
1432
|
"model_class": "diffsynth.models.minimax_h3_dit.MiniMaxH3DiT",
|
|
1402
1433
|
},
|
|
1434
|
+
{
|
|
1435
|
+
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="diffusion_models/minimax_h3_fl2va_int8_convrot.safetensors")
|
|
1436
|
+
"model_hash": "fb6c399412920c6b817d5c1f43ec62cd",
|
|
1437
|
+
"model_name": "minimax_h3_dit",
|
|
1438
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfy",
|
|
1439
|
+
"quant_config": {"method": "comfy_kitchen_int8_w8a8", "load_prequantized": True, "exclude_modules": ["video_patch_proj", "audio_patch_proj", "condition_proj", "time_embedder.proj_in", "time_embedder.proj_out", "final_layer.adaln_proj.linear", "final_layer.video_out", "final_layer.audio_out", "token_refiner.blocks.0.attn.qkv_proj", "token_refiner.blocks.0.attn.out_proj", "token_refiner.blocks.0.mlp.fc1", "token_refiner.blocks.0.mlp.fc2", "token_refiner.blocks.1.attn.qkv_proj", "token_refiner.blocks.1.attn.out_proj", "token_refiner.blocks.1.mlp.fc1", "token_refiner.blocks.1.mlp.fc2"]},
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="diffusion_models/minimax_h3_fl2va_pruned_int8_convrot.safetensors")
|
|
1443
|
+
"model_hash": "ac9fdcd56900c9a1a5ef21eaacf6cb76",
|
|
1444
|
+
"model_name": "minimax_h3_dit",
|
|
1445
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned",
|
|
1446
|
+
"quant_config": {"method": "comfy_kitchen_int8_w8a8", "load_prequantized": True, "exclude_modules": ["video_patch_proj", "audio_patch_proj", "condition_proj", "adaln_proj.linear", "final_layer.video_out", "final_layer.audio_out", "token_refiner.blocks.0.attn.qkv_proj", "token_refiner.blocks.0.attn.out_proj", "token_refiner.blocks.0.mlp.fc1", "token_refiner.blocks.0.mlp.fc2", "token_refiner.blocks.1.attn.qkv_proj", "token_refiner.blocks.1.attn.out_proj", "token_refiner.blocks.1.mlp.fc1", "token_refiner.blocks.1.mlp.fc2"]},
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="diffusion_models/minimax_h3_fl2va_pruned_fp8_scaled.safetensors")
|
|
1450
|
+
"model_hash": "7e410be9acd325ef8db3b8bed3d814cd",
|
|
1451
|
+
"model_name": "minimax_h3_dit",
|
|
1452
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned",
|
|
1453
|
+
"quant_config": {"method": "comfy_kitchen_fp8_w8a8", "load_prequantized": True, "exclude_modules": ["video_patch_proj", "audio_patch_proj", "condition_proj", "adaln_proj.linear", "final_layer.video_out", "final_layer.audio_out", "token_refiner.blocks.0.attn.qkv_proj", "token_refiner.blocks.0.attn.out_proj", "token_refiner.blocks.0.mlp.fc1", "token_refiner.blocks.0.mlp.fc2", "token_refiner.blocks.1.attn.qkv_proj", "token_refiner.blocks.1.attn.out_proj", "token_refiner.blocks.1.mlp.fc1", "token_refiner.blocks.1.mlp.fc2"]},
|
|
1454
|
+
},
|
|
1403
1455
|
{
|
|
1404
1456
|
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="diffusion_models/minimax_h3_fl2va_pruned_bf16.safetensors")
|
|
1405
1457
|
"model_hash": "b4e0df87da0c079979ae857edbcef49f",
|
|
1406
1458
|
"model_name": "minimax_h3_dit",
|
|
1407
|
-
"model_class": "diffsynth.models.
|
|
1408
|
-
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1459
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned",
|
|
1409
1460
|
},
|
|
1410
1461
|
{
|
|
1411
1462
|
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-fl2va-nf4.safetensors")
|
|
@@ -1425,16 +1476,14 @@ minimax_h3_series = [
|
|
|
1425
1476
|
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-fl2va-pruned-nf4.safetensors")
|
|
1426
1477
|
"model_hash": "9b8f1cbc6fb5fcd2e2c02b6691480427",
|
|
1427
1478
|
"model_name": "minimax_h3_dit",
|
|
1428
|
-
"model_class": "diffsynth.models.
|
|
1429
|
-
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1479
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned",
|
|
1430
1480
|
"quant_config": {"method": "bitsandbytes_nf4", "load_prequantized": True, "exclude_modules": ["time_embedder.proj_in", "time_embedder.proj_out", "video_patch_proj", "audio_patch_proj", "condition_proj", "final_layer.video_out", "final_layer.audio_out", "adaln_proj.linear"]},
|
|
1431
1481
|
},
|
|
1432
1482
|
{
|
|
1433
1483
|
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-ref2va-pruned-nf4.safetensors")
|
|
1434
1484
|
"model_hash": "072bd13242d6d67df79a154e7c4274b3",
|
|
1435
1485
|
"model_name": "minimax_h3_dit",
|
|
1436
|
-
"model_class": "diffsynth.models.
|
|
1437
|
-
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1486
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned",
|
|
1438
1487
|
"quant_config": {"method": "bitsandbytes_nf4", "load_prequantized": True, "exclude_modules": ["time_embedder.proj_in", "time_embedder.proj_out", "video_patch_proj", "audio_patch_proj", "condition_proj", "final_layer.video_out", "final_layer.audio_out", "adaln_proj.linear"]},
|
|
1439
1488
|
},
|
|
1440
1489
|
{
|
|
@@ -1462,8 +1511,42 @@ minimax_h3_series = [
|
|
|
1462
1511
|
},
|
|
1463
1512
|
]
|
|
1464
1513
|
|
|
1514
|
+
minimax_music3_series = [
|
|
1515
|
+
{
|
|
1516
|
+
# Example: ModelConfig(model_id="MiniMax/MiniMax-Music3", origin_file_pattern="transformer/diffusion_pytorch_model*.safetensors")
|
|
1517
|
+
"model_hash": "8d1f1aba6a5801220ccc3a531865f694",
|
|
1518
|
+
"model_name": "minimax_music3_dit",
|
|
1519
|
+
"model_class": "diffsynth.models.minimax_music3_dit.MiniMaxMusic3DiT",
|
|
1520
|
+
},
|
|
1521
|
+
{
|
|
1522
|
+
# Example: ModelConfig(model_id="MiniMax/MiniMax-Music3", origin_file_pattern="condition_encoder/diffusion_pytorch_model.safetensors")
|
|
1523
|
+
"model_hash": "1370ef6377206e5ceaa78b125b2d4e1f",
|
|
1524
|
+
"model_name": "minimax_music3_condition_encoder",
|
|
1525
|
+
"model_class": "diffsynth.models.minimax_music3_condition_encoder.MiniMaxMusic3ConditionEncoder",
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
# Example: ModelConfig(model_id="MiniMax/MiniMax-Music3", origin_file_pattern="vocoder/diffusion_pytorch_model.safetensors")
|
|
1529
|
+
"model_hash": "b6eded627c26c85b39804628ba4e5d1d",
|
|
1530
|
+
"model_name": "minimax_music3_vocoder",
|
|
1531
|
+
"model_class": "diffsynth.models.minimax_music3_vocoder.MiniMaxMusic3Vocoder",
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
# Example: ModelConfig(model_id="MiniMax/MiniMax-Music3", origin_file_pattern="rvq_depth_decoder/diffusion_pytorch_model.safetensors")
|
|
1535
|
+
"model_hash": "5e571ded532a131c02e9d8256cb3fded",
|
|
1536
|
+
"model_name": "minimax_music3_rvq_depth_decoder",
|
|
1537
|
+
"model_class": "diffsynth.models.minimax_music3_rvq_depth_decoder.MiniMaxMusic3RVQDepthDecoder",
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
# Example: ModelConfig(model_id="MiniMax/MiniMax-Music3", origin_file_pattern="language_model/model*.safetensors")
|
|
1541
|
+
"model_hash": "474b2197ab43bd2d4b69746506a952ef",
|
|
1542
|
+
"model_name": "minimax_music3_text_encoder",
|
|
1543
|
+
"model_class": "diffsynth.models.minimax_music3_text_encoder.MiniMaxMusic3TextEncoder",
|
|
1544
|
+
"state_dict_converter": "diffsynth.utils.state_dict_converters.minimax_music3_text_encoder.MiniMaxMusic3TextEncoderStateDictConverter",
|
|
1545
|
+
},
|
|
1546
|
+
]
|
|
1547
|
+
|
|
1465
1548
|
MODEL_CONFIGS = (
|
|
1466
1549
|
stable_diffusion_xl_series + stable_diffusion_series + qwen_image_series + wan_series + flux_series + flux2_series + ernie_image_series
|
|
1467
1550
|
+ z_image_series + ltx2_series + anima_series + mova_series + joyai_image_series + boogu_image_series + ace_step_series + hidream_o1_image_series
|
|
1468
|
-
+ image_metrics_series + ideogram4_series + krea2_series + lingbot_video_series + minimax_h3_series
|
|
1551
|
+
+ image_metrics_series + ideogram4_series + krea2_series + lingbot_video_series + minimax_h3_series + minimax_music3_series
|
|
1469
1552
|
)
|
|
@@ -14,7 +14,11 @@ VRAM_MANAGEMENT_MODULE_MAPS = {
|
|
|
14
14
|
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
15
15
|
"torch.nn.RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
16
16
|
},
|
|
17
|
-
"diffsynth.models.
|
|
17
|
+
"diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfy": {
|
|
18
|
+
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
19
|
+
"torch.nn.RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
20
|
+
},
|
|
21
|
+
"diffsynth.models.minimax_h3_dit_comfy.MiniMaxH3DiTComfyPruned": {
|
|
18
22
|
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
19
23
|
"torch.nn.RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
20
24
|
},
|
|
@@ -470,6 +474,28 @@ VRAM_MANAGEMENT_MODULE_MAPS = {
|
|
|
470
474
|
"diffsynth.models.lingbot_video_dit.LingBotVideoRMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
471
475
|
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
472
476
|
},
|
|
477
|
+
"diffsynth.models.minimax_music3_dit.MiniMaxMusic3DiT": {
|
|
478
|
+
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
479
|
+
"torch.nn.Conv1d": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
480
|
+
"torch.nn.LayerNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
481
|
+
"diffsynth.models.minimax_music3_dit.MiniMaxMusic3FourierEmbedding": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
482
|
+
},
|
|
483
|
+
"diffsynth.models.minimax_music3_rvq_depth_decoder.MiniMaxMusic3RVQDepthDecoder": {
|
|
484
|
+
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
485
|
+
"torch.nn.Embedding": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
486
|
+
"diffsynth.models.minimax_music3_rvq_depth_decoder.MiniMaxMusic3RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
487
|
+
},
|
|
488
|
+
"diffsynth.models.minimax_music3_vocoder.MiniMaxMusic3Vocoder": {
|
|
489
|
+
"torch.nn.Conv1d": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
490
|
+
"diffsynth.models.minimax_music3_vocoder.MiniMaxMusic3WeightNormConv1d": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
491
|
+
"diffsynth.models.minimax_music3_vocoder.MiniMaxMusic3WeightNormConvTranspose1d": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
492
|
+
"diffsynth.models.minimax_music3_vocoder.MiniMaxMusic3Snake1d": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
493
|
+
},
|
|
494
|
+
"diffsynth.models.minimax_music3_text_encoder.MiniMaxMusic3TextEncoder": {
|
|
495
|
+
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
496
|
+
"torch.nn.Embedding": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
497
|
+
"transformers.models.qwen3.modeling_qwen3.Qwen3RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
498
|
+
},
|
|
473
499
|
}
|
|
474
500
|
|
|
475
501
|
def QwenImageTextEncoder_Module_Map_Updater():
|
|
@@ -1,41 +1,52 @@
|
|
|
1
1
|
import torch, os, inspect
|
|
2
2
|
from einops import rearrange, repeat
|
|
3
3
|
|
|
4
|
+
if os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_REPO_ID") is not None:
|
|
5
|
+
try:
|
|
6
|
+
from kernels import get_kernel
|
|
7
|
+
kernel_module = get_kernel(os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_REPO_ID"), version=int(os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_VERSION")))
|
|
8
|
+
customized_flash_attn_func = kernel_module.flash_attn_func
|
|
9
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = True
|
|
10
|
+
except Exception:
|
|
11
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = False
|
|
12
|
+
else:
|
|
13
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = False
|
|
14
|
+
|
|
4
15
|
try:
|
|
5
16
|
from flash_attn.cute import flash_attn_func as flash_attn_func_cute
|
|
6
17
|
FLASH_ATTN_4_AVAILABLE = True
|
|
7
|
-
except
|
|
18
|
+
except Exception:
|
|
8
19
|
FLASH_ATTN_4_AVAILABLE = False
|
|
9
20
|
|
|
10
21
|
try:
|
|
11
22
|
import flash_attn_interface
|
|
12
23
|
FLASH_ATTN_3_AVAILABLE = True
|
|
13
|
-
except
|
|
24
|
+
except Exception:
|
|
14
25
|
FLASH_ATTN_3_AVAILABLE = False
|
|
15
26
|
|
|
16
27
|
try:
|
|
17
28
|
import flash_attn
|
|
18
29
|
FLASH_ATTN_2_AVAILABLE = True
|
|
19
|
-
except
|
|
30
|
+
except Exception:
|
|
20
31
|
FLASH_ATTN_2_AVAILABLE = False
|
|
21
32
|
|
|
22
33
|
try:
|
|
23
34
|
from sageattention import sageattn
|
|
24
35
|
SAGE_ATTN_AVAILABLE = True
|
|
25
|
-
except
|
|
36
|
+
except Exception:
|
|
26
37
|
SAGE_ATTN_AVAILABLE = False
|
|
27
38
|
|
|
28
39
|
try:
|
|
29
40
|
import xformers.ops as xops
|
|
30
41
|
XFORMERS_AVAILABLE = True
|
|
31
|
-
except
|
|
42
|
+
except Exception:
|
|
32
43
|
XFORMERS_AVAILABLE = False
|
|
33
44
|
|
|
34
45
|
try:
|
|
35
46
|
from torch.nn.attention.flex_attention import flex_attention as flex_attention_func
|
|
36
47
|
flex_attention_func = torch.compile(flex_attention_func, dynamic=False, mode="max-autotune-no-cudagraphs", fullgraph=True, backend="inductor")
|
|
37
48
|
FLEX_ATTN_AVAILABLE = True
|
|
38
|
-
except
|
|
49
|
+
except Exception:
|
|
39
50
|
FLEX_ATTN_AVAILABLE = False
|
|
40
51
|
|
|
41
52
|
try:
|
|
@@ -43,13 +54,15 @@ try:
|
|
|
43
54
|
TORCH_SUPPORT_GQA = True
|
|
44
55
|
else:
|
|
45
56
|
TORCH_SUPPORT_GQA = False
|
|
46
|
-
except:
|
|
57
|
+
except Exception:
|
|
47
58
|
TORCH_SUPPORT_GQA = False
|
|
48
59
|
|
|
49
60
|
|
|
50
61
|
def initialize_attention_priority():
|
|
51
62
|
if os.environ.get('DIFFSYNTH_ATTENTION_IMPLEMENTATION') is not None:
|
|
52
63
|
return os.environ.get('DIFFSYNTH_ATTENTION_IMPLEMENTATION').lower()
|
|
64
|
+
elif CUSTOMIZED_FA_KERNEL_AVAILABLE:
|
|
65
|
+
return "customized_fa_kernel"
|
|
53
66
|
elif FLASH_ATTN_4_AVAILABLE:
|
|
54
67
|
return "flash_attention_4"
|
|
55
68
|
elif FLASH_ATTN_3_AVAILABLE:
|
|
@@ -178,6 +191,17 @@ def flash_attention_2(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_patte
|
|
|
178
191
|
return out
|
|
179
192
|
|
|
180
193
|
|
|
194
|
+
def flash_attention_customized_kernel(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
195
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
196
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
197
|
+
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
198
|
+
out = customized_flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
199
|
+
if isinstance(out, tuple):
|
|
200
|
+
out = out[0]
|
|
201
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
202
|
+
return out
|
|
203
|
+
|
|
204
|
+
|
|
181
205
|
def sage_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
182
206
|
required_in_pattern, required_out_pattern= "b n s d", "b n s d"
|
|
183
207
|
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
@@ -213,6 +237,8 @@ def attention_forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_patte
|
|
|
213
237
|
# Sliding Window Attention is not compatible with `is_causal` and `attn_mask`.
|
|
214
238
|
assert is_causal == False and attn_mask is None
|
|
215
239
|
return torch_sdpa_sliding_window(q, k, v, window_size, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
240
|
+
elif ATTENTION_IMPLEMENTATION == "customized_fa_kernel":
|
|
241
|
+
return flash_attention_customized_kernel(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
216
242
|
elif ATTENTION_IMPLEMENTATION == "flash_attention_4":
|
|
217
243
|
return flash_attention_4(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
218
244
|
elif ATTENTION_IMPLEMENTATION == "flash_attention_3":
|
diffsynth/core/data/operators.py
CHANGED
|
@@ -307,8 +307,8 @@ class LoadAudioWithTorchaudio(DataProcessingOperator, FrameSamplerByRateMixin):
|
|
|
307
307
|
padding = target_samples - current_samples
|
|
308
308
|
waveform = torch.nn.functional.pad(waveform, (0, padding))
|
|
309
309
|
return waveform, sample_rate
|
|
310
|
-
except:
|
|
311
|
-
warnings.warn(f"Cannot load audio in {data}. The audio will be `None`.")
|
|
310
|
+
except Exception as e:
|
|
311
|
+
warnings.warn(f"Cannot load audio in {data} due to {e}. The audio will be `None`.")
|
|
312
312
|
return None
|
|
313
313
|
|
|
314
314
|
|
|
@@ -83,17 +83,17 @@ def enable_high_precision_for_bf16():
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
def parse_device_type(device):
|
|
86
|
-
if isinstance(device,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
if isinstance(device, torch.device):
|
|
87
|
+
return device.type
|
|
88
|
+
elif isinstance(device, str):
|
|
89
|
+
# `torch.device("npu")` raises when torch_npu is not installed, so keep npu ahead of the generic parse.
|
|
90
|
+
if device.startswith("npu"):
|
|
90
91
|
return "npu"
|
|
91
|
-
|
|
92
|
-
return
|
|
93
|
-
|
|
92
|
+
try:
|
|
93
|
+
return torch.device(device).type
|
|
94
|
+
except RuntimeError:
|
|
95
|
+
# Strings that are not device names at all
|
|
94
96
|
return "cpu"
|
|
95
|
-
elif isinstance(device, torch.device):
|
|
96
|
-
return device.type
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def parse_nccl_backend(device_type):
|
diffsynth/core/loader/file.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from safetensors import safe_open
|
|
2
|
-
import torch, hashlib
|
|
2
|
+
import torch, hashlib, json
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def load_state_dict(file_path, torch_dtype=None, device="cpu", pin_memory=False, verbose=0):
|
|
@@ -34,10 +34,26 @@ def load_state_dict_from_safetensors(file_path, torch_dtype=None, device="cpu"):
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def load_metadata_from_safetensors(file_path):
|
|
37
|
+
if isinstance(file_path, list):
|
|
38
|
+
metadata = {}
|
|
39
|
+
for file_path_ in file_path:
|
|
40
|
+
for key, value in load_metadata_from_safetensors(file_path_).items():
|
|
41
|
+
metadata[key] = merge_metadata_value(metadata[key], value) if key in metadata else value
|
|
42
|
+
return metadata
|
|
37
43
|
with safe_open(file_path, framework="pt", device="cpu") as f:
|
|
38
44
|
return f.metadata() or {}
|
|
39
45
|
|
|
40
46
|
|
|
47
|
+
def merge_metadata_value(old_value, new_value):
|
|
48
|
+
try:
|
|
49
|
+
old_items, new_items = json.loads(old_value), json.loads(new_value)
|
|
50
|
+
except (json.JSONDecodeError, TypeError):
|
|
51
|
+
return new_value
|
|
52
|
+
if isinstance(old_items, list) and isinstance(new_items, list):
|
|
53
|
+
return json.dumps(old_items + [i for i in new_items if i not in old_items])
|
|
54
|
+
return new_value
|
|
55
|
+
|
|
56
|
+
|
|
41
57
|
def load_state_dict_from_bin(file_path, torch_dtype=None, device="cpu"):
|
|
42
58
|
state_dict = torch.load(file_path, map_location=device, weights_only=True)
|
|
43
59
|
if len(state_dict) == 1:
|
diffsynth/core/loader/model.py
CHANGED
|
@@ -37,14 +37,13 @@ def load_model(model_class, path, config=None, torch_dtype=torch.bfloat16, devic
|
|
|
37
37
|
devices = [vram_config[k] for k in ("offload_device", "onload_device", "preparing_device", "computation_device")]
|
|
38
38
|
load_device = [d for d in devices if d != "disk"][0]
|
|
39
39
|
disk_map = DiskMap(path, load_device, torch_dtype=None, state_dict_converter=state_dict_converter)
|
|
40
|
-
metadata = load_metadata_from_safetensors(path
|
|
40
|
+
metadata = load_metadata_from_safetensors(path)
|
|
41
41
|
model = quantize.prepare_for_prequantized_load(model, compute_dtype=vram_config["computation_dtype"])
|
|
42
42
|
model = enable_vram_management(model, module_map, vram_config=vram_config, disk_map=disk_map, vram_limit=vram_limit, quantize=quantize, metadata=metadata)
|
|
43
43
|
else:
|
|
44
44
|
offload_device = vram_config["offload_device"]
|
|
45
45
|
computation_device = vram_config["computation_device"]
|
|
46
46
|
computation_dtype = vram_config["computation_dtype"]
|
|
47
|
-
offload_dtype = vram_config["offload_dtype"]
|
|
48
47
|
load_dtype = None if quantize.load_prequantized else computation_dtype
|
|
49
48
|
if state_dict is None: state_dict = DiskMap(path, offload_device, torch_dtype=load_dtype)
|
|
50
49
|
if state_dict_converter is not None:
|
|
@@ -61,7 +60,7 @@ def load_model(model_class, path, config=None, torch_dtype=torch.bfloat16, devic
|
|
|
61
60
|
|
|
62
61
|
model = quantize.quantize_model(model, compute_device=computation_device, model_device=offload_device)
|
|
63
62
|
model = quantize.dequantize_model(model, compute_dtype=computation_dtype, compute_device=computation_device, model_device=offload_device)
|
|
64
|
-
model = model.to(dtype=
|
|
63
|
+
model = model.to(dtype=computation_dtype, device=offload_device)
|
|
65
64
|
model = enable_vram_management(model, module_map, vram_config=vram_config, disk_map=None, vram_limit=vram_limit, quantize=quantize)
|
|
66
65
|
elif quantize is not None:
|
|
67
66
|
# Weight-only quantization (see `diffsynth.core.quant`), isolated from the normal path below.
|
diffsynth/core/quant/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .base import QuantBackend, QUANT_BACKENDS, register_quant_backend, check_differentiable, check_backend_contract
|
|
1
|
+
from .base import QuantBackend, BackendConfig, QUANT_BACKENDS, register_quant_backend, check_differentiable, check_backend_contract
|
|
2
2
|
from .config import QuantizeConfig, MixedQuantizeConfig, QuantMethodSpec, QUANT_METHODS, register_quant_method, describe_quant_method
|
|
3
3
|
from . import backends
|
|
@@ -1 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import importlib
|
|
2
|
+
|
|
3
|
+
_LAZY_BACKENDS = {
|
|
4
|
+
"bitsandbytes": ".bitsandbytes",
|
|
5
|
+
"torchao": ".torchao",
|
|
6
|
+
"comfy_kitchen": ".comfy_kitchen",
|
|
7
|
+
}
|
|
8
|
+
_loaded = set()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_backend(name):
|
|
12
|
+
module = _LAZY_BACKENDS.get(name)
|
|
13
|
+
if module is not None and name not in _loaded:
|
|
14
|
+
importlib.import_module(module, __name__)
|
|
15
|
+
_loaded.add(name)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def load_all_backends():
|
|
19
|
+
for name in _LAZY_BACKENDS:
|
|
20
|
+
load_backend(name)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_backend_for_method(method):
|
|
24
|
+
from ..config import QUANT_METHODS
|
|
25
|
+
for name in _LAZY_BACKENDS:
|
|
26
|
+
load_backend(name)
|
|
27
|
+
if method in QUANT_METHODS:
|
|
28
|
+
return
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
1
3
|
import torch
|
|
2
|
-
from ..base import QuantBackend, register_quant_backend
|
|
4
|
+
from ..base import QuantBackend, BackendConfig, register_quant_backend
|
|
3
5
|
from ..config import register_quant_method
|
|
4
6
|
|
|
7
|
+
try:
|
|
8
|
+
import bitsandbytes as bnb
|
|
9
|
+
BITSANDBYTES_AVAILABLE = True
|
|
10
|
+
except ImportError:
|
|
11
|
+
BITSANDBYTES_AVAILABLE = False
|
|
12
|
+
|
|
5
13
|
|
|
6
14
|
def _assign_params_from_state_dict(self, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs):
|
|
7
15
|
"""`_load_from_state_dict` replacement for shells: assigns tensors as-is, since packed weights do not pass the standard shape check."""
|
|
@@ -29,10 +37,10 @@ def _assign_params_from_state_dict(self, state_dict, prefix, local_metadata, str
|
|
|
29
37
|
class BitsAndBytesQuantBackend(QuantBackend):
|
|
30
38
|
"""Adapter over `bitsandbytes.nn.Linear4bit` (NF4 / FP4, weight-only)."""
|
|
31
39
|
|
|
40
|
+
project_url = "https://github.com/bitsandbytes-foundation/bitsandbytes"
|
|
41
|
+
|
|
32
42
|
def validate_environment(self):
|
|
33
|
-
|
|
34
|
-
import bitsandbytes # noqa: F401
|
|
35
|
-
except ImportError:
|
|
43
|
+
if not BITSANDBYTES_AVAILABLE:
|
|
36
44
|
raise ImportError(
|
|
37
45
|
"bitsandbytes is required for bitsandbytes quantization methods. "
|
|
38
46
|
'Please install it via `pip install bitsandbytes` or `pip install "diffsynth[quant]"`.'
|
|
@@ -47,23 +55,14 @@ class BitsAndBytesQuantBackend(QuantBackend):
|
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
def quantized_linear_classes(self):
|
|
50
|
-
try:
|
|
51
|
-
import bitsandbytes as bnb
|
|
52
|
-
except ImportError:
|
|
53
|
-
return ()
|
|
54
58
|
return (bnb.nn.Linear4bit,)
|
|
55
59
|
|
|
56
60
|
def create_quantized_linear(self, linear, compute_device=None, model_device=None):
|
|
57
61
|
"""The `meta` shell avoids allocating an fp weight; bnb quantizes while `Params4bit` moves to `compute_device`."""
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
cfg = self.config
|
|
60
63
|
compute_dtype = linear.weight.dtype
|
|
61
64
|
if compute_device is None:
|
|
62
65
|
compute_device = linear.weight.device
|
|
63
|
-
quant_type = self.config.get("quant_type", "nf4")
|
|
64
|
-
compress_statistics = self.config.get("compress_statistics", True)
|
|
65
|
-
blocksize = self.config.get("blocksize")
|
|
66
|
-
quant_storage = self.config.get("quant_storage", torch.uint8)
|
|
67
66
|
|
|
68
67
|
with torch.device("meta"):
|
|
69
68
|
quant_linear = bnb.nn.Linear4bit(
|
|
@@ -71,17 +70,17 @@ class BitsAndBytesQuantBackend(QuantBackend):
|
|
|
71
70
|
linear.out_features,
|
|
72
71
|
bias=linear.bias is not None,
|
|
73
72
|
compute_dtype=compute_dtype,
|
|
74
|
-
compress_statistics=compress_statistics,
|
|
75
|
-
quant_type=quant_type,
|
|
76
|
-
quant_storage=quant_storage,
|
|
73
|
+
compress_statistics=cfg.compress_statistics,
|
|
74
|
+
quant_type=cfg.quant_type,
|
|
75
|
+
quant_storage=cfg.quant_storage,
|
|
77
76
|
)
|
|
78
77
|
weight = bnb.nn.Params4bit(
|
|
79
78
|
linear.weight.data.contiguous(),
|
|
80
79
|
requires_grad=False,
|
|
81
|
-
compress_statistics=compress_statistics,
|
|
82
|
-
blocksize=blocksize,
|
|
83
|
-
quant_type=quant_type,
|
|
84
|
-
quant_storage=quant_storage,
|
|
80
|
+
compress_statistics=cfg.compress_statistics,
|
|
81
|
+
blocksize=cfg.blocksize,
|
|
82
|
+
quant_type=cfg.quant_type,
|
|
83
|
+
quant_storage=cfg.quant_storage,
|
|
85
84
|
)
|
|
86
85
|
quant_linear.weight = weight.to(compute_device)
|
|
87
86
|
if linear.bias is not None:
|
|
@@ -89,22 +88,20 @@ class BitsAndBytesQuantBackend(QuantBackend):
|
|
|
89
88
|
return quant_linear.to(device=model_device)
|
|
90
89
|
|
|
91
90
|
def create_quantized_linear_shell(self, linear, compute_dtype):
|
|
92
|
-
import bitsandbytes as bnb
|
|
93
91
|
with torch.device("meta"):
|
|
94
92
|
shell = bnb.nn.Linear4bit(
|
|
95
93
|
linear.in_features,
|
|
96
94
|
linear.out_features,
|
|
97
95
|
bias=linear.bias is not None,
|
|
98
96
|
compute_dtype=compute_dtype,
|
|
99
|
-
compress_statistics=self.config.
|
|
100
|
-
quant_type=self.config.
|
|
101
|
-
quant_storage=self.config.
|
|
97
|
+
compress_statistics=self.config.compress_statistics,
|
|
98
|
+
quant_type=self.config.quant_type,
|
|
99
|
+
quant_storage=self.config.quant_storage,
|
|
102
100
|
)
|
|
103
101
|
shell._load_from_state_dict = _assign_params_from_state_dict.__get__(shell)
|
|
104
102
|
return shell
|
|
105
103
|
|
|
106
104
|
def unflatten_state_dict(self, state_dict, metadata):
|
|
107
|
-
import bitsandbytes as bnb
|
|
108
105
|
rebuilt = {}
|
|
109
106
|
quant_state = {}
|
|
110
107
|
for key, value in state_dict.items():
|
|
@@ -122,7 +119,6 @@ class BitsAndBytesQuantBackend(QuantBackend):
|
|
|
122
119
|
return rebuilt
|
|
123
120
|
|
|
124
121
|
def dequantize_to_linear(self, module, compute_dtype, compute_device=None, model_device=None):
|
|
125
|
-
import bitsandbytes as bnb
|
|
126
122
|
if compute_device is not None:
|
|
127
123
|
module = module.to(device=compute_device)
|
|
128
124
|
weight = module.weight
|
|
@@ -136,17 +132,24 @@ class BitsAndBytesQuantBackend(QuantBackend):
|
|
|
136
132
|
return linear
|
|
137
133
|
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
135
|
+
@dataclass
|
|
136
|
+
class BitsAndBytes4bitConfig(BackendConfig):
|
|
137
|
+
"""Shared 4bit knobs; `quant_type` is pinned by the per-method subclass."""
|
|
138
|
+
|
|
139
|
+
compress_statistics: bool = True
|
|
140
|
+
blocksize: int = None # None -> bnb default (64)
|
|
141
|
+
quant_storage: torch.dtype = torch.uint8
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@dataclass
|
|
145
|
+
class BitsAndBytesNF4Config(BitsAndBytes4bitConfig):
|
|
146
|
+
quant_type: str = field(init=False, default="nf4")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass
|
|
150
|
+
class BitsAndBytesFP4Config(BitsAndBytes4bitConfig):
|
|
151
|
+
quant_type: str = field(init=False, default="fp4")
|
|
149
152
|
|
|
150
153
|
|
|
151
|
-
register_quant_method("bitsandbytes_nf4", "bitsandbytes",
|
|
152
|
-
register_quant_method("bitsandbytes_fp4", "bitsandbytes",
|
|
154
|
+
register_quant_method("bitsandbytes_nf4", "bitsandbytes", BitsAndBytesNF4Config.from_kwargs, label="4bit, nf4, weight-only")
|
|
155
|
+
register_quant_method("bitsandbytes_fp4", "bitsandbytes", BitsAndBytesFP4Config.from_kwargs, label="4bit, fp4, weight-only")
|