{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-02-make-your-zerogpu-spaces-go-brrr-with-ahead-of-time/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "ZeroGPU lets anyone spin up powerful **Nvidia H200** hardware in Hugging Face Spaces without keeping a GPU locked for idle traffic. It’s efficient, flexible, and ideal for demos but it doesn’t always make full use of everything the GPU and CUDA stack can offer. Generating images or videos can take a significant amount of time. Being able to squeeze out more performance, taking advantage of the H200 hardware, does matter in this case.\n\nThis is where PyTorch ahead-of-time (AoT) compilation comes in. Instead of compiling models on the fly (which doesn’t play nicely with ZeroGPU’s short-lived processes), AoT lets you optimize once and reload instantly.\n\n**The result**: snappier demos and a smoother experience, with speedups ranging from **1.3×–1.8×** on models like Flux, Wan, and LTX 🔥\n\nIn this post, we’ll show how to wire up Ahead-of-Time (AoT) compilation in ZeroGPU Spaces. We'll explore advanced tricks like FP8 quantization and dynamic shapes, and share working demos you can try right away. If you cannot wait, we invite you to check out some ZeroGPU-powered demos on the [zerogpu-aoti](https://huggingface.co/zerogpu-aoti) organization.\n\n> [Pro](https://huggingface.co/pro) users and [Team / Enterprise](https://huggingface.co/enterprise) org members can create ZeroGPU Spaces, while anyone can freely use them (Pro, Team and Enterprise users get **8x** more ZeroGPU quota)\n\n## Table of Contents\n\n- [What is ZeroGPU](https://huggingface.co/blog/zerogpu-aoti#what-is-zerogpu)\n- [PyTorch compilation](https://huggingface.co/blog/zerogpu-aoti#pytorch-compilation)\n- [Ahead-of-time compilation on ZeroGPU](https://huggingface.co/blog/zerogpu-aoti#ahead-of-time-compilation-on-zerogpu)\n- [Gotchas](https://huggingface.co/blog/zerogpu-aoti#gotchas)\n  - [Quantization](https://huggingface.co/blog/zerogpu-aoti#quantization)\n  - [Dynamic shapes](https://huggingface.co/blog/zerogpu-aoti#dynamic-shapes)\n  - [Multi-compile / shared weights](https://huggingface.co/blog/zerogpu-aoti#multi-compile--shared-weights)\n  - [FlashAttention-3](https://huggingface.co/blog/zerogpu-aoti#flashattention-3)\n  - [Regional compilation](https://huggingface.co/blog/zerogpu-aoti#regional-compilation)\n  - [Use a compiled graph from the Hub](https://huggingface.co/blog/zerogpu-aoti#use-a-compiled-graph-from-the-hub)\n- [AoT compiled ZeroGPU Spaces demos](https://huggingface.co/blog/zerogpu-aoti#aot-compiled-zerogpu-spaces-demos)\n- [Conclusion](https://huggingface.co/blog/zerogpu-aoti#conclusion)\n- [Resources](https://huggingface.co/blog/zerogpu-aoti#resources)\n\n## What is ZeroGPU\n\n[Spaces](https://huggingface.co/spaces) is a platform powered by Hugging Face that allows ML practitioners to easily publish demo apps.\n\nTypical demo apps on Spaces look like:\n\n```python\nimport gradio as gr\nfrom diffusers import DiffusionPipeline\n\npipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n\ndef generate(prompt):\n    return pipe(prompt).images\n\ngr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nThis works great, but ends up reserving a GPU for the Space during its entire lifetime – even when it has no user activity.\n\nWhen executing `.to('cuda')` on this line:\n\n```python\npipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n```\n\nPyTorch initializes the NVIDIA driver, which sets up the process on CUDA forever. This is not very resource-efficient given that app traffic is not perfectly smooth, but is rather extremely sparse and spiky.\n\nZeroGPU takes a just-in-time approach to GPU initialization. Instead of setting up the main process on CUDA, it automatically forks the process, sets it up on CUDA, runs the GPU tasks, and finally kills the fork when the GPU needs to be released.\n\nThis means that:\n\n- When the app does not receive traffic, it doesn't use any GPU\n- When it is actually performing a task, it will use one GPU\n- It can use multiple GPUs as needed to perform tasks concurrently\n\nThanks to the Python `spaces` package, the only code change needed to get this behaviour is as follows:\n\n```diff\n  import gradio as gr\n+ import spaces\n  from diffusers import DiffusionPipeline\n\n  pipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n\n+ @spaces.GPU\n  def generate(prompt):\n      return pipe(prompt).images\n\n  gr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nBy importing `spaces` and adding the `@spaces.GPU` decorator, we:\n\n- Intercept PyTorch API calls to postpone CUDA operations\n- Make the decorated function run in a fork when later called\n- (Call an internal API to make the right device visible to the fork but this is not in the scope of this blogpost)\n\n> ZeroGPU currently allocates an [MIG](https://docs.nvidia.com/datacenter/tesla/mig-user-guide/#h200-mig-profiles) slice of H200 (`3g.71gb` profile). Additional MIG sizes including full slice (`7g.141gb` profile) will come in late 2025.\n\n## PyTorch compilation\n\nModern ML frameworks like PyTorch and JAX have the concept of *compilation* that can be used to optimize model latency or inference time. Behind the scenes, compilation applies a series of (often hardware-dependent) optimization steps such as operator fusion, constant folding, etc.\n\nPyTorch (from 2.0 onwards) currently has two major interfaces for compilation:\n\n- Just-in-time with `torch.compile`\n- Ahead-of-time with `torch.export` + `AOTInductor`\n\n[`torch.compile`](https://docs.pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) works great in standard environments: it compiles your model the first time it runs, and reuses the optimized version for subsequent calls.\n\nHowever, on ZeroGPU, given that the process is freshly spun up for (almost) every GPU task, it means that `torch.compile` can’t efficiently re-use compilation and is thus forced to rely on its [filesystem cache](https://docs.pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html#modular-caching-of-torchdynamo-torchinductor-and-triton) to restore compiled models. Depending on the model being compiled, this process takes from a few dozen seconds to a couple of minutes, which is way too much for practical GPU tasks in Spaces.\n\nThis is where **ahead-of-time (AoT) compilation** shines.\n\nWith AoT, we can export a compiled model once, save it, and later reload it instantly in any process, which is exactly what we need for ZeroGPU. This helps us reduce framework overhead and also eliminates cold-start timings typically incurred in just-in-time compilation.\n\nBut how can we do ahead-of-time compilation on ZeroGPU? Let’s dive in.\n\n## Ahead-of-time compilation on ZeroGPU\n\nLet's go back to our ZeroGPU base example and unpack what we need to enable AoT compilation. For the purpose of this demo, we will use the `black-forest-labs/FLUX.1-dev` model:\n\n```python\nimport gradio as gr\nimport spaces\nimport torch\nfrom diffusers import DiffusionPipeline\n\nMODEL_ID = 'black-forest-labs/FLUX.1-dev'\n\npipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)\npipe.to('cuda')\n\n@spaces.GPU\ndef generate(prompt):\n    return pipe(prompt).images\n\ngr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\n> In the discussion below, we only compile the `transformer` component of `pipe` since, in these generative models, the transformer (or more generally, the denoiser) is the most computationally heavy component.\n\nCompiling a model ahead-of-time with PyTorch involves multiple steps:\n\n### 1. Getting example inputs\n\nRecall that we’re going to compile the model *ahead* of time. Therefore, we need to derive example inputs for the model. Note that these are the same kinds of inputs we expect to see during the actual runs. To capture those inputs, we will leverage the `spaces.aoti_capture` helper from the `spaces` package:\n\n```python\nwith spaces.aoti_capture(pipe.transformer) as call:\n    pipe(\"arbitrary example prompt\")\n```\n\nWhen used as a context manager, `aoti_capture` intercepts the call to any callable (`pipe.transformer` in our case), prevents it from executing, captures the input arguments that would have been passed to it, and stores their values in `call.args` and `call.kwargs`.\n\n### 2. Exporting the model\n\nNow that we have example args and kwargs for our transformer component, we can export it to a PyTorch [`ExportedProgram`](https://docs.pytorch.org/docs/stable/export.html#torch.export.ExportedProgram) by using [`torch.export.export`](https://docs.pytorch.org/docs/stable/export.html#torch.export.export) utility:\n\n```python\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n)\n```\n\nAn exported PyTorch program is a computation graph that represents the tensor computations along with the original model parameter values.\n\n### 3. Compiling the exported model\n\nOnce the model is exported, compiling it is pretty straightforward.\n\nA traditional AoT compilation in PyTorch often requires saving the model on disk so it can be later reloaded. In our case, we’ll leverage a helper function part of the `spaces` package: `spaces.aoti_compile`. It's a tiny wrapper around `torch._inductor.aot_compile` that manages saving and lazy-loading the model as needed. It's meant to be used like this:\n\n```python\ncompiled_transformer = spaces.aoti_compile(exported_transformer)\n```\n\nThis `compiled_transformer` is now an AoT-compiled binary ready to be used for inference.\n\n### 4. Using the compiled model in the pipeline\n\nNow we need to bind our compiled transformer to our original pipeline, i.e., the `pipeline`.\n\nA naive and almost working approach is to simply patch our pipeline like `pipe.transformer = compiled_transformer`. Unfortunately, this approach does not work because it deletes important attributes like `dtype`, `config`, etc. Only patching the `forward` method does not work well either because we are then keeping original model parameters in memory, often leading to OOM errors at runtime.\n\n`spaces` package provides a utility for this, too -- `spaces.aoti_apply`:\n\n```python\nspaces.aoti_apply(compiled_transformer, pipe.transformer)\n```\n\nEt voilà! It will take care of patching `pipe.transformer.forward` with our compiled model, as well as [cleaning old model parameters out of memory](https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py#L87).\n\n### 5. Wrapping it all together\n\nTo perform the first three steps (intercepting input examples, exporting the model, and compiling it with PyTorch inductor), we need a real GPU. CUDA emulation that you get outside of `@spaces.GPU` function is not enough because compilation is truly hardware-dependent, for instance, relying on micro-benchmark runs to tune the generated code. This is why we need to wrap it all inside a `@spaces.GPU` function and then get our compiled model back to the root of our app. Starting from our original demo code, this gives:\n\n```diff\n  import gradio as gr\n  import spaces\n  import torch\n  from diffusers import DiffusionPipeline\n  \n  MODEL_ID = 'black-forest-labs/FLUX.1-dev'\n  \n  pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)\n  pipe.to('cuda')\n  \n+ @spaces.GPU(duration=1500) # maximum duration allowed during startup\n+ def compile_transformer():\n+     with spaces.aoti_capture(pipe.transformer) as call:\n+         pipe(\"arbitrary example prompt\")\n+ \n+     exported = torch.export.export(\n+         pipe.transformer,\n+         args=call.args,\n+         kwargs=call.kwargs,\n+     )\n+     return spaces.aoti_compile(exported)\n+ \n+ compiled_transformer = compile_transformer()\n+ spaces.aoti_apply(compiled_transformer, pipe.transformer)\n  \n  @spaces.GPU\n  def generate(prompt):\n      return pipe(prompt).images\n  \n  gr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nWith just a dozen lines of additional code, we’ve successfully made our demo quite faster (**1.7x** faster in the case of FLUX.1-dev).\n\nIf you want to learn more about AoT compilation, you can read PyTorch's [AOTInductor tutorial](https://docs.pytorch.org/tutorials/recipes/torch_export_aoti_python.html)\n\n## Gotchas\n\nNow that we have demonstrated the speedups one can realize under the constraints of operating with ZeroGPUs, we will discuss a few gotchas that came up while working with this setup.\n\n### Quantization\n\nAoT can be combined with quantization to deliver even greater speedups. For image and video generation, the FP8 post-training dynamic quantization schemes deliver good speed-quality trade-offs. However, FP8 requires a CUDA compute capability of at least 9.0 to work. Thankfully, for ZeroGPUs, since they’re based on H200s, we can already take advantage of the FP8 quantization schemes.\n\nTo enable FP8 quantization within our AoT compilation workflow, we can leverage the APIs provided by [`torchao`](https://github.com/pytorch/ao) like so:\n\n```diff\n+ from torchao.quantization import quantize_, Float8DynamicActivationFloat8WeightConfig\n\n+ # Quantize the transformer just before the export step.\n+ quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())\n\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n)\n```\n\n(You can find more details about TorchAO [here](https://docs.pytorch.org/ao/stable/index.html).)\n\nAnd we can then proceed with the rest of the steps as outlined above. Using quantization provides another **1.2x** of speedup.\n\n### Dynamic shapes\n\nImages and videos can come in different shapes and sizes. Hence, it’s important to also account for shape dynamism when performing AoT compilation. The primitives provided by `torch.export.export` make it easily configurable to provide what inputs should be treated accordingly for dynamic shapes, as shown below.\n\nFor the case of Flux.1-Dev transformer, changes in different image resolutions will affect two of its `forward` arguments:\n\n- `hidden_states`: The noisy input latents, which the transformer is supposed to denoise. It’s a 3D tensor, representing `batch_size, flattened_latent_dim, embed_dim`. When the batch size is fixed, it’s the `flattened_latent_dim` that will change for any changes made to image resolutions.\n- `img_ids`: A 2D array of encoded pixel coordinates having a shape of `height * width, 3`. In this case, we want to make `height * width` dynamic.\n\nWe start by defining a range in which we want to let the (latent) image resolutions vary. To derive these value ranges, we inspected the shapes of [`hidden_states`](https://github.com/huggingface/diffusers/blob/0ff1aa910cf3d87193af79ec1ae4487be542e872/src/diffusers/pipelines/flux/pipeline_flux.py#L920) in the pipeline with respect to varied image resolutions. The exact values are model-dependent and require manual inspection and some intuition. For Flux.1-Dev, we ended up with:\n\n```python\ntransformer_hidden_dim = torch.export.Dim('hidden', min=4096, max=8212)\n```\n\nWe then define a map of argument names and which dimensions in their input values we expect to be dynamic:\n\n```python\ntransformer_dynamic_shapes = {\n    \"hidden_states\": {1: transformer_hidden_dim}, \n    \"img_ids\": {0: transformer_hidden_dim},\n}\n```\n\nThen we need to make our dynamic shapes object replicate the structure of our example inputs. The inputs that do not need dynamic shapes must be set to `None`. This can be done very easily with PyTorch [tree\\_map](https://github.com/pytorch/pytorch/blob/2f0de0ff9361ca4f2b1e6f9edbc600b5fb6abcd6/torch/utils/_pytree.py#L1341-L1373) utility:\n\n```python\nfrom torch.utils._pytree import tree_map\n\ndynamic_shapes = tree_map(lambda v: None, call.kwargs)\ndynamic_shapes |= transformer_dynamic_shapes\n```\n\nNow, when performing the export step, we simply supply `transformer_dynamic_shapes` to `torch.export.export`:\n\n```python\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n    dynamic_shapes=dynamic_shapes,\n)\n```\n\n> Check out [this Space](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev-fp8-dynamic) that shows how to use both quantization and dynamic shapes during the export step.\n\n### Multi-compile / shared weights\n\nDynamic shapes is sometimes not enough when dynamism is too important.\n\nThis is, for instance, the case with the Wan family of video generation models if you want your compiled model to generate different resolutions. One thing can be done in this case: compile one model per resolution while keeping the model parameters shared and dispatching the right one at runtime\n\nHere is a minimal example of this approach: [zerogpu-aoti-multi.py](https://gist.github.com/cbensimon/8dc0ffcd7ee024d91333f6df01907916). You can also see a fully working implementation of this paradigm in the [Wan 2.2 Space](https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster/blob/main/optimization.py).\n\n### FlashAttention-3\n\nSince the ZeroGPU hardware and CUDA drivers are perfectly compatible with Flash-Attention 3 (FA3), we can use it in our ZeroGPU Spaces to speed things up even further. FA3 works with ahead-of-time compilation. So, this is ideal for our case.\n\nCompiling and building FA3 from source can take several minutes, and this process is hardware-dependent. As users, we wouldn’t want to lose precious ZeroGPU compute hours. This is where Hugging Face [`kernels` library](https://github.com/huggingface/kernels) comes to the rescue. It provides access to pre-built kernels that are compatible for a given hardware. For example, when we try to run:\n\n```python\nfrom kernels import get_kernel\n\nvllm_flash_attn3 = get_kernel(\"kernels-community/vllm-flash-attn3\")\n```\n\nIt tries to load a kernel from the [`kernels-community/vllm-flash-attn3`](https://huggingface.co/kernels-community/vllm-flash-attn3) repository, which is compatible with the current setup. Otherwise, it will error out due to incompatibility issues. Luckily for us, this works seamlessly on the ZeroGPU Spaces. This means we can leverage the power of FA3 on ZeroGPU, using the `kernels` library.\n\nHere is a [fully working example of an FA3 attention processor](https://gist.github.com/sayakpaul/ff715f979793d4d44beb68e5e08ee067#file-fa3_qwen-py) for the Qwen-Image model.\n\n### Regional compilation\n\nSo far, we have been compiling the full model. Depending on the model, full model compilation can lead to significantly long cold start times. Long cold start times make the development experience unpleasant.\n\nWe can also choose to compile *regions* within a model, significantly reducing the cold start times, while retaining almost all the benefits of full model compilation. Regional compilation becomes promising when a model has repeated blocks of computation. A standard language model, for example, has a number of identically structured Transformer blocks.\n\nIn our example, we can compile the repeated blocks of the Flux transformer ahead of time, and propagate the compiled graph to the remaining repeated blocks. The [Flux Transformer](https://github.com/huggingface/diffusers/blob/c2e5ece08bf22d249c62e964f91bc326cf9e3759/src/diffusers/models/transformers/transformer_flux.py) has two kinds of repeated blocks: `FluxTransformerBlock` and `FluxSingleTransformerBlock`.\n\nYou can check out [this Space](https://huggingface.co/spaces/cbensimon/FLUX.1-dev-fa3-aoti/tree/main) for a complete example.\n\n> 💡 For Flux.1-Dev, switching to regional compilation reduces the compilation time from *6 minutes* to just *30 seconds* while delivering identical speedups.\n\n### Use a compiled graph from the Hub\n\nOnce a model (or even a model block) is compiled ahead of time, we can serialize the compiled graph module as an artifact and reuse later. In the context of a ZeroGPU-powered demo on Spaces, this will significantly cut down the demo startup time by skipping the compilation time.\n\nTo keep the storage light, we can just save the compiled model graph without including any model parameters inside the artifact.\n\nCheck out [this collection](https://huggingface.co/collections/zerogpu-aoti/using-compiled-graph-from-the-hub-68c2afcc03de7609f9f91e35) that shows a full workflow of obtaining compiled model graph, pushing it to the Hub, and then using it to build a demo.\n\n## AoT compiled ZeroGPU Spaces demos\n\n### Speedup comparison\n\n- [FLUX.1-dev without AoTI](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-base)\n- [FLUX.1-dev with AoTI and FA3](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-fa3-aoti) (**1.75x** speedup)\n\n### Featured AoTI Spaces\n\n- [FLUX.1 Kontext](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev)\n- [QwenImage Edit](https://huggingface.co/spaces/multimodalart/Qwen-Image-Edit-Fast)\n- [Wan 2.2](https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster)\n\n### Regional compilation\n\n- [Regional compilation recipe](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html)\n- [Regional compilation with AOT](https://docs.pytorch.org/tutorials/recipes/regional_aot.html)\n- [Native integration in Diffusers](https://huggingface.co/docs/diffusers/main/en/optimization/fp16)\n- [More performance numbers](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)\n\n## Conclusion\n\nZeroGPU within Hugging Face Spaces is a powerful feature that enables AI builders by providing access to powerful compute. In this post, we showed how users can benefit from PyTorch’s ahead-of-time compilation techniques to speed up their applications that leverage ZeroGPU.\n\nWe demonstrate speedups with Flux.1-Dev, but these techniques are not limited to just this model. Therefore, we encourage you to give these techniques a try and provide us with feedback in this [community discussion](https://huggingface.co/spaces/zerogpu-aoti/README/discussions/1).\n\n## Resources\n\n- Visit our [ZeroGPU-AOTI org on the Hub](https://huggingface.co/zerogpu-aoti) to refer to a collection of demos that leverage the techniques discussed in this post.\n- Browse `spaces.aoti_*` APIs [source code](https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py) to learn more about the interface\n- Check out [Kernels Community org on the hub](https://huggingface.co/kernels-community)\n- Learn more about regional compilation from [here](https://huggingface.co/blog/pytorch.org/tutorials/recipes/regional_compilation.html)\n- Upgrade to [Pro](https://huggingface.co/pro) on Hugging Face to create your own ZeroGPU Spaces (and get 25 minutes of H200 usage every day)\n\n*Acknowledgements: Thanks to ChunTe Lee for creating an awesome thumbnail for this post. Thanks to Pedro and Vaibhav for providing feedback on the post. Thanks to Angela Yi from the PyTorch team for helping us with AOT guidance.*\n",
  "authors": [],
  "captured_at": "2026-10-04T12:50:30.804479567+00:00",
  "category": "ai",
  "content_html": "<p>ZeroGPU lets anyone spin up powerful <strong>Nvidia H200</strong> hardware in Hugging Face Spaces without keeping a GPU locked for idle traffic. It’s efficient, flexible, and ideal for demos but it doesn’t always make full use of everything the GPU and CUDA stack can offer. Generating images or videos can take a significant amount of time. Being able to squeeze out more performance, taking advantage of the H200 hardware, does matter in this case.</p>\n<p>This is where PyTorch ahead-of-time (AoT) compilation comes in. Instead of compiling models on the fly (which doesn’t play nicely with ZeroGPU’s short-lived processes), AoT lets you optimize once and reload instantly.</p>\n<p><strong>The result</strong>: snappier demos and a smoother experience, with speedups ranging from <strong>1.3×–1.8×</strong> on models like Flux, Wan, and LTX 🔥</p>\n<p>In this post, we’ll show how to wire up Ahead-of-Time (AoT) compilation in ZeroGPU Spaces. We'll explore advanced tricks like FP8 quantization and dynamic shapes, and share working demos you can try right away. If you cannot wait, we invite you to check out some ZeroGPU-powered demos on the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/zerogpu-aoti\">zerogpu-aoti</a> organization.</p>\n<blockquote>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/pro\">Pro</a> users and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/enterprise\">Team / Enterprise</a> org members can create ZeroGPU Spaces, while anyone can freely use them (Pro, Team and Enterprise users get <strong>8x</strong> more ZeroGPU quota)</p>\n</blockquote>\n<h2>Table of Contents</h2>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#what-is-zerogpu\">What is ZeroGPU</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#pytorch-compilation\">PyTorch compilation</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#ahead-of-time-compilation-on-zerogpu\">Ahead-of-time compilation on ZeroGPU</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#gotchas\">Gotchas</a>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#quantization\">Quantization</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#dynamic-shapes\">Dynamic shapes</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#multi-compile--shared-weights\">Multi-compile / shared weights</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#flashattention-3\">FlashAttention-3</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#regional-compilation\">Regional compilation</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#use-a-compiled-graph-from-the-hub\">Use a compiled graph from the Hub</a></li>\n</ul>\n</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#aot-compiled-zerogpu-spaces-demos\">AoT compiled ZeroGPU Spaces demos</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#conclusion\">Conclusion</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/zerogpu-aoti#resources\">Resources</a></li>\n</ul>\n<h2>What is ZeroGPU</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces\">Spaces</a> is a platform powered by Hugging Face that allows ML practitioners to easily publish demo apps.</p>\n<p>Typical demo apps on Spaces look like:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gradio</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">diffusers</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">DiffusionPipeline</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">DiffusionPipeline</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-language syntax-python\">...</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">to</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">cuda<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generate</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">prompt</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">pipe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">prompt</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">images</span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Interface</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generate</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">text<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">gallery<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">launch</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>This works great, but ends up reserving a GPU for the Space during its entire lifetime – even when it has no user activity.</p>\n<p>When executing <code>.to('cuda')</code> on this line:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">DiffusionPipeline</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-language syntax-python\">...</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">to</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">cuda<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>PyTorch initializes the NVIDIA driver, which sets up the process on CUDA forever. This is not very resource-efficient given that app traffic is not perfectly smooth, but is rather extremely sparse and spiky.</p>\n<p>ZeroGPU takes a just-in-time approach to GPU initialization. Instead of setting up the main process on CUDA, it automatically forks the process, sets it up on CUDA, runs the GPU tasks, and finally kills the fork when the GPU needs to be released.</p>\n<p>This means that:</p>\n<ul>\n<li>When the app does not receive traffic, it doesn't use any GPU</li>\n<li>When it is actually performing a task, it will use one GPU</li>\n<li>It can use multiple GPUs as needed to perform tasks concurrently</li>\n</ul>\n<p>Thanks to the Python <code>spaces</code> package, the only code change needed to get this behaviour is as follows:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\">  import gradio as gr\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> import spaces\n</span>  from diffusers import DiffusionPipeline\n\n  pipe = DiffusionPipeline.from_pretrained(...).to(&#39;cuda&#39;)\n\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> @spaces.GPU\n</span>  def generate(prompt):\n      return pipe(prompt).images\n\n  gr.Interface(generate, &quot;text&quot;, &quot;gallery&quot;).launch()\n</span></span></code></pre>\n<p>By importing <code>spaces</code> and adding the <code>@spaces.GPU</code> decorator, we:</p>\n<ul>\n<li>Intercept PyTorch API calls to postpone CUDA operations</li>\n<li>Make the decorated function run in a fork when later called</li>\n<li>(Call an internal API to make the right device visible to the fork but this is not in the scope of this blogpost)</li>\n</ul>\n<blockquote>\n<p>ZeroGPU currently allocates an <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.nvidia.com/datacenter/tesla/mig-user-guide/#h200-mig-profiles\">MIG</a> slice of H200 (<code>3g.71gb</code> profile). Additional MIG sizes including full slice (<code>7g.141gb</code> profile) will come in late 2025.</p>\n</blockquote>\n<h2>PyTorch compilation</h2>\n<p>Modern ML frameworks like PyTorch and JAX have the concept of <em>compilation</em> that can be used to optimize model latency or inference time. Behind the scenes, compilation applies a series of (often hardware-dependent) optimization steps such as operator fusion, constant folding, etc.</p>\n<p>PyTorch (from 2.0 onwards) currently has two major interfaces for compilation:</p>\n<ul>\n<li>Just-in-time with <code>torch.compile</code></li>\n<li>Ahead-of-time with <code>torch.export</code> + <code>AOTInductor</code></li>\n</ul>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/tutorials/intermediate/torch_compile_tutorial.html\"><code>torch.compile</code></a> works great in standard environments: it compiles your model the first time it runs, and reuses the optimized version for subsequent calls.</p>\n<p>However, on ZeroGPU, given that the process is freshly spun up for (almost) every GPU task, it means that <code>torch.compile</code> can’t efficiently re-use compilation and is thus forced to rely on its <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html#modular-caching-of-torchdynamo-torchinductor-and-triton\">filesystem cache</a> to restore compiled models. Depending on the model being compiled, this process takes from a few dozen seconds to a couple of minutes, which is way too much for practical GPU tasks in Spaces.</p>\n<p>This is where <strong>ahead-of-time (AoT) compilation</strong> shines.</p>\n<p>With AoT, we can export a compiled model once, save it, and later reload it instantly in any process, which is exactly what we need for ZeroGPU. This helps us reduce framework overhead and also eliminates cold-start timings typically incurred in just-in-time compilation.</p>\n<p>But how can we do ahead-of-time compilation on ZeroGPU? Let’s dive in.</p>\n<h2>Ahead-of-time compilation on ZeroGPU</h2>\n<p>Let's go back to our ZeroGPU base example and unpack what we need to enable AoT compilation. For the purpose of this demo, we will use the <code>black-forest-labs/FLUX.1-dev</code> model:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gradio</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spaces</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">diffusers</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">DiffusionPipeline</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-other syntax-constant syntax-python\">MODEL_ID</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">black-forest-labs/FLUX.1-dev<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">DiffusionPipeline</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-other syntax-constant syntax-python\">MODEL_ID</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">torch_dtype</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">bfloat16</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">to</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">cuda<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spaces</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-python\">GPU</span></span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generate</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">prompt</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">pipe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">prompt</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">images</span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Interface</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generate</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">text<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">gallery<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">launch</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<blockquote>\n<p>In the discussion below, we only compile the <code>transformer</code> component of <code>pipe</code> since, in these generative models, the transformer (or more generally, the denoiser) is the most computationally heavy component.</p>\n</blockquote>\n<p>Compiling a model ahead-of-time with PyTorch involves multiple steps:</p>\n<h3>1. Getting example inputs</h3>\n<p>Recall that we’re going to compile the model <em>ahead</em> of time. Therefore, we need to derive example inputs for the model. Note that these are the same kinds of inputs we expect to see during the actual runs. To capture those inputs, we will leverage the <code>spaces.aoti_capture</code> helper from the <code>spaces</code> package:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-python\">with</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spaces</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">aoti_capture</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-as syntax-python\">as</span></span></span><span class=\"syntax-meta syntax-statement syntax-with syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-with syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">pipe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">arbitrary example prompt<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>When used as a context manager, <code>aoti_capture</code> intercepts the call to any callable (<code>pipe.transformer</code> in our case), prevents it from executing, captures the input arguments that would have been passed to it, and stores their values in <code>call.args</code> and <code>call.kwargs</code>.</p>\n<h3>2. Exporting the model</h3>\n<p>Now that we have example args and kwargs for our transformer component, we can export it to a PyTorch <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/docs/stable/export.html#torch.export.ExportedProgram\"><code>ExportedProgram</code></a> by using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/docs/stable/export.html#torch.export.export\"><code>torch.export.export</code></a> utility:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">exported_transformer</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">export</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">export</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">args</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">args</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">kwargs</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">kwargs</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>An exported PyTorch program is a computation graph that represents the tensor computations along with the original model parameter values.</p>\n<h3>3. Compiling the exported model</h3>\n<p>Once the model is exported, compiling it is pretty straightforward.</p>\n<p>A traditional AoT compilation in PyTorch often requires saving the model on disk so it can be later reloaded. In our case, we’ll leverage a helper function part of the <code>spaces</code> package: <code>spaces.aoti_compile</code>. It's a tiny wrapper around <code>torch._inductor.aot_compile</code> that manages saving and lazy-loading the model as needed. It's meant to be used like this:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">compiled_transformer</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spaces</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">aoti_compile</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">exported_transformer</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>This <code>compiled_transformer</code> is now an AoT-compiled binary ready to be used for inference.</p>\n<h3>4. Using the compiled model in the pipeline</h3>\n<p>Now we need to bind our compiled transformer to our original pipeline, i.e., the <code>pipeline</code>.</p>\n<p>A naive and almost working approach is to simply patch our pipeline like <code>pipe.transformer = compiled_transformer</code>. Unfortunately, this approach does not work because it deletes important attributes like <code>dtype</code>, <code>config</code>, etc. Only patching the <code>forward</code> method does not work well either because we are then keeping original model parameters in memory, often leading to OOM errors at runtime.</p>\n<p><code>spaces</code> package provides a utility for this, too -- <code>spaces.aoti_apply</code>:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spaces</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">aoti_apply</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">compiled_transformer</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Et voilà! It will take care of patching <code>pipe.transformer.forward</code> with our compiled model, as well as <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py#L87\">cleaning old model parameters out of memory</a>.</p>\n<h3>5. Wrapping it all together</h3>\n<p>To perform the first three steps (intercepting input examples, exporting the model, and compiling it with PyTorch inductor), we need a real GPU. CUDA emulation that you get outside of <code>@spaces.GPU</code> function is not enough because compilation is truly hardware-dependent, for instance, relying on micro-benchmark runs to tune the generated code. This is why we need to wrap it all inside a <code>@spaces.GPU</code> function and then get our compiled model back to the root of our app. Starting from our original demo code, this gives:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\">  import gradio as gr\n  import spaces\n  import torch\n  from diffusers import DiffusionPipeline\n  \n  MODEL_ID = &#39;black-forest-labs/FLUX.1-dev&#39;\n  \n  pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)\n  pipe.to(&#39;cuda&#39;)\n  \n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> @spaces.GPU(duration=1500) # maximum duration allowed during startup\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> def compile_transformer():\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>     with spaces.aoti_capture(pipe.transformer) as call:\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>         pipe(&quot;arbitrary example prompt&quot;)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> \n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>     exported = torch.export.export(\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>         pipe.transformer,\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>         args=call.args,\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>         kwargs=call.kwargs,\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>     )\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>     return spaces.aoti_compile(exported)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> \n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> compiled_transformer = compile_transformer()\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> spaces.aoti_apply(compiled_transformer, pipe.transformer)\n</span>  \n  @spaces.GPU\n  def generate(prompt):\n      return pipe(prompt).images\n  \n  gr.Interface(generate, &quot;text&quot;, &quot;gallery&quot;).launch()\n</span></span></code></pre>\n<p>With just a dozen lines of additional code, we’ve successfully made our demo quite faster (<strong>1.7x</strong> faster in the case of FLUX.1-dev).</p>\n<p>If you want to learn more about AoT compilation, you can read PyTorch's <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/tutorials/recipes/torch_export_aoti_python.html\">AOTInductor tutorial</a></p>\n<h2>Gotchas</h2>\n<p>Now that we have demonstrated the speedups one can realize under the constraints of operating with ZeroGPUs, we will discuss a few gotchas that came up while working with this setup.</p>\n<h3>Quantization</h3>\n<p>AoT can be combined with quantization to deliver even greater speedups. For image and video generation, the FP8 post-training dynamic quantization schemes deliver good speed-quality trade-offs. However, FP8 requires a CUDA compute capability of at least 9.0 to work. Thankfully, for ZeroGPUs, since they’re based on H200s, we can already take advantage of the FP8 quantization schemes.</p>\n<p>To enable FP8 quantization within our AoT compilation workflow, we can leverage the APIs provided by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/ao\"><code>torchao</code></a> like so:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> from torchao.quantization import quantize_, Float8DynamicActivationFloat8WeightConfig\n</span>\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> # Quantize the transformer just before the export step.\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span> quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())\n</span>\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n)\n</span></span></code></pre>\n<p>(You can find more details about TorchAO <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/ao/stable/index.html\">here</a>.)</p>\n<p>And we can then proceed with the rest of the steps as outlined above. Using quantization provides another <strong>1.2x</strong> of speedup.</p>\n<h3>Dynamic shapes</h3>\n<p>Images and videos can come in different shapes and sizes. Hence, it’s important to also account for shape dynamism when performing AoT compilation. The primitives provided by <code>torch.export.export</code> make it easily configurable to provide what inputs should be treated accordingly for dynamic shapes, as shown below.</p>\n<p>For the case of Flux.1-Dev transformer, changes in different image resolutions will affect two of its <code>forward</code> arguments:</p>\n<ul>\n<li><code>hidden_states</code>: The noisy input latents, which the transformer is supposed to denoise. It’s a 3D tensor, representing <code>batch_size, flattened_latent_dim, embed_dim</code>. When the batch size is fixed, it’s the <code>flattened_latent_dim</code> that will change for any changes made to image resolutions.</li>\n<li><code>img_ids</code>: A 2D array of encoded pixel coordinates having a shape of <code>height * width, 3</code>. In this case, we want to make <code>height * width</code> dynamic.</li>\n</ul>\n<p>We start by defining a range in which we want to let the (latent) image resolutions vary. To derive these value ranges, we inspected the shapes of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/diffusers/blob/0ff1aa910cf3d87193af79ec1ae4487be542e872/src/diffusers/pipelines/flux/pipeline_flux.py#L920\"><code>hidden_states</code></a> in the pipeline with respect to varied image resolutions. The exact values are model-dependent and require manual inspection and some intuition. For Flux.1-Dev, we ended up with:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer_hidden_dim</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">export</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Dim</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">hidden<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">min</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4096</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">max</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8212</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>We then define a map of argument names and which dimensions in their input values we expect to be dynamic:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer_dynamic_shapes</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span>\n    <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">hidden_states<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer_hidden_dim</span></span><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span> \n    <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">img_ids<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer_hidden_dim</span></span><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n<span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span>\n</span></span></code></pre>\n<p>Then we need to make our dynamic shapes object replicate the structure of our example inputs. The inputs that do not need dynamic shapes must be set to <code>None</code>. This can be done very easily with PyTorch <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/blob/2f0de0ff9361ca4f2b1e6f9edbc600b5fb6abcd6/torch/utils/_pytree.py#L1341-L1373\">tree_map</a> utility:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">utils</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">_pytree</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">tree_map</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dynamic_shapes</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tree_map</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function syntax-inline syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-inline syntax-python\">lambda</span></span><span class=\"syntax-meta syntax-function syntax-inline syntax-python\"><span class=\"syntax-meta syntax-function syntax-inline syntax-parameters syntax-python\"> <span class=\"syntax-variable syntax-parameter syntax-python\">v</span></span><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span> <span class=\"syntax-constant syntax-language syntax-python\">None</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">kwargs</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dynamic_shapes</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-augmented syntax-python\">|=</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer_dynamic_shapes</span></span>\n</span></span></code></pre>\n<p>Now, when performing the export step, we simply supply <code>transformer_dynamic_shapes</code> to <code>torch.export.export</code>:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">exported_transformer</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">export</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">export</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pipe</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">transformer</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">args</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">args</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">kwargs</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">call</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">kwargs</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">dynamic_shapes</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dynamic_shapes</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<blockquote>\n<p>Check out <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev-fp8-dynamic\">this Space</a> that shows how to use both quantization and dynamic shapes during the export step.</p>\n</blockquote>\n<h3>Multi-compile / shared weights</h3>\n<p>Dynamic shapes is sometimes not enough when dynamism is too important.</p>\n<p>This is, for instance, the case with the Wan family of video generation models if you want your compiled model to generate different resolutions. One thing can be done in this case: compile one model per resolution while keeping the model parameters shared and dispatching the right one at runtime</p>\n<p>Here is a minimal example of this approach: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://gist.github.com/cbensimon/8dc0ffcd7ee024d91333f6df01907916\">zerogpu-aoti-multi.py</a>. You can also see a fully working implementation of this paradigm in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster/blob/main/optimization.py\">Wan 2.2 Space</a>.</p>\n<h3>FlashAttention-3</h3>\n<p>Since the ZeroGPU hardware and CUDA drivers are perfectly compatible with Flash-Attention 3 (FA3), we can use it in our ZeroGPU Spaces to speed things up even further. FA3 works with ahead-of-time compilation. So, this is ideal for our case.</p>\n<p>Compiling and building FA3 from source can take several minutes, and this process is hardware-dependent. As users, we wouldn’t want to lose precious ZeroGPU compute hours. This is where Hugging Face <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/kernels\"><code>kernels</code> library</a> comes to the rescue. It provides access to pre-built kernels that are compatible for a given hardware. For example, when we try to run:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">kernels</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">get_kernel</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">vllm_flash_attn3</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">get_kernel</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">kernels-community/vllm-flash-attn3<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>It tries to load a kernel from the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/kernels-community/vllm-flash-attn3\"><code>kernels-community/vllm-flash-attn3</code></a> repository, which is compatible with the current setup. Otherwise, it will error out due to incompatibility issues. Luckily for us, this works seamlessly on the ZeroGPU Spaces. This means we can leverage the power of FA3 on ZeroGPU, using the <code>kernels</code> library.</p>\n<p>Here is a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://gist.github.com/sayakpaul/ff715f979793d4d44beb68e5e08ee067#file-fa3_qwen-py\">fully working example of an FA3 attention processor</a> for the Qwen-Image model.</p>\n<h3>Regional compilation</h3>\n<p>So far, we have been compiling the full model. Depending on the model, full model compilation can lead to significantly long cold start times. Long cold start times make the development experience unpleasant.</p>\n<p>We can also choose to compile <em>regions</em> within a model, significantly reducing the cold start times, while retaining almost all the benefits of full model compilation. Regional compilation becomes promising when a model has repeated blocks of computation. A standard language model, for example, has a number of identically structured Transformer blocks.</p>\n<p>In our example, we can compile the repeated blocks of the Flux transformer ahead of time, and propagate the compiled graph to the remaining repeated blocks. The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/diffusers/blob/c2e5ece08bf22d249c62e964f91bc326cf9e3759/src/diffusers/models/transformers/transformer_flux.py\">Flux Transformer</a> has two kinds of repeated blocks: <code>FluxTransformerBlock</code> and <code>FluxSingleTransformerBlock</code>.</p>\n<p>You can check out <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/cbensimon/FLUX.1-dev-fa3-aoti/tree/main\">this Space</a> for a complete example.</p>\n<blockquote>\n<p>💡 For Flux.1-Dev, switching to regional compilation reduces the compilation time from <em>6 minutes</em> to just <em>30 seconds</em> while delivering identical speedups.</p>\n</blockquote>\n<h3>Use a compiled graph from the Hub</h3>\n<p>Once a model (or even a model block) is compiled ahead of time, we can serialize the compiled graph module as an artifact and reuse later. In the context of a ZeroGPU-powered demo on Spaces, this will significantly cut down the demo startup time by skipping the compilation time.</p>\n<p>To keep the storage light, we can just save the compiled model graph without including any model parameters inside the artifact.</p>\n<p>Check out <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/collections/zerogpu-aoti/using-compiled-graph-from-the-hub-68c2afcc03de7609f9f91e35\">this collection</a> that shows a full workflow of obtaining compiled model graph, pushing it to the Hub, and then using it to build a demo.</p>\n<h2>AoT compiled ZeroGPU Spaces demos</h2>\n<h3>Speedup comparison</h3>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-base\">FLUX.1-dev without AoTI</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-fa3-aoti\">FLUX.1-dev with AoTI and FA3</a> (<strong>1.75x</strong> speedup)</li>\n</ul>\n<h3>Featured AoTI Spaces</h3>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev\">FLUX.1 Kontext</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/multimodalart/Qwen-Image-Edit-Fast\">QwenImage Edit</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster\">Wan 2.2</a></li>\n</ul>\n<h3>Regional compilation</h3>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/tutorials/recipes/regional_compilation.html\">Regional compilation recipe</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/tutorials/recipes/regional_aot.html\">Regional compilation with AOT</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/diffusers/main/en/optimization/fp16\">Native integration in Diffusers</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/\">More performance numbers</a></li>\n</ul>\n<h2>Conclusion</h2>\n<p>ZeroGPU within Hugging Face Spaces is a powerful feature that enables AI builders by providing access to powerful compute. In this post, we showed how users can benefit from PyTorch’s ahead-of-time compilation techniques to speed up their applications that leverage ZeroGPU.</p>\n<p>We demonstrate speedups with Flux.1-Dev, but these techniques are not limited to just this model. Therefore, we encourage you to give these techniques a try and provide us with feedback in this <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/zerogpu-aoti/README/discussions/1\">community discussion</a>.</p>\n<h2>Resources</h2>\n<ul>\n<li>Visit our <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/zerogpu-aoti\">ZeroGPU-AOTI org on the Hub</a> to refer to a collection of demos that leverage the techniques discussed in this post.</li>\n<li>Browse <code>spaces.aoti_*</code> APIs <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py\">source code</a> to learn more about the interface</li>\n<li>Check out <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/kernels-community\">Kernels Community org on the hub</a></li>\n<li>Learn more about regional compilation from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/pytorch.org/tutorials/recipes/regional_compilation.html\">here</a></li>\n<li>Upgrade to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/pro\">Pro</a> on Hugging Face to create your own ZeroGPU Spaces (and get 25 minutes of H200 usage every day)</li>\n</ul>\n<p><em>Acknowledgements: Thanks to ChunTe Lee for creating an awesome thumbnail for this post. Thanks to Pedro and Vaibhav for providing feedback on the post. Thanks to Angela Yi from the PyTorch team for helping us with AOT guidance.</em></p>\n",
  "content_markdown": "ZeroGPU lets anyone spin up powerful **Nvidia H200** hardware in Hugging Face Spaces without keeping a GPU locked for idle traffic. It’s efficient, flexible, and ideal for demos but it doesn’t always make full use of everything the GPU and CUDA stack can offer. Generating images or videos can take a significant amount of time. Being able to squeeze out more performance, taking advantage of the H200 hardware, does matter in this case.\n\nThis is where PyTorch ahead-of-time (AoT) compilation comes in. Instead of compiling models on the fly (which doesn’t play nicely with ZeroGPU’s short-lived processes), AoT lets you optimize once and reload instantly.\n\n**The result**: snappier demos and a smoother experience, with speedups ranging from **1.3×–1.8×** on models like Flux, Wan, and LTX 🔥\n\nIn this post, we’ll show how to wire up Ahead-of-Time (AoT) compilation in ZeroGPU Spaces. We'll explore advanced tricks like FP8 quantization and dynamic shapes, and share working demos you can try right away. If you cannot wait, we invite you to check out some ZeroGPU-powered demos on the [zerogpu-aoti](https://huggingface.co/zerogpu-aoti) organization.\n\n> [Pro](https://huggingface.co/pro) users and [Team / Enterprise](https://huggingface.co/enterprise) org members can create ZeroGPU Spaces, while anyone can freely use them (Pro, Team and Enterprise users get **8x** more ZeroGPU quota)\n\n## Table of Contents\n\n- [What is ZeroGPU](https://huggingface.co/blog/zerogpu-aoti#what-is-zerogpu)\n- [PyTorch compilation](https://huggingface.co/blog/zerogpu-aoti#pytorch-compilation)\n- [Ahead-of-time compilation on ZeroGPU](https://huggingface.co/blog/zerogpu-aoti#ahead-of-time-compilation-on-zerogpu)\n- [Gotchas](https://huggingface.co/blog/zerogpu-aoti#gotchas)\n  - [Quantization](https://huggingface.co/blog/zerogpu-aoti#quantization)\n  - [Dynamic shapes](https://huggingface.co/blog/zerogpu-aoti#dynamic-shapes)\n  - [Multi-compile / shared weights](https://huggingface.co/blog/zerogpu-aoti#multi-compile--shared-weights)\n  - [FlashAttention-3](https://huggingface.co/blog/zerogpu-aoti#flashattention-3)\n  - [Regional compilation](https://huggingface.co/blog/zerogpu-aoti#regional-compilation)\n  - [Use a compiled graph from the Hub](https://huggingface.co/blog/zerogpu-aoti#use-a-compiled-graph-from-the-hub)\n- [AoT compiled ZeroGPU Spaces demos](https://huggingface.co/blog/zerogpu-aoti#aot-compiled-zerogpu-spaces-demos)\n- [Conclusion](https://huggingface.co/blog/zerogpu-aoti#conclusion)\n- [Resources](https://huggingface.co/blog/zerogpu-aoti#resources)\n\n## What is ZeroGPU\n\n[Spaces](https://huggingface.co/spaces) is a platform powered by Hugging Face that allows ML practitioners to easily publish demo apps.\n\nTypical demo apps on Spaces look like:\n\n```python\nimport gradio as gr\nfrom diffusers import DiffusionPipeline\n\npipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n\ndef generate(prompt):\n    return pipe(prompt).images\n\ngr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nThis works great, but ends up reserving a GPU for the Space during its entire lifetime – even when it has no user activity.\n\nWhen executing `.to('cuda')` on this line:\n\n```python\npipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n```\n\nPyTorch initializes the NVIDIA driver, which sets up the process on CUDA forever. This is not very resource-efficient given that app traffic is not perfectly smooth, but is rather extremely sparse and spiky.\n\nZeroGPU takes a just-in-time approach to GPU initialization. Instead of setting up the main process on CUDA, it automatically forks the process, sets it up on CUDA, runs the GPU tasks, and finally kills the fork when the GPU needs to be released.\n\nThis means that:\n\n- When the app does not receive traffic, it doesn't use any GPU\n- When it is actually performing a task, it will use one GPU\n- It can use multiple GPUs as needed to perform tasks concurrently\n\nThanks to the Python `spaces` package, the only code change needed to get this behaviour is as follows:\n\n```diff\n  import gradio as gr\n+ import spaces\n  from diffusers import DiffusionPipeline\n\n  pipe = DiffusionPipeline.from_pretrained(...).to('cuda')\n\n+ @spaces.GPU\n  def generate(prompt):\n      return pipe(prompt).images\n\n  gr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nBy importing `spaces` and adding the `@spaces.GPU` decorator, we:\n\n- Intercept PyTorch API calls to postpone CUDA operations\n- Make the decorated function run in a fork when later called\n- (Call an internal API to make the right device visible to the fork but this is not in the scope of this blogpost)\n\n> ZeroGPU currently allocates an [MIG](https://docs.nvidia.com/datacenter/tesla/mig-user-guide/#h200-mig-profiles) slice of H200 (`3g.71gb` profile). Additional MIG sizes including full slice (`7g.141gb` profile) will come in late 2025.\n\n## PyTorch compilation\n\nModern ML frameworks like PyTorch and JAX have the concept of *compilation* that can be used to optimize model latency or inference time. Behind the scenes, compilation applies a series of (often hardware-dependent) optimization steps such as operator fusion, constant folding, etc.\n\nPyTorch (from 2.0 onwards) currently has two major interfaces for compilation:\n\n- Just-in-time with `torch.compile`\n- Ahead-of-time with `torch.export` + `AOTInductor`\n\n[`torch.compile`](https://docs.pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) works great in standard environments: it compiles your model the first time it runs, and reuses the optimized version for subsequent calls.\n\nHowever, on ZeroGPU, given that the process is freshly spun up for (almost) every GPU task, it means that `torch.compile` can’t efficiently re-use compilation and is thus forced to rely on its [filesystem cache](https://docs.pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html#modular-caching-of-torchdynamo-torchinductor-and-triton) to restore compiled models. Depending on the model being compiled, this process takes from a few dozen seconds to a couple of minutes, which is way too much for practical GPU tasks in Spaces.\n\nThis is where **ahead-of-time (AoT) compilation** shines.\n\nWith AoT, we can export a compiled model once, save it, and later reload it instantly in any process, which is exactly what we need for ZeroGPU. This helps us reduce framework overhead and also eliminates cold-start timings typically incurred in just-in-time compilation.\n\nBut how can we do ahead-of-time compilation on ZeroGPU? Let’s dive in.\n\n## Ahead-of-time compilation on ZeroGPU\n\nLet's go back to our ZeroGPU base example and unpack what we need to enable AoT compilation. For the purpose of this demo, we will use the `black-forest-labs/FLUX.1-dev` model:\n\n```python\nimport gradio as gr\nimport spaces\nimport torch\nfrom diffusers import DiffusionPipeline\n\nMODEL_ID = 'black-forest-labs/FLUX.1-dev'\n\npipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)\npipe.to('cuda')\n\n@spaces.GPU\ndef generate(prompt):\n    return pipe(prompt).images\n\ngr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\n> In the discussion below, we only compile the `transformer` component of `pipe` since, in these generative models, the transformer (or more generally, the denoiser) is the most computationally heavy component.\n\nCompiling a model ahead-of-time with PyTorch involves multiple steps:\n\n### 1. Getting example inputs\n\nRecall that we’re going to compile the model *ahead* of time. Therefore, we need to derive example inputs for the model. Note that these are the same kinds of inputs we expect to see during the actual runs. To capture those inputs, we will leverage the `spaces.aoti_capture` helper from the `spaces` package:\n\n```python\nwith spaces.aoti_capture(pipe.transformer) as call:\n    pipe(\"arbitrary example prompt\")\n```\n\nWhen used as a context manager, `aoti_capture` intercepts the call to any callable (`pipe.transformer` in our case), prevents it from executing, captures the input arguments that would have been passed to it, and stores their values in `call.args` and `call.kwargs`.\n\n### 2. Exporting the model\n\nNow that we have example args and kwargs for our transformer component, we can export it to a PyTorch [`ExportedProgram`](https://docs.pytorch.org/docs/stable/export.html#torch.export.ExportedProgram) by using [`torch.export.export`](https://docs.pytorch.org/docs/stable/export.html#torch.export.export) utility:\n\n```python\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n)\n```\n\nAn exported PyTorch program is a computation graph that represents the tensor computations along with the original model parameter values.\n\n### 3. Compiling the exported model\n\nOnce the model is exported, compiling it is pretty straightforward.\n\nA traditional AoT compilation in PyTorch often requires saving the model on disk so it can be later reloaded. In our case, we’ll leverage a helper function part of the `spaces` package: `spaces.aoti_compile`. It's a tiny wrapper around `torch._inductor.aot_compile` that manages saving and lazy-loading the model as needed. It's meant to be used like this:\n\n```python\ncompiled_transformer = spaces.aoti_compile(exported_transformer)\n```\n\nThis `compiled_transformer` is now an AoT-compiled binary ready to be used for inference.\n\n### 4. Using the compiled model in the pipeline\n\nNow we need to bind our compiled transformer to our original pipeline, i.e., the `pipeline`.\n\nA naive and almost working approach is to simply patch our pipeline like `pipe.transformer = compiled_transformer`. Unfortunately, this approach does not work because it deletes important attributes like `dtype`, `config`, etc. Only patching the `forward` method does not work well either because we are then keeping original model parameters in memory, often leading to OOM errors at runtime.\n\n`spaces` package provides a utility for this, too -- `spaces.aoti_apply`:\n\n```python\nspaces.aoti_apply(compiled_transformer, pipe.transformer)\n```\n\nEt voilà! It will take care of patching `pipe.transformer.forward` with our compiled model, as well as [cleaning old model parameters out of memory](https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py#L87).\n\n### 5. Wrapping it all together\n\nTo perform the first three steps (intercepting input examples, exporting the model, and compiling it with PyTorch inductor), we need a real GPU. CUDA emulation that you get outside of `@spaces.GPU` function is not enough because compilation is truly hardware-dependent, for instance, relying on micro-benchmark runs to tune the generated code. This is why we need to wrap it all inside a `@spaces.GPU` function and then get our compiled model back to the root of our app. Starting from our original demo code, this gives:\n\n```diff\n  import gradio as gr\n  import spaces\n  import torch\n  from diffusers import DiffusionPipeline\n  \n  MODEL_ID = 'black-forest-labs/FLUX.1-dev'\n  \n  pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)\n  pipe.to('cuda')\n  \n+ @spaces.GPU(duration=1500) # maximum duration allowed during startup\n+ def compile_transformer():\n+     with spaces.aoti_capture(pipe.transformer) as call:\n+         pipe(\"arbitrary example prompt\")\n+ \n+     exported = torch.export.export(\n+         pipe.transformer,\n+         args=call.args,\n+         kwargs=call.kwargs,\n+     )\n+     return spaces.aoti_compile(exported)\n+ \n+ compiled_transformer = compile_transformer()\n+ spaces.aoti_apply(compiled_transformer, pipe.transformer)\n  \n  @spaces.GPU\n  def generate(prompt):\n      return pipe(prompt).images\n  \n  gr.Interface(generate, \"text\", \"gallery\").launch()\n```\n\nWith just a dozen lines of additional code, we’ve successfully made our demo quite faster (**1.7x** faster in the case of FLUX.1-dev).\n\nIf you want to learn more about AoT compilation, you can read PyTorch's [AOTInductor tutorial](https://docs.pytorch.org/tutorials/recipes/torch_export_aoti_python.html)\n\n## Gotchas\n\nNow that we have demonstrated the speedups one can realize under the constraints of operating with ZeroGPUs, we will discuss a few gotchas that came up while working with this setup.\n\n### Quantization\n\nAoT can be combined with quantization to deliver even greater speedups. For image and video generation, the FP8 post-training dynamic quantization schemes deliver good speed-quality trade-offs. However, FP8 requires a CUDA compute capability of at least 9.0 to work. Thankfully, for ZeroGPUs, since they’re based on H200s, we can already take advantage of the FP8 quantization schemes.\n\nTo enable FP8 quantization within our AoT compilation workflow, we can leverage the APIs provided by [`torchao`](https://github.com/pytorch/ao) like so:\n\n```diff\n+ from torchao.quantization import quantize_, Float8DynamicActivationFloat8WeightConfig\n\n+ # Quantize the transformer just before the export step.\n+ quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())\n\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n)\n```\n\n(You can find more details about TorchAO [here](https://docs.pytorch.org/ao/stable/index.html).)\n\nAnd we can then proceed with the rest of the steps as outlined above. Using quantization provides another **1.2x** of speedup.\n\n### Dynamic shapes\n\nImages and videos can come in different shapes and sizes. Hence, it’s important to also account for shape dynamism when performing AoT compilation. The primitives provided by `torch.export.export` make it easily configurable to provide what inputs should be treated accordingly for dynamic shapes, as shown below.\n\nFor the case of Flux.1-Dev transformer, changes in different image resolutions will affect two of its `forward` arguments:\n\n- `hidden_states`: The noisy input latents, which the transformer is supposed to denoise. It’s a 3D tensor, representing `batch_size, flattened_latent_dim, embed_dim`. When the batch size is fixed, it’s the `flattened_latent_dim` that will change for any changes made to image resolutions.\n- `img_ids`: A 2D array of encoded pixel coordinates having a shape of `height * width, 3`. In this case, we want to make `height * width` dynamic.\n\nWe start by defining a range in which we want to let the (latent) image resolutions vary. To derive these value ranges, we inspected the shapes of [`hidden_states`](https://github.com/huggingface/diffusers/blob/0ff1aa910cf3d87193af79ec1ae4487be542e872/src/diffusers/pipelines/flux/pipeline_flux.py#L920) in the pipeline with respect to varied image resolutions. The exact values are model-dependent and require manual inspection and some intuition. For Flux.1-Dev, we ended up with:\n\n```python\ntransformer_hidden_dim = torch.export.Dim('hidden', min=4096, max=8212)\n```\n\nWe then define a map of argument names and which dimensions in their input values we expect to be dynamic:\n\n```python\ntransformer_dynamic_shapes = {\n    \"hidden_states\": {1: transformer_hidden_dim}, \n    \"img_ids\": {0: transformer_hidden_dim},\n}\n```\n\nThen we need to make our dynamic shapes object replicate the structure of our example inputs. The inputs that do not need dynamic shapes must be set to `None`. This can be done very easily with PyTorch [tree\\_map](https://github.com/pytorch/pytorch/blob/2f0de0ff9361ca4f2b1e6f9edbc600b5fb6abcd6/torch/utils/_pytree.py#L1341-L1373) utility:\n\n```python\nfrom torch.utils._pytree import tree_map\n\ndynamic_shapes = tree_map(lambda v: None, call.kwargs)\ndynamic_shapes |= transformer_dynamic_shapes\n```\n\nNow, when performing the export step, we simply supply `transformer_dynamic_shapes` to `torch.export.export`:\n\n```python\nexported_transformer = torch.export.export(\n    pipe.transformer,\n    args=call.args,\n    kwargs=call.kwargs,\n    dynamic_shapes=dynamic_shapes,\n)\n```\n\n> Check out [this Space](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev-fp8-dynamic) that shows how to use both quantization and dynamic shapes during the export step.\n\n### Multi-compile / shared weights\n\nDynamic shapes is sometimes not enough when dynamism is too important.\n\nThis is, for instance, the case with the Wan family of video generation models if you want your compiled model to generate different resolutions. One thing can be done in this case: compile one model per resolution while keeping the model parameters shared and dispatching the right one at runtime\n\nHere is a minimal example of this approach: [zerogpu-aoti-multi.py](https://gist.github.com/cbensimon/8dc0ffcd7ee024d91333f6df01907916). You can also see a fully working implementation of this paradigm in the [Wan 2.2 Space](https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster/blob/main/optimization.py).\n\n### FlashAttention-3\n\nSince the ZeroGPU hardware and CUDA drivers are perfectly compatible with Flash-Attention 3 (FA3), we can use it in our ZeroGPU Spaces to speed things up even further. FA3 works with ahead-of-time compilation. So, this is ideal for our case.\n\nCompiling and building FA3 from source can take several minutes, and this process is hardware-dependent. As users, we wouldn’t want to lose precious ZeroGPU compute hours. This is where Hugging Face [`kernels` library](https://github.com/huggingface/kernels) comes to the rescue. It provides access to pre-built kernels that are compatible for a given hardware. For example, when we try to run:\n\n```python\nfrom kernels import get_kernel\n\nvllm_flash_attn3 = get_kernel(\"kernels-community/vllm-flash-attn3\")\n```\n\nIt tries to load a kernel from the [`kernels-community/vllm-flash-attn3`](https://huggingface.co/kernels-community/vllm-flash-attn3) repository, which is compatible with the current setup. Otherwise, it will error out due to incompatibility issues. Luckily for us, this works seamlessly on the ZeroGPU Spaces. This means we can leverage the power of FA3 on ZeroGPU, using the `kernels` library.\n\nHere is a [fully working example of an FA3 attention processor](https://gist.github.com/sayakpaul/ff715f979793d4d44beb68e5e08ee067#file-fa3_qwen-py) for the Qwen-Image model.\n\n### Regional compilation\n\nSo far, we have been compiling the full model. Depending on the model, full model compilation can lead to significantly long cold start times. Long cold start times make the development experience unpleasant.\n\nWe can also choose to compile *regions* within a model, significantly reducing the cold start times, while retaining almost all the benefits of full model compilation. Regional compilation becomes promising when a model has repeated blocks of computation. A standard language model, for example, has a number of identically structured Transformer blocks.\n\nIn our example, we can compile the repeated blocks of the Flux transformer ahead of time, and propagate the compiled graph to the remaining repeated blocks. The [Flux Transformer](https://github.com/huggingface/diffusers/blob/c2e5ece08bf22d249c62e964f91bc326cf9e3759/src/diffusers/models/transformers/transformer_flux.py) has two kinds of repeated blocks: `FluxTransformerBlock` and `FluxSingleTransformerBlock`.\n\nYou can check out [this Space](https://huggingface.co/spaces/cbensimon/FLUX.1-dev-fa3-aoti/tree/main) for a complete example.\n\n> 💡 For Flux.1-Dev, switching to regional compilation reduces the compilation time from *6 minutes* to just *30 seconds* while delivering identical speedups.\n\n### Use a compiled graph from the Hub\n\nOnce a model (or even a model block) is compiled ahead of time, we can serialize the compiled graph module as an artifact and reuse later. In the context of a ZeroGPU-powered demo on Spaces, this will significantly cut down the demo startup time by skipping the compilation time.\n\nTo keep the storage light, we can just save the compiled model graph without including any model parameters inside the artifact.\n\nCheck out [this collection](https://huggingface.co/collections/zerogpu-aoti/using-compiled-graph-from-the-hub-68c2afcc03de7609f9f91e35) that shows a full workflow of obtaining compiled model graph, pushing it to the Hub, and then using it to build a demo.\n\n## AoT compiled ZeroGPU Spaces demos\n\n### Speedup comparison\n\n- [FLUX.1-dev without AoTI](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-base)\n- [FLUX.1-dev with AoTI and FA3](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-dev-fa3-aoti) (**1.75x** speedup)\n\n### Featured AoTI Spaces\n\n- [FLUX.1 Kontext](https://huggingface.co/spaces/zerogpu-aoti/FLUX.1-Kontext-Dev)\n- [QwenImage Edit](https://huggingface.co/spaces/multimodalart/Qwen-Image-Edit-Fast)\n- [Wan 2.2](https://huggingface.co/spaces/zerogpu-aoti/wan2-2-fp8da-aoti-faster)\n\n### Regional compilation\n\n- [Regional compilation recipe](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html)\n- [Regional compilation with AOT](https://docs.pytorch.org/tutorials/recipes/regional_aot.html)\n- [Native integration in Diffusers](https://huggingface.co/docs/diffusers/main/en/optimization/fp16)\n- [More performance numbers](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)\n\n## Conclusion\n\nZeroGPU within Hugging Face Spaces is a powerful feature that enables AI builders by providing access to powerful compute. In this post, we showed how users can benefit from PyTorch’s ahead-of-time compilation techniques to speed up their applications that leverage ZeroGPU.\n\nWe demonstrate speedups with Flux.1-Dev, but these techniques are not limited to just this model. Therefore, we encourage you to give these techniques a try and provide us with feedback in this [community discussion](https://huggingface.co/spaces/zerogpu-aoti/README/discussions/1).\n\n## Resources\n\n- Visit our [ZeroGPU-AOTI org on the Hub](https://huggingface.co/zerogpu-aoti) to refer to a collection of demos that leverage the techniques discussed in this post.\n- Browse `spaces.aoti_*` APIs [source code](https://pypi-browser.org/package/spaces/spaces-0.40.1-py3-none-any.whl/spaces/zero/torch/aoti.py) to learn more about the interface\n- Check out [Kernels Community org on the hub](https://huggingface.co/kernels-community)\n- Learn more about regional compilation from [here](https://huggingface.co/blog/pytorch.org/tutorials/recipes/regional_compilation.html)\n- Upgrade to [Pro](https://huggingface.co/pro) on Hugging Face to create your own ZeroGPU Spaces (and get 25 minutes of H200 usage every day)\n\n*Acknowledgements: Thanks to ChunTe Lee for creating an awesome thumbnail for this post. Thanks to Pedro and Vaibhav for providing feedback on the post. Thanks to Angela Yi from the PyTorch team for helping us with AOT guidance.*\n",
  "dateCreated": "2026-10-04T12:50:30.804479567+00:00",
  "date_created": "2025-09-02T00:00:00+00:00",
  "date_modified": "2025-09-02T00:00:00+00:00",
  "date_published": "2025-09-02T00:00:00+00:00",
  "description": "ZeroGPU lets anyone spin up powerful Nvidia H200 hardware in Hugging Face Spaces without keeping a GPU locked for idle traffic. It’s efficient, flexible, and ideal for demos but it doesn’t always make full use of everything the GPU and…",
  "external_url": "https://huggingface.co/blog/zerogpu-aoti",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/huggingface-co/2025/09/2025-09-02-make-your-zerogpu-spaces-go-brrr-with-ahead-of-time.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/huggingface-co/2025/09/2025-09-02-make-your-zerogpu-spaces-go-brrr-with-ahead-of-time.md"
  },
  "id": "urn:aggr:item:6eb2f07ddd7dce38a05ef35800ea1666c0fe0047",
  "isBasedOn": {
    "@id": "https://huggingface.co/blog/zerogpu-aoti"
  },
  "mainEntity": {
    "@id": "https://huggingface.co/blog/zerogpu-aoti",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-02-make-your-zerogpu-spaces-go-brrr-with-ahead-of-time/#webpage"
    },
    "dateModified": "2025-09-02T00:00:00+00:00",
    "datePublished": "2025-09-02T00:00:00+00:00",
    "headline": "Make your ZeroGPU Spaces go brrr with ahead-of-time compilation",
    "timeRequired": "PT13M",
    "url": "https://huggingface.co/blog/zerogpu-aoti",
    "wordCount": 2746
  },
  "name": "Archived snapshot: Make your ZeroGPU Spaces go brrr with ahead-of-time compilation",
  "preview": null,
  "reading_minutes": 13,
  "replicated_at": null,
  "source": "huggingface-co",
  "source_name": "Hugging Face - Blog",
  "summary": null,
  "tags": [],
  "temporalCoverage": "2026-10-04T12:50:30.804479567+00:00",
  "title": "Make your ZeroGPU Spaces go brrr with ahead-of-time compilation",
  "url": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-02-make-your-zerogpu-spaces-go-brrr-with-ahead-of-time/",
  "word_count": 2746
}