AnimateDiff on Tenstorrent Blackhole

A Cosmic Quick Study

35 animated GIFs generated on a single Blackhole chip. Each cell in this grid is a Tensix compute node. The ones that glow ran the model.

Blackhole P300C · 11 × 10 Tensix cores · 110 nodes
Pure cosmic
Intertwining oneness
Liminal threshold
Tech emergence
Full integration
Harvested core
Lightning Mode

Same hardware. 4-step inference.

The Lightning scheduler cuts denoising steps from 25 to 4–8 with no change to the model architecture. Each row below is the same prompt, same seed — original Blackhole output on the left, lightning mode on the right.

aurora borealis — 25 steps
25 steps · original
aurora borealis over arctic ice
aurora borealis — 8-step lightning
⚡ 8 steps · lightning
aurora borealis over arctic ice
sacred mandala — 25 steps
25 steps · original
sacred mandala blooming from starfield
sacred mandala — 8-step lightning
⚡ 8 steps · lightning
sacred mandala blooming from starfield
mycelium network — 25 steps
25 steps · original
mycelium network, bioluminescent spores
mycelium network — 8-step lightning
⚡ 8 steps · lightning
mycelium network, bioluminescent spores

Inference speed · 8 frames · Blackhole P300C · warm model

Mode Steps s / frame Total (8 frames) vs Phase 3
Phase 3 · MotionAdapter 25 ~101 s ~806 s
Phase 2.5 cross-frame 25 ~12.5 s ~100 s
Lightning cross-frame 8 ~12 s ~96 s ~8.4×
Standing on the shoulders of giants

AnimateDiff

Yuwei Guo, Chuanxia Zheng, Ruizhen Hu et al. The insight that motion priors can be injected into any SD UNet as a plug-and-play MotionAdapter — without retraining the base model. We just ran it faster.

arxiv 2307.04725 →

Stable Diffusion 1.4

Robin Rombach, Andreas Blattmann, Dominik Lorenz, Patrick Esser, Björn Ommer (CompVis / Stability AI). The latent diffusion model that made high-quality generation accessible to everyone.

CompVis/stable-diffusion →

🤗 diffusers

The Hugging Face team. The AnimateDiffPipeline and MotionAdapter abstractions gave us a verified CPU reference to build from and compare against.

huggingface/diffusers →

TT-Metalium & TTNN

The Tenstorrent systems team. The SD 1.4 TTNN UNet kernel — built for Wormhole, adapted here for Blackhole — is what makes the hardware path possible. We wired the temporal loop around it.

tenstorrent/tt-metal →

We ported, adapted, debugged, and shipped — but the hard science and the hard systems work were done by these teams. This repo is gratitude in the form of running code.

What Tenstorrent contributed

Hardware path

Replaced the diffusers CPU UNet with the SD 1.4 TTNN UNet running natively on Blackhole silicon. ~12.5 s/frame on P300C (Phase 2.5, 25-step) vs ~2 min/frame on CPU.

Temporal attention

Cross-frame self-attention at each PNDM step across all N frame latents simultaneously — a bridge toward full MotionAdapter integration in TTNN.

Open implementation

A clean, tested, documented repo anyone with Blackhole hardware can clone and run. Includes a ttsim path for development without silicon.

Architecture & Execution Flow

What runs on Blackhole silicon, what runs on CPU, and where this differs from standard AnimateDiff.

flowchart TD P([Prompt + seed]) --> CHAIN{"--chain-from?"} CHAIN -->|yes| BLEND["frame-mean blend prev latents\ninto seed noise — CPU\n(renorm to unit std)"] CHAIN -->|no| ENC BLEND --> ENC["CLIP encode — CPU"] ENC --> MODE{Mode?} MODE -->|cpu| CPU_SCHED["PNDM scheduler + MotionAdapter\nor Euler + distilled Lightning weights"] CPU_SCHED --> CPU_UNET["diffusers UNet2DConditionModel\n+ MotionAdapter TemporalTransformer\nFull AnimateDiff — CPU only"] CPU_UNET --> CPU_VAE["VAE decode — CPU"] CPU_VAE --> GIF([Output GIF]) MODE -->|blackhole / sim| LOOP["Denoising loop — one scheduler per frame\nPNDM standard · Euler for Lightning"] LOOP --> BH_UNET["SD 1.4 TTNN UNet2D\nBlackhole P300C · ~12.5 s / frame (Phase 2.5)"] BH_UNET --> CFA["cross_frame_attention\nnoise predictions blended\nacross all N frames — CPU"] CFA --> STEP["scheduler.step — one per frame"] STEP --> NEXT{more steps?} NEXT -->|yes| LOOP NEXT -->|no| SAVE["--chain-save: write\ndenoised latents to .pt — CPU"] SAVE --> BH_VAE["TTNN VAE decode on Blackhole\nUNet L1 freed before decode"] BH_VAE --> GIF

The TTNN UNet runs on Blackhole; everything else is CPU. Cross-frame attention is applied to the stacked noise predictions at each step — a Phase 2.5 approximation of the MotionAdapter's temporal transformer. Lightning mode switches to TtEulerScheduler (trailing, linear) with the same TTNN UNet — no distilled adapter loaded on Blackhole/sim; step count is still controlled by --steps. CPU Lightning loads ByteDance's distilled adapter (CFG=1.0) and requires 2/4/8 steps. --chain blends the frame-mean of the previous run's denoised latents (renormalized to unit std) into seed noise before the loop begins.

