Instructions to use ApacheOne/Wan2.2-Animate-2-14B-OrbitQuant-W4A4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use ApacheOne/Wan2.2-Animate-2-14B-OrbitQuant-W4A4 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline from diffusers.utils import load_image, export_to_video # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("ApacheOne/Wan2.2-Animate-2-14B-OrbitQuant-W4A4", dtype=torch.bfloat16, device_map="cuda") pipe.to("cuda") prompt = "A man with short gray hair plays a red electric guitar." image = load_image( "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/guitar-man.png" ) output = pipe(image=image, prompt=prompt).frames[0] export_to_video(output, "output.mp4") - Notebooks
- Google Colab
- Kaggle
| from __future__ import annotations | |
| from collections import OrderedDict | |
| import weakref | |
| import torch | |
| from torch import nn | |
| from .triton_w4a4 import PackedActivation, a4_pack_triton, w4a4_linear_triton | |
| class ActivationPackCache: | |
| """Small per-device cache to reuse identical A4 packing across Q/K/V linears.""" | |
| def __init__(self, capacity: int = 4): | |
| self.capacity = int(capacity) | |
| self._items: OrderedDict[tuple, tuple[weakref.ReferenceType, PackedActivation]] = OrderedDict() | |
| self.hits = 0 | |
| self.misses = 0 | |
| def _key(x: torch.Tensor, d: int) -> tuple: | |
| return ( | |
| x.device.type, | |
| -1 if x.device.index is None else int(x.device.index), | |
| int(x.data_ptr()), | |
| tuple(x.shape), | |
| tuple(x.stride()), | |
| int(getattr(x, '_version', 0)), | |
| int(d), | |
| ) | |
| def get_or_pack(self, x, d, rot): | |
| key = self._key(x, d) | |
| hit = self._items.get(key) | |
| if hit is not None and hit[0]() is x: | |
| self.hits += 1 | |
| self._items.move_to_end(key) | |
| return hit[1] | |
| self.misses += 1 | |
| packed = a4_pack_triton( | |
| x, | |
| rot['perm'], | |
| rot['signs'], | |
| int(rot['block_size']), | |
| rot['codebook'], | |
| ) | |
| self._items[key] = (weakref.ref(x), packed) | |
| self._items.move_to_end(key) | |
| while len(self._items) > self.capacity: | |
| self._items.popitem(last=False) | |
| return packed | |
| def clear(self): | |
| self._items.clear() | |
| def stats(self): | |
| return {"hits": int(self.hits), "misses": int(self.misses), "entries": len(self._items)} | |
| class OrbitQuantW4A4Engine: | |
| def __init__(self, rotation_bank, cache_capacity: int = 4): | |
| self.bank = rotation_bank | |
| self.activation_cache = ActivationPackCache(cache_capacity) | |
| self._device_rot = {} | |
| self.linear_calls = 0 | |
| def rotation(self, d: int, device: torch.device): | |
| idx = -1 if device.index is None else int(device.index) | |
| key = (int(d), device.type, idx) | |
| if key not in self._device_rot: | |
| src = self.bank.tensors[int(d)] | |
| self._device_rot[key] = { | |
| 'perm': src['perm'].to(device=device, dtype=torch.int32), | |
| 'signs': src['signs'].to(device=device, dtype=torch.int8), | |
| 'codebook': src['codebook'].to(device=device, dtype=torch.float32), | |
| 'block_size': int(src['block_size'].item()), | |
| } | |
| return self._device_rot[key] | |
| def linear(self, x, module: 'OrbitQuantPackedLinear'): | |
| self.linear_calls += 1 | |
| d = module.in_features | |
| rot = self.rotation(d, x.device) | |
| a = self.activation_cache.get_or_pack(x, d, rot) | |
| out = w4a4_linear_triton( | |
| a, | |
| module.packed_weight, | |
| module.row_scale, | |
| rot['codebook'], | |
| module.bias, | |
| out_dtype=x.dtype if x.dtype in (torch.bfloat16, torch.float16) else torch.bfloat16, | |
| ) | |
| return out.reshape(*x.shape[:-1], module.out_features) | |
| class OrbitQuantPackedLinear(nn.Module): | |
| """Packed nonuniform OrbitQuant W4 x online OrbitQuant A4 linear. | |
| There is deliberately no dense `weight` Parameter. Target weight residency is | |
| uint4 packed storage + one BF16 row norm from the artifact (promoted to FP32 for the kernel multiply). | |
| """ | |
| def __init__(self, in_features: int, out_features: int, bias: bool, engine: OrbitQuantW4A4Engine): | |
| super().__init__() | |
| self.in_features = int(in_features) | |
| self.out_features = int(out_features) | |
| self.engine = engine | |
| # Empty/meta bias is materialized by the streaming checkpoint loader. | |
| if bias: | |
| self.bias = nn.Parameter(torch.empty(out_features, device='meta', dtype=torch.bfloat16), requires_grad=False) | |
| else: | |
| self.register_parameter('bias', None) | |
| self.register_buffer('packed_weight', None, persistent=False) | |
| self.register_buffer('row_scale', None, persistent=False) | |
| self._orbitquant_w4a4 = True | |
| self._orbitquant_call_count = 0 | |
| def set_packed(self, packed: torch.Tensor, scale: torch.Tensor): | |
| expected = (self.in_features // 2, self.out_features) | |
| if packed.dtype != torch.uint8 or tuple(packed.shape) != expected: | |
| raise ValueError( | |
| f'packed shape/dtype mismatch: got {tuple(packed.shape)} {packed.dtype}, ' | |
| f'expected GEMM-native [K/2,N]={expected} uint8' | |
| ) | |
| if scale.shape != (self.out_features,): | |
| raise ValueError('row scale shape mismatch') | |
| self.packed_weight = packed.contiguous() | |
| self.row_scale = scale.float().contiguous() | |
| return self | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| if self.packed_weight is None or self.row_scale is None: | |
| raise RuntimeError('packed OrbitQuant weight has not been loaded') | |
| self._orbitquant_call_count += 1 | |
| return self.engine.linear(x, self) | |
| def extra_repr(self) -> str: | |
| return f'in_features={self.in_features}, out_features={self.out_features}, packed=W4, activation=A4' | |