Text-to-Video
Diffusers
Safetensors
MiniMax H3
MiniMaxH3ModularPipeline
image-to-video
audio-video-generation
sparse-attention
block-sparse
inference-acceleration
triton
comfyui
Instructions to use Aazeus/Spark-H3 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use Aazeus/Spark-H3 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("Aazeus/Spark-H3", 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
Download scripts/benchmark_qreuse_m2_optimizations.py from Aazeus/Spark-H3: direct link, hf CLI and curl.
- Browser
- Download file 5.58 kB
-
https://huggingface.co/Aazeus/Spark-H3/resolve/main/scripts/benchmark_qreuse_m2_optimizations.py
- Command line
-
hf download hf://Aazeus/Spark-H3/scripts/benchmark_qreuse_m2_optimizations.py
-
curl -L -o benchmark_qreuse_m2_optimizations.py https://huggingface.co/Aazeus/Spark-H3/resolve/main/scripts/benchmark_qreuse_m2_optimizations.py
5.58 kB
| #!/usr/bin/env python3 | |
| """Benchmark the source-side M2 optimization against the previous behavior.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import statistics | |
| import torch | |
| import h3_sparse_attention.spark_integration as integration | |
| from h3_sparse_attention.landmark_direction import ( | |
| landmark_direction_factors, | |
| landmark_single_direction_factor, | |
| ) | |
| from h3_sparse_attention.mahalanobis_kmeans import hilbert_midpoint_sample_indices | |
| from h3_sparse_attention.processor import H3SparseAttentionConfig, PackedLayout, _Controller | |
| def measure(call, *, warmup: int, repeats: int) -> list[float]: | |
| for _ in range(warmup): | |
| call() | |
| torch.cuda.synchronize() | |
| values = [] | |
| for _ in range(repeats): | |
| start = torch.cuda.Event(enable_timing=True) | |
| end = torch.cuda.Event(enable_timing=True) | |
| start.record() | |
| call() | |
| end.record() | |
| end.synchronize() | |
| values.append(start.elapsed_time(end)) | |
| return values | |
| def summary(values: list[float]) -> dict[str, float]: | |
| return { | |
| "mean_ms": statistics.mean(values), | |
| "median_ms": statistics.median(values), | |
| "min_ms": min(values), | |
| "max_ms": max(values), | |
| } | |
| def main() -> None: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--device", type=int, default=0) | |
| parser.add_argument("--heads", type=int, default=24) | |
| parser.add_argument("--repeats", type=int, default=10) | |
| args = parser.parse_args() | |
| torch.cuda.set_device(args.device) | |
| device = torch.device("cuda", args.device) | |
| grid = (21, 54, 64) | |
| tokens = 1 | |
| for value in grid: | |
| tokens *= value | |
| ids = torch.arange(tokens, device=device) | |
| positions = torch.stack( | |
| torch.meshgrid( | |
| *(torch.arange(size, device=device) for size in grid), indexing="ij" | |
| ), dim=-1, | |
| ).reshape(tokens, 3) | |
| layout = PackedLayout(ids, ids.clone(), grid, tokens, tokens, positions) | |
| torch.manual_seed(20261005) | |
| query = torch.randn( | |
| 1, tokens, args.heads, 128, device=device, dtype=torch.bfloat16 | |
| ) | |
| key = torch.randn_like(query) | |
| flat_query = query.permute(0, 2, 1, 3).reshape(args.heads, tokens, 128) | |
| flat_key = key.permute(0, 2, 1, 3).reshape(args.heads, tokens, 128) | |
| indices = hilbert_midpoint_sample_indices( | |
| grid, tokens // 64, device=device | |
| ) | |
| metric_both = measure( | |
| lambda: landmark_direction_factors( | |
| flat_query, flat_key, indices, m2_side="both" | |
| ), | |
| warmup=3, | |
| repeats=args.repeats, | |
| ) | |
| metric_source = measure( | |
| lambda: landmark_single_direction_factor( | |
| flat_query, flat_key, indices, "key" | |
| ), | |
| warmup=3, | |
| repeats=args.repeats, | |
| ) | |
| factor = landmark_single_direction_factor( | |
| flat_query, flat_key, indices, "key" | |
| ).to(torch.bfloat16) | |
| transformed = torch.empty_like(flat_key) | |
| identity = torch.eye(128, device=device, dtype=torch.bfloat16).expand( | |
| args.heads, -1, -1 | |
| ) | |
| identity_bmm = measure( | |
| lambda: torch.bmm(flat_key, identity, out=transformed), | |
| warmup=3, | |
| repeats=args.repeats, | |
| ) | |
| direct_copy = measure( | |
| lambda: transformed.copy_(flat_key), | |
| warmup=3, | |
| repeats=args.repeats, | |
| ) | |
| frozen_reference = measure( | |
| lambda: torch.bmm(flat_key, factor, out=transformed), | |
| warmup=3, | |
| repeats=args.repeats, | |
| ) | |
| config = H3SparseAttentionConfig.spark( | |
| 20, landmark_tree_v2_layout_reuse="q_from_k" | |
| ) | |
| old_controller = _Controller(config) | |
| new_controller = _Controller(config) | |
| required = integration._required_reblock_m2_side | |
| def old_call(): | |
| integration._required_reblock_m2_side = lambda m2_side, layout_reuse: m2_side | |
| try: | |
| return integration._landmark_tree_v2_combined_permutations( | |
| old_controller, query, key, layout, expand_shared=False | |
| ) | |
| finally: | |
| integration._required_reblock_m2_side = required | |
| def new_call(): | |
| return integration._landmark_tree_v2_combined_permutations( | |
| new_controller, query, key, layout, expand_shared=False | |
| ) | |
| # Three warmups cover eager execution, capture, and replay for each plan. | |
| for _ in range(3): | |
| old_result = old_call() | |
| new_result = new_call() | |
| bitwise = ( | |
| torch.equal(old_result[2], new_result[2]) | |
| and torch.equal(old_result[3], new_result[3]) | |
| ) | |
| old_full = measure(old_call, warmup=0, repeats=args.repeats) | |
| new_full = measure(new_call, warmup=0, repeats=args.repeats) | |
| result = { | |
| "device": args.device, | |
| "gpu": torch.cuda.get_device_name(device), | |
| "shape": [1, tokens, args.heads, 128], | |
| "repeats": args.repeats, | |
| "bitwise_permutation_and_inverse": bitwise, | |
| "metric_old_both": summary(metric_both), | |
| "metric_new_source_only": summary(metric_source), | |
| "metric_speedup": statistics.mean(metric_both) / statistics.mean(metric_source), | |
| "identity_bmm": summary(identity_bmm), | |
| "identity_copy": summary(direct_copy), | |
| "identity_speedup": statistics.mean(identity_bmm) / statistics.mean(direct_copy), | |
| "zero_tail_reference_transform_avoided": summary(frozen_reference), | |
| "full_old_emulation": summary(old_full), | |
| "full_new": summary(new_full), | |
| "full_speedup": statistics.mean(old_full) / statistics.mean(new_full), | |
| } | |
| print(json.dumps(result, indent=2)) | |
| if __name__ == "__main__": | |
| main() | |