[misc] Move environment var reads into env registry and rename unprefixed variables (#1897)
This commit is contained in:
@@ -34,10 +34,15 @@ on a summary here.
|
||||
1. **Declare or edit the variable in `fastvideo/envs.py`.**
|
||||
- Pick the field type and category that the policy doc lists.
|
||||
- Write a description that states what the variable does and its units.
|
||||
- To rename, keep the old name in `deprecated_names`. To remove, add the
|
||||
name to `DEPRECATED_VARIABLES`. Update the uses in `examples/`,
|
||||
`scripts/`, `docs/`, `apps/`, and the tests.
|
||||
2. **Read the variable with `envs.NAME.get()` inside a function.**
|
||||
- In tests, change the value with `envs.NAME.override(value)`.
|
||||
- Do not call `os.environ`, `os.getenv`, or `monkeypatch.setenv` for a
|
||||
FastVideo variable.
|
||||
- To set a variable that another tool reads, call `envs.set_external`,
|
||||
`envs.setdefault_external`, or `envs.unset_external`.
|
||||
3. **Regenerate the table in the policy doc.**
|
||||
- Run `python fastvideo/tests/contract/test_env_policy.py`.
|
||||
4. **Run the contract test.**
|
||||
|
||||
@@ -30,7 +30,7 @@ FastVideo and the reference model first produce different numbers?"
|
||||
| General logging | `init_logger(__name__)` |
|
||||
| Per-stage timing | `FASTVIDEO_STAGE_LOGGING` |
|
||||
| Profiling kernel timings | `FASTVIDEO_TORCH_PROFILER_DIR` (see [Profiling](profiling.md)) |
|
||||
| Function-call tracing | `FASTVIDEO_TRACE_FUNCTION` (heavy) |
|
||||
| Function-call tracing | `fastvideo.logger.enable_trace_function_call()` (heavy) |
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
||||
+123
-61
@@ -11,14 +11,16 @@ test in the same pull request.
|
||||
1. **Register every FastVideo variable in `fastvideo/envs.py`.** Each entry declares a type, a default, a category,
|
||||
and a description. Variables that other tools own (CUDA, NCCL, PyTorch, launchers) are not registered; code reads
|
||||
them directly with `os.environ.get("NAME")`, and the name must be in the external-variable allowlist
|
||||
(`EXTERNAL_ALLOWLIST` in the contract test).
|
||||
(`EXTERNAL_ALLOWLIST` in the contract test). When FastVideo sets such a variable for the other tool, it calls
|
||||
`envs.set_external`, `envs.setdefault_external`, or `envs.unset_external`, and the name must be in
|
||||
`EXTERNAL_WRITE_ALLOWLIST`.
|
||||
2. **Read with `envs.NAME.get()`, write with `envs.NAME.set()`, and change a value in tests with
|
||||
`envs.NAME.override()`.** Each type has one parsing rule. A value that the rule rejects raises
|
||||
`fastvideo.envs.EnvVarError` instead of falling back to the default.
|
||||
3. **Name FastVideo variables with the `FASTVIDEO_` prefix.** The second word states the purpose where one applies:
|
||||
`ENABLE_`, `DISABLE_`, `USE_`, `FORCE_`, `DEBUG_`, `TEST_`.
|
||||
4. **Keep a renamed variable as a deprecated alias until the next minor release.** Setting the old name logs a
|
||||
warning. Delete a variable that no code reads, and list it in a deprecation table so that setting it logs a
|
||||
warning. Delete a variable that no code reads, and list it in `DEPRECATED_VARIABLES` so that setting it logs a
|
||||
warning.
|
||||
5. **Give each setting one source: an argument or an environment variable.** Settings that users change per
|
||||
deployment are arguments (CLI or YAML). Expert switches, emergency off switches, and debugging and test switches
|
||||
@@ -85,6 +87,25 @@ with envs.FASTVIDEO_DEBUG_MY_STAGE.override(True):
|
||||
run_stage()
|
||||
```
|
||||
|
||||
## Rename or remove a variable
|
||||
|
||||
To rename a variable, declare it under the new name and list the old name in `deprecated_names`:
|
||||
|
||||
```python
|
||||
FASTVIDEO_LTX2_USE_DISTILLED_SIGMAS = EnvBool(True,
|
||||
category="sampling",
|
||||
doc="...",
|
||||
deprecated_names=("LTX2_USE_DISTILLED_SIGMAS", ))
|
||||
```
|
||||
|
||||
`get()` reads an old name only when the new name is unset, and logs a warning once. Update the uses of the old name
|
||||
in `examples/`, `scripts/`, `docs/`, `apps/`, and the tests in the same pull request. Delete the old name in the next
|
||||
minor release.
|
||||
|
||||
To remove a variable that no code reads, delete its entry and add the name to `DEPRECATED_VARIABLES` in
|
||||
`fastvideo/envs.py` with a reason. `FastVideoArgs` calls `envs.warn_deprecated_variables()`, which logs a warning for
|
||||
each listed variable that is set. Delete the entry in the next minor release.
|
||||
|
||||
## What the contract test checks
|
||||
|
||||
The test parses every Python file under `fastvideo/`, including `fastvideo/tests/`, with Python's `ast` module. It
|
||||
@@ -100,20 +121,24 @@ It reports each violation as `<path>: <kind> <name>`:
|
||||
| | with a name built at runtime (`<dynamic>`) | another tool owns, add it to |
|
||||
| | | `EXTERNAL_ALLOWLIST` with a reason. |
|
||||
| `write` | `os.environ[...] = ...`, `setdefault`, `pop`, `del`, | Pass an argument instead. In tests, use |
|
||||
| | `os.putenv`, `os.unsetenv`, `monkeypatch.setenv`/`delenv` | `envs.NAME.override()`. |
|
||||
| | `os.putenv`, `os.unsetenv`, `monkeypatch.setenv`/`delenv`, | `envs.NAME.override()`. For a variable that |
|
||||
| | or an `envs.*_external` call with a name outside | another tool reads, call an |
|
||||
| | `EXTERNAL_WRITE_ALLOWLIST` | `envs.*_external` helper and add the name to |
|
||||
| | | `EXTERNAL_WRITE_ALLOWLIST` with a reason. |
|
||||
| `whole-environ` | `os.environ.copy()`, `dict(os.environ)`, iteration, | Read the specific variables that the code |
|
||||
| | `mock.patch.dict(os.environ, ...)`, `os.environ.update` | needs. |
|
||||
| `bare-field` | A registry field used without calling one of its methods, | Call `envs.NAME.get()`. |
|
||||
| | as in `envs.NAME == "auto"` or `getter = envs.NAME.get` | |
|
||||
| `import-time-read` | `envs.NAME.get()` outside a function | Move the read into the function that uses |
|
||||
| | | the value. |
|
||||
| `prefix` | A registry entry without the `FASTVIDEO_` prefix | Rename the variable and keep the old name as |
|
||||
| | | a deprecated alias. |
|
||||
| `unread` | A registry entry that no code reads with `get()` or | Delete the variable and add it to the |
|
||||
| | `is_set()` | deprecation table. |
|
||||
| `prefix` | A registry entry without the `FASTVIDEO_` prefix | Rename the variable and keep the old name in |
|
||||
| | | `deprecated_names`. |
|
||||
| `unread` | A registry entry that no code reads with `get()` or | Delete the variable and add it to |
|
||||
| | `is_set()` | `DEPRECATED_VARIABLES`. |
|
||||
|
||||
The test recognizes `os` imported under another name and `from os import environ, getenv`. Code that reaches the
|
||||
environment through `importlib` or `getattr(os, "environ")` is left to code review.
|
||||
The test recognizes `os` imported under another name, `from os import environ, getenv`, and a name held in a
|
||||
module-level string constant. Code that reaches the environment through `importlib` or `getattr(os, "environ")` is
|
||||
left to code review.
|
||||
|
||||
The test also checks that every registry entry has a category from `envs.CATEGORIES` and a description, and that the
|
||||
table at the end of this page matches the registry.
|
||||
@@ -125,56 +150,93 @@ longer exists also fails the test, so the fixing pull request deletes its entry.
|
||||
## Registered variables
|
||||
|
||||
<!-- BEGIN GENERATED ENV TABLE: python fastvideo/tests/contract/test_env_policy.py -->
|
||||
| Variable | Type | Default | Category | Description |
|
||||
| ---------------------------------------------- | ------------------------------ | --------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `FASTVIDEO_TARGET_DEVICE` | str | `cuda` | build | Target device of FastVideo: cuda, rocm, neuron, cpu, or openvino. |
|
||||
| `MAX_JOBS` | str | unset | build | Maximum number of parallel compilation jobs. Defaults to the number of CPUs. |
|
||||
| `NVCC_THREADS` | str | unset | build | Number of nvcc threads. When set, MAX_JOBS is reduced to avoid oversubscribing the CPU. |
|
||||
| `FASTVIDEO_USE_PRECOMPILED` | bool | `0` | build | Use precompiled binaries (\*.so). |
|
||||
| `CMAKE_BUILD_TYPE` | str | unset | build | CMake build type: Debug, Release, or RelWithDebInfo. |
|
||||
| `VERBOSE` | bool | `0` | build | Print verbose logs during installation. |
|
||||
| `FASTVIDEO_CONFIG_ROOT` | path | computed | path | Root directory for FastVideo configuration files, at runtime and at installation. Defaults to ~/.config/fastvideo, or $XDG_CONFIG_HOME/fastvideo when XDG_CONFIG_HOME is set. |
|
||||
| `FASTVIDEO_CACHE_ROOT` | path | computed | path | Root directory for FastVideo cache files. Defaults to ~/.cache/fastvideo, or $XDG_CACHE_HOME/fastvideo when XDG_CACHE_HOME is set. |
|
||||
| `FASTVIDEO_HOST_IP` | str | `""` | distributed | IP address of this node when the node has several network interfaces. Set it on each node for multi-node inference. |
|
||||
| `FASTVIDEO_LOOPBACK_IP` | str | `""` | distributed | Loopback IP address to use instead of the detected one. |
|
||||
| `FASTVIDEO_RAY_PER_WORKER_GPUS` | float | `1.0` | distributed | GPUs per Ray worker. A fraction lets Ray schedule several actors on one GPU, so other actors can share the GPUs with FastVideo. |
|
||||
| `FASTVIDEO_RINGBUFFER_WARNING_INTERVAL` | int | `60` | distributed | Seconds between warnings while the ring buffer is full. |
|
||||
| `FASTVIDEO_NCCL_SO_PATH` | str | unset | distributed | Path to the NCCL library file. Needed because the nccl>=2.19 that PyTorch ships has a bug (https://github.com/NVIDIA/nccl/issues/1234). |
|
||||
| `HCCL_SO_PATH` | str | unset | distributed | Path to the HCCL library file on Ascend NPUs. |
|
||||
| `FASTVIDEO_ENGINE_ITERATION_TIMEOUT_S` | int | `60` | distributed | Timeout in seconds for each engine iteration. |
|
||||
| `FASTVIDEO_WORKER_MULTIPROC_METHOD` | one of spawn, fork, forkserver | `spawn` | distributed | Multiprocessing start method for worker processes. |
|
||||
| `FASTVIDEO_ULYSSES_A2A` | one of off, auto | `off` | distributed | Sequence-parallel all-to-all backend. off uses the NCCL path in DistributedAutograd.AllToAll4D. auto uses the fused NVLink kernel when the group is a load-store accessible mesh of 2, 4, 6, or 8 ranks in eager execution, and the NCCL path otherwise. |
|
||||
| `LD_LIBRARY_PATH` | str | unset | external | Searched for the NCCL library when FASTVIDEO_NCCL_SO_PATH is unset. |
|
||||
| `LOCAL_RANK` | int | `0` | external | Local rank of the process in a distributed run; selects the GPU device id. |
|
||||
| `CUDA_VISIBLE_DEVICES` | str | unset | external | Visible devices in a distributed run. |
|
||||
| `FASTVIDEO_CONFIGURE_LOGGING` | bool | `1` | logging | Configure logging at import. When true, FastVideo uses its default logging configuration or the file in FASTVIDEO_LOGGING_CONFIG_PATH. |
|
||||
| `FASTVIDEO_LOGGING_CONFIG_PATH` | str | unset | logging | Path to a JSON logging configuration file. |
|
||||
| `FASTVIDEO_LOGGING_LEVEL` | str | `INFO` | logging | Default logging level. |
|
||||
| `FASTVIDEO_LOGGING_PREFIX` | str | `""` | logging | Prefix prepended to every log message. |
|
||||
| `FASTVIDEO_STAGE_LOGGING` | bool | `0` | logging | Log the time that each pipeline stage takes. |
|
||||
| `FASTVIDEO_ATTENTION_BACKEND` | str | unset | attention | Attention backend, as an AttentionBackendEnum name such as TORCH_SDPA, FLASH_ATTN, VIDEO_SPARSE_ATTN, SAGE_ATTN, or SAGE_ATTN_THREE. FastVideoArgs uses it when FastVideoArgs.attention_backend is unset. |
|
||||
| `FASTVIDEO_FA4` | bool | `0` | attention | The FLASH_ATTN backend uses FlashAttention-4 (flash_attn.cute) instead of FA3 or FA2. |
|
||||
| `FASTVIDEO_MINIMAX_H3_FA4_PACKED_VARLEN` | bool | `0` | attention | MiniMax-H3 dense DiT self-attention uses the FlashAttention-4 packed-varlen entry point. This changes the floating-point reduction order, so it is an inference-only opt-in. |
|
||||
| `FASTVIDEO_VSA_SM100A` | bool | `0` | attention | VIDEO_SPARSE_ATTN_H3 sends no-grad tile-64 forwards to the data-center Blackwell (sm_100a) kernel. fastvideo-kernel reads the same variable with the same rule. |
|
||||
| `FASTVIDEO_INFERENCE_TORCH_COMPILE` | bool | `0` | performance | Compile each DiT transformer block with fullgraph torch.compile at inference. Same as FastVideoArgs.inference_torch_compile=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_DECODE` | bool | `0` | performance | MiniMax-H3 VAE decode splits its temporal chunks across the sequence-parallel ranks instead of running serially on the output rank. Same as FastVideoArgs.vae_parallel_decode=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_ENCODE` | bool | `0` | performance | MiniMax-H3 reference-video VAE encode splits its temporal chunks across the sequence-parallel ranks. Same as FastVideoArgs.vae_parallel_encode=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_DECODE_STRATEGY` | str | unset | performance | Collective that moves chunks in parallel VAE decode: gather (used when unset) or all_gather. |
|
||||
| `FASTVIDEO_MINIMAX_H3_FUSIONS` | str | `""` | performance | MiniMax-H3 inference-only Triton fusions: all, 1, or a comma-separated subset of modulate,qknorm_rope,swiglu. Empty, 0, or none keeps the eager implementation. |
|
||||
| `FASTVIDEO_TEST_DYNAMO_FULLGRAPH_CAPTURE` | bool | `1` | debug | Enable Dynamo fullgraph capture. |
|
||||
| `FASTVIDEO_NVTX_PROFILE` | bool | `0` | profiling | Emit NVTX ranges for external profilers such as Nsight Systems. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_DIR` | path | unset | profiling | Enables the torch profiler and sets the directory for its traces. Must be an absolute path. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_RECORD_SHAPES` | bool | `0` | profiling | Torch profiler records shapes. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_PROFILE_MEMORY` | bool | `0` | profiling | Torch profiler profiles memory. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_STACK` | bool | `0` | profiling | Torch profiler captures stacks. Costs about 1.5x runtime and 1.4x trace size. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_FLOPS` | bool | `0` | profiling | Torch profiler profiles FLOPs. |
|
||||
| `FASTVIDEO_TORCH_PROFILE_REGIONS` | str | `""` | profiling | Comma-separated profiler regions to record. The torch profiler requires at least one region. |
|
||||
| `FASTVIDEO_SERVER_DEV_MODE` | bool | `0` | debug | Run the server in development mode with extra debugging endpoints. |
|
||||
| `FASTVIDEO_TRACE_FUNCTION` | bool | `0` | debug | Trace function calls. |
|
||||
| `FASTVIDEO_TRACE_ACTIVATIONS` | bool | `0` | debug | Enable activation trace hooks. |
|
||||
| `FASTVIDEO_TRACE_LAYERS` | str | `""` | debug | Regex filter for traced module names. Empty means all. |
|
||||
| `FASTVIDEO_TRACE_STATS` | str | `abs_mean,sum` | debug | Comma-separated activation statistics dumped for each output tensor. |
|
||||
| `FASTVIDEO_TRACE_OUTPUT` | str | `/tmp/fv_trace_<pid>.jsonl` | debug | JSONL path for activation traces. The literal <pid> is replaced at runtime. |
|
||||
| `FASTVIDEO_TRACE_STEPS` | str | `""` | debug | Comma-separated denoising step indices. Empty means all. |
|
||||
| `FASTVIDEO_CFG_GATE_STEP` | float | `1.0` | sampling | CFG gating fraction in [0, 1]. Steps before len(timesteps) \* X run the conditional and unconditional forwards; later steps reuse the cached difference. 1.0 disables gating. |
|
||||
| Variable | Type | Default | Category | Description |
|
||||
| ---------------------------------------------------------- | ------------------------------ | ----------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `FASTVIDEO_CONFIG_ROOT` | path | computed | path | Root directory for FastVideo configuration files, at runtime and at installation. Defaults to ~/.config/fastvideo, or $XDG_CONFIG_HOME/fastvideo when XDG_CONFIG_HOME is set. |
|
||||
| `FASTVIDEO_CACHE_ROOT` | path | computed | path | Root directory for FastVideo cache files. Defaults to ~/.cache/fastvideo, or $XDG_CACHE_HOME/fastvideo when XDG_CACHE_HOME is set. |
|
||||
| `FASTVIDEO_REASON1_WEIGHTS_PATH` | str | unset | path | Local path or Hugging Face id of Reason1 weights to load instead of the checkpoint's own. |
|
||||
| `FASTVIDEO_HOST_IP` | str | `""` | distributed | IP address of this node when the node has several network interfaces. Set it on each node for multi-node inference. |
|
||||
| `FASTVIDEO_LOOPBACK_IP` | str | `""` | distributed | Loopback IP address to use instead of the detected one. |
|
||||
| `FASTVIDEO_RAY_PER_WORKER_GPUS` | float | `1.0` | distributed | GPUs per Ray worker. A fraction lets Ray schedule several actors on one GPU, so other actors can share the GPUs with FastVideo. |
|
||||
| `FASTVIDEO_NCCL_SO_PATH` | str | unset | distributed | Path to the NCCL library file. Needed because the nccl>=2.19 that PyTorch ships has a bug (https://github.com/NVIDIA/nccl/issues/1234). |
|
||||
| `FASTVIDEO_HCCL_SO_PATH` | str | unset | distributed | Path to the HCCL library file on Ascend NPUs. Deprecated names: `HCCL_SO_PATH`. |
|
||||
| `FASTVIDEO_WORKER_MULTIPROC_METHOD` | one of spawn, fork, forkserver | `spawn` | distributed | Multiprocessing start method for worker processes. |
|
||||
| `FASTVIDEO_ULYSSES_A2A` | one of off, auto | `off` | distributed | Sequence-parallel all-to-all backend. off uses the NCCL path in DistributedAutograd.AllToAll4D. auto uses the fused NVLink kernel when the group is a load-store accessible mesh of 2, 4, 6, or 8 ranks in eager execution, and the NCCL path otherwise. |
|
||||
| `FASTVIDEO_CONFIGURE_LOGGING` | bool | `1` | logging | Configure logging at import. When true, FastVideo uses its default logging configuration or the file in FASTVIDEO_LOGGING_CONFIG_PATH. |
|
||||
| `FASTVIDEO_LOGGING_CONFIG_PATH` | str | unset | logging | Path to a JSON logging configuration file. |
|
||||
| `FASTVIDEO_LOGGING_LEVEL` | str | `INFO` | logging | Default logging level. |
|
||||
| `FASTVIDEO_LOGGING_PREFIX` | str | `""` | logging | Prefix prepended to every log message. |
|
||||
| `FASTVIDEO_STAGE_LOGGING` | bool | `0` | logging | Log the time that each pipeline stage takes. |
|
||||
| `FASTVIDEO_ATTENTION_BACKEND` | str | unset | attention | Attention backend, as an AttentionBackendEnum name such as TORCH_SDPA, FLASH_ATTN, VIDEO_SPARSE_ATTN, SAGE_ATTN, or SAGE_ATTN_THREE. FastVideoArgs uses it when FastVideoArgs.attention_backend is unset. |
|
||||
| `FASTVIDEO_FA4` | bool | `0` | attention | The FLASH_ATTN backend uses FlashAttention-4 (flash_attn.cute) instead of FA3 or FA2. |
|
||||
| `FASTVIDEO_MINIMAX_H3_FA4_PACKED_VARLEN` | bool | `0` | attention | MiniMax-H3 dense DiT self-attention uses the FlashAttention-4 packed-varlen entry point. This changes the floating-point reduction order, so it is an inference-only opt-in. |
|
||||
| `FASTVIDEO_VSA_SM100A` | bool | `0` | attention | VIDEO_SPARSE_ATTN_H3 sends no-grad tile-64 forwards to the data-center Blackwell (sm_100a) kernel. fastvideo-kernel reads the same variable with the same rule. |
|
||||
| `FASTVIDEO_NVFP4_FA4` | bool | `0` | attention | FlashAttention-4 quantizes Q and K to NVFP4. An explicit nvfp4_fa4 attention implementation argument takes precedence. |
|
||||
| `FASTVIDEO_DISABLE_ATTENTION_COMPILE` | bool | `1` | attention | Keep attention forward out of torch.compile graphs (torch.compiler.disable). Set it to 0 to let attention constructed under that setting be traced. Setting it explicitly to true also blocks regional compile. |
|
||||
| `FASTVIDEO_MLX_WINDOW` | int | `0` | attention | MLX FastWan windowed attention size in tokens. 0 uses full attention. |
|
||||
| `FASTVIDEO_MLX_WINDOW_SINK` | int | `0` | attention | Number of sink tokens that MLX windowed attention always attends to. |
|
||||
| `FASTVIDEO_INFERENCE_TORCH_COMPILE` | bool | `0` | performance | Compile each DiT transformer block with fullgraph torch.compile at inference. Same as FastVideoArgs.inference_torch_compile=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_DECODE` | bool | `0` | performance | MiniMax-H3 VAE decode splits its temporal chunks across the sequence-parallel ranks instead of running serially on the output rank. Same as FastVideoArgs.vae_parallel_decode=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_ENCODE` | bool | `0` | performance | MiniMax-H3 reference-video VAE encode splits its temporal chunks across the sequence-parallel ranks. Same as FastVideoArgs.vae_parallel_encode=True. |
|
||||
| `FASTVIDEO_VAE_PARALLEL_DECODE_STRATEGY` | str | unset | performance | Collective that moves chunks in parallel VAE decode: gather (used when unset) or all_gather. |
|
||||
| `FASTVIDEO_MINIMAX_H3_FUSIONS` | str | `""` | performance | MiniMax-H3 inference-only Triton fusions: all, 1, or a comma-separated subset of modulate,qknorm_rope,swiglu. Empty, 0, or none keeps the eager implementation. |
|
||||
| `FASTVIDEO_FSDP2_AUTOWRAP` | bool | `0` | performance | FSDP2 shards modules by parameter count instead of the model's shard conditions. Not supported by self-forcing distillation. |
|
||||
| `FASTVIDEO_FSDP2_MIN_PARAMS` | int | `10000000` | performance | Minimum parameter count of a module that FASTVIDEO_FSDP2_AUTOWRAP shards. |
|
||||
| `FASTVIDEO_MLX_COMPILE` | bool | `0` | performance | Compile the MLX DiT forward with mx.compile. |
|
||||
| `FASTVIDEO_MLX_FAST_NORM` | bool | `0` | performance | Use MLX fast normalization kernels. |
|
||||
| `FASTVIDEO_MLX_DQ_GEMM` | str | `1` | performance | MLX dequantized GEMM for affine-quantized weights: 0 turns it off, 1 uses the measured minimum row count, and an integer sets the minimum row count. |
|
||||
| `FASTVIDEO_LTX2_VAE_CHANNELS_LAST_3D` | bool | `1` | performance | LTX-2 VAE uses the channels_last_3d memory format. |
|
||||
| `FASTVIDEO_LTX2_DISABLE_AUDIO_AUTOCAST` | bool | `1` | performance | LTX-2 audio decoding runs without CUDA autocast. Deprecated names: `LTX2_DISABLE_AUDIO_AUTOCAST`. |
|
||||
| `FASTVIDEO_FLUX2_DISABLE_BF16_REDUCED_PRECISION_REDUCTION` | bool | `0` | performance | Flux denoising disables reduced-precision reductions in bf16 matmuls, which tightens accumulation for the 4-step Klein model. |
|
||||
| `FASTVIDEO_FFMPEG_BIN` | str | `ffmpeg` | output | ffmpeg executable used to save video with audio. |
|
||||
| `FASTVIDEO_VIDEO_CODEC` | str | `libx264` | output | ffmpeg video codec for saved videos. |
|
||||
| `FASTVIDEO_NVENC_PRESET` | str | `p1` | output | NVENC preset when the codec is an \*_nvenc codec. |
|
||||
| `FASTVIDEO_NVENC_TUNE` | str | `ull` | output | NVENC tune option. |
|
||||
| `FASTVIDEO_NVENC_RC` | str | `constqp` | output | NVENC rate-control mode. |
|
||||
| `FASTVIDEO_NVENC_QP` | str | `28` | output | NVENC quantization parameter. |
|
||||
| `FASTVIDEO_NVENC_BF` | str | `0` | output | NVENC number of B-frames. |
|
||||
| `FASTVIDEO_X264_PRESET` | str | `ultrafast` | output | x264 preset for non-NVENC codecs. |
|
||||
| `FASTVIDEO_OUTPUT_PIX_FMT` | str | `yuv420p` | output | ffmpeg pixel format for saved videos. |
|
||||
| `FASTVIDEO_NVTX_PROFILE` | bool | `0` | profiling | Emit NVTX ranges for external profilers such as Nsight Systems. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_DIR` | path | unset | profiling | Enables the torch profiler and sets the directory for its traces. Must be an absolute path. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_RECORD_SHAPES` | bool | `0` | profiling | Torch profiler records shapes. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_PROFILE_MEMORY` | bool | `0` | profiling | Torch profiler profiles memory. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_STACK` | bool | `0` | profiling | Torch profiler captures stacks. Costs about 1.5x runtime and 1.4x trace size. |
|
||||
| `FASTVIDEO_TORCH_PROFILER_WITH_FLOPS` | bool | `0` | profiling | Torch profiler profiles FLOPs. |
|
||||
| `FASTVIDEO_TORCH_PROFILE_REGIONS` | str | `""` | profiling | Comma-separated profiler regions to record. The torch profiler requires at least one region. |
|
||||
| `FASTVIDEO_TRACE_ACTIVATIONS` | bool | `0` | debug | Enable activation trace hooks. |
|
||||
| `FASTVIDEO_TRACE_LAYERS` | str | `""` | debug | Regex filter for traced module names. Empty means all. |
|
||||
| `FASTVIDEO_TRACE_STATS` | str | `abs_mean,sum` | debug | Comma-separated activation statistics dumped for each output tensor. |
|
||||
| `FASTVIDEO_TRACE_OUTPUT` | str | `/tmp/fv_trace_<pid>.jsonl` | debug | JSONL path for activation traces. The literal <pid> is replaced at runtime. |
|
||||
| `FASTVIDEO_TRACE_STEPS` | str | `""` | debug | Comma-separated denoising step indices. Empty means all. |
|
||||
| `FASTVIDEO_H3_VSA_PROBE` | str | unset | debug | Output directory for the VSA-H3 attention-mass probe, which writes one .pt file per step, layer, and rank. Keeps the model out of regional compile. |
|
||||
| `FASTVIDEO_LTX2_GEMMA_LOG` | str | `""` | debug | Log file for LTX-2 Gemma text-encoder hidden states, used by parity tests. Deprecated names: `LTX2_FASTVIDEO_GEMMA_LOG`. |
|
||||
| `FASTVIDEO_COSMOS25_LOG_KNOBS` | bool | `0` | debug | Log the Cosmos 2.5 latent-preparation conditioning inputs. |
|
||||
| `FASTVIDEO_CFG_GATE_STEP` | float | `1.0` | sampling | CFG gating fraction in [0, 1]. Steps before len(timesteps) \* X run the conditional and unconditional forwards; later steps reuse the cached difference. 1.0 disables gating. |
|
||||
| `FASTVIDEO_LTX2_USE_DISTILLED_SIGMAS` | bool | `1` | sampling | LTX-2 uses the distilled sigma schedule when FastVideoArgs.ltx2_use_distilled_sigmas is also true. Deprecated names: `LTX2_USE_DISTILLED_SIGMAS`. |
|
||||
| `FASTVIDEO_EVAL_CACHE` | path | computed | eval | Cache directory for evaluation models and datasets. Defaults to $FASTVIDEO_CACHE_ROOT/eval. |
|
||||
| `FASTVIDEO_PHYSICS_IQ_BUCKET_URL` | str | `https://storage.googleapis.com/physics-iq-benchmark` | eval | Base URL of the Physics-IQ benchmark bucket. |
|
||||
| `FASTVIDEO_VBENCH_FULL_INFO_JSON` | str | unset | eval | Path to VBench_full_info.json, used instead of the vendored copy. Deprecated names: `VBENCH_FULL_INFO_JSON`. |
|
||||
| `FASTVIDEO_FVD_REF_FEATURES` | str | unset | eval | Cached reference-feature file for the FVD metric. |
|
||||
| `FASTVIDEO_FAD_REF_FEATURES` | str | unset | eval | Cached reference-feature file for the audio Frechet distance metric. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_DATA_DIR` | str | `data/cats` | test | Raw data directory for preprocess_ltx2_overfit.py. Deprecated names: `LTX2_OVERFIT_DATA_DIR`. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_CAPTION_JSON` | str | `videos2caption_1_sample.json` | test | Caption file, relative to the raw data directory. Deprecated names: `LTX2_OVERFIT_CAPTION_JSON`. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_VIDEO_SUBDIR` | str | `video` | test | Video subdirectory, relative to the raw data directory. Deprecated names: `LTX2_OVERFIT_VIDEO_SUBDIR`. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_OUTPUT_DIR` | str | `data/ltx2_overfit_preprocessed` | test | Output directory for preprocess_ltx2_overfit.py. Deprecated names: `LTX2_OVERFIT_OUTPUT_DIR`. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_MODEL` | str | `FastVideo/LTX2-Distilled-Diffusers` | test | Model repository whose encoders preprocess_ltx2_overfit.py uses. Deprecated names: `LTX2_OVERFIT_MODEL`. |
|
||||
| `FASTVIDEO_TEST_LTX2_OVERFIT_NUM_COPIES` | int | `4` | test | Number of copies of the overfit sample in the parquet file. Deprecated names: `LTX2_OVERFIT_NUM_COPIES`. |
|
||||
| `FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR` | str | `data/kandinsky5_overfit` | test | Raw data directory for preprocess_kandinsky5_overfit.py. Deprecated names: `KANDINSKY5_OVERFIT_DATA_DIR`. |
|
||||
| `FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR` | str | `data/kandinsky5_overfit_preprocessed` | test | Output directory for preprocess_kandinsky5_overfit.py. Deprecated names: `KANDINSKY5_OVERFIT_OUTPUT_DIR`. |
|
||||
|
||||
Variables that FastVideo no longer reads; setting one logs a warning:
|
||||
|
||||
| Deprecated variable | Reason |
|
||||
| ----------------------------------------- | ---------------- |
|
||||
| `FASTVIDEO_TARGET_DEVICE` | no code reads it |
|
||||
| `FASTVIDEO_USE_PRECOMPILED` | no code reads it |
|
||||
| `FASTVIDEO_RINGBUFFER_WARNING_INTERVAL` | no code reads it |
|
||||
| `FASTVIDEO_ENGINE_ITERATION_TIMEOUT_S` | no code reads it |
|
||||
| `FASTVIDEO_SERVER_DEV_MODE` | no code reads it |
|
||||
| `FASTVIDEO_TEST_DYNAMO_FULLGRAPH_CAPTURE` | no code reads it |
|
||||
| `FASTVIDEO_TRACE_FUNCTION` | no code reads it |
|
||||
<!-- END GENERATED ENV TABLE -->
|
||||
|
||||
@@ -27,7 +27,7 @@ layout) with:
|
||||
```bash
|
||||
# from the repo root; reads data/kandinsky5_overfit and writes
|
||||
# data/kandinsky5_overfit_preprocessed by default -- override with
|
||||
# KANDINSKY5_OVERFIT_DATA_DIR / KANDINSKY5_OVERFIT_OUTPUT_DIR env vars
|
||||
# FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR / FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR env vars
|
||||
python -m fastvideo.pipelines.preprocess.preprocess_kandinsky5_overfit
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
# (see docs/training/data_preprocess.md;
|
||||
# fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py is a minimal
|
||||
# LTX-2 reference to adapt — set
|
||||
# LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers). Data paths,
|
||||
# FASTVIDEO_TEST_LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers). Data paths,
|
||||
# step counts, and learning rate below are placeholders you must adapt
|
||||
# to your workload.
|
||||
#
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# (see docs/training/data_preprocess.md;
|
||||
# fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py is a minimal
|
||||
# LTX-2 reference to adapt — set
|
||||
# LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers).
|
||||
# FASTVIDEO_TEST_LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers).
|
||||
#
|
||||
# Run:
|
||||
# NUM_GPUS=4 bash examples/train/run.sh \
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#
|
||||
# Preprocess data first (writes data/ltx2_3_overfit_preprocessed):
|
||||
# CUDA_VISIBLE_DEVICES=0 \
|
||||
# LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers \
|
||||
# LTX2_OVERFIT_OUTPUT_DIR=data/ltx2_3_overfit_preprocessed \
|
||||
# FASTVIDEO_TEST_LTX2_OVERFIT_MODEL=FastVideo/LTX-2.3-Distilled-Diffusers \
|
||||
# FASTVIDEO_TEST_LTX2_OVERFIT_OUTPUT_DIR=data/ltx2_3_overfit_preprocessed \
|
||||
# python fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py
|
||||
#
|
||||
# Run:
|
||||
|
||||
@@ -5,6 +5,7 @@ import torch
|
||||
import torch.nn.functional as F
|
||||
from dataclasses import dataclass
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.attention.utils.flash_attn_default import (
|
||||
fa_version,
|
||||
flash_attn_func_compilable,
|
||||
@@ -264,7 +265,7 @@ class FlashAttentionImpl(AttentionImpl):
|
||||
# keeps its previous semantics.
|
||||
nvfp4_fa4 = extra_impl_args.get("nvfp4_fa4")
|
||||
if nvfp4_fa4 is None:
|
||||
nvfp4_fa4 = os.environ.get("FASTVIDEO_NVFP4_FA4", "0") == "1"
|
||||
nvfp4_fa4 = envs.FASTVIDEO_NVFP4_FA4.get()
|
||||
self.nvfp4_fa4 = bool(nvfp4_fa4)
|
||||
if self.nvfp4_fa4:
|
||||
cap = torch.cuda.get_device_capability()
|
||||
|
||||
@@ -23,12 +23,14 @@ import os
|
||||
|
||||
import torch
|
||||
|
||||
import fastvideo.envs as envs
|
||||
|
||||
_FRACS = (0.05, 0.10, 0.125, 0.25, 0.50, 0.75)
|
||||
_TRUE_ROWS = 128 # sampled query rows per layer for the token-true check
|
||||
|
||||
|
||||
def probe_enabled() -> str | None:
|
||||
return os.environ.get("FASTVIDEO_H3_VSA_PROBE") or None
|
||||
return envs.FASTVIDEO_H3_VSA_PROBE.get() or None
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
from functools import wraps
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.attention.selector import backend_name_to_enum, get_attn_backend
|
||||
from fastvideo.distributed.communication_op import (sequence_model_parallel_all_gather,
|
||||
sequence_model_parallel_all_to_all_4D)
|
||||
@@ -23,10 +23,7 @@ def _attention_compile_disabled() -> bool:
|
||||
``torch.compiler.disable``). Set ``FASTVIDEO_DISABLE_ATTENTION_COMPILE=0``
|
||||
to let attention instances constructed under that environment be traced.
|
||||
"""
|
||||
val = os.environ.get("FASTVIDEO_DISABLE_ATTENTION_COMPILE")
|
||||
if val is None:
|
||||
return True
|
||||
return val.strip().lower() not in ("0", "false", "no", "off", "")
|
||||
return envs.FASTVIDEO_DISABLE_ATTENTION_COMPILE.get()
|
||||
|
||||
|
||||
def _attention_compile_explicitly_disabled() -> bool:
|
||||
@@ -35,7 +32,7 @@ def _attention_compile_explicitly_disabled() -> bool:
|
||||
Regional compile can override the historical default for one loaded
|
||||
transformer, but it must still honor an explicit debugging escape hatch.
|
||||
"""
|
||||
return "FASTVIDEO_DISABLE_ATTENTION_COMPILE" in os.environ and _attention_compile_disabled()
|
||||
return envs.FASTVIDEO_DISABLE_ATTENTION_COMPILE.is_set() and _attention_compile_disabled()
|
||||
|
||||
|
||||
def _maybe_compiler_disable(fn):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Adapted from vllm: https://github.com/vllm-project/vllm/blob/v0.7.3/vllm/attention/selector.py
|
||||
|
||||
import os
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from contextvars import ContextVar
|
||||
@@ -15,7 +14,7 @@ import fastvideo.envs as envs
|
||||
from fastvideo.attention.backends.abstract import AttentionBackend
|
||||
from fastvideo.logger import init_logger
|
||||
from fastvideo.platforms import AttentionBackendEnum
|
||||
from fastvideo.utils import STR_BACKEND_ENV_VAR, resolve_obj_by_qualname
|
||||
from fastvideo.utils import resolve_obj_by_qualname
|
||||
|
||||
logger = init_logger(__name__)
|
||||
|
||||
@@ -65,7 +64,7 @@ def get_env_variable_attn_backend() -> AttentionBackendEnum | None:
|
||||
* _Backend enum value if an override is specified
|
||||
* None otherwise
|
||||
'''
|
||||
backend_name = os.environ.get(STR_BACKEND_ENV_VAR)
|
||||
backend_name = envs.FASTVIDEO_ATTENTION_BACKEND.get()
|
||||
return (None if backend_name is None else backend_name_to_enum(backend_name))
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ from examples.inference.basic.mlx_wan_prompt_to_video import (
|
||||
encode_prompt,
|
||||
make_rotary_embeddings,
|
||||
)
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.mlx_runtime.memory import add_memory_limit_args, apply_memory_limits, cleanup_mlx
|
||||
|
||||
# The highest-fidelity cell; used as the default SSIM reference when no external
|
||||
@@ -524,8 +525,8 @@ def _generate_cell(
|
||||
"peak_gib": max(load_peak, denoise_peak) / (1024**3),
|
||||
"quantization": quantization or "none",
|
||||
"compute_dtype": base_dtype,
|
||||
"compile": os.environ.get("FASTVIDEO_MLX_COMPILE", "0") == "1",
|
||||
"fast_norm": os.environ.get("FASTVIDEO_MLX_FAST_NORM", "0") == "1",
|
||||
"compile": envs.FASTVIDEO_MLX_COMPILE.get(),
|
||||
"fast_norm": envs.FASTVIDEO_MLX_FAST_NORM.get(),
|
||||
"mlx_memory_limit_gib": args.mlx_memory_limit_gib,
|
||||
"mlx_cache_limit_gib": args.mlx_cache_limit_gib,
|
||||
"mlx_disable_cache": args.mlx_disable_cache,
|
||||
|
||||
@@ -144,7 +144,7 @@ class HCCLLibrary:
|
||||
"Otherwise, the hccl library might not exist, be corrupted "
|
||||
"or it does not support the current platform %s. "
|
||||
"If you already have the library, please set the "
|
||||
"environment variable HCCL_SO_PATH"
|
||||
"environment variable FASTVIDEO_HCCL_SO_PATH"
|
||||
" to point to the correct hccl library path.", so_file, platform.platform())
|
||||
raise e
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ import torch.distributed
|
||||
import torch.distributed as dist
|
||||
from torch.distributed import Backend, ProcessGroup, ReduceOp
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.distributed.device_communicators.base_device_communicator import (DeviceCommunicatorBase)
|
||||
from fastvideo.distributed.device_communicators.cpu_communicator import (CpuCommunicator)
|
||||
from fastvideo.distributed.utils import StatelessProcessGroup
|
||||
@@ -759,7 +758,7 @@ def init_distributed_environment(
|
||||
if local_rank == -1:
|
||||
# local rank not set, this usually happens in single-node
|
||||
# setting, where we can use rank as local rank
|
||||
local_rank = envs.LOCAL_RANK.get() if distributed_init_method == "env://" else rank
|
||||
local_rank = int(os.environ.get("LOCAL_RANK", "0")) if distributed_init_method == "env://" else rank
|
||||
global _WORLD
|
||||
if _WORLD is None:
|
||||
ranks = list(range(torch.distributed.get_world_size()))
|
||||
@@ -884,9 +883,9 @@ def get_local_torch_device() -> torch.device:
|
||||
"""Return the torch device for the current rank."""
|
||||
from fastvideo.platforms import current_platform
|
||||
if current_platform.is_npu():
|
||||
device = torch.device(f"npu:{envs.LOCAL_RANK.get()}")
|
||||
device = torch.device(f"npu:{int(os.environ.get('LOCAL_RANK', '0'))}")
|
||||
elif current_platform.is_cuda_alike() or current_platform.is_cuda():
|
||||
device = torch.device(f"cuda:{envs.LOCAL_RANK.get()}")
|
||||
device = torch.device(f"cuda:{int(os.environ.get('LOCAL_RANK', '0'))}")
|
||||
else:
|
||||
device = torch.device("mps")
|
||||
return device
|
||||
|
||||
@@ -50,9 +50,9 @@ def worker_main(
|
||||
``VideoGenerator`` construction + generation happens here, not in
|
||||
the parent's event loop.
|
||||
"""
|
||||
import os
|
||||
import fastvideo.envs as envs
|
||||
|
||||
os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id)
|
||||
envs.set_external("CUDA_VISIBLE_DEVICES", str(gpu_id))
|
||||
try:
|
||||
from fastvideo import VideoGenerator
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import torch
|
||||
import torchvision
|
||||
from einops import rearrange
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.api.compat import (
|
||||
REQUEST_BATCH_EXTRA_PASSTHROUGH_FIELDS,
|
||||
expand_request_prompt_batch,
|
||||
@@ -200,7 +201,7 @@ class VideoGenerator:
|
||||
if kwargs.pop("nvfp4_fa4", False):
|
||||
import os
|
||||
os.environ["FASTVIDEO_NVFP4_FA4"] = "1"
|
||||
os.environ.setdefault("CUTE_DSL_ENABLE_TVM_FFI", "1")
|
||||
envs.setdefault_external("CUTE_DSL_ENABLE_TVM_FFI", "1")
|
||||
typed_config = kwargs.pop("config", None)
|
||||
if typed_config is not None:
|
||||
if model_path is not None:
|
||||
@@ -1191,7 +1192,7 @@ class VideoGenerator:
|
||||
sample_rate: int,
|
||||
) -> bool:
|
||||
"""Encode video+audio using ffmpeg via rawvideo stdin + WAV input."""
|
||||
ffmpeg_bin = shutil.which(os.getenv("FASTVIDEO_FFMPEG_BIN", "ffmpeg"))
|
||||
ffmpeg_bin = shutil.which(envs.FASTVIDEO_FFMPEG_BIN.get())
|
||||
if ffmpeg_bin is None:
|
||||
logger.warning("ffmpeg not found; cannot use ffmpeg pipe save.")
|
||||
return False
|
||||
@@ -1201,7 +1202,7 @@ class VideoGenerator:
|
||||
|
||||
height = int(frames[0].shape[0])
|
||||
width = int(frames[0].shape[1])
|
||||
codec = os.getenv("FASTVIDEO_VIDEO_CODEC", "libx264")
|
||||
codec = envs.FASTVIDEO_VIDEO_CODEC.get()
|
||||
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
@@ -1236,23 +1237,23 @@ class VideoGenerator:
|
||||
|
||||
if codec.endswith("_nvenc"):
|
||||
nvenc_options = [
|
||||
("preset", os.getenv("FASTVIDEO_NVENC_PRESET", "p1")),
|
||||
("tune", os.getenv("FASTVIDEO_NVENC_TUNE", "ull")),
|
||||
("rc", os.getenv("FASTVIDEO_NVENC_RC", "constqp")),
|
||||
("qp", os.getenv("FASTVIDEO_NVENC_QP", "28")),
|
||||
("bf", os.getenv("FASTVIDEO_NVENC_BF", "0")),
|
||||
("preset", envs.FASTVIDEO_NVENC_PRESET.get()),
|
||||
("tune", envs.FASTVIDEO_NVENC_TUNE.get()),
|
||||
("rc", envs.FASTVIDEO_NVENC_RC.get()),
|
||||
("qp", envs.FASTVIDEO_NVENC_QP.get()),
|
||||
("bf", envs.FASTVIDEO_NVENC_BF.get()),
|
||||
]
|
||||
for option_name, option_value in nvenc_options:
|
||||
if cls._ffmpeg_encoder_supports_option(ffmpeg_bin, codec, option_name):
|
||||
cmd += [f"-{option_name}", option_value]
|
||||
else:
|
||||
cmd += ["-preset", os.getenv("FASTVIDEO_X264_PRESET", "ultrafast")]
|
||||
cmd += ["-preset", envs.FASTVIDEO_X264_PRESET.get()]
|
||||
|
||||
cmd += [
|
||||
"-c:a",
|
||||
"aac",
|
||||
"-pix_fmt",
|
||||
os.getenv("FASTVIDEO_OUTPUT_PIX_FMT", "yuv420p"),
|
||||
envs.FASTVIDEO_OUTPUT_PIX_FMT.get(),
|
||||
# Audio and video decoders may produce different durations.
|
||||
# Preserve every video frame and pad/trim audio to match.
|
||||
"-af",
|
||||
|
||||
+219
-55
@@ -12,6 +12,7 @@ The policy for environment variables is in ``docs/contributing/env_vars.md``,
|
||||
and ``fastvideo/tests/contract/test_env_policy.py`` enforces it.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import Callable, Iterator
|
||||
from contextlib import contextmanager
|
||||
@@ -24,12 +25,23 @@ S = TypeVar("S", str, str | None)
|
||||
POLICY_DOC = "docs/contributing/env_vars.md"
|
||||
|
||||
# Allowed values of EnvField.category.
|
||||
CATEGORIES = ("build", "path", "distributed", "external", "logging", "attention", "performance", "profiling", "debug",
|
||||
"sampling")
|
||||
CATEGORIES = ("path", "distributed", "logging", "attention", "performance", "output", "profiling", "debug", "sampling",
|
||||
"eval", "test")
|
||||
|
||||
_TRUE_VALUES = frozenset({"1", "true", "yes", "on"})
|
||||
_FALSE_VALUES = frozenset({"0", "false", "no", "off", ""})
|
||||
|
||||
# fastvideo.logger imports this module, so warnings go through the standard
|
||||
# logging module; the "fastvideo" logger configuration still applies.
|
||||
_logger = logging.getLogger(__name__)
|
||||
_warned_messages: set[str] = set()
|
||||
|
||||
|
||||
def _warn_once(message: str) -> None:
|
||||
if message not in _warned_messages:
|
||||
_warned_messages.add(message)
|
||||
_logger.warning(message)
|
||||
|
||||
|
||||
class EnvVarError(ValueError):
|
||||
"""An environment variable holds a value that its registered type rejects."""
|
||||
@@ -39,16 +51,20 @@ class EnvField(Generic[T]):
|
||||
"""One registered environment variable: its type, default, category, and description.
|
||||
|
||||
``default`` is either the value itself or a zero-argument function that
|
||||
computes it on each read while the variable is unset.
|
||||
computes it on each read while the variable is unset. ``deprecated_names``
|
||||
lists earlier names of a renamed variable; they are read, with a warning,
|
||||
only when the variable itself is unset.
|
||||
"""
|
||||
|
||||
type_name = ""
|
||||
|
||||
def __init__(self, default: T | Callable[[], T], *, category: str, doc: str) -> None:
|
||||
def __init__(self, default: T | Callable[[], T], *, category: str, doc: str,
|
||||
deprecated_names: tuple[str, ...] = ()) -> None:
|
||||
self.name = "" # Set by _register_fields() from the module attribute name.
|
||||
self.default = default
|
||||
self.category = category
|
||||
self.doc = doc
|
||||
self.deprecated_names = deprecated_names
|
||||
|
||||
def parse(self, raw: str) -> T:
|
||||
raise NotImplementedError
|
||||
@@ -56,40 +72,55 @@ class EnvField(Generic[T]):
|
||||
def format(self, value: T) -> str:
|
||||
return str(value)
|
||||
|
||||
def _read_raw(self) -> tuple[str, str] | None:
|
||||
"""Return (name, raw value) from the variable or its first set deprecated name."""
|
||||
raw = os.environ.get(self.name)
|
||||
if raw is not None:
|
||||
return self.name, raw
|
||||
for old_name in self.deprecated_names:
|
||||
raw = os.environ.get(old_name)
|
||||
if raw is not None:
|
||||
_warn_once(f"{old_name} is deprecated and will be removed in the next minor release; "
|
||||
f"set {self.name} instead.")
|
||||
return old_name, raw
|
||||
return None
|
||||
|
||||
def get(self) -> T:
|
||||
"""Return the parsed value, or the default when the variable is unset."""
|
||||
raw = os.environ.get(self.name)
|
||||
if raw is None:
|
||||
found = self._read_raw()
|
||||
if found is None:
|
||||
return self.default() if callable(self.default) else self.default
|
||||
name, raw = found
|
||||
try:
|
||||
return self.parse(raw)
|
||||
except ValueError as exc:
|
||||
raise EnvVarError(f"Invalid value {raw!r} for {self.name}: {exc}. See {POLICY_DOC}.") from None
|
||||
raise EnvVarError(f"Invalid value {raw!r} for {name}: {exc}. See {POLICY_DOC}.") from None
|
||||
|
||||
def is_set(self) -> bool:
|
||||
return self.name in os.environ
|
||||
return any(name in os.environ for name in (self.name, *self.deprecated_names))
|
||||
|
||||
def set(self, value: T) -> None:
|
||||
os.environ[self.name] = self.format(value)
|
||||
|
||||
def clear(self) -> None:
|
||||
os.environ.pop(self.name, None)
|
||||
for name in (self.name, *self.deprecated_names):
|
||||
os.environ.pop(name, None)
|
||||
|
||||
@contextmanager
|
||||
def override(self, value: T | None) -> Iterator[None]:
|
||||
"""Set the variable, or unset it when ``value`` is None, and restore the previous value on exit."""
|
||||
previous = os.environ.get(self.name)
|
||||
if value is None:
|
||||
self.clear()
|
||||
else:
|
||||
"""Set the variable, or unset it when ``value`` is None, and restore the previous values on exit."""
|
||||
previous = {name: os.environ.get(name) for name in (self.name, *self.deprecated_names)}
|
||||
self.clear()
|
||||
if value is not None:
|
||||
self.set(value)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if previous is None:
|
||||
self.clear()
|
||||
else:
|
||||
os.environ[self.name] = previous
|
||||
for name, old_value in previous.items():
|
||||
if old_value is None:
|
||||
os.environ.pop(name, None)
|
||||
else:
|
||||
os.environ[name] = old_value
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
raise TypeError(f"Use envs.{self.name}.get() to read {self.name}.")
|
||||
@@ -171,20 +202,25 @@ def get_default_config_root() -> str:
|
||||
)
|
||||
|
||||
|
||||
# ================== Installation ==================
|
||||
# Variables that other tools read (CUDA, NCCL, PyTorch, launchers) are written
|
||||
# only through these helpers. The contract test checks each name against its
|
||||
# write allowlist.
|
||||
|
||||
|
||||
def set_external(name: str, value: str) -> None:
|
||||
"""Set an environment variable that another tool reads."""
|
||||
os.environ[name] = value
|
||||
|
||||
|
||||
def setdefault_external(name: str, value: str) -> None:
|
||||
"""Set an environment variable that another tool reads, unless it is already set."""
|
||||
os.environ.setdefault(name, value)
|
||||
|
||||
|
||||
def unset_external(name: str) -> None:
|
||||
"""Remove an environment variable that another tool reads."""
|
||||
os.environ.pop(name, None)
|
||||
|
||||
FASTVIDEO_TARGET_DEVICE = EnvStr("cuda",
|
||||
category="build",
|
||||
doc="Target device of FastVideo: cuda, rocm, neuron, cpu, or openvino.")
|
||||
MAX_JOBS = EnvStr(None,
|
||||
category="build",
|
||||
doc="Maximum number of parallel compilation jobs. Defaults to the number of CPUs.")
|
||||
NVCC_THREADS = EnvStr(None,
|
||||
category="build",
|
||||
doc="Number of nvcc threads. When set, MAX_JOBS is reduced to avoid oversubscribing the CPU.")
|
||||
FASTVIDEO_USE_PRECOMPILED = EnvBool(False, category="build", doc="Use precompiled binaries (*.so).")
|
||||
CMAKE_BUILD_TYPE = EnvStr(None, category="build", doc="CMake build type: Debug, Release, or RelWithDebInfo.")
|
||||
VERBOSE = EnvBool(False, category="build", doc="Print verbose logs during installation.")
|
||||
|
||||
# ================== Paths ==================
|
||||
|
||||
@@ -198,6 +234,10 @@ FASTVIDEO_CACHE_ROOT = EnvPath(
|
||||
category="path",
|
||||
doc="Root directory for FastVideo cache files. "
|
||||
"Defaults to ~/.cache/fastvideo, or $XDG_CACHE_HOME/fastvideo when XDG_CACHE_HOME is set.")
|
||||
FASTVIDEO_REASON1_WEIGHTS_PATH = EnvStr(None,
|
||||
category="path",
|
||||
doc="Local path or Hugging Face id of Reason1 weights to load instead of the "
|
||||
"checkpoint's own.")
|
||||
|
||||
# ================== Distributed ==================
|
||||
|
||||
@@ -214,18 +254,15 @@ FASTVIDEO_RAY_PER_WORKER_GPUS = EnvFloat(
|
||||
category="distributed",
|
||||
doc="GPUs per Ray worker. A fraction lets Ray schedule several actors on one GPU, so other actors can share "
|
||||
"the GPUs with FastVideo.")
|
||||
FASTVIDEO_RINGBUFFER_WARNING_INTERVAL = EnvInt(60,
|
||||
category="distributed",
|
||||
doc="Seconds between warnings while the ring buffer is full.")
|
||||
FASTVIDEO_NCCL_SO_PATH = EnvStr(
|
||||
None,
|
||||
category="distributed",
|
||||
doc="Path to the NCCL library file. Needed because the nccl>=2.19 that PyTorch ships has a bug "
|
||||
"(https://github.com/NVIDIA/nccl/issues/1234).")
|
||||
HCCL_SO_PATH = EnvStr(None, category="distributed", doc="Path to the HCCL library file on Ascend NPUs.")
|
||||
FASTVIDEO_ENGINE_ITERATION_TIMEOUT_S = EnvInt(60,
|
||||
category="distributed",
|
||||
doc="Timeout in seconds for each engine iteration.")
|
||||
FASTVIDEO_HCCL_SO_PATH = EnvStr(None,
|
||||
category="distributed",
|
||||
doc="Path to the HCCL library file on Ascend NPUs.",
|
||||
deprecated_names=("HCCL_SO_PATH", ))
|
||||
FASTVIDEO_WORKER_MULTIPROC_METHOD = EnvChoice("spawn",
|
||||
choices=("spawn", "fork", "forkserver"),
|
||||
category="distributed",
|
||||
@@ -238,18 +275,6 @@ FASTVIDEO_ULYSSES_A2A = EnvChoice(
|
||||
"the fused NVLink kernel when the group is a load-store accessible mesh of 2, 4, 6, or 8 ranks in eager "
|
||||
"execution, and the NCCL path otherwise.")
|
||||
|
||||
# ================== External variables ==================
|
||||
# Variables that other tools set. They stay registered so that Ray copies them
|
||||
# to its workers until the external-variable allowlist replaces them.
|
||||
|
||||
LD_LIBRARY_PATH = EnvStr(None,
|
||||
category="external",
|
||||
doc="Searched for the NCCL library when FASTVIDEO_NCCL_SO_PATH is unset.")
|
||||
LOCAL_RANK = EnvInt(0,
|
||||
category="external",
|
||||
doc="Local rank of the process in a distributed run; selects the GPU device id.")
|
||||
CUDA_VISIBLE_DEVICES = EnvStr(None, category="external", doc="Visible devices in a distributed run.")
|
||||
|
||||
# ================== Logging ==================
|
||||
|
||||
FASTVIDEO_CONFIGURE_LOGGING = EnvBool(
|
||||
@@ -285,6 +310,22 @@ FASTVIDEO_VSA_SM100A = EnvBool(
|
||||
category="attention",
|
||||
doc="VIDEO_SPARSE_ATTN_H3 sends no-grad tile-64 forwards to the data-center Blackwell (sm_100a) kernel. "
|
||||
"fastvideo-kernel reads the same variable with the same rule.")
|
||||
FASTVIDEO_NVFP4_FA4 = EnvBool(
|
||||
False,
|
||||
category="attention",
|
||||
doc="FlashAttention-4 quantizes Q and K to NVFP4. An explicit nvfp4_fa4 attention implementation argument "
|
||||
"takes precedence.")
|
||||
FASTVIDEO_DISABLE_ATTENTION_COMPILE = EnvBool(
|
||||
True,
|
||||
category="attention",
|
||||
doc="Keep attention forward out of torch.compile graphs (torch.compiler.disable). Set it to 0 to let attention "
|
||||
"constructed under that setting be traced. Setting it explicitly to true also blocks regional compile.")
|
||||
FASTVIDEO_MLX_WINDOW = EnvInt(0,
|
||||
category="attention",
|
||||
doc="MLX FastWan windowed attention size in tokens. 0 uses full attention.")
|
||||
FASTVIDEO_MLX_WINDOW_SINK = EnvInt(0,
|
||||
category="attention",
|
||||
doc="Number of sink tokens that MLX windowed attention always attends to.")
|
||||
|
||||
# ================== Performance ==================
|
||||
|
||||
@@ -316,7 +357,44 @@ FASTVIDEO_MINIMAX_H3_FUSIONS = EnvStr(
|
||||
category="performance",
|
||||
doc="MiniMax-H3 inference-only Triton fusions: all, 1, or a comma-separated subset of "
|
||||
"modulate,qknorm_rope,swiglu. Empty, 0, or none keeps the eager implementation.")
|
||||
FASTVIDEO_TEST_DYNAMO_FULLGRAPH_CAPTURE = EnvBool(True, category="debug", doc="Enable Dynamo fullgraph capture.")
|
||||
FASTVIDEO_FSDP2_AUTOWRAP = EnvBool(False,
|
||||
category="performance",
|
||||
doc="FSDP2 shards modules by parameter count instead of the model's shard "
|
||||
"conditions. Not supported by self-forcing distillation.")
|
||||
FASTVIDEO_FSDP2_MIN_PARAMS = EnvInt(10000000,
|
||||
category="performance",
|
||||
doc="Minimum parameter count of a module that FASTVIDEO_FSDP2_AUTOWRAP shards.")
|
||||
FASTVIDEO_MLX_COMPILE = EnvBool(False, category="performance", doc="Compile the MLX DiT forward with mx.compile.")
|
||||
FASTVIDEO_MLX_FAST_NORM = EnvBool(False, category="performance", doc="Use MLX fast normalization kernels.")
|
||||
FASTVIDEO_MLX_DQ_GEMM = EnvStr(
|
||||
"1",
|
||||
category="performance",
|
||||
doc="MLX dequantized GEMM for affine-quantized weights: 0 turns it off, 1 uses the measured minimum row count, "
|
||||
"and an integer sets the minimum row count.")
|
||||
FASTVIDEO_LTX2_VAE_CHANNELS_LAST_3D = EnvBool(True,
|
||||
category="performance",
|
||||
doc="LTX-2 VAE uses the channels_last_3d memory format.")
|
||||
FASTVIDEO_LTX2_DISABLE_AUDIO_AUTOCAST = EnvBool(True,
|
||||
category="performance",
|
||||
doc="LTX-2 audio decoding runs without CUDA autocast.",
|
||||
deprecated_names=("LTX2_DISABLE_AUDIO_AUTOCAST", ))
|
||||
FASTVIDEO_FLUX2_DISABLE_BF16_REDUCED_PRECISION_REDUCTION = EnvBool(
|
||||
False,
|
||||
category="performance",
|
||||
doc="Flux denoising disables reduced-precision reductions in bf16 matmuls, which tightens accumulation for "
|
||||
"the 4-step Klein model.")
|
||||
|
||||
# ================== Output encoding ==================
|
||||
|
||||
FASTVIDEO_FFMPEG_BIN = EnvStr("ffmpeg", category="output", doc="ffmpeg executable used to save video with audio.")
|
||||
FASTVIDEO_VIDEO_CODEC = EnvStr("libx264", category="output", doc="ffmpeg video codec for saved videos.")
|
||||
FASTVIDEO_NVENC_PRESET = EnvStr("p1", category="output", doc="NVENC preset when the codec is an *_nvenc codec.")
|
||||
FASTVIDEO_NVENC_TUNE = EnvStr("ull", category="output", doc="NVENC tune option.")
|
||||
FASTVIDEO_NVENC_RC = EnvStr("constqp", category="output", doc="NVENC rate-control mode.")
|
||||
FASTVIDEO_NVENC_QP = EnvStr("28", category="output", doc="NVENC quantization parameter.")
|
||||
FASTVIDEO_NVENC_BF = EnvStr("0", category="output", doc="NVENC number of B-frames.")
|
||||
FASTVIDEO_X264_PRESET = EnvStr("ultrafast", category="output", doc="x264 preset for non-NVENC codecs.")
|
||||
FASTVIDEO_OUTPUT_PIX_FMT = EnvStr("yuv420p", category="output", doc="ffmpeg pixel format for saved videos.")
|
||||
|
||||
# ================== Profiling ==================
|
||||
|
||||
@@ -341,10 +419,6 @@ FASTVIDEO_TORCH_PROFILE_REGIONS = EnvStr(
|
||||
|
||||
# ================== Debug ==================
|
||||
|
||||
FASTVIDEO_SERVER_DEV_MODE = EnvBool(False,
|
||||
category="debug",
|
||||
doc="Run the server in development mode with extra debugging endpoints.")
|
||||
FASTVIDEO_TRACE_FUNCTION = EnvBool(False, category="debug", doc="Trace function calls.")
|
||||
FASTVIDEO_TRACE_ACTIVATIONS = EnvBool(False, category="debug", doc="Enable activation trace hooks.")
|
||||
FASTVIDEO_TRACE_LAYERS = EnvStr("", category="debug", doc="Regex filter for traced module names. Empty means all.")
|
||||
FASTVIDEO_TRACE_STATS = EnvStr("abs_mean,sum",
|
||||
@@ -354,6 +428,18 @@ FASTVIDEO_TRACE_OUTPUT = EnvStr("/tmp/fv_trace_<pid>.jsonl",
|
||||
category="debug",
|
||||
doc="JSONL path for activation traces. The literal <pid> is replaced at runtime.")
|
||||
FASTVIDEO_TRACE_STEPS = EnvStr("", category="debug", doc="Comma-separated denoising step indices. Empty means all.")
|
||||
FASTVIDEO_H3_VSA_PROBE = EnvStr(
|
||||
None,
|
||||
category="debug",
|
||||
doc="Output directory for the VSA-H3 attention-mass probe, which writes one .pt file per step, layer, and rank. "
|
||||
"Keeps the model out of regional compile.")
|
||||
FASTVIDEO_LTX2_GEMMA_LOG = EnvStr("",
|
||||
category="debug",
|
||||
doc="Log file for LTX-2 Gemma text-encoder hidden states, used by parity tests.",
|
||||
deprecated_names=("LTX2_FASTVIDEO_GEMMA_LOG", ))
|
||||
FASTVIDEO_COSMOS25_LOG_KNOBS = EnvBool(False,
|
||||
category="debug",
|
||||
doc="Log the Cosmos 2.5 latent-preparation conditioning inputs.")
|
||||
|
||||
# ================== Sampling ==================
|
||||
|
||||
@@ -385,6 +471,84 @@ FASTVIDEO_CFG_GATE_STEP = EnvFloat(
|
||||
category="sampling",
|
||||
doc="CFG gating fraction in [0, 1]. Steps before len(timesteps) * X run the conditional and unconditional "
|
||||
"forwards; later steps reuse the cached difference. 1.0 disables gating.")
|
||||
FASTVIDEO_LTX2_USE_DISTILLED_SIGMAS = EnvBool(
|
||||
True,
|
||||
category="sampling",
|
||||
doc="LTX-2 uses the distilled sigma schedule when FastVideoArgs.ltx2_use_distilled_sigmas is also true.",
|
||||
deprecated_names=("LTX2_USE_DISTILLED_SIGMAS", ))
|
||||
|
||||
# ================== Evaluation ==================
|
||||
|
||||
FASTVIDEO_EVAL_CACHE = EnvPath(lambda: os.path.join(FASTVIDEO_CACHE_ROOT.get(), "eval"),
|
||||
category="eval",
|
||||
doc="Cache directory for evaluation models and datasets. Defaults to "
|
||||
"$FASTVIDEO_CACHE_ROOT/eval.")
|
||||
FASTVIDEO_PHYSICS_IQ_BUCKET_URL = EnvStr("https://storage.googleapis.com/physics-iq-benchmark",
|
||||
category="eval",
|
||||
doc="Base URL of the Physics-IQ benchmark bucket.")
|
||||
FASTVIDEO_VBENCH_FULL_INFO_JSON = EnvStr(None,
|
||||
category="eval",
|
||||
doc="Path to VBench_full_info.json, used instead of the vendored copy.",
|
||||
deprecated_names=("VBENCH_FULL_INFO_JSON", ))
|
||||
FASTVIDEO_FVD_REF_FEATURES = EnvStr(None, category="eval", doc="Cached reference-feature file for the FVD metric.")
|
||||
FASTVIDEO_FAD_REF_FEATURES = EnvStr(None,
|
||||
category="eval",
|
||||
doc="Cached reference-feature file for the audio Frechet distance metric.")
|
||||
|
||||
# ================== Tests ==================
|
||||
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_DATA_DIR = EnvStr("data/cats",
|
||||
category="test",
|
||||
doc="Raw data directory for preprocess_ltx2_overfit.py.",
|
||||
deprecated_names=("LTX2_OVERFIT_DATA_DIR", ))
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_CAPTION_JSON = EnvStr("videos2caption_1_sample.json",
|
||||
category="test",
|
||||
doc="Caption file, relative to the raw data directory.",
|
||||
deprecated_names=("LTX2_OVERFIT_CAPTION_JSON", ))
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_VIDEO_SUBDIR = EnvStr("video",
|
||||
category="test",
|
||||
doc="Video subdirectory, relative to the raw data directory.",
|
||||
deprecated_names=("LTX2_OVERFIT_VIDEO_SUBDIR", ))
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_OUTPUT_DIR = EnvStr("data/ltx2_overfit_preprocessed",
|
||||
category="test",
|
||||
doc="Output directory for preprocess_ltx2_overfit.py.",
|
||||
deprecated_names=("LTX2_OVERFIT_OUTPUT_DIR", ))
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_MODEL = EnvStr("FastVideo/LTX2-Distilled-Diffusers",
|
||||
category="test",
|
||||
doc="Model repository whose encoders preprocess_ltx2_overfit.py uses.",
|
||||
deprecated_names=("LTX2_OVERFIT_MODEL", ))
|
||||
FASTVIDEO_TEST_LTX2_OVERFIT_NUM_COPIES = EnvInt(4,
|
||||
category="test",
|
||||
doc="Number of copies of the overfit sample in the parquet file.",
|
||||
deprecated_names=("LTX2_OVERFIT_NUM_COPIES", ))
|
||||
FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR = EnvStr("data/kandinsky5_overfit",
|
||||
category="test",
|
||||
doc="Raw data directory for preprocess_kandinsky5_overfit.py.",
|
||||
deprecated_names=("KANDINSKY5_OVERFIT_DATA_DIR", ))
|
||||
FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR = EnvStr("data/kandinsky5_overfit_preprocessed",
|
||||
category="test",
|
||||
doc="Output directory for preprocess_kandinsky5_overfit.py.",
|
||||
deprecated_names=("KANDINSKY5_OVERFIT_OUTPUT_DIR", ))
|
||||
|
||||
# Variables that FastVideo no longer reads. Setting one logs a warning; delete
|
||||
# the entries in the next minor release.
|
||||
DEPRECATED_VARIABLES = {
|
||||
"FASTVIDEO_TARGET_DEVICE": "no code reads it",
|
||||
"FASTVIDEO_USE_PRECOMPILED": "no code reads it",
|
||||
"FASTVIDEO_RINGBUFFER_WARNING_INTERVAL": "no code reads it",
|
||||
"FASTVIDEO_ENGINE_ITERATION_TIMEOUT_S": "no code reads it",
|
||||
"FASTVIDEO_SERVER_DEV_MODE": "no code reads it",
|
||||
"FASTVIDEO_TEST_DYNAMO_FULLGRAPH_CAPTURE": "no code reads it",
|
||||
"FASTVIDEO_TRACE_FUNCTION": "no code reads it",
|
||||
}
|
||||
|
||||
|
||||
def warn_deprecated_variables() -> None:
|
||||
"""Log a warning for each variable in DEPRECATED_VARIABLES that is set."""
|
||||
for name, reason in DEPRECATED_VARIABLES.items():
|
||||
if name in os.environ:
|
||||
_warn_once(f"{name} is deprecated and has no effect ({reason}); it will be removed in the next minor "
|
||||
"release.")
|
||||
|
||||
|
||||
def _register_fields() -> dict[str, EnvField]:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.models import ensure_checkpoint, get_cache_dir
|
||||
|
||||
|
||||
@@ -14,9 +15,8 @@ def _redirect_third_party_caches() -> None:
|
||||
env vars at all; their callsites in metric.py files pass
|
||||
``download_root=str(get_cache_dir() / "<library>")`` directly.
|
||||
"""
|
||||
import os
|
||||
root = get_cache_dir()
|
||||
os.environ.setdefault("TORCH_HOME", str(root / "torch"))
|
||||
envs.setdefault_external("TORCH_HOME", str(root / "torch"))
|
||||
|
||||
|
||||
_redirect_third_party_caches()
|
||||
|
||||
@@ -27,7 +27,6 @@ pre-downloaded copy) to opt out of network fetches.
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from urllib.request import urlretrieve
|
||||
@@ -35,6 +34,7 @@ from urllib.request import urlretrieve
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.datasets.base import PromptDataset
|
||||
from fastvideo.eval.datasets.registry import register_dataset
|
||||
from fastvideo.eval.models import get_cache_dir
|
||||
@@ -59,11 +59,10 @@ _VENDORED_DESCRIPTIONS_CSV = (Path(__file__).resolve().parent.parent / "metrics"
|
||||
|
||||
# Public DeepMind bucket; HTTPS-readable, no auth. Override via
|
||||
# ``FASTVIDEO_PHYSICS_IQ_BUCKET_URL`` (e.g. for an internal mirror).
|
||||
_DEFAULT_BUCKET_URL = "https://storage.googleapis.com/physics-iq-benchmark"
|
||||
|
||||
|
||||
def _bucket_url() -> str:
|
||||
return os.environ.get("FASTVIDEO_PHYSICS_IQ_BUCKET_URL", _DEFAULT_BUCKET_URL)
|
||||
return envs.FASTVIDEO_PHYSICS_IQ_BUCKET_URL.get()
|
||||
|
||||
|
||||
def _default_dataset_root() -> Path:
|
||||
|
||||
@@ -7,9 +7,9 @@ keyed by dimension).
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.datasets.base import PromptDataset
|
||||
from fastvideo.eval.datasets.registry import register_dataset
|
||||
|
||||
@@ -23,12 +23,12 @@ _FULL_INFO_REL = "fastvideo/third_party/eval/vbench/vbench/VBench_full_info.json
|
||||
|
||||
|
||||
def _locate_full_info() -> Path:
|
||||
env = os.environ.get("VBENCH_FULL_INFO_JSON")
|
||||
env = envs.FASTVIDEO_VBENCH_FULL_INFO_JSON.get()
|
||||
if env:
|
||||
p = Path(env)
|
||||
if p.is_file():
|
||||
return p
|
||||
raise FileNotFoundError(f"VBENCH_FULL_INFO_JSON={env} does not point at a file")
|
||||
raise FileNotFoundError(f"FASTVIDEO_VBENCH_FULL_INFO_JSON={env} does not point at a file")
|
||||
here = Path(__file__).resolve()
|
||||
for ancestor in here.parents:
|
||||
candidate = ancestor / _FULL_INFO_REL
|
||||
@@ -38,7 +38,7 @@ def _locate_full_info() -> Path:
|
||||
break
|
||||
raise FileNotFoundError("Could not locate VBench_full_info.json. Initialize the upstream "
|
||||
"submodule (`git submodule update --init "
|
||||
"fastvideo/third_party/eval/vbench`) or set VBENCH_FULL_INFO_JSON.")
|
||||
"fastvideo/third_party/eval/vbench`) or set FASTVIDEO_VBENCH_FULL_INFO_JSON.")
|
||||
|
||||
|
||||
@register_dataset("vbench")
|
||||
|
||||
@@ -11,7 +11,6 @@ two finite embeddings.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -19,6 +18,7 @@ import numpy as np
|
||||
import torch
|
||||
from scipy import linalg
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.metrics.base import BaseMetric
|
||||
from fastvideo.eval.registry import register
|
||||
from fastvideo.eval.types import MetricResult
|
||||
@@ -94,7 +94,7 @@ class FrechetAudioDistanceMetric(BaseMetric):
|
||||
self._model: Any = None
|
||||
self._gen_buf: list[np.ndarray] = []
|
||||
self._ref_buf: list[np.ndarray] = []
|
||||
self._cached_ref_path: str | None = os.environ.get(REF_FEATURES_ENV)
|
||||
self._cached_ref_path: str | None = envs.FASTVIDEO_FAD_REF_FEATURES.get()
|
||||
self._cached_ref_mu: np.ndarray | None = None
|
||||
self._cached_ref_sigma: np.ndarray | None = None
|
||||
self._n_cached_ref: int = 0
|
||||
|
||||
@@ -75,13 +75,13 @@ import numpy as np
|
||||
import scipy.linalg
|
||||
import torch
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.metrics.base import BaseMetric
|
||||
from fastvideo.eval.metrics.common.fvd.extractors import (_BaseExtractor, available_extractors, load_extractor)
|
||||
from fastvideo.eval.registry import register
|
||||
from fastvideo.eval.types import MetricResult
|
||||
|
||||
_MIN_VIDEOS_WARN = 256 # below this FVD is unreliable
|
||||
_REF_FEATURES_ENV = "FASTVIDEO_FVD_REF_FEATURES"
|
||||
|
||||
|
||||
def _gaussian_params(features: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
||||
@@ -220,7 +220,7 @@ class FVDMetric(BaseMetric):
|
||||
# import. Precedence: kwarg > env-var > default.
|
||||
if self._cache_path_arg is not None:
|
||||
self.cache_path = os.path.expanduser(self._cache_path_arg)
|
||||
elif env_path := os.environ.get(_REF_FEATURES_ENV):
|
||||
elif env_path := envs.FASTVIDEO_FVD_REF_FEATURES.get():
|
||||
self.cache_path = os.path.expanduser(env_path)
|
||||
else:
|
||||
self.cache_path = _default_cache_path(self._extractor_name)
|
||||
|
||||
@@ -110,10 +110,9 @@ def _path_of(sample: dict, key: str) -> str | None:
|
||||
|
||||
|
||||
def _resolve_api_key() -> str:
|
||||
for env in ("GEMINI_API_KEY", "GOOGLE_API_KEY"):
|
||||
key = os.environ.get(env)
|
||||
if key:
|
||||
return key.strip()
|
||||
key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")
|
||||
if key:
|
||||
return key.strip()
|
||||
token = Path("~/.gemini_token").expanduser()
|
||||
if token.is_file():
|
||||
return token.read_text().strip()
|
||||
|
||||
@@ -21,6 +21,7 @@ import tempfile
|
||||
import torch
|
||||
import torchvision.io
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.eval.metrics.base import BaseMetric
|
||||
from fastvideo.eval.registry import register
|
||||
from fastvideo.eval.types import MetricResult
|
||||
@@ -58,7 +59,7 @@ class SceneMetric(BaseMetric):
|
||||
from transformers import Qwen2_5OmniForConditionalGeneration, Qwen2_5OmniProcessor
|
||||
|
||||
# AVoCaDO uses Qwen2.5-Omni — large multimodal model
|
||||
os.environ.setdefault("VIDEO_MAX_PIXELS", str(20070400)) # 512*28*28*50
|
||||
envs.setdefault_external("VIDEO_MAX_PIXELS", str(20070400)) # 512*28*28*50
|
||||
|
||||
self._model = Qwen2_5OmniForConditionalGeneration.from_pretrained(
|
||||
self._model_path,
|
||||
|
||||
@@ -44,10 +44,7 @@ def get_cache_dir() -> Path:
|
||||
``cache_dir``, etc.), pass ``str(get_cache_dir() / "<library>")`` so
|
||||
users get a single ``FASTVIDEO_EVAL_CACHE`` knob to redirect them all.
|
||||
"""
|
||||
return Path(os.environ.get(
|
||||
"FASTVIDEO_EVAL_CACHE",
|
||||
os.path.join(envs.FASTVIDEO_CACHE_ROOT.get(), "eval"),
|
||||
))
|
||||
return Path(envs.FASTVIDEO_EVAL_CACHE.get())
|
||||
|
||||
|
||||
def ensure_checkpoint(
|
||||
|
||||
@@ -361,6 +361,8 @@ class FastVideoArgs:
|
||||
if env_backend is not None and backend_name_to_enum(env_backend) is not None:
|
||||
self.attention_backend = env_backend
|
||||
self._fold_vae_parallel_env()
|
||||
import fastvideo.envs as envs
|
||||
envs.warn_deprecated_variables()
|
||||
self.check_fastvideo_args()
|
||||
|
||||
def _fold_vae_parallel_env(self) -> None:
|
||||
|
||||
+39
-39
@@ -15,11 +15,6 @@ from typing import Any, cast
|
||||
|
||||
import fastvideo.envs as envs
|
||||
|
||||
FASTVIDEO_CONFIGURE_LOGGING = envs.FASTVIDEO_CONFIGURE_LOGGING.get()
|
||||
FASTVIDEO_LOGGING_CONFIG_PATH = envs.FASTVIDEO_LOGGING_CONFIG_PATH.get()
|
||||
FASTVIDEO_LOGGING_LEVEL = envs.FASTVIDEO_LOGGING_LEVEL.get()
|
||||
FASTVIDEO_LOGGING_PREFIX = envs.FASTVIDEO_LOGGING_PREFIX.get()
|
||||
|
||||
RED = '\033[91m'
|
||||
GREEN = '\033[92m'
|
||||
RESET = '\033[0;0m'
|
||||
@@ -27,40 +22,43 @@ RESET = '\033[0;0m'
|
||||
_warned_local_main_process = False
|
||||
_warned_main_process = False
|
||||
|
||||
_FORMAT = (f"{FASTVIDEO_LOGGING_PREFIX}%(levelname)s %(asctime)s.%(msecs)03d "
|
||||
_FORMAT = ("%(levelname)s %(asctime)s.%(msecs)03d "
|
||||
"[%(filename)s:%(lineno)d] %(message)s")
|
||||
_DATE_FORMAT = "%m-%d %H:%M:%S"
|
||||
|
||||
DEFAULT_LOGGING_CONFIG = {
|
||||
"formatters": {
|
||||
"fastvideo": {
|
||||
"class": "fastvideo.logging_utils.NewLineFormatter",
|
||||
"datefmt": _DATE_FORMAT,
|
||||
"format": _FORMAT,
|
||||
|
||||
def _default_logging_config() -> dict[str, Any]:
|
||||
"""Build the default logging configuration from FASTVIDEO_LOGGING_PREFIX and FASTVIDEO_LOGGING_LEVEL."""
|
||||
return {
|
||||
"formatters": {
|
||||
"fastvideo": {
|
||||
"class": "fastvideo.logging_utils.NewLineFormatter",
|
||||
"datefmt": _DATE_FORMAT,
|
||||
"format": envs.FASTVIDEO_LOGGING_PREFIX.get() + _FORMAT,
|
||||
},
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"fastvideo": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "fastvideo",
|
||||
"level": FASTVIDEO_LOGGING_LEVEL,
|
||||
"stream": "ext://sys.stdout",
|
||||
"handlers": {
|
||||
"fastvideo": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "fastvideo",
|
||||
"level": envs.FASTVIDEO_LOGGING_LEVEL.get(),
|
||||
"stream": "ext://sys.stdout",
|
||||
},
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"fastvideo": {
|
||||
"loggers": {
|
||||
"fastvideo": {
|
||||
"handlers": ["fastvideo"],
|
||||
"level": "DEBUG",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["fastvideo"],
|
||||
"level": "DEBUG",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["fastvideo"],
|
||||
"level": "DEBUG",
|
||||
},
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False
|
||||
}
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False
|
||||
}
|
||||
|
||||
|
||||
@lru_cache
|
||||
@@ -180,20 +178,22 @@ class _FastvideoLogger(Logger):
|
||||
|
||||
def _configure_fastvideo_root_logger() -> None:
|
||||
logging_config = dict[str, Any]()
|
||||
configure_logging = envs.FASTVIDEO_CONFIGURE_LOGGING.get()
|
||||
logging_config_path = envs.FASTVIDEO_LOGGING_CONFIG_PATH.get()
|
||||
|
||||
if not FASTVIDEO_CONFIGURE_LOGGING and FASTVIDEO_LOGGING_CONFIG_PATH:
|
||||
if not configure_logging and logging_config_path:
|
||||
raise RuntimeError("FASTVIDEO_CONFIGURE_LOGGING evaluated to false, but "
|
||||
"FASTVIDEO_LOGGING_CONFIG_PATH was given. FASTVIDEO_LOGGING_CONFIG_PATH "
|
||||
"implies FASTVIDEO_CONFIGURE_LOGGING. Please enable "
|
||||
"FASTVIDEO_CONFIGURE_LOGGING or unset FASTVIDEO_LOGGING_CONFIG_PATH.")
|
||||
|
||||
if FASTVIDEO_CONFIGURE_LOGGING:
|
||||
logging_config = DEFAULT_LOGGING_CONFIG
|
||||
if configure_logging:
|
||||
logging_config = _default_logging_config()
|
||||
|
||||
if FASTVIDEO_LOGGING_CONFIG_PATH:
|
||||
if not path.exists(FASTVIDEO_LOGGING_CONFIG_PATH):
|
||||
raise RuntimeError("Could not load logging config. File does not exist: %s", FASTVIDEO_LOGGING_CONFIG_PATH)
|
||||
with open(FASTVIDEO_LOGGING_CONFIG_PATH, encoding="utf-8") as file:
|
||||
if logging_config_path:
|
||||
if not path.exists(logging_config_path):
|
||||
raise RuntimeError("Could not load logging config. File does not exist: %s", logging_config_path)
|
||||
with open(logging_config_path, encoding="utf-8") as file:
|
||||
custom_config = json.loads(file.read())
|
||||
|
||||
if not isinstance(custom_config, dict):
|
||||
@@ -286,7 +286,7 @@ def enable_trace_function_call(log_file_path: str, root_dir: str | None = None):
|
||||
Note that this call is thread-level, any threads calling this function
|
||||
will have the trace enabled. Other threads will not be affected.
|
||||
"""
|
||||
logger.warning("FASTVIDEO_TRACE_FUNCTION is enabled. It will record every"
|
||||
logger.warning("Function-call tracing is enabled. It will record every"
|
||||
" function executed by Python. This will slow down the code. It "
|
||||
"is suggested to be used for debugging hang or crashes only.")
|
||||
logger.info("Trace frame log is saved to %s", log_file_path)
|
||||
|
||||
@@ -6,7 +6,6 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import statistics
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
@@ -14,6 +13,7 @@ from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from collections.abc import Callable
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.logger import init_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -326,7 +326,7 @@ def dq_gemm_engaged() -> int:
|
||||
|
||||
|
||||
def affine_dq_gemm_min_m() -> int | None:
|
||||
raw = os.environ.get("FASTVIDEO_MLX_DQ_GEMM", "1").strip().lower()
|
||||
raw = envs.FASTVIDEO_MLX_DQ_GEMM.get().strip().lower()
|
||||
if raw in {"", "0", "off", "false", "no"}:
|
||||
return None
|
||||
if raw in {"1", "on", "true", "yes"}:
|
||||
@@ -400,9 +400,7 @@ def _use_fast_norm() -> bool:
|
||||
traffic) and benchmark the speedup.
|
||||
H3 uses its own fused RMSNorm default and does not consult this toggle.
|
||||
"""
|
||||
import os
|
||||
|
||||
return os.environ.get("FASTVIDEO_MLX_FAST_NORM", "0") == "1"
|
||||
return envs.FASTVIDEO_MLX_FAST_NORM.get()
|
||||
|
||||
|
||||
def layer_norm(x, weight=None, bias=None, eps: float = 1e-6):
|
||||
@@ -633,12 +631,12 @@ class MLXWanTransformerBlock:
|
||||
k_bh = key.transpose(0, 2, 1, 3)
|
||||
v_bh = value.transpose(0, 2, 1, 3)
|
||||
scale = self.head_dim**-0.5
|
||||
window = int(os.environ.get("FASTVIDEO_MLX_WINDOW", "0") or "0")
|
||||
window = envs.FASTVIDEO_MLX_WINDOW.get()
|
||||
if window > 0:
|
||||
from fastvideo.mlx_runtime.windowed_attention import windowed_attention
|
||||
|
||||
_warn_windowed_attention_once(window)
|
||||
sink = int(os.environ.get("FASTVIDEO_MLX_WINDOW_SINK", "0") or "0")
|
||||
sink = envs.FASTVIDEO_MLX_WINDOW_SINK.get()
|
||||
attn_output = windowed_attention(q_bh, k_bh, v_bh, window=window, sink=sink, scale=scale)
|
||||
else:
|
||||
attn_output = mx.fast.scaled_dot_product_attention(q_bh, k_bh, v_bh, scale=scale)
|
||||
@@ -693,7 +691,6 @@ class MLXWanDiT:
|
||||
*,
|
||||
compile: bool = False,
|
||||
) -> None:
|
||||
import os
|
||||
|
||||
self.weights = weights
|
||||
self.blocks = blocks
|
||||
@@ -711,7 +708,7 @@ class MLXWanDiT:
|
||||
# good mx.compile target. Off by default so the eager path stays the
|
||||
# baseline; enable via constructor or FASTVIDEO_MLX_COMPILE=1 and verify
|
||||
# with the benchmark's SSIM ~= 1.0 check.
|
||||
self._enable_compile = compile or os.environ.get("FASTVIDEO_MLX_COMPILE", "0") == "1"
|
||||
self._enable_compile = compile or envs.FASTVIDEO_MLX_COMPILE.get()
|
||||
self._compiled_forward: Callable[..., Any] | None = None
|
||||
self._compiled_signature: tuple | None = None
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from collections.abc import Callable
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.logger import init_logger
|
||||
from fastvideo.mlx_runtime.fastwan import (
|
||||
MLXWanT2VCrossAttention,
|
||||
@@ -132,7 +133,6 @@ class MLXWan22DiT:
|
||||
*,
|
||||
compile: bool = False,
|
||||
) -> None:
|
||||
import os
|
||||
|
||||
self.weights = weights
|
||||
self.blocks = blocks
|
||||
@@ -144,7 +144,7 @@ class MLXWan22DiT:
|
||||
self.patch_size = tuple(config["patch_size"])
|
||||
self.out_channels = int(config["out_channels"])
|
||||
self.eps = float(config.get("eps", 1e-6))
|
||||
self._enable_compile = compile or os.environ.get("FASTVIDEO_MLX_COMPILE", "0") == "1"
|
||||
self._enable_compile = compile or envs.FASTVIDEO_MLX_COMPILE.get()
|
||||
self._compiled_forward: Callable[..., Any] | None = None
|
||||
self._compiled_signature: tuple | None = None
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import torch
|
||||
from torch import nn
|
||||
from transformers import AutoTokenizer, Gemma3ForConditionalGeneration
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.configs.models.encoders import BaseEncoderOutput, TextEncoderConfig
|
||||
from fastvideo.models.encoders.base import TextEncoder
|
||||
from fastvideo.models.dits.ltx2 import (
|
||||
@@ -27,7 +28,7 @@ import math
|
||||
|
||||
|
||||
def _debug_gemma_log_line(message: str) -> None:
|
||||
log_path = os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", "")
|
||||
log_path = envs.FASTVIDEO_LTX2_GEMMA_LOG.get()
|
||||
if not log_path:
|
||||
return
|
||||
log_dir = os.path.dirname(log_path)
|
||||
@@ -459,7 +460,7 @@ class LTX2GemmaTextEncoderModel(TextEncoder):
|
||||
padding_side: str,
|
||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||
encoded_text_features = torch.stack(hidden_states, dim=-1)
|
||||
if os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", ""):
|
||||
if envs.FASTVIDEO_LTX2_GEMMA_LOG.get():
|
||||
for idx, layer in enumerate(hidden_states):
|
||||
_debug_gemma_log_line(f"fastvideo:gemma_hidden_state_{idx}"
|
||||
f":sum={layer.float().sum().item():.6f}")
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Reason1 (Qwen2.5-VL) text encoder."""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from collections.abc import Iterable
|
||||
|
||||
import torch
|
||||
from transformers import AutoProcessor
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.configs.models.encoders import BaseEncoderOutput, Reason1Config
|
||||
from fastvideo.logger import init_logger
|
||||
from fastvideo.models.encoders.base import TextEncoder
|
||||
@@ -89,7 +89,7 @@ class Reason1TextEncoder(TextEncoder):
|
||||
trust_remote_code=True,
|
||||
)
|
||||
|
||||
weights_override = os.getenv("FASTVIDEO_REASON1_WEIGHTS_PATH")
|
||||
weights_override = envs.FASTVIDEO_REASON1_WEIGHTS_PATH.get()
|
||||
if weights_override:
|
||||
self.secondary_weights = (_WeightsSource(
|
||||
model_or_path=weights_override,
|
||||
|
||||
@@ -21,6 +21,7 @@ import time
|
||||
import torch
|
||||
import torch.distributed as dist
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.distributed.parallel_state import (
|
||||
cleanup_dist_env_and_memory,
|
||||
get_node_group,
|
||||
@@ -121,14 +122,10 @@ def main() -> None:
|
||||
files = resolve_safetensors_files(load_path)
|
||||
|
||||
# Set default env vars for single-GPU standalone mode (no torchrun)
|
||||
if "MASTER_ADDR" not in os.environ:
|
||||
os.environ["MASTER_ADDR"] = "localhost"
|
||||
if "MASTER_PORT" not in os.environ:
|
||||
os.environ["MASTER_PORT"] = "29500"
|
||||
if "RANK" not in os.environ:
|
||||
os.environ["RANK"] = "0"
|
||||
if "WORLD_SIZE" not in os.environ:
|
||||
os.environ["WORLD_SIZE"] = "1"
|
||||
envs.setdefault_external("MASTER_ADDR", "localhost")
|
||||
envs.setdefault_external("MASTER_PORT", "29500")
|
||||
envs.setdefault_external("RANK", "0")
|
||||
envs.setdefault_external("WORLD_SIZE", "1")
|
||||
|
||||
maybe_init_distributed_environment_and_model_parallel(1, 1)
|
||||
rank = dist.get_rank() if dist.is_initialized() else 0
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
# Copyright 2025 The FastVideo Authors.
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import contextlib
|
||||
import re
|
||||
from collections.abc import Callable, Generator
|
||||
@@ -392,7 +391,7 @@ def _regional_compile_unsupported_reason(
|
||||
resolved = getattr(config, "_resolved_attention_backend", None)
|
||||
resolved_name = getattr(resolved, "name", "")
|
||||
if resolved_name == "VIDEO_SPARSE_ATTN_H3":
|
||||
if os.environ.get("FASTVIDEO_H3_VSA_PROBE"):
|
||||
if envs.FASTVIDEO_H3_VSA_PROBE.get():
|
||||
return ("FASTVIDEO_H3_VSA_PROBE records tensors and files from the VSA-H3 attention body, which "
|
||||
"regional fullgraph compile cannot capture; this model stays eager")
|
||||
if not envs.FASTVIDEO_VSA_SM100A.get():
|
||||
@@ -508,7 +507,7 @@ def shard_model(
|
||||
ValueError: If no layer modules were sharded, indicating that no shard_condition was triggered.
|
||||
"""
|
||||
# Check if we should use size-based filtering
|
||||
use_size_filtering = os.environ.get("FASTVIDEO_FSDP2_AUTOWRAP", "0") == "1"
|
||||
use_size_filtering = envs.FASTVIDEO_FSDP2_AUTOWRAP.get()
|
||||
|
||||
if not fsdp_shard_conditions:
|
||||
logger.warning("No FSDP shard conditions provided; nothing will be sharded.")
|
||||
@@ -543,7 +542,7 @@ def shard_model(
|
||||
|
||||
if use_size_filtering:
|
||||
# Size-based filtering mode
|
||||
min_params = int(os.environ.get("FASTVIDEO_FSDP2_MIN_PARAMS", "10000000"))
|
||||
min_params = envs.FASTVIDEO_FSDP2_MIN_PARAMS.get()
|
||||
logger.info("Using size-based filtering with threshold: %.2fM", min_params / 1e6)
|
||||
|
||||
for n, m in reversed(named_modules):
|
||||
|
||||
@@ -7,7 +7,6 @@ from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import math
|
||||
import os
|
||||
from dataclasses import dataclass, replace
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Iterator, List, NamedTuple, Tuple
|
||||
@@ -17,14 +16,10 @@ import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from einops import rearrange
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.models.vaes.common import DiagonalGaussianDistribution
|
||||
|
||||
|
||||
def _is_env_enabled(name: str, default: str = "") -> bool:
|
||||
value = os.getenv(name, default)
|
||||
return value.lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Enums
|
||||
# =============================================================================
|
||||
@@ -1595,7 +1590,7 @@ class LTX2CausalVideoAutoencoder(nn.Module):
|
||||
self._use_tiling: bool = False
|
||||
self._use_channels_last_3d: bool = False
|
||||
|
||||
if _is_env_enabled("FASTVIDEO_LTX2_VAE_CHANNELS_LAST_3D", default="1"):
|
||||
if envs.FASTVIDEO_LTX2_VAE_CHANNELS_LAST_3D.get():
|
||||
self.enable_channels_last_3d()
|
||||
|
||||
def _as_channels_last_3d(self, tensor: torch.Tensor) -> torch.Tensor:
|
||||
|
||||
@@ -5,10 +5,9 @@ Audio decoding stage for LTX-2 pipelines.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
import torch
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.distributed import get_local_torch_device
|
||||
from fastvideo.fastvideo_args import FastVideoArgs
|
||||
from fastvideo.logger import init_logger
|
||||
@@ -55,7 +54,7 @@ class LTX2AudioDecodingStage(PipelineStage):
|
||||
self.vocoder = self.vocoder.to(device)
|
||||
audio_latents = audio_latents.to(device)
|
||||
|
||||
disable_autocast = os.getenv("LTX2_DISABLE_AUDIO_AUTOCAST", "1") == "1"
|
||||
disable_autocast = envs.FASTVIDEO_LTX2_DISABLE_AUDIO_AUTOCAST.get()
|
||||
with torch.no_grad(), torch.autocast(
|
||||
device_type="cuda",
|
||||
dtype=audio_latents.dtype,
|
||||
|
||||
@@ -8,12 +8,12 @@ from __future__ import annotations
|
||||
from contextlib import contextmanager
|
||||
from itertools import combinations
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from tqdm.auto import tqdm
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.attention.backends.video_sparse_attn import (VideoSparseAttentionMetadataBuilder)
|
||||
from fastvideo.attention.selector import component_attention_backend
|
||||
from fastvideo.fastvideo_args import FastVideoArgs
|
||||
@@ -54,7 +54,7 @@ except ImportError:
|
||||
|
||||
@contextmanager
|
||||
def _nvtx_range(name: str):
|
||||
if os.getenv("FASTVIDEO_NVTX_PROFILE", "0") == "1" and torch.cuda.is_available():
|
||||
if envs.FASTVIDEO_NVTX_PROFILE.get() and torch.cuda.is_available():
|
||||
torch.cuda.nvtx.range_push(name)
|
||||
try:
|
||||
yield
|
||||
@@ -245,7 +245,7 @@ class LTX2DenoisingStage(PipelineStage):
|
||||
else:
|
||||
# Use distilled hardcoded schedule (or subsets) when enabled.
|
||||
use_distilled_sigmas = (fastvideo_args.ltx2_use_distilled_sigmas
|
||||
and os.getenv("LTX2_USE_DISTILLED_SIGMAS", "1") == "1")
|
||||
and envs.FASTVIDEO_LTX2_USE_DISTILLED_SIGMAS.get())
|
||||
max_distilled_steps = len(DISTILLED_SIGMA_VALUES) - 1
|
||||
if use_distilled_sigmas and num_inference_steps <= max_distilled_steps:
|
||||
sigmas, distilled_indices = _distilled_subset_sigmas(
|
||||
|
||||
@@ -29,6 +29,7 @@ from typing import Any
|
||||
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.configs.models.encoders.t5gemma import T5GemmaEncoderConfig
|
||||
from fastvideo.configs.models.vaes import OobleckVAEConfig
|
||||
from fastvideo.fastvideo_args import FastVideoArgs
|
||||
@@ -71,7 +72,7 @@ def _ensure_hf_token_env() -> str | None:
|
||||
"""
|
||||
token = resolve_hf_token()
|
||||
if token:
|
||||
os.environ.setdefault("HF_TOKEN", token)
|
||||
envs.setdefault_external("HF_TOKEN", token)
|
||||
return token
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Usage:
|
||||
|
||||
Input/output roots default to ``data/kandinsky5_overfit`` /
|
||||
``data/kandinsky5_overfit_preprocessed`` and can be overridden with the
|
||||
``KANDINSKY5_OVERFIT_DATA_DIR`` / ``KANDINSKY5_OVERFIT_OUTPUT_DIR`` env
|
||||
``FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR`` / ``FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR`` env
|
||||
vars (used by the nightly e2e test to keep its disposable roots separate
|
||||
from a user's real dataset at the defaults).
|
||||
"""
|
||||
@@ -34,9 +34,6 @@ from a user's real dataset at the defaults).
|
||||
import json
|
||||
import os
|
||||
|
||||
os.environ.setdefault("MASTER_ADDR", "localhost")
|
||||
os.environ.setdefault("MASTER_PORT", "29520")
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import pyarrow as pa
|
||||
@@ -44,6 +41,7 @@ import pyarrow.parquet as pq
|
||||
import torch
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.configs.pipelines.base import preprocess_text
|
||||
from fastvideo.configs.pipelines.kandinsky5 import (
|
||||
Kandinsky5T2VConfig,
|
||||
@@ -70,11 +68,6 @@ MAX_WIDTH = 768
|
||||
TRAIN_FPS = 24.0
|
||||
|
||||
MODEL_PATH = "kandinskylab/Kandinsky-5.0-T2V-Lite-sft-5s-Diffusers"
|
||||
# Overridable so automation (e.g. the nightly e2e test) can point at its own
|
||||
# test-owned directories instead of clobbering the documented default paths
|
||||
# a user may have populated with their real dataset.
|
||||
DATA_DIR = os.environ.get("KANDINSKY5_OVERFIT_DATA_DIR", "data/kandinsky5_overfit")
|
||||
OUTPUT_DIR = os.environ.get("KANDINSKY5_OVERFIT_OUTPUT_DIR", "data/kandinsky5_overfit_preprocessed")
|
||||
|
||||
|
||||
def load_video(path: str, num_frames: int, height: int, width: int) -> torch.Tensor:
|
||||
@@ -143,17 +136,25 @@ def main() -> None:
|
||||
# FastVideo's native text-encoder layers (e.g. CLIPAttention's
|
||||
# QKVParallelLinear) are tensor-parallel-aware and assert the TP process
|
||||
# group is initialized, even for a single-process/single-GPU run.
|
||||
envs.setdefault_external("MASTER_ADDR", "localhost")
|
||||
envs.setdefault_external("MASTER_PORT", "29520")
|
||||
maybe_init_distributed_environment_and_model_parallel(1, 1)
|
||||
|
||||
# Overridable so automation (e.g. the nightly e2e test) can point at its own
|
||||
# test-owned directories instead of clobbering the documented default paths
|
||||
# a user may have populated with their real dataset.
|
||||
data_dir = envs.FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR.get()
|
||||
output_dir = envs.FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR.get()
|
||||
|
||||
device = torch.device("cuda:0")
|
||||
model_path = maybe_download_model(MODEL_PATH)
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Load captions. Validate up front (before spending minutes loading the
|
||||
# VAE + two text encoders): an empty/malformed manifest would otherwise
|
||||
# only surface as an IndexError on records[0] at parquet-write time.
|
||||
manifest_path = os.path.join(DATA_DIR, "videos2caption.json")
|
||||
manifest_path = os.path.join(data_dir, "videos2caption.json")
|
||||
with open(manifest_path) as f:
|
||||
caption_data = json.load(f)
|
||||
if not isinstance(caption_data, list) or not caption_data:
|
||||
@@ -212,7 +213,7 @@ def main() -> None:
|
||||
for item in caption_data:
|
||||
video_name = item["path"]
|
||||
caption = get_caption(item)
|
||||
video_path = os.path.join(DATA_DIR, "videos", video_name)
|
||||
video_path = os.path.join(data_dir, "videos", video_name)
|
||||
|
||||
print(f"\nProcessing: {video_name}")
|
||||
print(f" Caption: {caption[:80]}...")
|
||||
@@ -289,7 +290,7 @@ def main() -> None:
|
||||
for k in records[0]},
|
||||
schema=pyarrow_schema_t2v,
|
||||
)
|
||||
output_path = os.path.join(OUTPUT_DIR, "data_00000.parquet")
|
||||
output_path = os.path.join(output_dir, "data_00000.parquet")
|
||||
pq.write_table(table, output_path)
|
||||
print(f"\nWrote {len(records)} records to {output_path}")
|
||||
|
||||
@@ -297,12 +298,12 @@ def main() -> None:
|
||||
# Wrap in "data" key -- ValidationDataset expects field="data".
|
||||
# Use "caption" field -- ValidationDataset aliases it to "prompt".
|
||||
val_prompts = {"data": [{"caption": get_caption(item)} for item in caption_data]}
|
||||
val_path = os.path.join(OUTPUT_DIR, "validation_prompts.json")
|
||||
val_path = os.path.join(output_dir, "validation_prompts.json")
|
||||
with open(val_path, "w") as f:
|
||||
json.dump(val_prompts, f, indent=2)
|
||||
print(f"Wrote validation prompts to {val_path}")
|
||||
|
||||
print("\nDone! Use data_path: " + OUTPUT_DIR + " in training config.")
|
||||
print("\nDone! Use data_path: " + output_dir + " in training config.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -32,6 +32,7 @@ import pyarrow as pa
|
||||
import pyarrow.parquet as pq
|
||||
import torch
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.dataset.dataloader.schema import pyarrow_schema_t2v
|
||||
from fastvideo.utils import maybe_download_model, verify_model_config_and_directory
|
||||
|
||||
@@ -41,25 +42,14 @@ MAX_HEIGHT = 480 # divisible by 32 (spatial compression)
|
||||
MAX_WIDTH = 832
|
||||
TRAIN_FPS = 24.0 # matches the LTX-2 preset fps used at validation
|
||||
|
||||
DATA_DIR = os.environ.get("LTX2_OVERFIT_DATA_DIR", "data/cats")
|
||||
CAPTION_JSON = os.environ.get("LTX2_OVERFIT_CAPTION_JSON", "videos2caption_1_sample.json")
|
||||
VIDEO_SUBDIR = os.environ.get("LTX2_OVERFIT_VIDEO_SUBDIR", "video")
|
||||
OUTPUT_DIR = os.environ.get("LTX2_OVERFIT_OUTPUT_DIR", "data/ltx2_overfit_preprocessed")
|
||||
MODEL_REPO = os.environ.get("LTX2_OVERFIT_MODEL", "FastVideo/LTX2-Distilled-Diffusers")
|
||||
# The train dataloader samples with drop_last=True across data-parallel
|
||||
# groups, so the dataset must hold at least num_sp_groups * batch_size
|
||||
# rows or every rank gets zero batches. Replicate the overfit sample so
|
||||
# a 4-GPU FSDP run still sees one batch per rank.
|
||||
NUM_COPIES = int(os.environ.get("LTX2_OVERFIT_NUM_COPIES", "4"))
|
||||
|
||||
|
||||
def _init_single_process_distributed() -> None:
|
||||
"""FastVideo component loaders expect an initialized distributed env."""
|
||||
os.environ.setdefault("MASTER_ADDR", "127.0.0.1")
|
||||
os.environ.setdefault("MASTER_PORT", "29511")
|
||||
os.environ.setdefault("RANK", "0")
|
||||
os.environ.setdefault("WORLD_SIZE", "1")
|
||||
os.environ.setdefault("LOCAL_RANK", "0")
|
||||
envs.setdefault_external("MASTER_ADDR", "127.0.0.1")
|
||||
envs.setdefault_external("MASTER_PORT", "29511")
|
||||
envs.setdefault_external("RANK", "0")
|
||||
envs.setdefault_external("WORLD_SIZE", "1")
|
||||
envs.setdefault_external("LOCAL_RANK", "0")
|
||||
from fastvideo.distributed import (
|
||||
maybe_init_distributed_environment_and_model_parallel, )
|
||||
maybe_init_distributed_environment_and_model_parallel(1, 1)
|
||||
@@ -106,16 +96,27 @@ def main() -> None:
|
||||
PipelineComponentLoader, )
|
||||
from fastvideo.pipelines.basic.ltx2.pipeline_configs import LTX2T2VConfig
|
||||
|
||||
data_dir = envs.FASTVIDEO_TEST_LTX2_OVERFIT_DATA_DIR.get()
|
||||
caption_json = envs.FASTVIDEO_TEST_LTX2_OVERFIT_CAPTION_JSON.get()
|
||||
video_subdir = envs.FASTVIDEO_TEST_LTX2_OVERFIT_VIDEO_SUBDIR.get()
|
||||
output_dir = envs.FASTVIDEO_TEST_LTX2_OVERFIT_OUTPUT_DIR.get()
|
||||
model_repo = envs.FASTVIDEO_TEST_LTX2_OVERFIT_MODEL.get()
|
||||
# The train dataloader samples with drop_last=True across data-parallel
|
||||
# groups, so the dataset must hold at least num_sp_groups * batch_size
|
||||
# rows or every rank gets zero batches. Replicate the overfit sample so
|
||||
# a 4-GPU FSDP run still sees one batch per rank.
|
||||
num_copies = envs.FASTVIDEO_TEST_LTX2_OVERFIT_NUM_COPIES.get()
|
||||
|
||||
device = torch.device("cuda:0")
|
||||
model_path = maybe_download_model(MODEL_REPO)
|
||||
model_path = maybe_download_model(model_repo)
|
||||
model_index = verify_model_config_and_directory(model_path)
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
# The map-style dataset caches parquet file metadata; a stale cache
|
||||
# next to a regenerated parquet can crash or serve old rows.
|
||||
shutil.rmtree(os.path.join(OUTPUT_DIR, "map_style_cache"), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(output_dir, "map_style_cache"), ignore_errors=True)
|
||||
|
||||
with open(os.path.join(DATA_DIR, CAPTION_JSON)) as f:
|
||||
with open(os.path.join(data_dir, caption_json)) as f:
|
||||
caption_data = json.load(f)
|
||||
|
||||
pipeline_config = LTX2T2VConfig()
|
||||
@@ -163,7 +164,7 @@ def main() -> None:
|
||||
video_name = item["path"]
|
||||
record_id = f"{idx:04d}_{video_name}"
|
||||
caption = item["cap"][0] if isinstance(item["cap"], list) else item["cap"]
|
||||
video_path = os.path.join(DATA_DIR, VIDEO_SUBDIR, video_name)
|
||||
video_path = os.path.join(data_dir, video_subdir, video_name)
|
||||
|
||||
print(f"\nProcessing: {video_name}")
|
||||
print(f" Caption: {caption[:80]}...")
|
||||
@@ -213,7 +214,7 @@ def main() -> None:
|
||||
# Save the preprocessed clip so overfit tests can compare
|
||||
# validation output against the memorization target.
|
||||
import imageio
|
||||
ref_path = os.path.join(OUTPUT_DIR, f"training_sample_{idx}.mp4")
|
||||
ref_path = os.path.join(output_dir, f"training_sample_{idx}.mp4")
|
||||
with imageio.get_writer(ref_path, fps=TRAIN_FPS) as writer:
|
||||
for frame in frames_np:
|
||||
writer.append_data(frame)
|
||||
@@ -223,9 +224,9 @@ def main() -> None:
|
||||
del text_encoder, tokenizer, vae
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
# Write parquet (replicated NUM_COPIES times; see comment at top)
|
||||
# Write parquet (replicated num_copies times; see the comment above num_copies)
|
||||
replicated = []
|
||||
for copy_idx in range(max(1, NUM_COPIES)):
|
||||
for copy_idx in range(max(1, num_copies)):
|
||||
for r in records:
|
||||
row = dict(r)
|
||||
row["id"] = f"{r['id']}_copy{copy_idx}"
|
||||
@@ -235,10 +236,10 @@ def main() -> None:
|
||||
for k in replicated[0]},
|
||||
schema=pyarrow_schema_t2v,
|
||||
)
|
||||
output_path = os.path.join(OUTPUT_DIR, "data_00000.parquet")
|
||||
output_path = os.path.join(output_dir, "data_00000.parquet")
|
||||
pq.write_table(table, output_path)
|
||||
print(f"\nWrote {len(replicated)} records "
|
||||
f"({len(records)} unique x {max(1, NUM_COPIES)} copies) to {output_path}")
|
||||
f"({len(records)} unique x {max(1, num_copies)} copies) to {output_path}")
|
||||
|
||||
# Write validation prompts for the validation callback
|
||||
val_prompts = {
|
||||
@@ -246,12 +247,12 @@ def main() -> None:
|
||||
"caption": (item["cap"][0] if isinstance(item["cap"], list) else item["cap"]),
|
||||
} for item in caption_data],
|
||||
}
|
||||
val_path = os.path.join(OUTPUT_DIR, "validation_prompts.json")
|
||||
val_path = os.path.join(output_dir, "validation_prompts.json")
|
||||
with open(val_path, "w") as f:
|
||||
json.dump(val_prompts, f, indent=2)
|
||||
print(f"Wrote validation prompts to {val_path}")
|
||||
|
||||
print("\nDone! Use data_path: " + OUTPUT_DIR + " in training config.")
|
||||
print("\nDone! Use data_path: " + output_dir + " in training config.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -10,7 +10,6 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import gc
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from typing import Any
|
||||
@@ -20,6 +19,7 @@ import pyarrow as pa
|
||||
import pyarrow.parquet as pq
|
||||
import torch
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.configs.pipelines.minimax_h3 import MiniMaxH3PipelineConfig
|
||||
from fastvideo.dataset.dataloader.schema import pyarrow_schema_t2va
|
||||
from fastvideo.fastvideo_args import FastVideoArgs
|
||||
@@ -50,11 +50,11 @@ TRAINING_VIDEO_NAME = "1gGQy4nxyUo-Scene-016.mp4"
|
||||
|
||||
def _init_single_process_distributed() -> None:
|
||||
"""Initialize the one-rank process groups required by component loaders."""
|
||||
os.environ.setdefault("MASTER_ADDR", "127.0.0.1")
|
||||
os.environ.setdefault("MASTER_PORT", "29531")
|
||||
os.environ.setdefault("RANK", "0")
|
||||
os.environ.setdefault("WORLD_SIZE", "1")
|
||||
os.environ.setdefault("LOCAL_RANK", "0")
|
||||
envs.setdefault_external("MASTER_ADDR", "127.0.0.1")
|
||||
envs.setdefault_external("MASTER_PORT", "29531")
|
||||
envs.setdefault_external("RANK", "0")
|
||||
envs.setdefault_external("WORLD_SIZE", "1")
|
||||
envs.setdefault_external("LOCAL_RANK", "0")
|
||||
from fastvideo.distributed import maybe_init_distributed_environment_and_model_parallel
|
||||
|
||||
maybe_init_distributed_environment_and_model_parallel(1, 1)
|
||||
|
||||
@@ -4,7 +4,6 @@ Denoising stage for diffusion pipelines.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import weakref
|
||||
from collections.abc import Iterable
|
||||
from dataclasses import dataclass
|
||||
@@ -141,8 +140,7 @@ class DenoisingStage(PipelineStage):
|
||||
# gates should graduate to arch-config declarations like the precision
|
||||
# policies above.
|
||||
_is_flux = (getattr(fastvideo_args.pipeline_config.dit_config, "prefix", "") == "Flux")
|
||||
if _is_flux and os.getenv("FASTVIDEO_FLUX2_DISABLE_BF16_REDUCED_PRECISION_REDUCTION",
|
||||
"").lower() in {"1", "true", "yes"}:
|
||||
if _is_flux and envs.FASTVIDEO_FLUX2_DISABLE_BF16_REDUCED_PRECISION_REDUCTION.get():
|
||||
# Gate 1: tighten bf16 matmul accumulation for the 4-step Klein model (opt-in via env var).
|
||||
torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = False
|
||||
# Gate 2: Flux2 runs its bf16 transformer WITHOUT autocast — autocast perturbs long-sequence attention enough to break 4-step latent parity.
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Latent preparation stage for diffusion pipelines.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
from diffusers.utils.torch_utils import randn_tensor
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.distributed import get_local_torch_device
|
||||
from fastvideo.fastvideo_args import FastVideoArgs
|
||||
from fastvideo.image_processor import ImageProcessor
|
||||
@@ -475,7 +475,7 @@ class Cosmos25LatentPreparationStage(CosmosLatentPreparationStage):
|
||||
)
|
||||
video = torch.cat([cond_video, padding], dim=2)
|
||||
|
||||
if os.environ.get("FASTVIDEO_COSMOS25_LOG_KNOBS", "0") in ("1", "true", "True"):
|
||||
if envs.FASTVIDEO_COSMOS25_LOG_KNOBS.get():
|
||||
logger.info(
|
||||
"[Cosmos2.5 latent_prep] using conditioning input: image=%s video_latent=%s video_path=%s | "
|
||||
"num_video_frames=%s num_cond_frames=%s num_frames=%s",
|
||||
|
||||
@@ -6,7 +6,9 @@ The test parses every Python file under fastvideo/ (except fastvideo/third_party
|
||||
and the registry fastvideo/envs.py) with ``ast`` and reports code that:
|
||||
|
||||
- reads the environment directly for a name outside EXTERNAL_ALLOWLIST;
|
||||
- writes the environment directly (os.environ, os.putenv, monkeypatch.setenv);
|
||||
- writes the environment directly (os.environ, os.putenv, monkeypatch.setenv),
|
||||
or through the envs.*_external helpers for a name outside
|
||||
EXTERNAL_WRITE_ALLOWLIST;
|
||||
- uses the whole environment (os.environ.copy(), dict(os.environ), patch.dict);
|
||||
- uses a registry field without calling one of its methods (``envs.X == "a"``,
|
||||
``getter = envs.X.get``);
|
||||
@@ -61,8 +63,33 @@ EXTERNAL_ALLOWLIST = {
|
||||
"PATH": "Executable search path.",
|
||||
"HF_TOKEN": "Token variable that huggingface_hub reads.",
|
||||
"HUGGING_FACE_HUB_TOKEN": "Token variable that huggingface_hub reads.",
|
||||
"GEMINI_API_KEY": "Gemini API key for the judge metrics.",
|
||||
"GOOGLE_API_KEY": "Google API key, which the Gemini SDK also accepts.",
|
||||
"CEREBRAS_API_KEY": "Cerebras API key for the streaming prompt provider.",
|
||||
"GROQ_API_KEY": "Groq API key for the streaming prompt provider.",
|
||||
"RAY_USAGE_STATS_ENABLED": "Ray usage-statistics switch.",
|
||||
}
|
||||
|
||||
# Variables that FastVideo sets for other tools. Code writes them only through
|
||||
# envs.set_external, envs.setdefault_external, or envs.unset_external, with a
|
||||
# literal name.
|
||||
EXTERNAL_WRITE_ALLOWLIST = {
|
||||
"RANK": "torch.distributed rendezvous for single-process runs and workers.",
|
||||
"LOCAL_RANK": "torch.distributed rendezvous for single-process runs and workers.",
|
||||
"WORLD_SIZE": "torch.distributed rendezvous for single-process runs and workers.",
|
||||
"MASTER_ADDR": "torch.distributed rendezvous for single-process runs.",
|
||||
"MASTER_PORT": "torch.distributed rendezvous for single-process runs.",
|
||||
"CUDA_VISIBLE_DEVICES": "Pins a streaming worker process to its GPU.",
|
||||
"TORCH_NCCL_AVOID_RECORD_STREAMS": "Avoids NCCL record-stream memory growth in workers.",
|
||||
"NCCL_ASYNC_ERROR_HANDLING": "Unset in workers because the value that Ray sets breaks graph building.",
|
||||
"TORCH_HOME": "Points torch.hub at the evaluation cache.",
|
||||
"HF_TOKEN": "Passes the resolved Hugging Face token to huggingface_hub.",
|
||||
"VIDEO_MAX_PIXELS": "Pixel budget that qwen_vl_utils reads for Qwen2.5-Omni.",
|
||||
"RAY_USAGE_STATS_ENABLED": "Turns off Ray usage statistics unless the user turned them on.",
|
||||
"CUTE_DSL_ENABLE_TVM_FFI": "CUTLASS DSL switch that the NVFP4 FlashAttention-4 path needs.",
|
||||
}
|
||||
EXTERNAL_WRITE_HELPERS = {"set_external", "setdefault_external", "unset_external"}
|
||||
|
||||
# Methods that registry fields expose; ``get`` and ``is_set`` count as reads.
|
||||
REGISTRY_METHODS = {"get", "set", "override", "is_set", "clear"}
|
||||
REGISTRY_READ_METHODS = {"get", "is_set"}
|
||||
@@ -72,111 +99,17 @@ REGISTRY_READ_METHODS = {"get", "is_set"}
|
||||
# its violations are fixed; never add one. Kinds are described in
|
||||
# docs/contributing/env_vars.md.
|
||||
KNOWN_VIOLATIONS: dict[str, int] = {
|
||||
'fastvideo/attention/backends/flash_attn.py: read FASTVIDEO_NVFP4_FA4': 1,
|
||||
'fastvideo/attention/backends/video_sparse_attn_h3_probe.py: read FASTVIDEO_H3_VSA_PROBE': 1,
|
||||
'fastvideo/attention/layer.py: read FASTVIDEO_DISABLE_ATTENTION_COMPILE': 2,
|
||||
'fastvideo/attention/selector.py: read <dynamic>': 1,
|
||||
'fastvideo/attention/utils/flash_attn_default.py: import-time-read FASTVIDEO_FA4': 1,
|
||||
'fastvideo/benchmarks/eval_metalfx_rife.py: write FASTVIDEO_MLX_COMPILE': 1,
|
||||
'fastvideo/benchmarks/mlx_fastwan_bench.py: read FASTVIDEO_MLX_COMPILE': 1,
|
||||
'fastvideo/benchmarks/mlx_fastwan_bench.py: read FASTVIDEO_MLX_FAST_NORM': 1,
|
||||
'fastvideo/benchmarks/mlx_fastwan_bench.py: write FASTVIDEO_MLX_COMPILE': 1,
|
||||
'fastvideo/distributed/device_communicators/cpu_communicator.py: read VLLM_DIST_IDENT': 1,
|
||||
'fastvideo/entrypoints/cli/utils.py: whole-environ': 1,
|
||||
'fastvideo/entrypoints/openai/api_server.py: write FASTVIDEO_STAGE_LOGGING': 1,
|
||||
'fastvideo/entrypoints/streaming/prompt/providers/cerebras.py: read <dynamic>': 1,
|
||||
'fastvideo/entrypoints/streaming/prompt/providers/groq.py: read <dynamic>': 1,
|
||||
'fastvideo/entrypoints/streaming/worker.py: write CUDA_VISIBLE_DEVICES': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_FFMPEG_BIN': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_NVENC_BF': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_NVENC_PRESET': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_NVENC_QP': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_NVENC_RC': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_NVENC_TUNE': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_OUTPUT_PIX_FMT': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_VIDEO_CODEC': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: read FASTVIDEO_X264_PRESET': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: write CUTE_DSL_ENABLE_TVM_FFI': 1,
|
||||
'fastvideo/entrypoints/video_generator.py: write FASTVIDEO_NVFP4_FA4': 1,
|
||||
'fastvideo/envs.py: prefix CMAKE_BUILD_TYPE': 1,
|
||||
'fastvideo/envs.py: prefix CUDA_VISIBLE_DEVICES': 1,
|
||||
'fastvideo/envs.py: prefix HCCL_SO_PATH': 1,
|
||||
'fastvideo/envs.py: prefix LD_LIBRARY_PATH': 1,
|
||||
'fastvideo/envs.py: prefix LOCAL_RANK': 1,
|
||||
'fastvideo/envs.py: prefix MAX_JOBS': 1,
|
||||
'fastvideo/envs.py: prefix NVCC_THREADS': 1,
|
||||
'fastvideo/envs.py: prefix VERBOSE': 1,
|
||||
'fastvideo/envs.py: unread CMAKE_BUILD_TYPE': 1,
|
||||
'fastvideo/envs.py: unread CUDA_VISIBLE_DEVICES': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_ENGINE_ITERATION_TIMEOUT_S': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_RINGBUFFER_WARNING_INTERVAL': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_SERVER_DEV_MODE': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_TARGET_DEVICE': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_TEST_DYNAMO_FULLGRAPH_CAPTURE': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_TRACE_FUNCTION': 1,
|
||||
'fastvideo/envs.py: unread FASTVIDEO_USE_PRECOMPILED': 1,
|
||||
'fastvideo/envs.py: unread LD_LIBRARY_PATH': 1,
|
||||
'fastvideo/envs.py: unread MAX_JOBS': 1,
|
||||
'fastvideo/envs.py: unread NVCC_THREADS': 1,
|
||||
'fastvideo/envs.py: unread VERBOSE': 1,
|
||||
'fastvideo/eval/__init__.py: write TORCH_HOME': 1,
|
||||
'fastvideo/eval/datasets/physics_iq.py: read FASTVIDEO_PHYSICS_IQ_BUCKET_URL': 1,
|
||||
'fastvideo/eval/datasets/vbench.py: read VBENCH_FULL_INFO_JSON': 1,
|
||||
'fastvideo/eval/metrics/audio/frechet_distance/metric.py: read <dynamic>': 1,
|
||||
'fastvideo/eval/metrics/common/fvd/metric.py: read <dynamic>': 1,
|
||||
'fastvideo/eval/metrics/judge/third_person_separation/metric.py: read <dynamic>': 1,
|
||||
'fastvideo/eval/metrics/vbench/scene/metric.py: write VIDEO_MAX_PIXELS': 1,
|
||||
'fastvideo/eval/models.py: read FASTVIDEO_EVAL_CACHE': 1,
|
||||
'fastvideo/logger.py: import-time-read FASTVIDEO_CONFIGURE_LOGGING': 1,
|
||||
'fastvideo/logger.py: import-time-read FASTVIDEO_LOGGING_CONFIG_PATH': 1,
|
||||
'fastvideo/logger.py: import-time-read FASTVIDEO_LOGGING_LEVEL': 1,
|
||||
'fastvideo/logger.py: import-time-read FASTVIDEO_LOGGING_PREFIX': 1,
|
||||
'fastvideo/mlx_runtime/fastwan.py: read FASTVIDEO_MLX_COMPILE': 1,
|
||||
'fastvideo/mlx_runtime/fastwan.py: read FASTVIDEO_MLX_DQ_GEMM': 1,
|
||||
'fastvideo/mlx_runtime/fastwan.py: read FASTVIDEO_MLX_FAST_NORM': 1,
|
||||
'fastvideo/mlx_runtime/fastwan.py: read FASTVIDEO_MLX_WINDOW': 1,
|
||||
'fastvideo/mlx_runtime/fastwan.py: read FASTVIDEO_MLX_WINDOW_SINK': 1,
|
||||
'fastvideo/mlx_runtime/memory.py: write <dynamic>': 1,
|
||||
'fastvideo/mlx_runtime/wan22.py: read FASTVIDEO_MLX_COMPILE': 1,
|
||||
'fastvideo/models/encoders/gemma.py: read LTX2_FASTVIDEO_GEMMA_LOG': 2,
|
||||
'fastvideo/models/encoders/reason1.py: read FASTVIDEO_REASON1_WEIGHTS_PATH': 1,
|
||||
'fastvideo/models/loader/benchmarks/benchmark_weight_loading.py: write MASTER_ADDR': 1,
|
||||
'fastvideo/models/loader/benchmarks/benchmark_weight_loading.py: write MASTER_PORT': 1,
|
||||
'fastvideo/models/loader/benchmarks/benchmark_weight_loading.py: write RANK': 1,
|
||||
'fastvideo/models/loader/benchmarks/benchmark_weight_loading.py: write WORLD_SIZE': 1,
|
||||
'fastvideo/models/loader/fsdp_load.py: read FASTVIDEO_FSDP2_AUTOWRAP': 1,
|
||||
'fastvideo/models/loader/fsdp_load.py: read FASTVIDEO_FSDP2_MIN_PARAMS': 1,
|
||||
'fastvideo/models/loader/fsdp_load.py: read FASTVIDEO_H3_VSA_PROBE': 1,
|
||||
'fastvideo/models/vaes/ltx2vae.py: read <dynamic>': 1,
|
||||
'fastvideo/performance/hf_store.py: read HF_REPO_ID': 1,
|
||||
'fastvideo/performance/hf_store.py: read PERFORMANCE_TRACKING_SYNC_REUSE_TTL_SECONDS': 1,
|
||||
'fastvideo/performance_dashboard/api.py: read PERFORMANCE_TRACKING_ROOT': 1,
|
||||
'fastvideo/pipelines/basic/ltx2/stages/ltx2_audio_decoding.py: read LTX2_DISABLE_AUDIO_AUTOCAST': 1,
|
||||
'fastvideo/pipelines/basic/ltx2/stages/ltx2_denoising.py: read FASTVIDEO_NVTX_PROFILE': 1,
|
||||
'fastvideo/pipelines/basic/ltx2/stages/ltx2_denoising.py: read LTX2_USE_DISTILLED_SIGMAS': 1,
|
||||
'fastvideo/pipelines/basic/magi_human/magi_human_pipeline.py: write HF_TOKEN': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_kandinsky5_overfit.py: read KANDINSKY5_OVERFIT_DATA_DIR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_kandinsky5_overfit.py: read KANDINSKY5_OVERFIT_OUTPUT_DIR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_kandinsky5_overfit.py: write MASTER_ADDR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_kandinsky5_overfit.py: write MASTER_PORT': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_CAPTION_JSON': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_DATA_DIR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_MODEL': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_NUM_COPIES': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_OUTPUT_DIR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: read LTX2_OVERFIT_VIDEO_SUBDIR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: write LOCAL_RANK': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: write MASTER_ADDR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: write MASTER_PORT': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: write RANK': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_ltx2_overfit.py: write WORLD_SIZE': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_minimax_h3_overfit.py: write LOCAL_RANK': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_minimax_h3_overfit.py: write MASTER_ADDR': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_minimax_h3_overfit.py: write MASTER_PORT': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_minimax_h3_overfit.py: write RANK': 1,
|
||||
'fastvideo/pipelines/preprocess/preprocess_minimax_h3_overfit.py: write WORLD_SIZE': 1,
|
||||
'fastvideo/pipelines/stages/denoising.py: read FASTVIDEO_FLUX2_DISABLE_BF16_REDUCED_PRECISION_REDUCTION': 1,
|
||||
'fastvideo/pipelines/stages/latent_preparation.py: read FASTVIDEO_COSMOS25_LOG_KNOBS': 1,
|
||||
'fastvideo/tests/api/test_attention_selector_resolution.py: write FASTVIDEO_ATTENTION_BACKEND': 17,
|
||||
'fastvideo/tests/attention/test_flash_attn_no_pad_resolver.py: write FASTVIDEO_FA4': 3,
|
||||
'fastvideo/tests/attention/test_flash_attn_nvfp4_opt_out.py: write FASTVIDEO_NVFP4_FA4': 4,
|
||||
@@ -345,8 +278,8 @@ KNOWN_VIOLATIONS: dict[str, int] = {
|
||||
'fastvideo/tests/modal/test_pr_test.py: write BUILDKITE_REPO': 2,
|
||||
'fastvideo/tests/nightly/test_e2e_dmd_t2v_crush_smol.py: write WANDB_MODE': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_i2v_overfit_single_sample.py: write WANDB_MODE': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_kandinsky5_dmd_t2v_overfit.py: read <dynamic>': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_kandinsky5_dmd_t2v_overfit.py: read KANDINSKY5_E2E_NUM_GPUS': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_kandinsky5_dmd_t2v_overfit.py: read KANDINSKY5_E2E_WRITE_REFERENCE': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_kandinsky5_dmd_t2v_overfit.py: whole-environ': 3,
|
||||
'fastvideo/tests/nightly/test_e2e_kandinsky5_dmd_t2v_overfit.py: write WANDB_MODE': 1,
|
||||
'fastvideo/tests/nightly/test_e2e_ltx2_overfit_new_stack.py: read FASTVIDEO_NIGHTLY': 1,
|
||||
@@ -420,8 +353,10 @@ KNOWN_VIOLATIONS: dict[str, int] = {
|
||||
'fastvideo/tests/ssim/conftest.py: write <dynamic>': 3,
|
||||
'fastvideo/tests/ssim/inference_similarity_utils.py: read FASTVIDEO_ATTENTION_BACKEND': 1,
|
||||
'fastvideo/tests/ssim/inference_similarity_utils.py: write FASTVIDEO_ATTENTION_BACKEND': 3,
|
||||
'fastvideo/tests/ssim/reference_utils.py: read <dynamic>': 1,
|
||||
'fastvideo/tests/ssim/reference_videos_cli.py: read <dynamic>': 3,
|
||||
'fastvideo/tests/ssim/reference_utils.py: read FASTVIDEO_SSIM_FULL_QUALITY': 1,
|
||||
'fastvideo/tests/ssim/reference_videos_cli.py: read <dynamic>': 1,
|
||||
'fastvideo/tests/ssim/reference_videos_cli.py: read FASTVIDEO_SSIM_REFERENCE_HF_REPO': 1,
|
||||
'fastvideo/tests/ssim/reference_videos_cli.py: read FASTVIDEO_SSIM_REFERENCE_HF_REPO_TYPE': 1,
|
||||
'fastvideo/tests/ssim/test_dreamx_world_similarity.py: read DREAMX_WORLD_AR_SSIM_MODEL_PATH': 1,
|
||||
'fastvideo/tests/ssim/test_dreamx_world_similarity.py: read DREAMX_WORLD_SSIM_MODEL_PATH': 1,
|
||||
'fastvideo/tests/ssim/test_flux_t2i_similarity.py: read FLUX_T2I_MODEL_DIR': 1,
|
||||
@@ -444,7 +379,7 @@ KNOWN_VIOLATIONS: dict[str, int] = {
|
||||
'fastvideo/tests/stages/_denoising_fixtures.py: write FASTVIDEO_CFG_GATE_STEP': 2,
|
||||
'fastvideo/tests/stages/test_kandinsky5_dmd_stage_backend_engages.py: write FASTVIDEO_ATTENTION_BACKEND': 1,
|
||||
'fastvideo/tests/stages/test_minimax_h3_encoding_offload.py: write FASTVIDEO_ATTENTION_BACKEND': 1,
|
||||
'fastvideo/tests/train/methods/grad_norm_regression.py: read <dynamic>': 1,
|
||||
'fastvideo/tests/train/methods/grad_norm_regression.py: read FASTVIDEO_GRADNORM_UPDATE': 1,
|
||||
'fastvideo/tests/train/methods/test_cosmos_finetune.py: write MASTER_ADDR': 1,
|
||||
'fastvideo/tests/train/methods/test_cosmos_finetune.py: write MASTER_PORT': 1,
|
||||
'fastvideo/tests/train/methods/test_ltx2_finetune.py: write MASTER_ADDR': 1,
|
||||
@@ -534,23 +469,11 @@ KNOWN_VIOLATIONS: dict[str, int] = {
|
||||
'fastvideo/tests/vaes/test_wan_vae.py: write MASTER_PORT': 1,
|
||||
'fastvideo/tests/worker/test_gpu_worker.py: write FASTVIDEO_NVTX_PROFILE': 2,
|
||||
'fastvideo/tests/worker/test_gpu_worker.py: write LOCAL_RANK': 1,
|
||||
'fastvideo/train/entrypoint/dcp_to_diffusers.py: write <dynamic>': 1,
|
||||
'fastvideo/train/entrypoint/train.py: write FASTVIDEO_ATTENTION_BACKEND': 2,
|
||||
'fastvideo/training/self_forcing_distillation_pipeline.py: read FASTVIDEO_FSDP2_AUTOWRAP': 1,
|
||||
'fastvideo/utils.py: read <dynamic>': 5,
|
||||
'fastvideo/utils.py: read FASTVIDEO_WORKER_MULTIPROC_METHOD': 1,
|
||||
'fastvideo/utils.py: write <dynamic>': 1,
|
||||
'fastvideo/utils.py: write FASTVIDEO_WORKER_MULTIPROC_METHOD': 1,
|
||||
'fastvideo/worker/gpu_worker.py: write LOCAL_RANK': 1,
|
||||
'fastvideo/worker/gpu_worker.py: write NCCL_ASYNC_ERROR_HANDLING': 1,
|
||||
'fastvideo/worker/gpu_worker.py: write RANK': 1,
|
||||
'fastvideo/worker/gpu_worker.py: write TORCH_NCCL_AVOID_RECORD_STREAMS': 1,
|
||||
'fastvideo/worker/gpu_worker.py: write WORLD_SIZE': 1,
|
||||
'fastvideo/worker/ray_distributed_executor.py: read <dynamic>': 2,
|
||||
'fastvideo/worker/ray_distributed_executor.py: read RAY_USAGE_STATS_ENABLED': 1,
|
||||
'fastvideo/worker/ray_distributed_executor.py: whole-environ': 1,
|
||||
'fastvideo/worker/ray_distributed_executor.py: write RAY_USAGE_STATS_ENABLED': 1,
|
||||
'fastvideo/worker/ray_env.py: import-time-read FASTVIDEO_CONFIG_ROOT': 1,
|
||||
'fastvideo/worker/ray_env.py: read <dynamic>': 1,
|
||||
'fastvideo/worker/ray_utils.py: whole-environ': 1,
|
||||
'fastvideo/worker/worker_base.py: read <dynamic>': 1,
|
||||
@@ -576,12 +499,6 @@ def is_allowlisted(name: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _literal(node: ast.AST | None) -> str:
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
return node.value
|
||||
return "<dynamic>"
|
||||
|
||||
|
||||
class EnvAccessScanner:
|
||||
"""Find environment accesses and registry-field uses in one module.
|
||||
|
||||
@@ -604,6 +521,13 @@ class EnvAccessScanner:
|
||||
self.getenv_names: set[str] = set()
|
||||
self.setenv_names: set[str] = set()
|
||||
self.envs_module_names: set[str] = set()
|
||||
# Module-level string constants, so that os.environ.get(NAME_ENV) resolves to the name.
|
||||
self.constants: dict[str, str] = {}
|
||||
for statement in tree.body:
|
||||
if (isinstance(statement, ast.Assign) and len(statement.targets) == 1
|
||||
and isinstance(statement.targets[0], ast.Name) and isinstance(statement.value, ast.Constant)
|
||||
and isinstance(statement.value.value, str)):
|
||||
self.constants[statement.targets[0].id] = statement.value.value
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
@@ -624,6 +548,14 @@ class EnvAccessScanner:
|
||||
elif node.module == "fastvideo" and alias.name == "envs":
|
||||
self.envs_module_names.add(local)
|
||||
|
||||
def _literal(self, node: ast.AST | None) -> str:
|
||||
"""Return the variable name that a call argument spells, or "<dynamic>"."""
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
return node.value
|
||||
if isinstance(node, ast.Name) and node.id in self.constants:
|
||||
return self.constants[node.id]
|
||||
return "<dynamic>"
|
||||
|
||||
def _is_os_attr(self, node: ast.AST, attrs: tuple[str, ...]) -> bool:
|
||||
return (isinstance(node, ast.Attribute) and node.attr in attrs and isinstance(node.value, ast.Name)
|
||||
and node.value.id in self.os_names)
|
||||
@@ -670,24 +602,24 @@ class EnvAccessScanner:
|
||||
call = self.parents[parent]
|
||||
assert isinstance(call, ast.Call)
|
||||
if call.func is parent and parent.attr == "get":
|
||||
self.violations.append(("read", _literal(call.args[0] if call.args else None), line))
|
||||
self.violations.append(("read", self._literal(call.args[0] if call.args else None), line))
|
||||
return
|
||||
if call.func is parent and parent.attr in ("setdefault", "pop"):
|
||||
self.violations.append(("write", _literal(call.args[0] if call.args else None), line))
|
||||
self.violations.append(("write", self._literal(call.args[0] if call.args else None), line))
|
||||
return
|
||||
if isinstance(parent, ast.Subscript) and parent.value is node:
|
||||
kind = "read" if isinstance(parent.ctx, ast.Load) else "write"
|
||||
self.violations.append((kind, _literal(parent.slice), line))
|
||||
self.violations.append((kind, self._literal(parent.slice), line))
|
||||
return
|
||||
if (isinstance(parent, ast.Compare) and len(parent.ops) == 1 and isinstance(parent.ops[0], (ast.In, ast.NotIn))
|
||||
and parent.comparators[0] is node):
|
||||
self.violations.append(("read", _literal(parent.left), line))
|
||||
self.violations.append(("read", self._literal(parent.left), line))
|
||||
return
|
||||
self.violations.append(("whole-environ", "", line))
|
||||
|
||||
def _check_call(self, node: ast.Call) -> None:
|
||||
func = node.func
|
||||
name = _literal(node.args[0] if node.args else None)
|
||||
name = self._literal(node.args[0] if node.args else None)
|
||||
if self._is_os_attr(func, ("getenv", "getenvb")) or (isinstance(func, ast.Name)
|
||||
and func.id in self.getenv_names):
|
||||
self.violations.append(("read", name, node.lineno))
|
||||
@@ -695,6 +627,9 @@ class EnvAccessScanner:
|
||||
or (isinstance(func, ast.Name) and func.id in self.setenv_names)
|
||||
or (isinstance(func, ast.Attribute) and func.attr in ("setenv", "delenv"))):
|
||||
self.violations.append(("write", name, node.lineno))
|
||||
elif (isinstance(func, ast.Attribute) and func.attr in EXTERNAL_WRITE_HELPERS
|
||||
and self._is_envs_module(func.value) and name not in EXTERNAL_WRITE_ALLOWLIST):
|
||||
self.violations.append(("write", name, node.lineno))
|
||||
|
||||
def _check_registry_use(self, node: ast.Attribute, parent: ast.AST | None, in_function: bool) -> None:
|
||||
# Only a call counts: ``getter = envs.X.get`` neither reads the variable
|
||||
@@ -715,11 +650,21 @@ def scanned_files() -> list[Path]:
|
||||
if path != REGISTRY_PATH and not any(excluded in path.parents for excluded in EXCLUDED_DIRS))
|
||||
|
||||
|
||||
def registry_internal_reads(registry_names: set[str]) -> Counter[str]:
|
||||
"""Count registry reads inside fastvideo/envs.py itself, such as a computed default that reads another field."""
|
||||
reads: Counter[str] = Counter()
|
||||
for node in ast.walk(ast.parse(REGISTRY_PATH.read_text(encoding="utf-8"))):
|
||||
if (isinstance(node, ast.Attribute) and node.attr in REGISTRY_READ_METHODS and isinstance(node.value, ast.Name)
|
||||
and node.value.id in registry_names):
|
||||
reads[node.value.id] += 1
|
||||
return reads
|
||||
|
||||
|
||||
def collect_violations(registry: ModuleType) -> tuple[dict[str, list[int]], Counter[str]]:
|
||||
"""Return every violation key with its line numbers, plus registry read counts."""
|
||||
registry_names = set(registry.environment_variables)
|
||||
found: dict[str, list[int]] = {}
|
||||
reads: Counter[str] = Counter()
|
||||
reads: Counter[str] = registry_internal_reads(registry_names)
|
||||
for path in scanned_files():
|
||||
relative = path.relative_to(REPO_ROOT).as_posix()
|
||||
scanner = EnvAccessScanner(ast.parse(path.read_text(encoding="utf-8"), filename=relative), registry_names)
|
||||
@@ -793,10 +738,21 @@ def _escape(text: str) -> str:
|
||||
|
||||
|
||||
def render_env_table(registry: ModuleType) -> str:
|
||||
"""Render the registry as an aligned Markdown table, in declaration order."""
|
||||
"""Render the registry and the deprecation table as aligned Markdown tables, in declaration order."""
|
||||
rows = [["Variable", "Type", "Default", "Category", "Description"]]
|
||||
for name, field in registry.environment_variables.items():
|
||||
rows.append([f"`{name}`", field.type_name, _render_default(field), field.category, _escape(field.doc)])
|
||||
doc = _escape(field.doc)
|
||||
if field.deprecated_names:
|
||||
doc += " Deprecated names: " + ", ".join(f"`{old}`" for old in field.deprecated_names) + "."
|
||||
rows.append([f"`{name}`", field.type_name, _render_default(field), field.category, doc])
|
||||
deprecated_rows = [["Deprecated variable", "Reason"]]
|
||||
deprecated_rows.extend([f"`{name}`", reason] for name, reason in registry.DEPRECATED_VARIABLES.items())
|
||||
return (_render_table(rows) + "\n\nVariables that FastVideo no longer reads; setting one logs a warning:\n\n" +
|
||||
_render_table(deprecated_rows))
|
||||
|
||||
|
||||
def _render_table(rows: list[list[str]]) -> str:
|
||||
"""Render rows as a Markdown table whose pipes line up."""
|
||||
widths = [max(len(row[column]) for row in rows) for column in range(len(rows[0]))]
|
||||
|
||||
def render_row(cells: list[str]) -> str:
|
||||
|
||||
@@ -84,7 +84,7 @@ NUM_GPUS = os.environ.get("KANDINSKY5_E2E_NUM_GPUS", "1")
|
||||
# with their real videos/captions for the actual recipe:
|
||||
# _clean_previous_artifacts() deletes this root wholesale on every run,
|
||||
# and the preprocess subprocess is pointed here via the
|
||||
# KANDINSKY5_OVERFIT_DATA_DIR / KANDINSKY5_OVERFIT_OUTPUT_DIR env
|
||||
# FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR / FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR env
|
||||
# overrides instead of the script's user-facing defaults.
|
||||
E2E_ROOT = Path("data") / "kandinsky5_e2e"
|
||||
RAW_DATA_DIR = E2E_ROOT / "raw"
|
||||
@@ -223,8 +223,8 @@ def _run_preprocessing() -> None:
|
||||
# (data/kandinsky5_overfit{,_preprocessed}) -- the very directories a
|
||||
# user populates for the real recipe, which this test must never touch.
|
||||
env = dict(os.environ)
|
||||
env["KANDINSKY5_OVERFIT_DATA_DIR"] = str(RAW_DATA_DIR)
|
||||
env["KANDINSKY5_OVERFIT_OUTPUT_DIR"] = str(PREPROCESSED_DIR)
|
||||
env["FASTVIDEO_TEST_KANDINSKY5_OVERFIT_DATA_DIR"] = str(RAW_DATA_DIR)
|
||||
env["FASTVIDEO_TEST_KANDINSKY5_OVERFIT_OUTPUT_DIR"] = str(PREPROCESSED_DIR)
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
|
||||
@@ -82,9 +82,9 @@ def download_data():
|
||||
def run_preprocessing(case: dict):
|
||||
env = os.environ.copy()
|
||||
env["CUDA_VISIBLE_DEVICES"] = env.get("CUDA_VISIBLE_DEVICES", "0").split(",")[0]
|
||||
env["LTX2_OVERFIT_DATA_DIR"] = str(LOCAL_RAW_DATA_DIR)
|
||||
env["LTX2_OVERFIT_OUTPUT_DIR"] = str(case["prep_dir"])
|
||||
env["LTX2_OVERFIT_MODEL"] = case["model"]
|
||||
env["FASTVIDEO_TEST_LTX2_OVERFIT_DATA_DIR"] = str(LOCAL_RAW_DATA_DIR)
|
||||
env["FASTVIDEO_TEST_LTX2_OVERFIT_OUTPUT_DIR"] = str(case["prep_dir"])
|
||||
env["FASTVIDEO_TEST_LTX2_OVERFIT_MODEL"] = case["model"]
|
||||
cmd = [sys.executable, PREPROCESSING_SCRIPT]
|
||||
print(f"Running preprocessing: {cmd} (model={case['model']})")
|
||||
subprocess.run(cmd, check=True, env=env)
|
||||
|
||||
@@ -33,6 +33,7 @@ import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import fastvideo.envs as envs
|
||||
from fastvideo.logger import init_logger
|
||||
|
||||
logger = init_logger(__name__)
|
||||
@@ -45,14 +46,11 @@ def _ensure_distributed() -> None:
|
||||
For plain ``python`` we fill in the minimum required vars so
|
||||
that ``init_process_group`` succeeds with world_size=1.
|
||||
"""
|
||||
for key, default in [
|
||||
("RANK", "0"),
|
||||
("LOCAL_RANK", "0"),
|
||||
("WORLD_SIZE", "1"),
|
||||
("MASTER_ADDR", "127.0.0.1"),
|
||||
("MASTER_PORT", "29500"),
|
||||
]:
|
||||
os.environ.setdefault(key, default)
|
||||
envs.setdefault_external("RANK", "0")
|
||||
envs.setdefault_external("LOCAL_RANK", "0")
|
||||
envs.setdefault_external("WORLD_SIZE", "1")
|
||||
envs.setdefault_external("MASTER_ADDR", "127.0.0.1")
|
||||
envs.setdefault_external("MASTER_PORT", "29500")
|
||||
|
||||
|
||||
def _save_role_pretrained(
|
||||
|
||||
@@ -396,7 +396,7 @@ class LTX2Model(WanModel):
|
||||
f"checkpoint's expected text context dim {expected_dim}. "
|
||||
"The parquet was likely preprocessed with a different "
|
||||
"LTX-2 version (2.0 stores 3840-d, 2.3 stores 4096-d); "
|
||||
"re-run preprocess_ltx2_overfit.py with LTX2_OVERFIT_MODEL "
|
||||
"re-run preprocess_ltx2_overfit.py with FASTVIDEO_TEST_LTX2_OVERFIT_MODEL "
|
||||
"set to the same checkpoint as models.student.init_from.")
|
||||
|
||||
def _update_rope_fps(self, infos: list[dict[str, Any]] | None) -> None:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import copy
|
||||
import os
|
||||
import time
|
||||
from collections import deque
|
||||
from typing import Any
|
||||
@@ -47,7 +46,7 @@ class SelfForcingDistillationPipeline(DistillationPipeline):
|
||||
def initialize_training_pipeline(self, training_args: TrainingArgs):
|
||||
"""Initialize the self-forcing training pipeline."""
|
||||
# Check if FSDP2 auto wrap is enabled - not supported for self-forcing distillation
|
||||
if os.environ.get("FASTVIDEO_FSDP2_AUTOWRAP", "0") == "1":
|
||||
if envs.FASTVIDEO_FSDP2_AUTOWRAP.get():
|
||||
raise NotImplementedError("FASTVIDEO_FSDP2_AUTOWRAP is not implemented for self-forcing distillation. "
|
||||
"Please set FASTVIDEO_FSDP2_AUTOWRAP=0 or unset the environment variable.")
|
||||
|
||||
|
||||
+5
-5
@@ -82,16 +82,16 @@ def find_nccl_library() -> str:
|
||||
|
||||
def find_hccl_library() -> str:
|
||||
"""
|
||||
We either use the library file specified by the `HCCL_SO_PATH`
|
||||
We either use the library file specified by the `FASTVIDEO_HCCL_SO_PATH`
|
||||
environment variable, or we find the library file brought by PyTorch.
|
||||
After importing `torch`, `libhccl.so` can be
|
||||
found by `ctypes` automatically.
|
||||
"""
|
||||
so_file = envs.HCCL_SO_PATH.get()
|
||||
so_file = envs.FASTVIDEO_HCCL_SO_PATH.get()
|
||||
|
||||
# manually load the nccl library
|
||||
if so_file:
|
||||
logger.info("Found hccl from environment variable HCCL_SO_PATH=%s", so_file)
|
||||
logger.info("Found hccl from environment variable FASTVIDEO_HCCL_SO_PATH=%s", so_file)
|
||||
else:
|
||||
if torch.version.cann is not None: # codespell:ignore cann
|
||||
so_file = "libhccl.so"
|
||||
@@ -1240,9 +1240,9 @@ def xpu_is_initialized() -> bool:
|
||||
|
||||
|
||||
def force_spawn() -> None:
|
||||
if os.environ.get("FASTVIDEO_WORKER_MULTIPROC_METHOD") == "fork":
|
||||
if envs.FASTVIDEO_WORKER_MULTIPROC_METHOD.get() == "fork":
|
||||
logger.warning("We must use the `spawn` multiprocessing start method.")
|
||||
os.environ["FASTVIDEO_WORKER_MULTIPROC_METHOD"] = "spawn"
|
||||
envs.FASTVIDEO_WORKER_MULTIPROC_METHOD.set("spawn")
|
||||
|
||||
|
||||
def get_mp_context() -> BaseContext:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import os
|
||||
from typing import Any, cast
|
||||
|
||||
import torch
|
||||
@@ -50,9 +49,9 @@ class Worker:
|
||||
# this behavior.
|
||||
# Related issue:
|
||||
# https://discuss.pytorch.org/t/cuda-allocation-lifetime-for-inputs-to-distributed-all-reduce/191573
|
||||
os.environ["TORCH_NCCL_AVOID_RECORD_STREAMS"] = "1"
|
||||
envs.set_external("TORCH_NCCL_AVOID_RECORD_STREAMS", "1")
|
||||
# This env var set by Ray causes exceptions with graph building.
|
||||
os.environ.pop("NCCL_ASYNC_ERROR_HANDLING", None)
|
||||
envs.unset_external("NCCL_ASYNC_ERROR_HANDLING")
|
||||
|
||||
# Set environment variables BEFORE calling get_local_torch_device()
|
||||
# so that each worker uses the correct device
|
||||
@@ -60,9 +59,9 @@ class Worker:
|
||||
# Ray deliberately excludes LOCAL_RANK from the copied driver
|
||||
# environment and exposes all GPUs assigned to the node, so leaving an
|
||||
# inherited or missing value here would bind every Ray actor to cuda:0.
|
||||
os.environ["LOCAL_RANK"] = str(self.local_rank)
|
||||
os.environ["RANK"] = str(self.rank)
|
||||
os.environ["WORLD_SIZE"] = str(self.fastvideo_args.num_gpus)
|
||||
envs.set_external("LOCAL_RANK", str(self.local_rank))
|
||||
envs.set_external("RANK", str(self.rank))
|
||||
envs.set_external("WORLD_SIZE", str(self.fastvideo_args.num_gpus))
|
||||
|
||||
# Platform-agnostic device initialization
|
||||
self.device = get_local_torch_device()
|
||||
|
||||
@@ -94,6 +94,7 @@ class RayDistributedExecutor(Executor):
|
||||
"NCCL_NVLS_ENABLE",
|
||||
"NCCL_DEBUG",
|
||||
"NCCL_DEBUG_SUBSYS",
|
||||
"LD_LIBRARY_PATH",
|
||||
}
|
||||
|
||||
def _init_executor(self) -> None:
|
||||
@@ -103,7 +104,7 @@ class RayDistributedExecutor(Executor):
|
||||
# Disable Ray usage stats collection.
|
||||
ray_usage = os.environ.get("RAY_USAGE_STATS_ENABLED", "0")
|
||||
if ray_usage != "1":
|
||||
os.environ["RAY_USAGE_STATS_ENABLED"] = "0"
|
||||
envs.set_external("RAY_USAGE_STATS_ENABLED", "0")
|
||||
|
||||
self._init_workers_ray(placement_group)
|
||||
|
||||
|
||||
+25
-21
@@ -8,24 +8,20 @@ from fastvideo.logger import init_logger
|
||||
|
||||
logger = init_logger(__name__)
|
||||
|
||||
CONFIG_HOME = envs.FASTVIDEO_CONFIG_ROOT.get()
|
||||
|
||||
# This file contains a list of env vars that should not be copied
|
||||
# from the driver to the Ray workers.
|
||||
RAY_NON_CARRY_OVER_ENV_VARS_FILE = os.path.join(CONFIG_HOME, "ray_non_carry_over_env_vars.json")
|
||||
|
||||
try:
|
||||
if os.path.exists(RAY_NON_CARRY_OVER_ENV_VARS_FILE):
|
||||
with open(RAY_NON_CARRY_OVER_ENV_VARS_FILE) as f:
|
||||
RAY_NON_CARRY_OVER_ENV_VARS = set(json.load(f))
|
||||
else:
|
||||
RAY_NON_CARRY_OVER_ENV_VARS = set()
|
||||
except json.JSONDecodeError:
|
||||
logger.warning(
|
||||
"Failed to parse %s. Using an empty set for non-carry-over env vars.",
|
||||
RAY_NON_CARRY_OVER_ENV_VARS_FILE,
|
||||
)
|
||||
RAY_NON_CARRY_OVER_ENV_VARS = set()
|
||||
def _load_non_carry_over_env_vars(non_carry_over_file: str) -> set[str]:
|
||||
"""Read the env vars that must not be copied from the driver to the Ray workers."""
|
||||
try:
|
||||
if os.path.exists(non_carry_over_file):
|
||||
with open(non_carry_over_file) as f:
|
||||
return set(json.load(f))
|
||||
return set()
|
||||
except json.JSONDecodeError:
|
||||
logger.warning(
|
||||
"Failed to parse %s. Using an empty set for non-carry-over env vars.",
|
||||
non_carry_over_file,
|
||||
)
|
||||
return set()
|
||||
|
||||
|
||||
def get_env_vars_to_copy(
|
||||
@@ -52,18 +48,26 @@ def get_env_vars_to_copy(
|
||||
"""
|
||||
exclude_vars = exclude_vars or set()
|
||||
additional_vars = additional_vars or set()
|
||||
# This file contains a list of env vars that should not be copied
|
||||
# from the driver to the Ray workers.
|
||||
non_carry_over_file = os.path.join(envs.FASTVIDEO_CONFIG_ROOT.get(), "ray_non_carry_over_env_vars.json")
|
||||
non_carry_over_vars = _load_non_carry_over_env_vars(non_carry_over_file)
|
||||
registered_vars = {
|
||||
name
|
||||
for field in envs.environment_variables.values()
|
||||
for name in (field.name, *field.deprecated_names)
|
||||
}
|
||||
|
||||
env_vars_to_copy = {
|
||||
v
|
||||
for v in set(envs.environment_variables).union(additional_vars)
|
||||
if v not in exclude_vars and v not in RAY_NON_CARRY_OVER_ENV_VARS
|
||||
for v in registered_vars.union(additional_vars) if v not in exclude_vars and v not in non_carry_over_vars
|
||||
}
|
||||
|
||||
to_destination = " to " + destination if destination is not None else ""
|
||||
|
||||
logger.info(
|
||||
"RAY_NON_CARRY_OVER_ENV_VARS from config: %s",
|
||||
RAY_NON_CARRY_OVER_ENV_VARS,
|
||||
non_carry_over_vars,
|
||||
)
|
||||
logger.info(
|
||||
"Copying the following environment variables%s: %s",
|
||||
@@ -72,7 +76,7 @@ def get_env_vars_to_copy(
|
||||
)
|
||||
logger.info(
|
||||
"If certain env vars should NOT be copied, add them to %s file",
|
||||
RAY_NON_CARRY_OVER_ENV_VARS_FILE,
|
||||
non_carry_over_file,
|
||||
)
|
||||
|
||||
return env_vars_to_copy
|
||||
|
||||
@@ -16,7 +16,7 @@ skip or fail. Skipped in CI; run locally on a single GPU.
|
||||
| Official commit/version | `<TODO>` |
|
||||
| HF weights | `Lightricks/LTX-2`, `FastVideo/LTX2-base`, `FastVideo/LTX2-Distilled-Diffusers` |
|
||||
| HF revision | `<TODO>` |
|
||||
| Local weights dir | `<TODO>` (env: `LTX2_DIFFUSERS_PATH`, `LTX2_FASTVIDEO_GEMMA_LOG`, etc.) |
|
||||
| Local weights dir | `<TODO>` (env: `LTX2_DIFFUSERS_PATH`, `FASTVIDEO_LTX2_GEMMA_LOG`, etc.) |
|
||||
| Source layout | `<TODO: diffusers / raw_official / mixed>` |
|
||||
| Needs conversion | `<TODO>` |
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ if ltx_core_path.exists() and str(ltx_core_path) not in sys.path:
|
||||
|
||||
def _init_log_paths() -> tuple[Path, Path]:
|
||||
base_dir = Path(os.getenv("LTX2_DEBUG_DIR", "ltx2_debug"))
|
||||
fastvideo_log = Path(os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", base_dir / "fastvideo_gemma.log"))
|
||||
fastvideo_log = Path(os.getenv("FASTVIDEO_LTX2_GEMMA_LOG", base_dir / "fastvideo_gemma.log"))
|
||||
reference_log = Path(os.getenv("LTX2_REFERENCE_GEMMA_LOG", base_dir / "reference_gemma.log"))
|
||||
fastvideo_log.parent.mkdir(parents=True, exist_ok=True)
|
||||
reference_log.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user