Text-to-Video
Diffusers
Safetensors
hunyuanvideo
diffusionart
vanzl commited on
Commit
06b4c62
·
verified ·
1 Parent(s): 65cf63f

Add pinned public inference entry and installation guide

Browse files
Files changed (4) hide show
  1. README.md +93 -54
  2. infer.py +200 -0
  3. install.sh +80 -0
  4. requirements-inference.txt +42 -0
README.md CHANGED
@@ -11,68 +11,107 @@ tags:
11
 
12
  # DiffusionART HunyuanVideo 7:2:1 — selected step 30
13
 
14
- This private release contains **one full HunyuanVideo transformer**, not a LoRA
15
- adapter or a complete video pipeline. It is the author-selected model-only
16
- checkpoint from W&B run [`tk1w4go1`](https://wandb.ai/vanzl3386-chinese-university-of-hong-kong-shenzhen/flow-grpo-algo/runs/tk1w4go1),
17
- at optimizer step 30 / rollout 15. The planned 100-update run later stopped at
18
- step 40; this package makes no claim that 100 updates completed.
 
 
 
 
19
 
20
- The original HunyuanVideo-13B transformer was trained with masked scalar
21
- DiffusionART feedback from fixed-normalized temporal alignment, video quality,
22
- and motion quality rewards at weights **0.7 / 0.2 / 0.1**, plus a frozen
23
- pretrained-velocity MSE regularizer with beta **0.1**. This is a full F32
24
- transformer export. Tensor names, shapes, dtypes, and values were preserved
25
- when the original safetensors file was split into shards smaller than 5 GB.
26
- The package includes no optimizer state, RNG state, VAE, text encoders, or
27
- tokenizers.
28
 
29
- ## Base and native loading
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- Use the separate public base pipeline assets from
32
- [`hunyuanvideo-community/HunyuanVideo`](https://huggingface.co/hunyuanvideo-community/HunyuanVideo)
33
- at revision `e8c2aaa66fe3742a32c11a6766aecbf07c56e773`. The training and
34
- evaluation runtime used the native `hunyuan_hf` loader in
35
- [`XueZeyue/DanceGRPO`](https://github.com/XueZeyue/DanceGRPO) at revision
36
- `15cc71d53cc2e6e18a68ee607d5fb6ba9a99e344`. Its transformer loading
37
- call takes the downloaded `transformer/` directory as the checkpoint and the
38
- public base snapshot as the model root:
39
 
40
- ```python
41
- import torch
42
- from fastvideo.utils.load import load_transformer
43
- from huggingface_hub import snapshot_download
44
 
45
- release = snapshot_download("vanzl/DiffusionART-HunyuanVideo-7-2-1")
46
- base = snapshot_download(
47
- "hunyuanvideo-community/HunyuanVideo",
48
- revision="e8c2aaa66fe3742a32c11a6766aecbf07c56e773",
49
- )
50
- transformer = load_transformer(
51
- "hunyuan_hf", f"{release}/transformer", base, torch.float32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  )
 
 
 
 
 
 
 
 
 
53
  ```
54
 
55
- This shows the native loader interface and does not constitute an independently
56
- tested inference example. Compatibility with a standard Diffusers pipeline has
57
- not been validated for this release. The original `config.json` was preserved
58
- byte for byte, including its source `_name_or_path` metadata; loading should
59
- use the supplied checkpoint directory and public base snapshot as above.
 
 
 
 
 
60
 
61
- The fixed evaluation protocol used 53 frames at 640×640 and 8 FPS, 30 sampling
62
- steps, shift 7, eta 0, no classic CFG, and embedded guidance tensor 6018. The
63
- step 30 eval had 150 scored samples; its validation100 raw VQ/MQ/TA means were
64
- 6.51484375 / 2.6786230605840684 / 1.6762551510334014. These are recorded
65
- evaluation results, not an independent GPU inference check of this upload.
 
 
 
66
 
67
- ## Provenance and terms
68
 
69
- See `release.json` for the exact run, runtime/contract revisions, source and
70
- shard hashes, and validation status. Tencent's original HunyuanVideo weights
71
- and derivatives are subject to the **Tencent Hunyuan Community License
72
- Agreement**. The official upstream [`LICENSE.txt`](LICENSE.txt) and
73
- [`Notice`](Notice) are included unchanged from
74
- [`tencent/HunyuanVideo`](https://huggingface.co/tencent/HunyuanVideo)
75
- revision `6204ad6aea1a77ff5aba337c88278bb9500eb37`. Review those terms,
76
- including their territory and use restrictions, before distributing or using
77
- the model. The community Diffusers conversion did not provide a separate
78
- license file at the pinned base revision.
 
11
 
12
  # DiffusionART HunyuanVideo 7:2:1 — selected step 30
13
 
14
+ This private release is a **full HunyuanVideo transformer**, not a complete
15
+ pipeline or LoRA adapter. It is the selected optimizer-step-30 checkpoint from
16
+ [run `tk1w4go1`](https://wandb.ai/vanzl3386-chinese-university-of-hong-kong-shenzhen/flow-grpo-algo/runs/tk1w4go1).
17
+ The original HunyuanVideo-13B transformer was trained with temporal alignment,
18
+ video quality, and motion quality rewards weighted 0.7 / 0.2 / 0.1, plus a
19
+ frozen pretrained-velocity MSE regularizer with beta 0.1. The transformer is
20
+ stored as F32 safetensors shards. The public base model supplies the VAE, text
21
+ encoders, tokenizers, and scheduler. `release.json` records the source and shard
22
+ hashes; this inference update does not alter those files.
23
 
24
+ ## Requirements
 
 
 
 
 
 
 
25
 
26
+ - Access to this private Hugging Face repository through `HF_TOKEN` or an
27
+ interactive Hugging Face login. The commands keep the login and model cache
28
+ in the chosen work directory. Do not put a token in a script or shell history.
29
+ - Linux x86-64, Python **3.12**, a CUDA 12.1 compatible NVIDIA driver and CUDA
30
+ toolkit (`nvcc`) for building the pinned `flash-attn` version, plus `curl`,
31
+ `tar`, and `sha256sum`.
32
+ - One H800 with **at least 100 GiB available GPU memory** for the verified
33
+ default path. Independent inference used one 140 GiB H800 and peaked at
34
+ 92.39 GiB allocated. Allow at least **100 GiB writable disk space** for the
35
+ private transformer, pinned public base assets, and installation caches.
36
+ `--cpu-offload` is available for constrained GPUs but was not part of the
37
+ independent acceptance run.
38
 
39
+ ## Install and generate one MP4
 
 
 
 
 
 
 
40
 
41
+ The commands use only this release and the fixed **public**
42
+ [`XueZeyue/DanceGRPO`](https://github.com/XueZeyue/DanceGRPO/tree/15cc71d53cc2e6e18a68ee607d5fb6ba9a99e344)
43
+ runtime. No private training repository, saved prompt embeddings, notebook, or
44
+ MPI launcher is needed. Choose a work directory with the required free space.
45
 
46
+ ```bash
47
+ export RUN_DIR="${RUN_DIR:-$PWD/diffusionart-t2v-demo}"
48
+ export HF_HOME="$RUN_DIR/cache/hf"
49
+ export HF_HUB_CACHE="$HF_HOME/hub"
50
+ export PIP_CACHE_DIR="$RUN_DIR/pip-cache"
51
+ export TMPDIR="$RUN_DIR/tmp"
52
+ export XDG_CACHE_HOME="$RUN_DIR/xdg-cache"
53
+ mkdir -p "$RUN_DIR" "$HF_HOME" "$HF_HUB_CACHE" "$PIP_CACHE_DIR" "$TMPDIR" "$XDG_CACHE_HOME"
54
+ cd "$RUN_DIR"
55
+ python3.12 -m venv bootstrap
56
+ bootstrap/bin/python -m pip install 'huggingface-hub==0.26.1'
57
+ if [ -z "${HF_TOKEN:-}" ] && [ ! -f "$HF_HOME/token" ]; then
58
+ bootstrap/bin/huggingface-cli login
59
+ fi
60
+
61
+ # If MODEL_REVISION is already set to a known 40-character commit SHA, keep it.
62
+ # Otherwise resolve main exactly once, then pin every download to that SHA.
63
+ if [ -z "${MODEL_REVISION:-}" ]; then
64
+ MODEL_REVISION="$(bootstrap/bin/python -c 'from huggingface_hub import HfApi; print(HfApi().model_info("vanzl/DiffusionART-HunyuanVideo-7-2-1", token=True).sha)')"
65
+ fi
66
+ export MODEL_REVISION
67
+ printf 'Pinned model revision: %s\n' "$MODEL_REVISION"
68
+
69
+ bootstrap/bin/python - <<'PY'
70
+ import os
71
+ from huggingface_hub import snapshot_download
72
+ snapshot_download(
73
+ repo_id="vanzl/DiffusionART-HunyuanVideo-7-2-1",
74
+ revision=os.environ["MODEL_REVISION"],
75
+ token=True,
76
+ allow_patterns=["README.md", "infer.py", "install.sh", "requirements-inference.txt"],
77
+ local_dir="release",
78
  )
79
+ PY
80
+
81
+ bash release/install.sh "$RUN_DIR/venv" "$RUN_DIR/DanceGRPO-public"
82
+ "$RUN_DIR/venv/bin/python" release/infer.py \
83
+ --revision "$MODEL_REVISION" \
84
+ --prompt 'A white horse gallops through shallow water along a sunlit beach.' \
85
+ --seed 42 \
86
+ --output "$RUN_DIR/horse_seed42.mp4" \
87
+ --cache-dir "$RUN_DIR/cache"
88
  ```
89
 
90
+ `install.sh` installs PyTorch **2.5.0+cu121**, torchvision **0.20.0+cu121**,
91
+ the versions in `requirements-inference.txt`, `flash-attn==2.7.0.post2`,
92
+ `liger-kernel==0.4.1`, and the public DanceGRPO commit
93
+ `15cc71d53cc2e6e18a68ee607d5fb6ba9a99e344`. It verifies the public
94
+ source archive SHA256 before installation. `infer.py` downloads this model at
95
+ `--revision` and the base model at fixed revision
96
+ `e8c2aaa66fe3742a32c11a6766aecbf07c56e773` into `--cache-dir`.
97
+ Pass a different `--prompt`, `--seed`, or `--output` to make another video.
98
+ `infer.py` refuses to overwrite an existing MP4 and validates the generated
99
+ file by decoding every frame.
100
 
101
+ The verified protocol is **640×640, 53 frames, 8 FPS, 30 sampling steps,
102
+ FlowMatchEulerDiscreteScheduler shift 7, eta 0, and no classic CFG**. The
103
+ public pipeline takes `guidance_scale=6.018` as the user-facing value and
104
+ multiplies it by 1000 internally, yielding embedded guidance **6018**. Do not
105
+ pass 6018 as `guidance_scale`. The loader keeps the transformer in F32, runs
106
+ with BF16 autocast, loads both tokenizers from the pinned public base model,
107
+ and enables VAE tiling. The script prints the MP4 SHA256, decoded frame count,
108
+ resolution, FPS, and pixel statistics after a successful run.
109
 
110
+ ## Terms and provenance
111
 
112
+ The package has no optimizer, RNG state, or training code. Tencent's original
113
+ HunyuanVideo weights and derivatives are subject to the **Tencent Hunyuan
114
+ Community License Agreement**. Read the included [LICENSE.txt](LICENSE.txt)
115
+ and [Notice](Notice) before use. The model card and inference helpers do not
116
+ change their terms. The original run was planned for 100 updates but stopped
117
+ at step 40; this release selects step 30 and does not claim 100 updates.
 
 
 
 
infer.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Generate one video with the pinned public HunyuanVideo inference pipeline."""
3
+
4
+ import argparse
5
+ import hashlib
6
+ import json
7
+ import os
8
+ import re
9
+ import sys
10
+ import time
11
+ from pathlib import Path
12
+
13
+
14
+ MODEL_ID = "vanzl/DiffusionART-HunyuanVideo-7-2-1"
15
+ BASE_ID = "hunyuanvideo-community/HunyuanVideo"
16
+ BASE_REVISION = "e8c2aaa66fe3742a32c11a6766aecbf07c56e773"
17
+ FRAMES = 53
18
+ WIDTH = HEIGHT = 640
19
+ FPS = 8
20
+ STEPS = 30
21
+ SHIFT = 7.0
22
+ GUIDANCE_SCALE = 6.018 # The public pipeline multiplies this by 1000.
23
+
24
+
25
+ def arguments():
26
+ parser = argparse.ArgumentParser(description=__doc__)
27
+ parser.add_argument("--prompt", required=True, help="Text prompt for one video")
28
+ parser.add_argument("--seed", type=int, default=42)
29
+ parser.add_argument("--output", required=True, type=Path, help="Output MP4 path")
30
+ parser.add_argument("--cache-dir", required=True, type=Path,
31
+ help="Writable directory for both pinned Hugging Face snapshots and runtime caches")
32
+ parser.add_argument("--revision", required=True,
33
+ help="Exact 40-character commit SHA of the private model release")
34
+ parser.add_argument("--cpu-offload", action="store_true",
35
+ help="Move inactive modules to CPU; the default H800 acceptance did not need this")
36
+ args = parser.parse_args()
37
+ if not args.prompt.strip():
38
+ parser.error("--prompt must contain text")
39
+ if not re.fullmatch(r"[0-9a-f]{40}", args.revision):
40
+ parser.error("--revision must be a fixed 40-character lowercase commit SHA")
41
+ if args.output.suffix.lower() != ".mp4":
42
+ parser.error("--output must end in .mp4")
43
+ if args.output.exists():
44
+ parser.error(f"output already exists: {args.output}")
45
+ return args
46
+
47
+
48
+ def configure_caches(root: Path):
49
+ root.mkdir(parents=True, exist_ok=True)
50
+ hf_home = root / "hf"
51
+ hub = hf_home / "hub"
52
+ for directory in (hf_home, hub, root / "xdg", root / "tmp", root / "triton"):
53
+ directory.mkdir(parents=True, exist_ok=True)
54
+ os.environ.update({
55
+ "HF_HOME": str(hf_home),
56
+ "HF_HUB_CACHE": str(hub),
57
+ "HUGGINGFACE_HUB_CACHE": str(hub),
58
+ "HF_ASSETS_CACHE": str(hf_home / "assets"),
59
+ "XDG_CACHE_HOME": str(root / "xdg"),
60
+ "TMPDIR": str(root / "tmp"),
61
+ "TRITON_CACHE_DIR": str(root / "triton"),
62
+ "TOKENIZERS_PARALLELISM": "false",
63
+ "HF_HUB_DISABLE_TELEMETRY": "1",
64
+ "PYTHONNOUSERSITE": "1",
65
+ })
66
+ return hub
67
+
68
+
69
+ def sha256(path: Path):
70
+ digest = hashlib.sha256()
71
+ with path.open("rb") as source:
72
+ for block in iter(lambda: source.read(16 * 1024 * 1024), b""):
73
+ digest.update(block)
74
+ return digest.hexdigest()
75
+
76
+
77
+ def validate_video(path: Path):
78
+ import av
79
+ import numpy as np
80
+
81
+ frame_count = 0
82
+ pixel_sum = 0.0
83
+ squared_sum = 0.0
84
+ pixel_min = 255
85
+ pixel_max = 0
86
+ with av.open(str(path)) as container:
87
+ streams = [stream for stream in container.streams if stream.type == "video"]
88
+ if len(streams) != 1:
89
+ raise RuntimeError(f"expected one video stream, got {len(streams)}")
90
+ stream = streams[0]
91
+ width, height = stream.width, stream.height
92
+ fps = float(stream.average_rate)
93
+ for frame in container.decode(stream):
94
+ pixels = frame.to_ndarray(format="rgb24")
95
+ if pixels.shape != (HEIGHT, WIDTH, 3):
96
+ raise RuntimeError(f"unexpected frame shape: {pixels.shape}")
97
+ values = pixels.astype(np.float64)
98
+ pixel_sum += float(values.sum())
99
+ squared_sum += float(np.square(values).sum())
100
+ pixel_min = min(pixel_min, int(pixels.min()))
101
+ pixel_max = max(pixel_max, int(pixels.max()))
102
+ frame_count += 1
103
+ if (frame_count, width, height) != (FRAMES, WIDTH, HEIGHT):
104
+ raise RuntimeError(f"unexpected video geometry: {(frame_count, width, height)}")
105
+ if abs(fps - FPS) > 0.01:
106
+ raise RuntimeError(f"unexpected FPS: {fps}")
107
+ count = frame_count * width * height * 3
108
+ mean = pixel_sum / count
109
+ std = max(0.0, squared_sum / count - mean * mean) ** 0.5
110
+ if pixel_max <= pixel_min or pixel_max == 0 or std <= 1.0:
111
+ raise RuntimeError(f"blank or nearly constant video: range={pixel_min}:{pixel_max}, std={std}")
112
+ return {"decoded_frames": frame_count, "width": width, "height": height,
113
+ "fps": fps, "pixel_min": pixel_min, "pixel_max": pixel_max,
114
+ "pixel_mean": mean, "pixel_std": std}
115
+
116
+
117
+ def main():
118
+ args = arguments()
119
+ cache_root = args.cache_dir.expanduser().resolve()
120
+ hub_cache = configure_caches(cache_root)
121
+ output = args.output.expanduser().resolve()
122
+ output.parent.mkdir(parents=True, exist_ok=True)
123
+
124
+ # Import after setting cache variables, so neither library selects a home cache.
125
+ import torch
126
+ from diffusers import FlowMatchEulerDiscreteScheduler
127
+ from diffusers.utils import export_to_video
128
+ from fastvideo.models.hunyuan_hf.pipeline_hunyuan import HunyuanVideoPipeline
129
+ from fastvideo.utils.load import load_transformer
130
+ from huggingface_hub import snapshot_download
131
+
132
+ if not torch.cuda.is_available():
133
+ raise RuntimeError("A CUDA GPU is required")
134
+ if torch.version.cuda != "12.1":
135
+ raise RuntimeError(f"expected the verified PyTorch CUDA 12.1 build, got {torch.version.cuda}")
136
+ model = Path(snapshot_download(MODEL_ID, revision=args.revision,
137
+ cache_dir=str(hub_cache), token=True))
138
+ base = Path(snapshot_download(BASE_ID, revision=BASE_REVISION,
139
+ cache_dir=str(hub_cache)))
140
+ if model.name != args.revision or base.name != BASE_REVISION:
141
+ raise RuntimeError("Hugging Face snapshot revision differs from the requested commit")
142
+
143
+ started = time.perf_counter()
144
+ transformer = load_transformer("hunyuan_hf", str(model / "transformer"),
145
+ str(base), torch.float32)
146
+ if transformer.dtype != torch.float32:
147
+ raise RuntimeError(f"unexpected transformer dtype: {transformer.dtype}")
148
+ # The public base snapshot supplies both text tokenizers and encoders. This
149
+ # preserves the pipeline's default prompt template and avoids saved embeds.
150
+ pipe = HunyuanVideoPipeline.from_pretrained(
151
+ str(base), transformer=transformer, torch_dtype=torch.bfloat16)
152
+ if not isinstance(pipe.scheduler, FlowMatchEulerDiscreteScheduler):
153
+ raise RuntimeError(f"unexpected scheduler: {type(pipe.scheduler).__name__}")
154
+ if abs(float(pipe.scheduler.config.shift) - SHIFT) > 1e-6:
155
+ raise RuntimeError(f"unexpected scheduler shift: {pipe.scheduler.config.shift}")
156
+ pipe.enable_vae_tiling()
157
+ if args.cpu_offload:
158
+ pipe.enable_model_cpu_offload()
159
+ else:
160
+ pipe.to("cuda:0")
161
+ load_seconds = time.perf_counter() - started
162
+
163
+ generator = torch.Generator(device="cpu").manual_seed(args.seed)
164
+ torch.cuda.reset_peak_memory_stats(0)
165
+ started = time.perf_counter()
166
+ with torch.inference_mode(), torch.autocast("cuda", dtype=torch.bfloat16):
167
+ frames = pipe(prompt=[args.prompt], height=HEIGHT, width=WIDTH,
168
+ num_frames=FRAMES, num_inference_steps=STEPS,
169
+ guidance_scale=GUIDANCE_SCALE, generator=generator).frames[0]
170
+ inference_seconds = time.perf_counter() - started
171
+ peak_bytes = torch.cuda.max_memory_allocated(0)
172
+
173
+ partial = output.with_name(f"{output.stem}.partial.{os.getpid()}.mp4")
174
+ try:
175
+ export_to_video(frames, str(partial), fps=FPS)
176
+ del frames
177
+ decoded = validate_video(partial)
178
+ partial.replace(output)
179
+ finally:
180
+ if partial.exists():
181
+ partial.unlink()
182
+ result = {"output": str(output), "sha256": sha256(output),
183
+ "model_revision": args.revision, "base_revision": BASE_REVISION,
184
+ "prompt": args.prompt, "seed": args.seed,
185
+ "sampling": {"frames": FRAMES, "width": WIDTH, "height": HEIGHT,
186
+ "fps": FPS, "steps": STEPS, "shift": SHIFT, "eta": 0,
187
+ "classic_cfg": False, "guidance_scale": GUIDANCE_SCALE,
188
+ "embedded_guidance": 6018},
189
+ "load_seconds": round(load_seconds, 2),
190
+ "inference_seconds": round(inference_seconds, 2),
191
+ "peak_cuda_allocated_bytes": peak_bytes, "decoded": decoded}
192
+ print(json.dumps(result, ensure_ascii=False, indent=2), flush=True)
193
+
194
+
195
+ if __name__ == "__main__":
196
+ try:
197
+ main()
198
+ except Exception as error:
199
+ print(f"inference failed: {error}", file=sys.stderr, flush=True)
200
+ raise
install.sh ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if [[ $# -ne 2 ]]; then
5
+ echo "usage: bash install.sh ABSOLUTE_VENV_DIR ABSOLUTE_PUBLIC_RUNTIME_DIR" >&2
6
+ exit 2
7
+ fi
8
+ VENV_DIR="$1"
9
+ PUBLIC_DIR="$2"
10
+ [[ "$VENV_DIR" = /* && "$PUBLIC_DIR" = /* ]] || {
11
+ echo "Both paths must be absolute." >&2
12
+ exit 2
13
+ }
14
+ [[ ! -e "$VENV_DIR" && ! -e "$PUBLIC_DIR" ]] || {
15
+ echo "Use fresh venv and public-runtime directories." >&2
16
+ exit 2
17
+ }
18
+
19
+ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
20
+ PUBLIC_COMMIT=15cc71d53cc2e6e18a68ee607d5fb6ba9a99e344
21
+ PUBLIC_ARCHIVE_SHA256=65e1e74b26989af16ba2232486d461d500249f69ebaa164eb210b69ed17cb1f6
22
+ WORK_DIR="$(dirname -- "$VENV_DIR")"
23
+ export PYTHONNOUSERSITE=1
24
+ unset PYTHONPATH
25
+ export PIP_CONFIG_FILE=/dev/null
26
+ export PIP_EXTRA_INDEX_URL=
27
+ export PIP_DISABLE_PIP_VERSION_CHECK=1
28
+ export PIP_CACHE_DIR="${PIP_CACHE_DIR:-$WORK_DIR/pip-cache}"
29
+ export TMPDIR="${TMPDIR:-$WORK_DIR/tmp}"
30
+ export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$WORK_DIR/xdg-cache}"
31
+ export MAX_JOBS="${MAX_JOBS:-4}"
32
+ mkdir -p "$PIP_CACHE_DIR" "$TMPDIR" "$XDG_CACHE_HOME" "$(dirname -- "$PUBLIC_DIR")"
33
+
34
+ echo "STAGE create isolated Python 3.12 environment"
35
+ python3.12 -m venv "$VENV_DIR"
36
+ PYTHON="$VENV_DIR/bin/python"
37
+
38
+ echo "STAGE install PyTorch 2.5.0 CUDA 12.1"
39
+ timeout 1800s "$PYTHON" -m pip install --timeout 60 --retries 3 \
40
+ --index-url https://download.pytorch.org/whl/cu121 \
41
+ --extra-index-url https://pypi.org/simple \
42
+ 'torch==2.5.0+cu121' 'torchvision==0.20.0+cu121'
43
+
44
+ echo "STAGE install pinned inference dependencies"
45
+ timeout 1800s "$PYTHON" -m pip install --timeout 60 --retries 3 \
46
+ --index-url https://pypi.org/simple \
47
+ -r "$SCRIPT_DIR/requirements-inference.txt"
48
+
49
+ echo "STAGE fetch fixed public DanceGRPO source"
50
+ ARCHIVE="$WORK_DIR/DanceGRPO-$PUBLIC_COMMIT.tar.gz"
51
+ timeout 600s curl --fail --location --retry 3 --retry-delay 2 \
52
+ "https://github.com/XueZeyue/DanceGRPO/archive/$PUBLIC_COMMIT.tar.gz" \
53
+ --output "$ARCHIVE"
54
+ printf '%s %s\n' "$PUBLIC_ARCHIVE_SHA256" "$ARCHIVE" | sha256sum --check --status
55
+ mkdir "$PUBLIC_DIR"
56
+ tar --extract --gzip --file "$ARCHIVE" --directory "$PUBLIC_DIR" --strip-components=1 \
57
+ --no-same-owner --no-same-permissions
58
+ test -f "$PUBLIC_DIR/fastvideo/models/hunyuan_hf/pipeline_hunyuan.py"
59
+ timeout 600s "$PYTHON" -m pip install --timeout 60 --retries 3 \
60
+ --index-url https://pypi.org/simple --no-deps --editable "$PUBLIC_DIR"
61
+
62
+ echo "STAGE build fixed flash-attn and install required public loader import"
63
+ timeout 3600s "$PYTHON" -m pip install --timeout 60 --retries 3 \
64
+ --index-url https://pypi.org/simple --no-build-isolation 'flash-attn==2.7.0.post2'
65
+ timeout 600s "$PYTHON" -m pip install --timeout 60 --retries 3 \
66
+ --index-url https://pypi.org/simple --no-deps 'liger-kernel==0.4.1'
67
+
68
+ echo "STAGE verify inference imports and installed versions"
69
+ "$PYTHON" - <<'PY'
70
+ import av, diffusers, fastvideo, huggingface_hub, torch, transformers
71
+ from fastvideo.models.hunyuan_hf.pipeline_hunyuan import HunyuanVideoPipeline
72
+ from fastvideo.utils.load import load_transformer
73
+ assert torch.__version__ == '2.5.0+cu121', torch.__version__
74
+ assert torch.version.cuda == '12.1', torch.version.cuda
75
+ assert diffusers.__version__ == '0.32.0', diffusers.__version__
76
+ assert transformers.__version__ == '4.46.1', transformers.__version__
77
+ print('verified:', torch.__version__, diffusers.__version__, transformers.__version__,
78
+ av.__version__, huggingface_hub.__version__, flush=True)
79
+ PY
80
+ echo "INSTALL COMPLETE: $VENV_DIR"
requirements-inference.txt ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Versions used by the independent public-pipeline inference acceptance.
2
+ # PyTorch, the fixed public runtime, flash-attn, and liger-kernel are installed
3
+ # in that order by install.sh because flash-attn builds against PyTorch.
4
+ accelerate==1.0.1
5
+ av==13.1.0
6
+ certifi==2026.7.22
7
+ charset-normalizer==3.5.2
8
+ diffusers==0.32.0
9
+ einops==0.8.0
10
+ filelock==4.0.12
11
+ fsspec==2026.9.0
12
+ hf_transfer==0.1.9
13
+ huggingface-hub==0.26.1
14
+ idna==3.20
15
+ imageio==2.36.0
16
+ imageio-ffmpeg==0.5.1
17
+ importlib_metadata==9.0.1
18
+ Jinja2==3.1.6
19
+ MarkupSafe==3.0.4
20
+ mpmath==1.3.0
21
+ networkx==3.7
22
+ ninja==1.11.1.1
23
+ numpy==1.26.3
24
+ packaging==26.3
25
+ peft==0.13.2
26
+ pillow==10.2.0
27
+ protobuf==5.28.3
28
+ psutil==7.2.2
29
+ PyYAML==6.0.3
30
+ regex==2026.9.29
31
+ requests==2.34.2
32
+ safetensors==0.8.0
33
+ sentencepiece==0.2.0
34
+ setuptools==84.0.0
35
+ sympy==1.13.1
36
+ tokenizers==0.20.3
37
+ typing_extensions==4.16.0
38
+ tqdm==4.70.1
39
+ transformers==4.46.1
40
+ urllib3==2.8.0
41
+ wheel==0.44.0
42
+ zipp==4.1.1