Skip to content

Commit 2c13793

Browse files
authored
[bugfix] Fix Dreamverse Modal compile warmup latency (#1394)
1 parent 3668279 commit 2c13793

5 files changed

Lines changed: 53 additions & 7 deletions

File tree

apps/dreamverse/dreamverse/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def _optional_env(*names: str) -> str | None:
164164

165165
DEVTOOLS_ENABLED = _env_bool("FASTVIDEO_ENABLE_DEVTOOLS", False)
166166
PROMPT_SAFETY_ENABLED = _env_bool("FASTVIDEO_ENABLE_PROMPT_SAFETY", False)
167+
DREAMVERSE_MAX_AUTOTUNE = _env_bool("DREAMVERSE_MAX_AUTOTUNE", True)
167168

168169

169170
def _resolve_devtools_paths(

apps/dreamverse/dreamverse/video_generation.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
MODEL_CONFIG,
2626
NUM_FRAMES,
2727
NUM_INFERENCE_STEPS,
28+
DREAMVERSE_MAX_AUTOTUNE,
2829
)
2930

3031
# Multi-frame decoded continuation defaults from
@@ -257,6 +258,7 @@ def initialize(self, model_config: dict | None = None) -> None:
257258
or self.current_model_config["model_path"])
258259

259260
enable_compile = os.getenv("ENABLE_TORCH_COMPILE", "1") == "1"
261+
compile_mode = "max-autotune-no-cudagraphs" if DREAMVERSE_MAX_AUTOTUNE else None
260262

261263
components = ComponentConfig(
262264
config_root=config_model_path,
@@ -280,9 +282,10 @@ def initialize(self, model_config: dict | None = None) -> None:
280282
compile=CompileConfig(
281283
enabled=enable_compile,
282284
text_encoder_enabled=enable_compile,
285+
vae_enabled=enable_compile,
283286
backend="inductor",
284287
fullgraph=True,
285-
mode="max-autotune-no-cudagraphs",
288+
mode=compile_mode,
286289
dynamic=False,
287290
),
288291
use_fsdp_inference=False,

apps/dreamverse/scripts/modal/README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,26 @@ knobs below live in the image or `modal_app.py` unless you intentionally change
9797
- `FASTVIDEO_ENABLE_DEVTOOLS`: enable Dreamverse devtools behavior.
9898
- `FASTVIDEO_PROMPT_PROVIDER` / `FASTVIDEO_PROMPT_*_MODEL`: try prompt-rewriter provider or model choices.
9999
- `FASTVIDEO_ENABLE_STARTUP_WARMUP`: trade slower startup for a warmer first request.
100+
- `DREAMVERSE_MAX_AUTOTUNE`: enable or disable PyTorch Inductor max-autotune for the compiled Dreamverse runtime.
101+
102+
The Modal wrapper defaults to torch compile with Inductor max-autotune enabled
103+
for the fastest generation after startup warmup. If you need shorter
104+
compile/warmup time, disable max-autotune via:
105+
106+
```bash
107+
DREAMVERSE_IMAGE=ghcr.io/<org>/<repo>/dreamverse:<tag> \
108+
DREAMVERSE_MAX_AUTOTUNE=0 \
109+
modal deploy apps/dreamverse/scripts/modal/modal_app.py
110+
```
100111

101112
### Autoscaling and cost safety
102113

103-
The current deployed script is capped with `max_containers=1`. If uncapped, concurrent requests could
104-
spawn multiple containers, while `max_containers=1` queued requests onto one
105-
container instead of multiplying B200 cost.
114+
The current deployed script keeps exactly one B200 container warm by setting
115+
`min_containers=1` and `max_containers=1`. `min_containers=1` prevents Modal
116+
from scaling the deployment down to zero after idle periods, which avoids paying
117+
the expensive torch-compile/startup-warmup cost again on the next request.
118+
`max_containers=1` caps concurrency so concurrent requests queue onto the warm
119+
container instead of spawning additional B200 containers and multiplying cost.
106120

107121
### Common gotchas
108122

apps/dreamverse/scripts/modal/modal_app.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
image = modal.Image.from_registry(IMAGE)
1818
image = image.env({
19+
"DREAMVERSE_IMAGE": IMAGE,
1920
"HF_HOME": "/root/.cache/huggingface",
2021
"FASTVIDEO_DREAMVERSE_HOME": "/var/lib/dreamverse",
21-
"FASTVIDEO_ENABLE_STARTUP_WARMUP": "0",
22+
"FASTVIDEO_ENABLE_STARTUP_WARMUP": "1",
2223
"FASTVIDEO_GPU_COUNT": "1",
23-
"ENABLE_TORCH_COMPILE": "0",
24+
"ENABLE_TORCH_COMPILE": "1",
25+
"DREAMVERSE_MAX_AUTOTUNE": os.environ.get("DREAMVERSE_MAX_AUTOTUNE", "1"),
2426
"STREAM_MODE": "av_fmp4",
2527
})
2628

@@ -37,6 +39,7 @@
3739
memory=65536,
3840
timeout=7200,
3941
startup_timeout=4800,
42+
min_containers=1,
4043
max_containers=1,
4144
secrets=[modal.Secret.from_name("dreamverse-api-keys")],
4245
volumes={

fastvideo/models/encoders/gemma.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,32 @@ def named_parameters(self, prefix: str = "", recurse: bool = True):
363363

364364
def prepare_for_compile(self) -> None:
365365
# Load Gemma outside Dynamo so torch.compile does not trace HF file-system checks.
366-
_ = self.gemma_model
366+
model = self.gemma_model
367+
# Run one tiny eager forward before torch.compile. FastVideo calls the text encoder with
368+
# Transformers' output_hidden_states path, which wraps each Gemma layer
369+
# forward method and restores it by setting an instance-level forward
370+
# attribute. If that attribute appears after Dynamo captures guards, the
371+
# next text-encoder call recompiles; doing it here makes the first
372+
# compiled call see the stable layer state.
373+
token_id = getattr(model.config, "eos_token_id", None)
374+
if isinstance(token_id, (list, tuple)):
375+
token_id = token_id[0] if token_id else None
376+
if token_id is None:
377+
token_id = getattr(model.config, "pad_token_id", 0)
378+
input_ids = torch.full(
379+
(1, 1),
380+
int(token_id or 0),
381+
dtype=torch.long,
382+
device=model.device,
383+
)
384+
attention_mask = torch.ones_like(input_ids)
385+
with torch.no_grad():
386+
model(
387+
input_ids=input_ids,
388+
attention_mask=attention_mask,
389+
output_hidden_states=True,
390+
return_dict=True,
391+
)
367392

368393
@property
369394
def gemma_model(self) -> Gemma3ForConditionalGeneration:

0 commit comments

Comments
 (0)