Text-to-Image
Diffusers
Safetensors
English
Chinese
orbitquant
w4a8
4-bit precision
gptq
quantized
moss-image
arxiv:2607.02461
Instructions to use WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
Download moss_orbitquant.py from WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8: direct link, hf CLI and curl.
- Browser
- Download file 6.34 kB
-
https://huggingface.co/WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8/resolve/main/moss_orbitquant.py
- Command line
-
hf download hf://WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8/moss_orbitquant.py
-
curl -L -o moss_orbitquant.py https://huggingface.co/WaveCut/MOSS-Image-SFT-OrbitQuant-W4A8/resolve/main/moss_orbitquant.py
6.34 kB
| """Load MOSS-Image-SFT with OrbitQuant W4A8 components into the model's own pipeline (``pipeline_moss_image.py``).""" | |
| from __future__ import annotations | |
| import dataclasses | |
| import json | |
| import os | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| from torch import nn | |
| GROUPS = ("qkv", "mlp", "attn_out", "mlp_out") | |
| def _allocator(device: str) -> None: | |
| # Growable segments return the transient blocks of one stage to the next. An explicit setting is left untouched. | |
| if not device.startswith("cuda") or {"PYTORCH_CUDA_ALLOC_CONF", "PYTORCH_ALLOC_CONF"} & set(os.environ): | |
| return | |
| if not torch.cuda.is_initialized(): | |
| os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True" | |
| else: | |
| setter = getattr(torch._C, "_accelerator_setAllocatorSettings", None) | |
| (setter or torch.cuda.memory._set_allocator_settings)("expandable_segments:True") | |
| def _load_transformer(path: Path, transformer_class, device: str, fused: bool, attention: str, activation_bits: int): | |
| import orbitquant # noqa: F401 -- registers the OrbitQuant layers | |
| from orbitquant.adaln import RTNInt4Linear | |
| from orbitquant.artifacts.manifest import OrbitQuantManifest | |
| from orbitquant.config import OrbitQuantConfig | |
| from orbitquant.layers import OrbitQuantLinear | |
| from orbitquant.modeling import _parent_and_child, _set_child | |
| from safetensors.torch import load_file | |
| config = OrbitQuantConfig.from_dict(json.loads((path / "quantization_config.json").read_text())) | |
| manifest = OrbitQuantManifest.from_dict(json.loads((path / "orbitquant_manifest.json").read_text())) | |
| with torch.device("meta"): | |
| model = transformer_class.from_config(transformer_class.load_config(str(path))) | |
| for name in manifest.quantized_modules: | |
| bits = manifest.module_bits.get(name) | |
| layer_config = dataclasses.replace(config, weight_bits=bits) if bits and bits != config.weight_bits else config | |
| parent, child = _parent_and_child(model, name) | |
| _set_child(parent, child, OrbitQuantLinear.empty_from_linear( | |
| model.get_submodule(name), config=layer_config, module_name=name)) | |
| for name in manifest.adaln_modules: | |
| parent, child = _parent_and_child(model, name) | |
| _set_child(parent, child, RTNInt4Linear.empty_from_linear(model.get_submodule(name), config=config, module_name=name)) | |
| model.load_state_dict(load_file(str(path / "model.safetensors"), device=device), strict=True, assign=True) | |
| model = model.to(device).eval() | |
| if fused: | |
| from orbitquant.fused import fuse | |
| widths = dict.fromkeys(GROUPS, activation_bits) if activation_bits != config.activation_bits else None | |
| fuse(model, config=config, attention=attention, activation_bits=widths) | |
| return model | |
| def _park(model: nn.Module) -> None: | |
| """Move a component to host memory right after its GPU build, so the next build does not stack on it.""" | |
| from orbitquant.fused import release | |
| release(model) | |
| model.to("cpu") | |
| torch.cuda.empty_cache() | |
| class HostEmbedding(nn.Module): | |
| """Token embedding kept in host memory: a prompt reads a few hundred of its 248k rows, so the 2 GiB table stays | |
| off the GPU. The table is not a registered parameter, so moving the text encoder does not move it.""" | |
| def __init__(self, embedding: nn.Embedding): | |
| super().__init__() | |
| self.__dict__["table"] = embedding.weight.detach().to("cpu") | |
| self.num_embeddings, self.embedding_dim = self.table.shape | |
| def weight(self): | |
| return self.table | |
| def forward(self, ids: torch.Tensor) -> torch.Tensor: | |
| return nn.functional.embedding(ids.cpu(), self.table).to(ids.device, non_blocking=True) | |
| def _load_text_encoder(path: Path, device: str, fused: bool, activation_bits: int, host_embedding: bool): | |
| import orbitquant # noqa: F401 -- registers the OrbitQuant backend with Transformers | |
| from transformers import AutoModel | |
| model = AutoModel.from_pretrained(str(path), dtype=torch.bfloat16, device_map={"": device}).eval() | |
| if fused: | |
| from orbitquant.fused import fuse_linears | |
| fuse_linears(model, activation_bits=activation_bits) | |
| if host_embedding: | |
| model.embed_tokens = HostEmbedding(model.embed_tokens) | |
| return model | |
| def load_pipeline(path: str | Path, device: str = "cuda", attention: str = "cudnn", offload: bool = False, | |
| fused: bool | None = None, activation_bits: int = 8, host_embedding: bool = True): | |
| """MOSS-Image pipeline with the W4A8 transformer and text encoder; call it as the original pipeline. | |
| ``attention`` is ``cudnn`` (default), ``flash``, ``sdpa`` or ``int8`` (faster, changes the image slightly). | |
| ``offload`` keeps the components in host memory and moves each to the GPU only while it runs. ``fused=None`` | |
| fuses the projections on CUDA devices with compute capability 8.0 or newer (needed for 8-bit activations).""" | |
| path = Path(path) | |
| _allocator(device) | |
| if str(path) not in sys.path: | |
| sys.path.insert(0, str(path)) | |
| from diffusers import AutoencoderKLFlux2 | |
| from pipeline_moss_image import MOSSImagePipeline, MOSSImageScheduler, MOSSImageTransformer | |
| from transformers import AutoTokenizer | |
| if fused is None: | |
| fused = device.startswith("cuda") and torch.cuda.get_device_capability(device) >= (8, 0) | |
| # The transformer is fused on the GPU even with offload: on the host the group build runs many small parallel | |
| # copies, which stall for minutes when a container's CPU quota is far below its visible core count. | |
| transformer = _load_transformer(path / "transformer", MOSSImageTransformer, device, fused, attention, activation_bits) | |
| if offload: | |
| _park(transformer) | |
| text_encoder = _load_text_encoder(path / "text_encoder", device, fused, activation_bits, host_embedding) | |
| if offload: | |
| _park(text_encoder) | |
| vae = AutoencoderKLFlux2.from_pretrained(str(path / "vae"), torch_dtype=torch.float32) | |
| vae = vae.to("cpu" if offload else device).eval() | |
| tokenizer = AutoTokenizer.from_pretrained(str(path / "tokenizer")) | |
| pipeline = MOSSImagePipeline(transformer, MOSSImageScheduler(), text_encoder, tokenizer, vae) | |
| if offload: | |
| pipeline.enable_model_cpu_offload(device=device) | |
| torch.cuda.empty_cache() | |
| return pipeline | |