mirror of
https://github.com/huggingface/diffusers.git
synced 2026-10-24 20:59:27 +03:00
* feat: add torchtpu * feat:draft TorchTPU support * fix: wan overflow issue + compile mode error on sdxl * doc: enhance with TorchTPU doc * doc: enhance with TorchTPU doc * style: remove unused imports flagged by ruff Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: remove Debug Eager and Fused Eager sections from tpu.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add TP for TPU * style: fix import sorting in TPU test scripts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: ruff format TPU test scripts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: style * fix: test for native 4 devices * fix: propagate TPU device fixes to Flux/Flux2/Wan-family copies; register tpu.md; drop redundant execution_device check - Propagate the text_encoder.device-based fix (introduced for TPU CPU-offload support) from FluxPipeline/Flux2KleinPipeline/WanPipeline into their `# Copied from` copies (flux/*, flux2_klein_inpaint, visualcloze, anyflow, chronoedit, lucy_edit, skyreels_v2/*). SDXL-family copies of StableDiffusionXLPipeline.encode_prompt are intentionally left untouched; they'll be handled in a follow-up PR that fixes device placement for every pipeline component (not just text encoders). - Register docs/source/en/optimization/tpu.md in _toctree.yml (was breaking the docs build: "not present in the table of contents"). - Remove the redundant "prefer non-CPU, non-meta component" loop from DiffusionPipeline._execution_device: PR #14383 already fixed this in DiffusionPipeline.device, which _execution_device falls back to. Verified on TPU hardware that _execution_device still resolves correctly for a split-placement pipeline after the removal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * tests: cleanup * fix: fix compile mode * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * test: remove flux2 e2e test * doc: apply suggestions * doc: apply suggestions * review: remove monkey patch * review: revert neuron-specific changes in the tests * review: apply suggestions * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * doc: add tpu to tp doc * review: remove unnecessary for tpu * test: assert every _tp_plan parameter is sharded after a TP load Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * removal: delete redundant tp shard helpers * removal: drop TPU workarounds no longer needed after recent main changes * doc: keep the FLUX.2-dev text encoder off a single TPU chip in the TP example * doc: encode the prompt on CPU in the TPU TP example so it runs end to end * test: tighten TPU TP tolerance and simplify the TPU TP worker * doc: use enable_model_cpu_offload() in the TPU eager example * doc: shard both FLUX.2-dev text encoder and transformer in the TPU TP example * doc: run the text encoders on TPU in the compiled example * test: drop the redundant TPU sync in the TP worker * test: trim comments in the TPU TP tests * test: run the TPU TP test with mp.spawn like the CUDA one * test: pin the TPU TP test to 4 chips * Update docs/source/en/optimization/tpu.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> * doc: use DistributedConfig and dtype, and drop the torch_tpu import in the TPU examples * test: skip the TPU TP test for models without a _tp_plan * doc: correct the warning of recompilation * fix: clone the SD3 timestep so torch.compile doesn't recompile every step, thus we can use it for the tpu.md compile mode snippet * doc: update advice for compile mode when one chip doesn't fit * test: pass the TPU TP tolerances as test arguments * review: apply suggestions to the doc * review: view compilation patch for tpu-only --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: JingyaHuang <huang_jingya@outlok.com> Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> Co-authored-by: Sayak Paul <spsayakpaul@gmail.com>
158 lines
6.6 KiB
Markdown
158 lines
6.6 KiB
Markdown
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
|
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations under the License.
|
|
-->
|
|
|
|
# TorchTPU
|
|
|
|
[TorchTPU](https://github.com/google-pytorch/torch_tpu/) is a PyTorch backend for Google's Tensor Processing Units
|
|
(TPUs), which lets you run Diffusers pipelines on Cloud TPUs (v6e, v7x) with minimal code changes.
|
|
|
|
Two execution modes are available:
|
|
|
|
| Mode | Constant | How to activate | Notes |
|
|
|---|---|---|---|
|
|
| Strict eager (default) | `EagerMode.DEFER_NEVER` | `pipe.to("tpu")` | Operations dispatched one at a time, asynchronous |
|
|
| Compile | — | `torch.compile(module, backend="tpu")` | AOT compilation with `TpuBackend` |
|
|
|
|
Follow the [TorchTPU installation guide](https://github.com/google-pytorch/torch_tpu/). Once installed, `import torch`
|
|
loads it automatically and registers the `"tpu"` device, so `pipe.to("tpu")` is the only change needed. Add
|
|
`import torch_tpu` only if you disabled backend autoloading with `TORCH_DEVICE_BACKEND_AUTOLOAD=0`.
|
|
|
|
## Eager mode
|
|
|
|
FLUX.1-schnell doesn't fit on a single v6e chip all at once, so use [`~DiffusionPipeline.enable_model_cpu_offload`] to
|
|
move each model to the TPU only while it runs. It detects the `"tpu"` device automatically.
|
|
|
|
```python
|
|
import torch
|
|
|
|
from diffusers import FluxPipeline
|
|
|
|
pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-schnell", dtype=torch.bfloat16)
|
|
pipe.enable_model_cpu_offload()
|
|
|
|
image = pipe(
|
|
prompt="a golden retriever surfing a wave, photorealistic",
|
|
height=1024,
|
|
width=1024,
|
|
num_inference_steps=4,
|
|
guidance_scale=0.0,
|
|
).images[0]
|
|
|
|
image.save("output.png")
|
|
```
|
|
|
|
If a model is too large for a single chip, or you have several chips and want lower latency, shard the models
|
|
across chips instead. See the [Tensor parallelism](#tensor-parallelism) section.
|
|
|
|
## Compiled mode
|
|
|
|
TorchTPU registers `"tpu"` as a `torch.compile` backend name (`TpuBackend` under the hood), so
|
|
components compile like any other `torch.compile` target. The first
|
|
call (warmup) is slow because it compiles; later calls with the same shapes reuse the compiled graph.
|
|
|
|
> [!IMPORTANT]
|
|
> TorchTPU requires **static shapes**, so pass `dynamic=False`. A new `height` or `width` compiles again for that
|
|
> shape, once; shapes already seen are reused. Changing `num_inference_steps` doesn't recompile.
|
|
|
|
When the whole pipeline fits on one chip, move it to the TPU and compile the full transformer. Stable Diffusion 3.5
|
|
Medium (~15GB in bf16) fits on a single v6e chip.
|
|
|
|
```python
|
|
import torch
|
|
|
|
from diffusers import StableDiffusion3Pipeline
|
|
|
|
pipe = StableDiffusion3Pipeline.from_pretrained("stabilityai/stable-diffusion-3.5-medium", dtype=torch.bfloat16)
|
|
pipe.to("tpu")
|
|
pipe.transformer.compile(backend="tpu", fullgraph=True, dynamic=False)
|
|
|
|
# Warmup — triggers static graph compilation.
|
|
pipe(prompt="warmup", height=1024, width=1024, num_inference_steps=40, guidance_scale=4.5)
|
|
|
|
# Later calls with the same shapes reuse the compiled graph.
|
|
image = pipe(
|
|
prompt="a golden retriever surfing a wave, photorealistic",
|
|
height=1024,
|
|
width=1024,
|
|
num_inference_steps=40,
|
|
guidance_scale=4.5,
|
|
).images[0]
|
|
|
|
image.save("output.png")
|
|
```
|
|
|
|
If the pipeline doesn't fit on one chip:
|
|
|
|
- With several chips, shard it with [tensor parallelism](#tensor-parallelism) instead. Everything stays on the TPU,
|
|
and `pipe.transformer.compile(...)` works the same way on the sharded transformer.
|
|
- With [`~DiffusionPipeline.enable_model_cpu_offload`], the offload hooks can't be traced by `torch.compile`. Compile
|
|
only the transformer's repeated blocks instead, with
|
|
`pipe.transformer.compile_repeated_blocks(backend="tpu", fullgraph=True, dynamic=False)`.
|
|
|
|
## Tensor parallelism
|
|
|
|
Shard models too large for one chip across several. FLUX.2-dev's text encoder (~48GB) and transformer (~64GB) each
|
|
exceed a single chip, so the example below shards both:
|
|
|
|
- the transformer with [`TensorParallelConfig`], passed to the `parallel_config` argument of [`~ModelMixin.from_pretrained`]. Each rank reads only its own slice of every sharded weight, so the full model is never materialized. For general TP details (`_tp_plan`, colwise/rowwise), see the [Tensor parallelism](../training/distributed_inference#tensor-parallelism) guide.
|
|
- the text encoder with Transformers' own [tensor parallelism](https://huggingface.co/docs/transformers/perf_infer_gpu_multi), passing a [`~transformers.DistributedConfig`] and the same mesh.
|
|
|
|
On TPU, initialize the process group with `backend="tpu_dist"` and build the mesh with `DeviceMesh("tpu", ...)`.
|
|
|
|
```python
|
|
import torch
|
|
import torch.distributed as dist
|
|
from torch.distributed.device_mesh import DeviceMesh
|
|
from transformers import DistributedConfig, Mistral3ForConditionalGeneration
|
|
|
|
from diffusers import Flux2Pipeline, Flux2Transformer2DModel, TensorParallelConfig
|
|
|
|
dist.init_process_group(backend="tpu_dist")
|
|
mesh = DeviceMesh("tpu", list(range(dist.get_world_size())))
|
|
|
|
repo_id = "black-forest-labs/FLUX.2-dev"
|
|
text_encoder = Mistral3ForConditionalGeneration.from_pretrained(
|
|
repo_id,
|
|
subfolder="text_encoder",
|
|
dtype=torch.bfloat16,
|
|
distributed_config=DistributedConfig(tp_plan="auto"),
|
|
device_mesh=mesh,
|
|
)
|
|
transformer = Flux2Transformer2DModel.from_pretrained(
|
|
repo_id, subfolder="transformer", dtype=torch.bfloat16, parallel_config=TensorParallelConfig(mesh=mesh)
|
|
)
|
|
pipe = Flux2Pipeline.from_pretrained(
|
|
repo_id, text_encoder=text_encoder, transformer=transformer, dtype=torch.bfloat16
|
|
)
|
|
pipe.vae.to("tpu")
|
|
|
|
image = pipe(
|
|
prompt="a golden retriever surfing a wave, photorealistic",
|
|
num_inference_steps=28,
|
|
generator=torch.Generator("cpu").manual_seed(0),
|
|
).images[0]
|
|
if dist.get_rank() == 0:
|
|
image.save("output.png")
|
|
```
|
|
|
|
Launch one process per chip. Set `--nproc_per_node` to use all the number of TPU chips on your host.
|
|
|
|
```bash
|
|
eval $(python -m torch_tpu._internal.distributed.launchers.singlehost_wrapper | sed 's/^/export /')
|
|
torchrun --nproc_per_node=8 flux2_tp.py
|
|
```
|
|
|
|
> [!WARNING]
|
|
> The launch command above uses a TorchTPU internal module (`torch_tpu._internal`), not a stable API, and is expected
|
|
> to change in a future TorchTPU release. Check the [TorchTPU repository](https://github.com/google-pytorch/torch_tpu/)
|
|
> for the current way to launch multi-chip jobs.
|