diffsynth 2.1.1__tar.gz → 2.1.2__tar.gz
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-2.1.1 → diffsynth-2.1.2}/PKG-INFO +1 -1
- {diffsynth-2.1.1 → diffsynth-2.1.2}/README.md +8 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/configs/model_configs.py +23 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/configs/vram_management_module_maps.py +4 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/quant/__init__.py +1 -1
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/quant/backends/torchao.py +25 -8
- diffsynth-2.1.2/diffsynth/core/quant/base.py +241 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/quant/config.py +126 -34
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/vram/layers.py +16 -7
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/flow_match.py +24 -1
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/template.py +5 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/training_module.py +6 -3
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ideogram4_dit.py +18 -14
- diffsynth-2.1.2/diffsynth/models/minimax_h3_dit_comfy_pruned.py +72 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/lingbot_video.py +13 -6
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/minimax_h3_audio_video.py +30 -3
- diffsynth-2.1.2/diffsynth/utils/lora/minimax_h3.py +97 -0
- diffsynth-2.1.2/diffsynth/utils/quant/serialization.py +57 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth.egg-info/PKG-INFO +1 -1
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth.egg-info/SOURCES.txt +3 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/pyproject.toml +1 -1
- diffsynth-2.1.1/diffsynth/core/quant/base.py +0 -127
- {diffsynth-2.1.1 → diffsynth-2.1.2}/LICENSE +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/configs/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/attention/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/attention/attention.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/data/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/data/operators.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/data/unified_dataset.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/device/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/device/npu_compatible_device.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/gradient/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/gradient/gradient_checkpoint.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/loader/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/loader/config.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/loader/file.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/loader/model.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/npu_patch/npu_fused_operator.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/offload_training/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/offload_training/manager.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/offload_training/memory_buffer.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/offload_training/offloader.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/quant/backends/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/quant/backends/bitsandbytes.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/vram/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/vram/disk_map.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/core/vram/initialization.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/base_pipeline.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/ddim_scheduler.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/dmd2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/logger.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/loss.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/parsers.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/diffusion/runner.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/aesthetic.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/base.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/bioclip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/clip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/fid.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/hpsv2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/hpsv3.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/image_reward.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/lpips.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/pickscore.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/qwen_image_bench.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/unified_reward_2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/metrics/unified_reward_edit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_conditioner.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_residual_fsq.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_tokenizer.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ace_step_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/aesthetic.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/anima_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/bioclip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/boogu_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/clip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/demucs.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/dinov3_image_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ernie_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ernie_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/fid.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux2_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_controlnet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_infiniteyou.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_ipadapter.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_lora_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_lora_patcher.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_text_encoder_clip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_text_encoder_t5.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/flux_value_control.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/general_modules.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/hidream_common.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/hidream_o1_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/hpsv2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/hpsv3.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ideogram4_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ideogram4_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/image_reward.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/joyai_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/joyai_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/krea2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/krea2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/lingbot_video_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/longcat_video_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/lpips.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_audio_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_common.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_upsampler.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/ltx2_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/minimax_h3_audio_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/minimax_h3_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/minimax_h3_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/minimax_h3_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/model_loader.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/mova_audio_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/mova_audio_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/mova_dual_tower_bridge.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/nexus_gen.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/nexus_gen_ar_model.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/nexus_gen_projector.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/pickscore.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_bench.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_controlnet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_image2lora.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/qwen_image_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/sd_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/siglip2_image_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/stable_diffusion_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/stable_diffusion_unet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/stable_diffusion_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/stable_diffusion_xl_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/stable_diffusion_xl_unet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/step1x_connector.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/step1x_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/unified_reward_2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/unified_reward_edit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_animate_2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_animate_adapter.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_camera_controller.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_dit_s2v.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_image_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_mot.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_motion_controller.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_vace.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wan_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wantodance.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/wav2vec.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/z_image_controlnet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/z_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/z_image_image2lora.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/models/z_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/ace_step.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/anima_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/boogu_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/ernie_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/flux2_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/flux_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/hidream_o1_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/ideogram4.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/joyai_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/krea2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/ltx2_audio_video.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/mova_audio_video.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/qwen_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/stable_diffusion.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/stable_diffusion_xl.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/wan_video.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/pipelines/z_image.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/controlnet/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/controlnet/annotator.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/controlnet/controlnet_input.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/data/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/data/audio.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/data/audio_video.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/data/media_io_ltx2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/data/minimax_h3.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/demucs/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/dequantizer/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/flux.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/flux_timestep.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/general.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/krea2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/merge.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/reset_rank.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/lora/sdxl.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/ses/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/ses/ses.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ace_step_conditioner.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ace_step_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ace_step_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ace_step_tokenizer.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/anima_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/dino_v3.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ernie_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_controlnet.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_infiniteyou.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_ipadapter.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_text_encoder_clip.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_text_encoder_t5.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/flux_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ideogram4_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/image_metrics.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/joyai_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/krea2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/krea2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/lingbot_video_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ltx2_audio_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ltx2_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ltx2_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/ltx2_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/minimax_h3_audio_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/minimax_h3_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/minimax_h3_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/nexus_gen.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/nexus_gen_projector.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/qwen_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/sdxl.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/sdxl_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/sdxl_text_encoder_2.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/sdxl_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/stable_diffusion_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/stable_diffusion_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/stable_diffusion_xl_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/step1x_connector.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_animate_adapter.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_image_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_mot.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_vace.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wan_video_vae.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/wans2v_audio_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/z_image_dit.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/state_dict_converters/z_image_text_encoder.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/tile/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/tile/tile_worker.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/xfuser/__init__.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/utils/xfuser/xdit_context_parallel.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth/version.py +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth.egg-info/dependency_links.txt +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth.egg-info/requires.txt +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/diffsynth.egg-info/top_level.txt +0 -0
- {diffsynth-2.1.1 → diffsynth-2.1.2}/setup.cfg +0 -0
|
@@ -1527,6 +1527,8 @@ Example code for LingBot-Video is available at: [/examples/lingbot_video/](/exam
|
|
|
1527
1527
|
|[Robbyant/lingbot-video-moe-30b-a3b: T2V](https://modelscope.cn/models/Robbyant/lingbot-video-moe-30b-a3b)|[code](/examples/lingbot_video/model_inference/lingbot-video-moe-30b-a3b_t2v.py)|[code](/examples/lingbot_video/model_inference_low_vram/lingbot-video-moe-30b-a3b_t2v.py)|[code](/examples/lingbot_video/model_training/full/lingbot-video-moe-30b-a3b_t2v.sh)|[code](/examples/lingbot_video/model_training/validate_full/lingbot-video-moe-30b-a3b_t2v.py)|[code](/examples/lingbot_video/model_training/lora/lingbot-video-moe-30b-a3b_t2v.sh)|[code](/examples/lingbot_video/model_training/validate_lora/lingbot-video-moe-30b-a3b_t2v.py)|
|
|
1528
1528
|
|[Robbyant/lingbot-video-moe-30b-a3b: TI2V](https://modelscope.cn/models/Robbyant/lingbot-video-moe-30b-a3b)|[code](/examples/lingbot_video/model_inference/lingbot-video-moe-30b-a3b_ti2v.py)|[code](/examples/lingbot_video/model_inference_low_vram/lingbot-video-moe-30b-a3b_ti2v.py)|[code](/examples/lingbot_video/model_training/full/lingbot-video-moe-30b-a3b_ti2v.sh)|[code](/examples/lingbot_video/model_training/validate_full/lingbot-video-moe-30b-a3b_ti2v.py)|[code](/examples/lingbot_video/model_training/lora/lingbot-video-moe-30b-a3b_ti2v.sh)|[code](/examples/lingbot_video/model_training/validate_lora/lingbot-video-moe-30b-a3b_ti2v.py)|
|
|
1529
1529
|
|[Robbyant/lingbot-video-moe-30b-a3b: T2I](https://modelscope.cn/models/Robbyant/lingbot-video-moe-30b-a3b)|[code](/examples/lingbot_video/model_inference/lingbot-video-moe-30b-a3b_t2i.py)|[code](/examples/lingbot_video/model_inference_low_vram/lingbot-video-moe-30b-a3b_t2i.py)|-|-|-|-|
|
|
1530
|
+
|[Robbyant/lingbot-video-moe-30b-a3b: T2V + Refinement](https://modelscope.cn/models/Robbyant/lingbot-video-moe-30b-a3b)|[code](/examples/lingbot_video/model_inference/lingbot-video-moe-30b-a3b_t2v_refiner.py)|[code](/examples/lingbot_video/model_inference_low_vram/lingbot-video-moe-30b-a3b_t2v_refiner.py)|-|-|-|-|
|
|
1531
|
+
|[Robbyant/lingbot-video-moe-30b-a3b: TI2V + Refinement](https://modelscope.cn/models/Robbyant/lingbot-video-moe-30b-a3b)|[code](/examples/lingbot_video/model_inference/lingbot-video-moe-30b-a3b_ti2v_refiner.py)|[code](/examples/lingbot_video/model_inference_low_vram/lingbot-video-moe-30b-a3b_ti2v_refiner.py)|-|-|-|-|
|
|
1530
1532
|
|
|
1531
1533
|
</details>
|
|
1532
1534
|
|
|
@@ -1593,6 +1595,12 @@ Example code for MiniMax-H3 is available at: [/examples/minimax_h3/](/examples/m
|
|
|
1593
1595
|
|[MiniMax/MiniMax-H3: Retake](https://www.modelscope.cn/models/MiniMax/MiniMax-H3)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Retake.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Retake.py)|-|-|-|-|
|
|
1594
1596
|
|[DiffSynth-Studio/MiniMax-H3-NF4: FL2VA](https://www.modelscope.cn/models/DiffSynth-Studio/MiniMax-H3-NF4)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-NF4-FL2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-NF4-FL2VA.py)|-|-|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-NF4-FL2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-NF4-FL2VA.py)|
|
|
1595
1597
|
|[DiffSynth-Studio/MiniMax-H3-NF4: Ref2VA](https://www.modelscope.cn/models/DiffSynth-Studio/MiniMax-H3-NF4)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-NF4-Ref2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-NF4-Ref2VA.py)|-|-|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-NF4-Ref2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-NF4-Ref2VA.py)|
|
|
1598
|
+
|[Comfy-Org/MiniMax-H3: FL2VA pruned](https://www.modelscope.cn/models/Comfy-Org/MiniMax-H3)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Pruned-FL2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Pruned-FL2VA.py)|[code](/examples/minimax_h3/model_training/full/MiniMax-H3-Pruned-FL2VA.sh)|[code](/examples/minimax_h3/model_training/validate_full/MiniMax-H3-Pruned-FL2VA.py)|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-Pruned-FL2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-Pruned-FL2VA.py)|
|
|
1599
|
+
|[Comfy-Org/MiniMax-H3: Ref2VA pruned](https://www.modelscope.cn/models/Comfy-Org/MiniMax-H3)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Pruned-Ref2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Pruned-Ref2VA.py)|[code](/examples/minimax_h3/model_training/full/MiniMax-H3-Pruned-Ref2VA.sh)|[code](/examples/minimax_h3/model_training/validate_full/MiniMax-H3-Pruned-Ref2VA.py)|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-Pruned-Ref2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-Pruned-Ref2VA.py)|
|
|
1600
|
+
|[DiffSynth-Studio/MiniMax-H3-NF4: FL2VA pruned](https://www.modelscope.cn/models/DiffSynth-Studio/MiniMax-H3-NF4)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Pruned-NF4-FL2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Pruned-NF4-FL2VA.py)|-|-|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-Pruned-NF4-FL2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-Pruned-NF4-FL2VA.py)|
|
|
1601
|
+
|[DiffSynth-Studio/MiniMax-H3-NF4: Ref2VA pruned](https://www.modelscope.cn/models/DiffSynth-Studio/MiniMax-H3-NF4)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Pruned-NF4-Ref2VA.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Pruned-NF4-Ref2VA.py)|-|-|[code](/examples/minimax_h3/model_training/lora/MiniMax-H3-Pruned-NF4-Ref2VA.sh)|[code](/examples/minimax_h3/model_training/validate_lora/MiniMax-H3-Pruned-NF4-Ref2VA.py)|
|
|
1602
|
+
|[lightx2v/Minimax-h3-Turbo: FL2VA 4steps](https://www.modelscope.cn/models/lightx2v/Minimax-h3-Turbo)|[code](https://github.com/modelscope/DiffSynth-Studio/blob/main/examples/minimax_h3/model_inference/MiniMax-H3-FL2VA-Turbo.py)|[code](https://github.com/modelscope/DiffSynth-Studio/blob/main/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-FL2VA-Turbo.py)|-|-|-|-|
|
|
1603
|
+
|[DiffSynth-Studio/MiniMax-H3-Text-Embeddings](https://www.modelscope.cn/models/DiffSynth-Studio/MiniMax-H3-Text-Embeddings)|[code](/examples/minimax_h3/model_inference/MiniMax-H3-Text-Embeddings.py)|[code](/examples/minimax_h3/model_inference_low_vram/MiniMax-H3-Text-Embeddings.py)|[code](/examples/minimax_h3/model_training/full/MiniMax-H3-Text-Embeddings.sh)|[code](/examples/minimax_h3/model_training/validate_full/MiniMax-H3-Text-Embeddings.py)|-|-|
|
|
1596
1604
|
|
|
1597
1605
|
</details>
|
|
1598
1606
|
|
|
@@ -1400,6 +1400,13 @@ minimax_h3_series = [
|
|
|
1400
1400
|
"model_name": "minimax_h3_dit",
|
|
1401
1401
|
"model_class": "diffsynth.models.minimax_h3_dit.MiniMaxH3DiT",
|
|
1402
1402
|
},
|
|
1403
|
+
{
|
|
1404
|
+
# Example: ModelConfig(model_id="Comfy-Org/MiniMax-H3", origin_file_pattern="diffusion_models/minimax_h3_fl2va_pruned_bf16.safetensors")
|
|
1405
|
+
"model_hash": "b4e0df87da0c079979ae857edbcef49f",
|
|
1406
|
+
"model_name": "minimax_h3_dit",
|
|
1407
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy_pruned.MiniMaxH3DiTComfyPruned",
|
|
1408
|
+
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1409
|
+
},
|
|
1403
1410
|
{
|
|
1404
1411
|
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-fl2va-nf4.safetensors")
|
|
1405
1412
|
"model_hash": "4b27efacefbc4d8670e0d7b876699648",
|
|
@@ -1414,6 +1421,22 @@ minimax_h3_series = [
|
|
|
1414
1421
|
"model_class": "diffsynth.models.minimax_h3_dit.MiniMaxH3DiT",
|
|
1415
1422
|
"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"]},
|
|
1416
1423
|
},
|
|
1424
|
+
{
|
|
1425
|
+
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-fl2va-pruned-nf4.safetensors")
|
|
1426
|
+
"model_hash": "9b8f1cbc6fb5fcd2e2c02b6691480427",
|
|
1427
|
+
"model_name": "minimax_h3_dit",
|
|
1428
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy_pruned.MiniMaxH3DiTComfyPruned",
|
|
1429
|
+
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1430
|
+
"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
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
# Example: ModelConfig(model_id="DiffSynth-Studio/MiniMax-H3-NF4", origin_file_pattern="minimax-h3-ref2va-pruned-nf4.safetensors")
|
|
1434
|
+
"model_hash": "072bd13242d6d67df79a154e7c4274b3",
|
|
1435
|
+
"model_name": "minimax_h3_dit",
|
|
1436
|
+
"model_class": "diffsynth.models.minimax_h3_dit_comfy_pruned.MiniMaxH3DiTComfyPruned",
|
|
1437
|
+
"extra_kwargs": {"adaln_curve_grid": 1025, "time_embed_dim": 8},
|
|
1438
|
+
"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
|
+
},
|
|
1417
1440
|
{
|
|
1418
1441
|
# Example: ModelConfig(model_id="MiniMax/MiniMax-H3-FL2VA", origin_file_pattern="video_vae/source/model.safetensors")
|
|
1419
1442
|
"model_hash": "24b80900992e2024fab17c991c57da23",
|
|
@@ -14,6 +14,10 @@ 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.minimax_h3_dit_comfy_pruned.MiniMaxH3DiTComfyPruned": {
|
|
18
|
+
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
19
|
+
"torch.nn.RMSNorm": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
20
|
+
},
|
|
17
21
|
"diffsynth.models.minimax_h3_text_encoder.MiniMaxH3TextEncoder": {
|
|
18
22
|
"torch.nn.Linear": "diffsynth.core.vram.layers.AutoWrappedLinear",
|
|
19
23
|
"torch.nn.Embedding": "diffsynth.core.vram.layers.AutoWrappedModule",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .base import QuantBackend, QUANT_BACKENDS, register_quant_backend, check_differentiable
|
|
1
|
+
from .base import QuantBackend, QUANT_BACKENDS, register_quant_backend, check_differentiable, check_backend_contract, resolve_checkpoint_keys
|
|
2
2
|
from .config import QuantizeConfig, MixedQuantizeConfig, QuantMethodSpec, QUANT_METHODS, register_quant_method, describe_quant_method
|
|
3
3
|
from . import backends
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import importlib.util
|
|
2
|
+
import json
|
|
2
3
|
|
|
3
4
|
import torch
|
|
4
5
|
from ..base import QuantBackend, register_quant_backend
|
|
5
6
|
from ..config import register_quant_method
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
class TorchaoLinear(torch.nn.Linear):
|
|
10
|
+
"""Marker class for torchao-quantized Linears."""
|
|
11
|
+
|
|
12
|
+
|
|
8
13
|
@register_quant_backend("torchao")
|
|
9
14
|
class TorchaoQuantBackend(QuantBackend):
|
|
10
15
|
"""Adapter over torchao `quantize_` (weight-only configs); the quantization lives in the weight tensor subclass, not the module class."""
|
|
@@ -21,27 +26,32 @@ class TorchaoQuantBackend(QuantBackend):
|
|
|
21
26
|
def capabilities(self):
|
|
22
27
|
return {
|
|
23
28
|
"is_serializable": True,
|
|
24
|
-
"is_differentiable":
|
|
29
|
+
"is_differentiable": True,
|
|
25
30
|
"is_compileable": True,
|
|
26
31
|
"requires_calibration": False,
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
def quantized_linear_classes(self):
|
|
35
|
+
return (TorchaoLinear,)
|
|
36
|
+
|
|
37
|
+
def checkpoint_key_patterns(self):
|
|
38
|
+
return ("weight", "_weight_qdata", "_weight_scale", "_weight_zero_point", "bias")
|
|
32
39
|
|
|
33
40
|
def create_quantized_linear(self, linear, compute_device=None, model_device=None):
|
|
34
41
|
from torchao.quantization import quantize_
|
|
35
42
|
linear.requires_grad_(False)
|
|
36
43
|
if compute_device is not None:
|
|
37
44
|
linear = linear.to(device=compute_device)
|
|
38
|
-
|
|
45
|
+
quant_linear = TorchaoLinear(linear.in_features, linear.out_features, bias=linear.bias is not None, device="meta")
|
|
46
|
+
quant_linear.weight = linear.weight
|
|
47
|
+
quant_linear.bias = linear.bias
|
|
48
|
+
quantize_(quant_linear, self.config)
|
|
39
49
|
if model_device is not None:
|
|
40
|
-
|
|
41
|
-
return
|
|
50
|
+
quant_linear = quant_linear.to(device=model_device)
|
|
51
|
+
return quant_linear
|
|
42
52
|
|
|
43
53
|
def create_quantized_linear_shell(self, linear, compute_dtype):
|
|
44
|
-
return
|
|
54
|
+
return TorchaoLinear(linear.in_features, linear.out_features, bias=linear.bias is not None, device="meta")
|
|
45
55
|
|
|
46
56
|
def flatten_state_dict(self, state_dict):
|
|
47
57
|
self._require_safetensors_support()
|
|
@@ -61,9 +71,16 @@ class TorchaoQuantBackend(QuantBackend):
|
|
|
61
71
|
"safetensors header), so its tensor subclasses cannot be rebuilt. It was most "
|
|
62
72
|
"likely not saved by torchao."
|
|
63
73
|
)
|
|
74
|
+
tensor_names = json.loads(metadata["tensor_names"])
|
|
75
|
+
root_names = [name for name in tensor_names if "." not in name]
|
|
76
|
+
if root_names:
|
|
77
|
+
metadata = {**metadata, "tensor_names": json.dumps([name for name in tensor_names if "." in name])}
|
|
64
78
|
rebuilt = unflatten_tensor_state_dict(state_dict, metadata)
|
|
65
79
|
if isinstance(rebuilt, tuple):
|
|
66
80
|
rebuilt = rebuilt[0]
|
|
81
|
+
for name in root_names:
|
|
82
|
+
if name in state_dict:
|
|
83
|
+
rebuilt[name] = state_dict[name]
|
|
67
84
|
return rebuilt
|
|
68
85
|
|
|
69
86
|
def _require_safetensors_support(self):
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
import torch
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
QUANT_BACKENDS = {}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QuantBackend(ABC):
|
|
9
|
+
"""
|
|
10
|
+
Adapter between the framework and a quantization library (bnb / torchao / custom).
|
|
11
|
+
Subclasses are registered in `QUANT_BACKENDS` ({name -> class}) and instantiated by
|
|
12
|
+
`QuantizeConfig` with the method's backend config. A backend operates on single
|
|
13
|
+
Linears; model-level traversal and replacement is done by the `QuantizeConfig` methods.
|
|
14
|
+
|
|
15
|
+
The quantized Linear produced by a backend must satisfy:
|
|
16
|
+
(a) It is an `nn.Linear` drop-in: `forward(x)` internally performs dequant + matmul.
|
|
17
|
+
(b) `.to(...)` moves devices but never re-types the packed weight / quant state:
|
|
18
|
+
a dtype cast (`.to(dtype)` / `.half()` / `.float()`) must leave their storage
|
|
19
|
+
format and values intact.
|
|
20
|
+
(c) `state_dict()` / `load_state_dict(assign=True)` round-trips (optionally via
|
|
21
|
+
`flatten_state_dict` / `unflatten_state_dict`).
|
|
22
|
+
(d) (Training branch only) `forward` is differentiable w.r.t. its input, so
|
|
23
|
+
gradients can pass through frozen quantized layers to reach LoRA branches.
|
|
24
|
+
Declared statically by `capabilities()["is_differentiable"]` and verifiable
|
|
25
|
+
at runtime by calling `check_differentiable` on a quantized Linear the
|
|
26
|
+
backend produced.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
name: str = ""
|
|
30
|
+
|
|
31
|
+
def __init__(self, config=None):
|
|
32
|
+
self.config = config
|
|
33
|
+
|
|
34
|
+
def capabilities(self) -> dict:
|
|
35
|
+
return {
|
|
36
|
+
"is_serializable": False,
|
|
37
|
+
"is_differentiable": False,
|
|
38
|
+
"is_compileable": False,
|
|
39
|
+
"requires_calibration": False,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def validate_environment(self):
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
def create_quantized_linear(self, linear: torch.nn.Linear, compute_device=None, model_device=None) -> torch.nn.Module:
|
|
46
|
+
raise NotImplementedError(
|
|
47
|
+
f"Backend `{self.name}` cannot quantize an fp model online. Use a method whose "
|
|
48
|
+
"backend supports it, or load an already quantized checkpoint."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def create_quantized_linear_shell(self, linear: torch.nn.Linear, compute_dtype: torch.dtype) -> torch.nn.Module:
|
|
52
|
+
raise NotImplementedError(
|
|
53
|
+
f"Backend `{self.name}` cannot load pre-quantized checkpoints. Use "
|
|
54
|
+
"`load_prequantized=False` to quantize an fp model online instead."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def dequantize_to_linear(self, module: torch.nn.Module, compute_dtype: torch.dtype, compute_device=None, model_device=None) -> torch.nn.Linear:
|
|
58
|
+
raise NotImplementedError(
|
|
59
|
+
f"Backend `{self.name}` cannot dequantize back to `nn.Linear`, so "
|
|
60
|
+
'`mode="dequant_once"` is unavailable.'
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def quantized_linear_classes(self) -> tuple:
|
|
64
|
+
"""The Linear classes this backend produces. MUST be subclass of `torch.nn.Linear`."""
|
|
65
|
+
raise NotImplementedError(
|
|
66
|
+
f"Backend `{self.name}` must declare the Linear classes it produces."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def checkpoint_key_patterns(self) -> tuple:
|
|
70
|
+
"""Checkpoint entries one quantized Linear needs, relative to its dotted name."""
|
|
71
|
+
return ("weight", "weight.", "bias")
|
|
72
|
+
|
|
73
|
+
def is_quantized_linear(self, module) -> bool:
|
|
74
|
+
return isinstance(module, self.quantized_linear_classes())
|
|
75
|
+
|
|
76
|
+
def flatten_state_dict(self, state_dict: dict):
|
|
77
|
+
self._require_serializable()
|
|
78
|
+
return state_dict, {}
|
|
79
|
+
|
|
80
|
+
def unflatten_state_dict(self, state_dict: dict, metadata: dict):
|
|
81
|
+
self._require_serializable()
|
|
82
|
+
return state_dict
|
|
83
|
+
|
|
84
|
+
def _require_serializable(self):
|
|
85
|
+
if not self.capabilities().get("is_serializable", False):
|
|
86
|
+
raise NotImplementedError(
|
|
87
|
+
f"Backend `{self.name}` declares `is_serializable=False`, so its quantized state "
|
|
88
|
+
"dict cannot be flattened or rebuilt. Override these methods if it actually can."
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def register_quant_backend(name):
|
|
92
|
+
def decorator(cls):
|
|
93
|
+
cls.name = name
|
|
94
|
+
QUANT_BACKENDS[name] = cls
|
|
95
|
+
return cls
|
|
96
|
+
return decorator
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def resolve_checkpoint_keys(patterns, layer_name: str, available_keys) -> list:
|
|
100
|
+
"""Expand a backend's `checkpoint_key_patterns` into the absolute keys of one layer.
|
|
101
|
+
|
|
102
|
+
`available_keys` is anything supporting `in` and iteration (a dict or a `DiskMap`).
|
|
103
|
+
Exact patterns are probed with `in`, so a whole-file key index costs O(1) per pattern;
|
|
104
|
+
only patterns ending in "." require scanning the index.
|
|
105
|
+
"""
|
|
106
|
+
prefix = f"{layer_name}." if layer_name else ""
|
|
107
|
+
nested_prefixes = tuple(prefix + pattern for pattern in patterns if pattern.endswith("."))
|
|
108
|
+
keys = [prefix + pattern for pattern in patterns
|
|
109
|
+
if not pattern.endswith(".") and prefix + pattern in available_keys]
|
|
110
|
+
if nested_prefixes:
|
|
111
|
+
keys += [key for key in available_keys if key.startswith(nested_prefixes)]
|
|
112
|
+
return list(dict.fromkeys(keys))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def check_differentiable(module: torch.nn.Module, example_input: torch.Tensor = None, verbose: bool = True) -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Check whether gradients pass through `module` w.r.t. its input: run a real
|
|
118
|
+
backward pass from the output (`torch.autograd.grad`) and verify a finite
|
|
119
|
+
gradient arrives at the input. This is what LoRA training requires from
|
|
120
|
+
frozen (e.g. quantized) layers. The module is cast to bfloat16 in place and
|
|
121
|
+
probed with a bfloat16 input; if `example_input` is None, a random one is
|
|
122
|
+
built for modules exposing `in_features`.
|
|
123
|
+
|
|
124
|
+
Example (probing a torchao-quantized Linear):
|
|
125
|
+
|
|
126
|
+
import torch
|
|
127
|
+
from diffsynth.core.quant import check_differentiable
|
|
128
|
+
from torchao.quantization import quantize_, Int8WeightOnlyConfig
|
|
129
|
+
|
|
130
|
+
linear = torch.nn.Linear(1024, 1024, dtype=torch.bfloat16, device="cuda")
|
|
131
|
+
quantize_(linear, Int8WeightOnlyConfig(version=2))
|
|
132
|
+
check_differentiable(linear)
|
|
133
|
+
"""
|
|
134
|
+
def report(result, detail):
|
|
135
|
+
if verbose:
|
|
136
|
+
print(f"check_differentiable ({type(module).__name__}): {'OK' if result else 'FAIL'} -- {detail}")
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
module = module.to(torch.bfloat16)
|
|
141
|
+
if example_input is None:
|
|
142
|
+
if not hasattr(module, "in_features"):
|
|
143
|
+
raise ValueError("`example_input` is required for modules without `in_features`.")
|
|
144
|
+
device = next((t.device for t in list(module.parameters()) + list(module.buffers())), torch.device("cpu"))
|
|
145
|
+
example_input = torch.randn(4, module.in_features, device=device)
|
|
146
|
+
x = example_input.detach().to(torch.bfloat16).requires_grad_(True)
|
|
147
|
+
y = module(x)
|
|
148
|
+
if not y.requires_grad:
|
|
149
|
+
return report(False, "the output does not require grad, so no autograd graph was recorded")
|
|
150
|
+
input_grad = torch.autograd.grad(y, x, grad_outputs=torch.randn_like(y), allow_unused=True)[0]
|
|
151
|
+
except Exception as error:
|
|
152
|
+
return report(False, f"{type(error).__name__}: {error}")
|
|
153
|
+
if input_grad is None:
|
|
154
|
+
return report(False, "backward finished but no gradient reached the input")
|
|
155
|
+
if not torch.isfinite(input_grad.float()).all():
|
|
156
|
+
return report(False, "the input gradient contains non-finite values")
|
|
157
|
+
return report(True, "gradients pass through the module to its input")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def check_backend_contract(backend, in_features: int = 512, out_features: int = 512,
|
|
161
|
+
compute_dtype: torch.dtype = torch.bfloat16,
|
|
162
|
+
compute_device: str = "cuda", verbose: bool = True) -> bool:
|
|
163
|
+
"""
|
|
164
|
+
Verify a backend satisfies the quantized-Linear contract: it declares its classes,
|
|
165
|
+
both factory methods return instances of them, and every declared class subclasses
|
|
166
|
+
`torch.nn.Linear` so LoRA target detection and VRAM management can see it. The
|
|
167
|
+
checkpoint key patterns are checked against the keys the backend actually writes,
|
|
168
|
+
since a pattern list that misses a scale makes disk offload load corrupt layers
|
|
169
|
+
without raising.
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
|
|
173
|
+
from diffsynth.core.quant import QUANT_BACKENDS, QUANT_METHODS, check_backend_contract
|
|
174
|
+
spec = QUANT_METHODS["bitsandbytes_nf4"]
|
|
175
|
+
check_backend_contract(QUANT_BACKENDS[spec.backend](spec.config_factory({})))
|
|
176
|
+
"""
|
|
177
|
+
failures = []
|
|
178
|
+
|
|
179
|
+
def check(condition, detail):
|
|
180
|
+
if not condition:
|
|
181
|
+
failures.append(detail)
|
|
182
|
+
if verbose:
|
|
183
|
+
print(f" [{'PASS' if condition else 'FAIL'}] {detail}")
|
|
184
|
+
return condition
|
|
185
|
+
|
|
186
|
+
if verbose:
|
|
187
|
+
print(f"check_backend_contract ({backend.name}):")
|
|
188
|
+
try:
|
|
189
|
+
classes = backend.quantized_linear_classes()
|
|
190
|
+
except NotImplementedError as error:
|
|
191
|
+
if verbose:
|
|
192
|
+
print(f" [FAIL] quantized_linear_classes() is not implemented: {error}")
|
|
193
|
+
return False
|
|
194
|
+
if not check(len(classes) > 0, f"quantized_linear_classes() is non-empty: {[cls.__name__ for cls in classes]}"):
|
|
195
|
+
return False
|
|
196
|
+
for cls in classes:
|
|
197
|
+
check(issubclass(cls, torch.nn.Linear), f"{cls.__name__} subclasses torch.nn.Linear")
|
|
198
|
+
|
|
199
|
+
plain = torch.nn.Linear(in_features, out_features, bias=True, dtype=compute_dtype, device=compute_device)
|
|
200
|
+
plain.requires_grad_(False)
|
|
201
|
+
check(not backend.is_quantized_linear(plain), "a plain nn.Linear is not reported as quantized")
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
shell = backend.create_quantized_linear_shell(plain, compute_dtype)
|
|
205
|
+
except NotImplementedError:
|
|
206
|
+
shell = None
|
|
207
|
+
if verbose:
|
|
208
|
+
print(" [SKIP] create_quantized_linear_shell() is unsupported by this backend")
|
|
209
|
+
if shell is not None:
|
|
210
|
+
check(isinstance(shell, classes), f"create_quantized_linear_shell() returns a declared class, got {type(shell).__name__}")
|
|
211
|
+
check(backend.is_quantized_linear(shell), "the shell is recognized before load_state_dict (disk offload routing)")
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
quantized = backend.create_quantized_linear(plain, compute_device=compute_device)
|
|
215
|
+
except NotImplementedError:
|
|
216
|
+
quantized = None
|
|
217
|
+
if verbose:
|
|
218
|
+
print(" [SKIP] create_quantized_linear() is unsupported by this backend")
|
|
219
|
+
if quantized is not None:
|
|
220
|
+
check(isinstance(quantized, classes), f"create_quantized_linear() returns a declared class, got {type(quantized).__name__}")
|
|
221
|
+
|
|
222
|
+
patterns = backend.checkpoint_key_patterns()
|
|
223
|
+
check(len(patterns) > 0, f"checkpoint_key_patterns() is non-empty: {list(patterns)}")
|
|
224
|
+
saved = quantized if quantized is not None else shell
|
|
225
|
+
if saved is None:
|
|
226
|
+
if verbose:
|
|
227
|
+
print(" [SKIP] neither factory method is supported, so the stored keys cannot be checked")
|
|
228
|
+
else:
|
|
229
|
+
state_dict = {f"proj.{key}": value for key, value in saved.state_dict().items()}
|
|
230
|
+
if backend.capabilities().get("is_serializable", False):
|
|
231
|
+
try:
|
|
232
|
+
state_dict = backend.flatten_state_dict(state_dict)[0]
|
|
233
|
+
except Exception as error:
|
|
234
|
+
if verbose:
|
|
235
|
+
print(f" [SKIP] flatten_state_dict() failed, falling back to the raw state dict keys: {type(error).__name__}: {error}")
|
|
236
|
+
uncovered = sorted(set(state_dict) - set(resolve_checkpoint_keys(patterns, "proj", state_dict)))
|
|
237
|
+
check(len(uncovered) == 0, f"checkpoint_key_patterns() covers every stored key; uncovered: {uncovered}")
|
|
238
|
+
|
|
239
|
+
if verbose:
|
|
240
|
+
print(f" => {'OK' if not failures else str(len(failures)) + ' FAILED'}")
|
|
241
|
+
return not failures
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass, field, fields, is_dataclass
|
|
2
2
|
from typing import Any, Callable, Optional
|
|
3
3
|
import torch
|
|
4
|
-
from .base import QUANT_BACKENDS
|
|
4
|
+
from .base import QUANT_BACKENDS, resolve_checkpoint_keys
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
QUANT_METHODS = {}
|
|
@@ -166,6 +166,40 @@ class QuantizeConfig:
|
|
|
166
166
|
"""Whether `module` is one of this config's backend-native quantized Linears."""
|
|
167
167
|
return self.backend.is_quantized_linear(module)
|
|
168
168
|
|
|
169
|
+
def checkpoint_keys(self, module, layer_name: str, available_keys) -> list:
|
|
170
|
+
"""
|
|
171
|
+
Resolve the backend's `checkpoint_key_patterns` for `layer_name` against
|
|
172
|
+
`available_keys` (anything supporting `in` and iteration, including a `DiskMap`).
|
|
173
|
+
Raises when the layer contributes no key at all, since silently loading a
|
|
174
|
+
quantized layer without its packed weight or scale corrupts it without any error.
|
|
175
|
+
|
|
176
|
+
Parameters:
|
|
177
|
+
module: the quantized layer the keys are fetched for.
|
|
178
|
+
layer_name: its dotted name inside the checkpoint.
|
|
179
|
+
available_keys: the key index of the whole checkpoint.
|
|
180
|
+
"""
|
|
181
|
+
keys = resolve_checkpoint_keys(self.backend.checkpoint_key_patterns(), layer_name, available_keys)
|
|
182
|
+
if not keys:
|
|
183
|
+
raise ValueError(
|
|
184
|
+
f"Found no checkpoint entry for the quantized layer `{layer_name}` "
|
|
185
|
+
f"(backend `{self.backend.name}`, patterns {list(self.backend.checkpoint_key_patterns())}). "
|
|
186
|
+
"Check that the checkpoint really holds this layer quantized and that "
|
|
187
|
+
"`target_modules` matches the layers it quantized."
|
|
188
|
+
)
|
|
189
|
+
return keys
|
|
190
|
+
|
|
191
|
+
def build_quantized_shell(self, module, compute_dtype: torch.dtype, **kwargs):
|
|
192
|
+
"""
|
|
193
|
+
Build an empty quantized Linear matching `module`, used to release a layer's
|
|
194
|
+
weights while keeping it routable, and to stage a transient copy on the
|
|
195
|
+
computation device.
|
|
196
|
+
|
|
197
|
+
Parameters:
|
|
198
|
+
module: the quantized layer whose shape and bias presence are mirrored.
|
|
199
|
+
compute_dtype: dtype the shell dequantizes to at forward time.
|
|
200
|
+
"""
|
|
201
|
+
return self.backend.create_quantized_linear_shell(module, compute_dtype)
|
|
202
|
+
|
|
169
203
|
def prepare_for_prequantized_load(self, model: torch.nn.Module, compute_dtype: torch.dtype = torch.bfloat16):
|
|
170
204
|
"""
|
|
171
205
|
Replace the targeted `nn.Linear` layers with empty quantized Linears matching a
|
|
@@ -226,6 +260,8 @@ class QuantizeConfig:
|
|
|
226
260
|
def _should_quantize(self, full_name, module):
|
|
227
261
|
if not isinstance(module, torch.nn.Linear):
|
|
228
262
|
return False
|
|
263
|
+
if self.is_quantized_linear(module):
|
|
264
|
+
return False
|
|
229
265
|
if self.target_modules is not None and not self._name_matches(full_name, self.target_modules):
|
|
230
266
|
return False
|
|
231
267
|
if self._name_matches(full_name, self.exclude_modules):
|
|
@@ -302,6 +338,7 @@ class MixedQuantizeConfig:
|
|
|
302
338
|
modes = {config.mode for config in self.configs}
|
|
303
339
|
if len(modes) > 1:
|
|
304
340
|
raise ValueError(f"All configs in `MixedQuantizeConfig` should share the same `mode`, but got {sorted(modes)}.")
|
|
341
|
+
self._ownership = {}
|
|
305
342
|
|
|
306
343
|
@property
|
|
307
344
|
def method(self):
|
|
@@ -324,7 +361,7 @@ class MixedQuantizeConfig:
|
|
|
324
361
|
"""
|
|
325
362
|
if self.load_prequantized:
|
|
326
363
|
return model
|
|
327
|
-
self.
|
|
364
|
+
self._build_ownership(model)
|
|
328
365
|
for config in self.configs:
|
|
329
366
|
config.quantize_model(model, compute_device=compute_device, model_device=model_device)
|
|
330
367
|
return model
|
|
@@ -351,6 +388,43 @@ class MixedQuantizeConfig:
|
|
|
351
388
|
"""Whether `module` is a quantized Linear of any config's backend."""
|
|
352
389
|
return any(config.is_quantized_linear(module) for config in self.configs)
|
|
353
390
|
|
|
391
|
+
def checkpoint_keys(self, module, layer_name: str, available_keys) -> list:
|
|
392
|
+
"""
|
|
393
|
+
Resolve the checkpoint keys of `layer_name` using the config whose backend owns
|
|
394
|
+
that layer, so each layer set is read with its own key shape.
|
|
395
|
+
|
|
396
|
+
Parameters:
|
|
397
|
+
module: the quantized layer the keys are fetched for.
|
|
398
|
+
layer_name: its dotted name inside the checkpoint.
|
|
399
|
+
available_keys: the key index of the whole checkpoint.
|
|
400
|
+
"""
|
|
401
|
+
return self._owning_config(module, layer_name).checkpoint_keys(module, layer_name, available_keys)
|
|
402
|
+
|
|
403
|
+
def build_quantized_shell(self, module, compute_dtype: torch.dtype, layer_name: str = None):
|
|
404
|
+
"""
|
|
405
|
+
Build an empty quantized Linear for `module` using the config that owns it.
|
|
406
|
+
|
|
407
|
+
Parameters:
|
|
408
|
+
module: the quantized layer whose shape and bias presence are mirrored.
|
|
409
|
+
compute_dtype: dtype the shell dequantizes to at forward time.
|
|
410
|
+
layer_name: its dotted name inside the model; required to pick the right config
|
|
411
|
+
when several configs share one backend, since their quantized Linears are
|
|
412
|
+
then the same class.
|
|
413
|
+
"""
|
|
414
|
+
return self._owning_config(module, layer_name).build_quantized_shell(module, compute_dtype)
|
|
415
|
+
|
|
416
|
+
def _owning_config(self, module, layer_name=None):
|
|
417
|
+
config = self._ownership.get(layer_name)
|
|
418
|
+
if config is not None:
|
|
419
|
+
return config
|
|
420
|
+
for config in self.configs:
|
|
421
|
+
if config.is_quantized_linear(module):
|
|
422
|
+
return config
|
|
423
|
+
raise ValueError(
|
|
424
|
+
f"`{type(module).__name__}` is not a quantized Linear of any config in this "
|
|
425
|
+
f"`MixedQuantizeConfig` (methods: {self.method})."
|
|
426
|
+
)
|
|
427
|
+
|
|
354
428
|
def prepare_for_prequantized_load(self, model: torch.nn.Module, compute_dtype: torch.dtype = torch.bfloat16):
|
|
355
429
|
"""
|
|
356
430
|
Replace each config's targeted Linears by that backend's shells, after verifying
|
|
@@ -360,26 +434,29 @@ class MixedQuantizeConfig:
|
|
|
360
434
|
model: the freshly constructed model whose targeted layers become shells.
|
|
361
435
|
compute_dtype: dtype the quantized layers dequantize to at forward time.
|
|
362
436
|
"""
|
|
363
|
-
self.
|
|
437
|
+
self._build_ownership(model)
|
|
364
438
|
for config in self.configs:
|
|
365
439
|
config.prepare_for_prequantized_load(model, compute_dtype=compute_dtype)
|
|
366
440
|
return model
|
|
367
441
|
|
|
368
442
|
def unflatten_state_dict(self, state_dict: dict, metadata: dict):
|
|
369
443
|
"""
|
|
370
|
-
Rebuild composite quantized tensors from a flat (safetensors) state dict
|
|
371
|
-
running each distinct backend's `unflatten_state_dict` once.
|
|
444
|
+
Rebuild composite quantized tensors from a flat (safetensors) state dict.
|
|
372
445
|
"""
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
446
|
+
if not self._ownership:
|
|
447
|
+
for config in self._distinct_backend_configs():
|
|
448
|
+
state_dict = config.unflatten_state_dict(state_dict, metadata)
|
|
449
|
+
return state_dict
|
|
450
|
+
rebuilt = {}
|
|
451
|
+
for config, keys in self._grouped_by_backend(state_dict):
|
|
452
|
+
rebuilt.update(config.unflatten_state_dict(keys, metadata) if config else keys)
|
|
453
|
+
return rebuilt
|
|
376
454
|
|
|
377
455
|
def flatten_state_dict(self, state_dict: dict):
|
|
378
456
|
"""
|
|
379
|
-
Flatten the mixed model's state dict into plain tensors and string-only
|
|
380
|
-
metadata,
|
|
381
|
-
|
|
382
|
-
metadata=metadata)`.
|
|
457
|
+
Flatten the mixed model's state dict into plain tensors and string-only metadata.
|
|
458
|
+
Returns (state_dict, metadata), ready for `safetensors.torch.save_file(tensors,
|
|
459
|
+
path, metadata=metadata)`.
|
|
383
460
|
"""
|
|
384
461
|
for config in self.configs:
|
|
385
462
|
if not config.backend.capabilities().get("is_serializable", False):
|
|
@@ -389,10 +466,21 @@ class MixedQuantizeConfig:
|
|
|
389
466
|
"state dict cannot be flattened for saving."
|
|
390
467
|
)
|
|
391
468
|
merged_metadata = {}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
469
|
+
if not self._ownership:
|
|
470
|
+
flattened = state_dict
|
|
471
|
+
for config in self._distinct_backend_configs():
|
|
472
|
+
flattened, metadata = config.backend.flatten_state_dict(flattened)
|
|
473
|
+
merged_metadata.update(metadata)
|
|
474
|
+
else:
|
|
475
|
+
flattened = {}
|
|
476
|
+
for config, keys in self._grouped_by_backend(state_dict):
|
|
477
|
+
if config is None:
|
|
478
|
+
flattened.update(keys)
|
|
479
|
+
continue
|
|
480
|
+
tensors, metadata = config.backend.flatten_state_dict(keys)
|
|
481
|
+
flattened.update(tensors)
|
|
482
|
+
merged_metadata.update(metadata)
|
|
483
|
+
tensors = {key: value.contiguous() for key, value in flattened.items()}
|
|
396
484
|
metadata = {"format": "pt", **{key: value if isinstance(value, str) else str(value) for key, value in merged_metadata.items()}}
|
|
397
485
|
return tensors, metadata
|
|
398
486
|
|
|
@@ -405,21 +493,25 @@ class MixedQuantizeConfig:
|
|
|
405
493
|
distinct.append(config)
|
|
406
494
|
return distinct
|
|
407
495
|
|
|
408
|
-
def
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
496
|
+
def _grouped_by_backend(self, state_dict):
|
|
497
|
+
groups = {}
|
|
498
|
+
for key, value in state_dict.items():
|
|
499
|
+
parts = key.split(".")
|
|
500
|
+
config = next((owner for end in range(len(parts) - 1, 0, -1)
|
|
501
|
+
if (owner := self._ownership.get(".".join(parts[:end]))) is not None), None)
|
|
502
|
+
groups.setdefault(config.backend.name if config else None, (config, {}))[1][key] = value
|
|
503
|
+
return groups.values()
|
|
504
|
+
|
|
505
|
+
def _build_ownership(self, model):
|
|
506
|
+
ownership = {}
|
|
507
|
+
for index, config in enumerate(self.configs):
|
|
508
|
+
names = [name for name, module in model.named_modules() if name and config._should_quantize(name, module)]
|
|
509
|
+
overlap = sorted(set(names) & ownership.keys())
|
|
510
|
+
if overlap:
|
|
511
|
+
owner = self.configs.index(ownership[overlap[0]])
|
|
512
|
+
raise ValueError(
|
|
513
|
+
f"Configs {owner} (`{self.configs[owner].method}`) and {index} (`{config.method}`) "
|
|
514
|
+
f"in `MixedQuantizeConfig` both match {len(overlap)} layers (e.g. {', '.join(overlap[:5])}). "
|
|
515
|
+
)
|
|
516
|
+
ownership.update({name: config for name in names})
|
|
517
|
+
self._ownership.update(ownership)
|