{{ message }}
Repository navigation
feat: ConvRot INT8 for MOSS-Image (stage 4: DiT and text encoder, ported from Musubi Tuner) - #2461
Merged
Merged
Conversation
…from Musubi Tuner - library/convrot_int8_kernels.py / convrot_int8_utils.py: ConvRot INT8 (Hadamard rotation + per-channel int8, fused Triton GEMM with eager fallback, custom autograd for LoRA training). ComfyUI pre-quantized checkpoints (`.weight` int8 + `.weight_scale` + `.comfy_quant`) are loaded as they are; quantized nn.Embedding (token embedding of the text encoder) gets a dequantizing lookup with the inverse rotation - MOSS-Image: `--convrot_int8` (DiT), `--convrot_int8_text_encoder` (text encoder, also for tools/cache_text_encoder_outputs.py) and `--convrot_int8_bwd`; the ComfyUI `*_int8_convrot.safetensors` files are detected automatically. The fused `qkv` of the ComfyUI int8 DiT is split into q/k/v (weight, scale and spec). The dynamic quantization is bit-identical to the ComfyUI files - lora_utils: `quantizer` pass-through for the streaming loaders; accept a scalar LoRA multiplier (the default of `--lora_multiplier`) - fix: MossImageBlock cast the activations to the projection weight dtype (int8 after quantization) - fix: TensorWeightAdapter loaded a split tensor once per piece (the ComfyUI bf16 DiT took 13.9GB instead of 9.5GB) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d on a CPU-only machine)
`triton.autotune` needs an active GPU driver when the kernels are defined at import time and raises
RuntimeError ("0 active drivers") instead of ImportError on a CPU-only machine with triton installed
(the CI runners). HAS_TRITON now also requires CUDA and an active driver; the eager fallback is used
otherwise.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Oct 18, 2026
Merged
UR-al
added a commit
to UR-al/sd-scripts
that referenced
this pull request
Oct 20, 2026
…ning; ports from kohya-ss dev Fork fixes: - Multi-line caption files are used whole unless enable_wildcard picks one line (read_caption, process_caption and the canonical caption of train_util, MOSS and Anima-3.8B); a log line counts multi-line captions. - Transparent images are composited onto white when loaded for training (image_utils.flatten_alpha; alpha_mask keeps the alpha; opaque RGBA unchanged). - library/config_validation.py: unknown TOML keys warn with suggestions (error with --strict_config_keys or strict_config_keys = true), values are converted like the command line, choices and booleans are checked. Ported from kohya-ss/sd-scripts dev (PRs kohya-ss#2454, kohya-ss#2455, kohya-ss#2458-kohya-ss#2461, kohya-ss#2438): - caption_prefix / caption_suffix are added after the enable_wildcard line choice. - Text Encoder caches encode the processed caption for every strategy (strategy_base.caption_for_cache, info.cache_caption); warning for enable_wildcard without caption variants; Anima-3.8B caches also store and check a digest of the processed caption. - BaseSubsetParams defaults match argparse; tags-only fine-tuning metadata keeps its tags (build_finetuning_caption); literal \n in line-format sample prompts becomes a line break; dpmsolver / dpmsingle samplers work on diffusers 0.39; load_safetensors accepts a torch.device; cache_text_encoder_outputs weighted_captions assert. - MOSS: --show_timesteps console|image (+ --show_timesteps_epoch; library/timestep_visualization.py from upstream), modelspec architecture "moss-image-base/lora" and 1024x1024, networks.lora_moss train_llm_adapter / train_text_embedder adds the text refiner blocks. Tests: embedded reference DiT so the parity tests always run, fake-tokenizer TE cache round trip, lora_moss and LoKr merge round trips, caption order / processed-caption cache tests, config validation tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Stage 4 of the MOSS-Image support (after #2458 models / inference, #2459 strategies / caching and #2460 LoRA trainer): ConvRot INT8 (arXiv:2512.03673) for the frozen base weights of the DiT and the text encoder, ported from Musubi Tuner. This is the low-VRAM alternative to fp8 for MOSS-Image (
--fp8_basestays unsupported).library/convrot_int8_kernels.py(Musubi Tuner as is, vendored from comfy-kitchen, Apache-2.0): block-diagonal Hadamard rotation, row-wise int8 quantization, fused Triton int8 GEMM (online activation rotation + dynamic per-row int8 quantization + dequantization epilogue). Eager fallback without triton (same memory saving, no speedup).library/convrot_int8_utils.py(Musubiconvrot_int8_utils+comfy_quant_utils): streamingConvRotInt8Quantizer(dynamic quantization at load time, after the LoRA merge) and thenn.Linearmonkey patch with a customautograd.Function(frozen base: only grad_x in backward,bf16transient dequant orint8fused GEMM). ComfyUI pre-quantized checkpoints (.weightint8 +.weight_scalefp32 +.comfy_quantJSON) are loaded as they are. Additions over Musubi:key_filter(skip the vision tower /lm_headof the TE file without reading them), skipping ComfyUI's.comfy_attention.configtensors, row-chunked quantization for the 248k-row token embedding, and a quantizednn.Embeddingpatch: the ComfyUI int8 text encoder quantizesembed_tokensin the rotated basis too, so the lookup dequantizes the rows and applies the inverse rotation (without the rotation the rows do not match the bf16 weights).--convrot_int8(DiT),--convrot_int8_text_encoder(text encoder; also intools/cache_text_encoder_outputs.py) and--convrot_int8_bwd bf16|int8in the trainer,--convrot_int8/--convrot_int8_text_encoderinmoss_image_minimal_inference.py. The ComfyUI*_int8_convrot.safetensorsfiles are detected automatically and do not need the options. Scope: DiT = Linear layers of the 42 main blocks (252 modules), TE = attention / GDN / MLP projections andembed_tokens(201 modules), the same as the ComfyUI files. The fusedqkvof the ComfyUI int8 DiT is split into q / k / v (int8 weight and per-row scale along the rows, spec duplicated). The quantized models are frozen on load;cast_unetis disabled in the trainer so the fp32scale_weightbuffers survive, ConvRot Linears are excluded from--compile, block swap works as is, and the TE gradient checkpointing workaround picks the first floating point parameter (the token embedding is int8). Load-time LoRA merge into a pre-quantized file is rejected with a clear error (use the bf16 weights with--convrot_int8; LoRA training on a pre-quantized base is fine).library/lora_utils.py:quantizerpass-through forload_safetensors_with_lora_and_fp8/..._and_hook(as in Musubi).create_lora_merge_hookaccepts a scalar multiplier: the default1.0of--lora_multiplier(nargs="*") crashed the load-time merge when the option was omitted.ss_convrot_int8/ss_convrot_int8_text_encoder(effective values, including auto-detected files).Fixes of existing bugs found on the way
MossImageBlock._forwardcast the activations toself.proj.q.weight.dtype; with int8 weights the activations were rounded to int8 (under autocast silently, relerr 1.6 vs bf16). Now the norm weight dtype is used. Regression test added.TensorWeightAdapter.get_tensorchecked the split cache with the original key while the cache is filled with the new keys, so a split tensor was read once per piece: the ComfyUI bf16 DiT allocated 13.9 GB instead of 9.47 GB (3 fused qkv copies per block). Same fix as Musubi Tuner 6c6d57b. Regression test added.Verification (real weights, RTX PRO 6000, torch 2.12, triton 3.7)
bwd int81681 ms). Trainer steady state 1.41 s/it vs 1.45 s/it bf16 (the first ~20 steps look slower because of the Triton autotune / compile).--blocks_to_swap 20;--compile; official shards with--convrot_int8 --convrot_int8_text_encoderand sampling; inference with the stage 3 LoRA merged into the bf16 shards +--convrot_int8(training concept reproduced); pre-quantized + LoRA merge → error as intended.tests/test_convrot_int8.py(45, CPU eager + CUDA Triton),tests/test_safetensors_utils.py.Documentation (
docs/moss_image_train_network.md, README) follows in the next PR.🤖 Generated with Claude Code