Introduction

ModelScope just open-sourced EntroPack, an Apache 2.0 PyTorch library that compresses model weights at any bits-per-parameter you ask for, not just the usual 4-bit or 8-bit steps. The announcement landed on Oct 14 (about 18:00 MYT) alongside ready-to-load packs for three models creators actually run locally: Z-Image-Turbo, Qwen-Image-2.1, and MiniMax-H3. Today they load through DiffSynth-Studio; ModelScope's post also names ComfyUI as a target.

The pitch is simple and very local-rig friendly: instead of a fixed quant that either overshoots your card or leaves VRAM on the table, you dial a bitrate like 4.8 bpp and fill the GPU you actually own.

Code: modelscope/entropack on GitHub · Packs: EntroPackPreQuants on ModelScope · Report: EntroPack technical report

What shipped

  • Library: entropack (Python 3.10+, CUDA build of PyTorch 2.10+, cuda13 or cuda12 extras), Apache 2.0.
  • Lossy mode: EntroPackLossyConfig(target_bpp=...) takes any target from 0.001 to 11 bpp, fractions included. No activation calibration or fine-tuning.
  • Lossless modes: DFloat11Config() for exact BF16 recovery and TileANSConfig() for BF16, FP16, FP32, FP8, INT8, and more.
  • Drop-in layers: CompressedLinear.from_linear swaps a normal torch.nn.Linear for a compressed one you call the same way.
  • Decoding: E8 lattice quantization plus entropy coding, decoded and reconstructed in one fused GPU kernel. ModelScope reports over 340 GB/s on a single BF16 tensor test.

The 16 GB headline

ModelScope's showcase number is the one most of us care about. In a Qwen-Image-2.1 test at 1024×1024, targeting 4.8 bpp peaked at 15.86 GiB, so it fits a 16 GB card, while cutting weight reconstruction error from NF4's 9.40% to 4.26%.

Speed cost looks small too. On one NVIDIA H20, compressing all 276 linear layers of Z-Image-Turbo's DiT at 4 bpp took 3.5 seconds, and a denoising step ran at 544.7 ms versus 505.7 ms for the original BF16 model, about 7.7% slower.

The pre-quantized packs

Every model gets DiT and text-encoder files at 4, 5, 6, 7, and 8 bpp, an fp8@5 pack (FP8 W8A8 codes stored at 5 bpp, running FP8 GEMM), and an "extreme" mixed-bit pack that keeps sensitive layers higher and squeezes the rest. You can mix DiT and text-encoder rates freely, for example an 8 bpp DiT with a 4 bpp text encoder.

Z-Image-Turbo DiT sizes from the model card:

  • 8 bpp: 5.78 GB, 0.53% reconstruction error
  • 6 bpp: 4.34 GB, 1.85% error
  • 4 bpp: 2.88 GB, 7.01% error
  • Extreme 2.3 bpp: 1.66 GB, 24.0% error (about one-seventh of BF16)

Qwen-Image-2.1 DiT sizes:

  • 8 bpp: 6.68 GB, 0.54% error
  • 5 bpp: 4.19 GB, 3.66% error
  • 4 bpp: 3.34 GB, 7.06% error
  • Extreme 3.0 bpp: 2.50 GB, 14.2% error

MiniMax-H3 ships both FL2VA and Ref2VA DiTs plus a shared text encoder and video VAE:

  • DiT 8 bpp: 31.16 GB each, 0.50% error
  • DiT 5 bpp: 19.54 GB each, 3.39% error
  • DiT 4 bpp: 15.58 GB each, 6.57% error
  • DiT extreme 3.0 bpp: 11.68 GB each, 13.2% error
  • Video VAE: 1.47 GB at 4 bpp up to 2.61 GB at 8 bpp

A quick read of those error numbers: 6 to 8 bpp is close to lossless territory, 4 to 5 bpp is the sweet spot for tight cards, and the extreme packs are for "I just want it to run" experiments. Check the validation images and videos under assets/ on the model card before you commit a rig to the low end.

Try it

Install both pieces from source, picking the CUDA extra that matches your setup:

git clone https://github.com/modelscope/DiffSynth-Studio.git
cd DiffSynth-Studio && pip install -e .
cd ..
git clone https://github.com/modelscope/entropack.git
cd entropack && pip install -e '.[cuda13]'

Then point DiffSynth-Studio at a pack. Each .safetensors file has a same-named .json sidecar that registers it, so the Z-Image-Turbo example only needs the package paths:

import json
import torch
from diffsynth.configs import MODEL_CONFIGS
from diffsynth.pipelines.z_image import ZImagePipeline, ModelConfig

repo = "DiffSynth-Studio/EntroPackPreQuants"

def prequant(path):
    pkg = ModelConfig(model_id=repo, origin_file_pattern=path)
    pkg.download_if_necessary()
    side = ModelConfig(model_id=repo, origin_file_pattern=path.replace(".safetensors", ".json"))
    side.download_if_necessary()
    with open(side.path) as f:
        MODEL_CONFIGS.append(json.load(f))
    return pkg

pipe = ZImagePipeline.from_pretrained(
    torch_dtype=torch.bfloat16,
    device="cuda",
    model_configs=[
        prequant("models/Z-Image-Turbo/dit_4bpp.safetensors"),
        prequant("models/Z-Image-Turbo/text_encoder_4bpp.safetensors"),
        ModelConfig(model_id="Tongyi-MAI/Z-Image-Turbo", origin_file_pattern="vae/diffusion_pytorch_model.safetensors"),
    ],
    tokenizer_config=ModelConfig(model_id="Tongyi-MAI/Z-Image-Turbo", origin_file_pattern="tokenizer/"),
)
image = pipe(prompt="a lantern-lit night market in the rain, cinematic, shallow depth of field", seed=42, rand_device="cuda")
image.save("z-image-turbo-entropack.jpg")

For Qwen-Image-2.1 or MiniMax-H3, swap in that model's pipeline and package paths. The extreme and fp8@5 packs load the same way.

Good to know

  • The library is Apache 2.0. The packs inherit each base model's own license, so check Qwen-Image-2.1, Z-Image-Turbo, and MiniMax-H3 terms before commercial use.
  • The model card documents DiffSynth-Studio loading today. ModelScope's announcement also mentions ComfyUI, so watch for a node or loader before assuming a drag-and-drop workflow.
  • You can compress your own checkpoints too: ep.compress(tensor, config) and CompressedLinear work on any 2D weight, which is handy for fine-tunes and LoRA-merged bases.

Original Source

Conclusion

EntroPack turns quantization from a menu of fixed sizes into a slider, and the first packs already cover the image and video models local creators lean on hardest. If a 16 GB card has been your ceiling for Qwen-Image-2.1, this is the one to test tonight.

—Aurelia ♡