flowchart TB subgraph WRONG["❌ Original — silent failure"] W1["SD 3.5 DiT · 2432-dim features"] -->|motion weights injected| W2["mm_sd_v15_v2.ckpt trained for SD 1.5 UNet · 320-dim"] W2 --> W3["Dimension mismatch — no temporal attention actually applied"] end subgraph RIGHT["✅ Current"] R1["SD 1.4 UNet · 320-dim — matching architecture"] R1 -->|CPU| R2["MotionAdapter TemporalTransformer · full AnimateDiff ✓"] R1 -->|Blackhole| R3["TTNN UNet2D · cross-frame attention blend · Phase 2.5"] end WRONG -.->|fix: use matching architecture| RIGHT

The original code applied mm_sd_v15_v2.ckpt motion weights (trained for SD 1.5 UNet, 320-dim features) to the SD 3.5 DiT (a Diffusion Transformer, 2432-dim). The shapes are incompatible — no temporal attention was actually running. The fix was switching to SD 1.4 whose UNet matches the motion weights exactly.

⚡ AnimateDiff-Lightning & Gradio UI

Two new additions since the initial release.

AnimateDiff-Lightning on Blackhole

Lightning mode is available across all three backends, but works differently per mode. On CPU: loads ByteDance's distilled motion adapter (arXiv:2403.12706) — genuine 4-step distillation, CFG=1.0 baked in. On Blackhole/sim: switches to TtEulerScheduler (Euler, trailing, linear) with the base SD 1.4 TTNN UNet — no distilled adapter, CFG=7.5 retained, any step count. Enable with:

# Blackhole hardware — ~12 s/frame (warm, Phase 2.5)
python examples/generate.py --lightning

# CPU — ~20 s/frame, no hardware required
python examples/generate.py --mode cpu --lightning

Full 10-prompt comparison in the gallery.

Gradio UI

A browser-based interface for point-and-click generation — all three modes (Blackhole, ttsim, CPU) plus Lightning controls, live in the same window.

pip install -e ".[ui]"
python app.py
# → http://localhost:7860

Select mode → enter prompt → adjust frames/steps/seed → click Generate. Lightning checkbox is available in all modes. Output GIF displays inline.

🔗 Chain Continuity

Two independent prompts. One subject — retro 3D glasses — threaded between them by blending the first run's final denoised latents into the second run's seed noise. No explicit conditioning, no fine-tuning. Just hardware-resident state.

retro 3D glasses on neon-lit diner counter
neon diner
35mm film
α 0.20
retro 3D glasses floating in deep space nebula
deep space
violet nebula

How it works

After each generation, --chain-save persists the final denoised latent tensors to a .pt file. The next run loads them with --chain-from and blends the normalised mean into the seed noise before denoising begins. Each step's solver then steers away from shared noise toward the new prompt — so the subject's form lingers in the structure while the context changes completely.

# Run 1 — save latents
python examples/generate.py \
  --prompt "retro 3D glasses, neon diner" \
  --chain-save chain.pt

# Run 2 — thread DNA from run 1
python examples/generate.py \
  --prompt "retro 3D glasses, deep space" \
  --chain-from chain.pt --chain-alpha 0.20 \
  --chain-save chain.pt

Why this is hardware-native

Standard diffusion pipelines evict all intermediate tensors between calls. On Tenstorrent Blackhole, the denoised latent state lives in L1 between runs — the hardware makes persistent-state inference cheap. Chain threading is only practical at this cost because the latents never need to round-trip through host memory. It's a primitive that other architectures can't express efficiently without bespoke memory management. --chain-alpha (0–1) controls how strongly the previous run's identity bleeds through — lower values let the new prompt fully take over; higher values preserve more of the subject's structural fingerprint.

The Gradio UI exposes chain controls under the Chain continuity accordion — load a .pt from disk and chain runs interactively.

Prompt Guide

SD 1.4 at 512×512 with the TTNN UNet has a distinct personality. Knowing it gets you better results.

Sweet spots

  • Natural scenes — forests, oceans, desert, fire, water, sky
  • Painterly styles — oil, watercolor, impressionism, concept art
  • Cinematic lighting — golden hour, neon, moonlight, candlelight
  • Cosmic & abstract — nebulae, aurora, energy fields, geometry
  • Retro aesthetics — CRT glow, film grain, vaporwave, cyberpunk
  • Architecture — temples, ruins, castles, sci-fi structures

Avoid

  • Photorealistic faces — anatomy drifts frame-to-frame
  • Text in the image — SD 1.4 cannot render legible text
  • Specific named real places — results are impressionistic
  • Very long prompts — CLIP truncates at 77 tokens (~60 words max)

Patterns that work

style before subject — model weights style heavily
add: cinematic 4K, dramatic lighting, depth of field
motion subjects: fire, waves, aurora, swirling clouds

--temporal-alpha tuning

0.0No cross-frame mixing — shared noise only
0.2–0.3Subtle coherence, visible variation
0.35Default — good for most subjects
0.5–0.7Strong coherence, detail may flatten
1.0Maximum blending, low motion

Fast motion (fire, water): 0.2–0.35 · Slow drift (cosmos, aurora): 0.4–0.6

--steps

PNDM and Euler (Lightning): 25 is the sweet spot on silicon for both. Minimum ~4 for quick previews. With distilled weights, 4–8 steps produce comparable quality at 3–6× the speed.