Skip to content

Commit f7c4f08

Browse files
committed
Merge remote-tracking branch 'origin/main' into klin/5090-test-scripts
2 parents 2c4ad17 + 8208536 commit f7c4f08

1,032 files changed

Lines changed: 84125 additions & 31152 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/add-model-01-prep/scripts/clone_reference_repo.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010

1111

1212
def parse_args() -> argparse.Namespace:
13-
parser = argparse.ArgumentParser(
14-
description="Clone a reference repo for FastVideo parity tests."
15-
)
13+
parser = argparse.ArgumentParser(description="Clone a reference repo for FastVideo parity tests.")
1614
parser.add_argument("repo_url", help="Official reference repository URL")
1715
parser.add_argument("target_dir", help="Directory to clone into")
1816
parser.add_argument("--branch", help="Branch or tag to clone")
@@ -62,9 +60,7 @@ def gitignore_entry_for(target: Path) -> str:
6260
try:
6361
relative = resolved.relative_to(root)
6462
except ValueError as exc:
65-
raise ValueError(
66-
"--update-gitignore requires target_dir to be under the current directory"
67-
) from exc
63+
raise ValueError("--update-gitignore requires target_dir to be under the current directory") from exc
6864

6965
text = relative.as_posix().rstrip("/")
7066
return "/" + text + "/"

.agents/skills/add-model-01-prep/scripts/download_hf_weights.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
import sys
99
from pathlib import Path
1010

11-
1211
HF_TOKEN_ENV_KEYS = ("HF_TOKEN", "HUGGINGFACE_HUB_TOKEN", "HF_API_KEY")
1312

1413

1514
def parse_args() -> argparse.Namespace:
1615
parser = argparse.ArgumentParser(
17-
description="Download a HF model snapshot or selected files into a local directory."
18-
)
16+
description="Download a HF model snapshot or selected files into a local directory.")
1917
parser.add_argument("repo_id", help="HF repo id, for example Org/Model")
2018
parser.add_argument("local_dir", help="Destination directory")
2119
parser.add_argument("--repo-type", default="model", help="HF repo type (default: model)")

.agents/skills/add-model-01-prep/scripts/inspect_hf_layout.py

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from pathlib import Path
1111
from typing import Any
1212

13-
1413
HF_TOKEN_ENV_KEYS = ("HF_TOKEN", "HUGGINGFACE_HUB_TOKEN", "HF_API_KEY")
1514
RAW_WEIGHT_SUFFIXES = (".safetensors", ".pt", ".pth", ".ckpt", ".bin")
1615
KNOWN_COMPONENTS = {
@@ -34,8 +33,7 @@
3433

3534
def parse_args() -> argparse.Namespace:
3635
parser = argparse.ArgumentParser(
37-
description="Classify a HF repo or local directory as Diffusers, raw, custom, or unknown."
38-
)
36+
description="Classify a HF repo or local directory as Diffusers, raw, custom, or unknown.")
3937
parser.add_argument("source", help="HF repo id or local weights directory")
4038
parser.add_argument("--repo-type", default="model", help="HF repo type (default: model)")
4139
parser.add_argument("--revision", help="HF revision to inspect")
@@ -94,14 +92,12 @@ def load_remote_files(
9492
) -> list[str]:
9593
from huggingface_hub import list_repo_files
9694

97-
return sorted(
98-
list_repo_files(
99-
repo_id,
100-
repo_type=repo_type,
101-
revision=revision,
102-
token=token,
103-
)
104-
)
95+
return sorted(list_repo_files(
96+
repo_id,
97+
repo_type=repo_type,
98+
revision=revision,
99+
token=token,
100+
))
105101

106102

107103
def load_remote_model_index(
@@ -215,24 +211,24 @@ def build_result(args: argparse.Namespace) -> dict[str, Any]:
215211
"components_seen": components,
216212
"file_count": len(files),
217213
"file_scan_truncated": truncated,
218-
"files_sample": files[: args.sample_limit],
214+
"files_sample": files[:args.sample_limit],
219215
}
220216

221217

222218
def print_human(result: dict[str, Any]) -> None:
223219
for key in (
224-
"source",
225-
"source_kind",
226-
"repo_type",
227-
"revision",
228-
"token_env",
229-
"source_layout",
230-
"needs_conversion",
231-
"model_index_class",
232-
"model_index_diffusers_version",
233-
"model_index_error",
234-
"file_count",
235-
"file_scan_truncated",
220+
"source",
221+
"source_kind",
222+
"repo_type",
223+
"revision",
224+
"token_env",
225+
"source_layout",
226+
"needs_conversion",
227+
"model_index_class",
228+
"model_index_diffusers_version",
229+
"model_index_error",
230+
"file_count",
231+
"file_scan_truncated",
236232
):
237233
value = result.get(key)
238234
if value is not None:

.agents/skills/add-model-02-parity/templates/component_parity_test.py

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import torch
1919
from torch.testing import assert_close
2020

21-
2221
os.environ.setdefault("MASTER_ADDR", "localhost")
2322
os.environ.setdefault("MASTER_PORT", "29519")
2423
os.environ.setdefault("DISABLE_SP", "1")
@@ -35,15 +34,10 @@
3534
FASTVIDEO_MODEL_MODULE = "fastvideo.models.<bucket>.<module>" # TODO.
3635
FASTVIDEO_MODEL_CLASS = "<FastVideoModel>" # TODO.
3736

38-
OFFICIAL_REF_DIR = Path(
39-
os.getenv("<FAMILY_UPPER>_OFFICIAL_REF_DIR", REPO_ROOT / "<ReferenceDir>")
40-
)
41-
LOCAL_WEIGHTS_DIR = Path(
42-
os.getenv("<FAMILY_UPPER>_LOCAL_WEIGHTS_DIR", REPO_ROOT / "official_weights" / FAMILY)
43-
)
44-
CONVERTED_WEIGHTS_DIR = Path(
45-
os.getenv("<FAMILY_UPPER>_CONVERTED_WEIGHTS_DIR", REPO_ROOT / "converted_weights" / FAMILY)
46-
)
37+
OFFICIAL_REF_DIR = Path(os.getenv("<FAMILY_UPPER>_OFFICIAL_REF_DIR", REPO_ROOT / "<ReferenceDir>"))
38+
LOCAL_WEIGHTS_DIR = Path(os.getenv("<FAMILY_UPPER>_LOCAL_WEIGHTS_DIR", REPO_ROOT / "official_weights" / FAMILY))
39+
CONVERTED_WEIGHTS_DIR = Path(os.getenv("<FAMILY_UPPER>_CONVERTED_WEIGHTS_DIR",
40+
REPO_ROOT / "converted_weights" / FAMILY))
4741

4842

4943
def _resolve_hf_token() -> str | None:
@@ -99,18 +93,14 @@ def _load_official_model(device: torch.device, dtype: torch.dtype) -> torch.nn.M
9993
model = OfficialClass() # TODO: pass official config kwargs.
10094
state_dict = {} # TODO: load official state dict from LOCAL_WEIGHTS_DIR.
10195
missing, unexpected = model.load_state_dict(state_dict, strict=True)
102-
assert not missing and not unexpected, (
103-
f"official load mismatch missing={missing[:5]} unexpected={unexpected[:5]}"
104-
)
96+
assert not missing and not unexpected, (f"official load mismatch missing={missing[:5]} unexpected={unexpected[:5]}")
10597
return model.to(device=device, dtype=dtype).eval()
10698

10799

108100
def _load_fastvideo_model(device: torch.device, dtype: torch.dtype) -> torch.nn.Module:
109101
"""Load the FastVideo component with the same tensor content."""
110102
if not CONVERTED_WEIGHTS_DIR.exists() and not LOCAL_WEIGHTS_DIR.exists():
111-
pytest.skip(
112-
f"No FastVideo loadable weights: {CONVERTED_WEIGHTS_DIR} or {LOCAL_WEIGHTS_DIR}"
113-
)
103+
pytest.skip(f"No FastVideo loadable weights: {CONVERTED_WEIGHTS_DIR} or {LOCAL_WEIGHTS_DIR}")
114104

115105
# TODO: replace with the bucket-specific FastVideo config/class/loader.
116106
# DiT examples:
@@ -127,8 +117,7 @@ def _load_fastvideo_model(device: torch.device, dtype: torch.dtype) -> torch.nn.
127117
state_dict = {} # TODO: load converted or directly mapped state dict.
128118
missing, unexpected = model.load_state_dict(state_dict, strict=True)
129119
assert not missing and not unexpected, (
130-
f"FastVideo load mismatch missing={missing[:5]} unexpected={unexpected[:5]}"
131-
)
120+
f"FastVideo load mismatch missing={missing[:5]} unexpected={unexpected[:5]}")
132121
return model.to(device=device, dtype=dtype).eval()
133122

134123

@@ -187,11 +176,9 @@ def test_component_parity():
187176

188177
assert official_out.shape == fastvideo_out.shape
189178
diff = (official_out - fastvideo_out).abs()
190-
print(
191-
f"official abs_mean={official_out.abs().mean().item():.6f} "
192-
f"fastvideo abs_mean={fastvideo_out.abs().mean().item():.6f} "
193-
f"diff_max={diff.max().item():.6f} diff_mean={diff.mean().item():.6f}"
194-
)
179+
print(f"official abs_mean={official_out.abs().mean().item():.6f} "
180+
f"fastvideo abs_mean={fastvideo_out.abs().mean().item():.6f} "
181+
f"diff_max={diff.max().item():.6f} diff_mean={diff.mean().item():.6f}")
195182

196183
# TODO: pick tolerance by scope:
197184
# - single block / same kernel: 1e-4

.agents/skills/add-model-07-conversion/templates/family_to_diffusers.py

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
except ImportError: # pragma: no cover - optional local conversion dependency
2828
snapshot_download = None
2929

30-
3130
# TODO: fill with authoritative component prefixes for monolithic checkpoints.
3231
# Example: {"model.model.": "transformer", "pretransform.model.": "vae"}
3332
COMPONENT_PREFIXES: dict[str, str] = {}
@@ -47,10 +46,7 @@
4746

4847

4948
def _hf_token() -> str | None:
50-
return (
51-
os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_HUB_TOKEN")
52-
or os.environ.get("HF_API_KEY")
53-
)
49+
return (os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_HUB_TOKEN") or os.environ.get("HF_API_KEY"))
5450

5551

5652
def resolve_src(src: str, revision: str | None) -> Path:
@@ -95,11 +91,10 @@ def apply_mapping(key: str) -> str | None:
9591
return key
9692

9793

98-
def split_monolithic(
99-
state: dict[str, torch.Tensor],
100-
) -> dict[str, OrderedDict[str, torch.Tensor]]:
94+
def split_monolithic(state: dict[str, torch.Tensor], ) -> dict[str, OrderedDict[str, torch.Tensor]]:
10195
components: dict[str, OrderedDict[str, torch.Tensor]] = {
102-
name: OrderedDict() for name in set(COMPONENT_PREFIXES.values())
96+
name: OrderedDict()
97+
for name in set(COMPONENT_PREFIXES.values())
10398
}
10499
intentionally_skipped: list[str] = []
105100
unowned: list[str] = []
@@ -117,10 +112,8 @@ def split_monolithic(
117112
unowned.append(key)
118113
if unowned:
119114
sample = ", ".join(unowned[:10])
120-
raise ValueError(
121-
f"Unowned monolithic keys: {len(unowned)}. "
122-
f"Add COMPONENT_PREFIXES or SKIP_PATTERNS entries. Sample: {sample}"
123-
)
115+
raise ValueError(f"Unowned monolithic keys: {len(unowned)}. "
116+
f"Add COMPONENT_PREFIXES or SKIP_PATTERNS entries. Sample: {sample}")
124117
if intentionally_skipped:
125118
print(f"Intentionally skipped {len(intentionally_skipped)} keys")
126119
return {name: weights for name, weights in components.items() if weights}
@@ -143,8 +136,12 @@ def build_component_configs(_src_dir: Path) -> dict[str, dict[str, Any]]:
143136
# TODO: emit config content accepted by FastVideo loaders. Most components use
144137
# config.json; schedulers use scheduler_config.json.
145138
return {
146-
"transformer": {"_class_name": "<FastVideoTransformerClass>"},
147-
"vae": {"_class_name": "<FastVideoVAEClass>"},
139+
"transformer": {
140+
"_class_name": "<FastVideoTransformerClass>"
141+
},
142+
"vae": {
143+
"_class_name": "<FastVideoVAEClass>"
144+
},
148145
}
149146

150147

@@ -177,19 +174,13 @@ def build_model_index(
177174
}
178175
if revision:
179176
index["_fastvideo_converted_revision"] = revision
180-
return {
181-
key: value
182-
for key, value in index.items()
183-
if key.startswith("_") or key in available_components
184-
}
177+
return {key: value for key, value in index.items() if key.startswith("_") or key in available_components}
185178

186179

187180
def validate_component_configs(configs: dict[str, dict[str, Any]]) -> None:
188181
# TODO: instantiate each FastVideo config and call update_model_arch(...) or
189182
# update_model_config(...) with this JSON so unknown emitted keys fail here.
190-
placeholder_configs = [
191-
name for name, config in configs.items() if "<" in json.dumps(config)
192-
]
183+
placeholder_configs = [name for name, config in configs.items() if "<" in json.dumps(config)]
193184
if placeholder_configs:
194185
raise ValueError(f"Replace config placeholders for: {placeholder_configs}")
195186

@@ -201,9 +192,7 @@ def verify_conversion(
201192
del dst_dir, components
202193
# TODO: load each emitted stateful component through its production loader and
203194
# assert strict load, or document exact allowed missing/unexpected keys.
204-
raise NotImplementedError(
205-
"Implement production config validation and strict-load checks"
206-
)
195+
raise NotImplementedError("Implement production config validation and strict-load checks")
207196

208197

209198
def write_component(
@@ -216,9 +205,7 @@ def write_component(
216205
if component_dir.exists() and any(component_dir.iterdir()):
217206
shutil.rmtree(component_dir)
218207
component_dir.mkdir(parents=True, exist_ok=True)
219-
save_file(
220-
dict(state), str(component_dir / "diffusion_pytorch_model.safetensors")
221-
)
208+
save_file(dict(state), str(component_dir / "diffusion_pytorch_model.safetensors"))
222209
if config is not None:
223210
config_path = component_dir / config_filename(name)
224211
with config_path.open("w", encoding="utf-8") as f:
@@ -261,19 +248,15 @@ def convert(
261248

262249
if layout in {"monolithic", "raw_official"}:
263250
# TODO: replace model.safetensors with the official monolithic file name.
264-
components = split_monolithic(
265-
load_checkpoint(default_monolithic_checkpoint(src_path))
266-
)
251+
components = split_monolithic(load_checkpoint(default_monolithic_checkpoint(src_path)))
267252
elif layout in {"separate_components", "mixed"}:
268253
if not src_path.is_dir():
269254
raise ValueError(f"{layout} layout requires a source directory: {src_path}")
270255
components = load_separate_components(src_path)
271256
else:
272257
raise ValueError(f"Unsupported template layout: {layout}")
273258

274-
copied = (
275-
copy_passthrough(src_path, dst_dir) if src_path.is_dir() else []
276-
)
259+
copied = (copy_passthrough(src_path, dst_dir) if src_path.is_dir() else [])
277260
configs = build_component_configs(src_path if src_path.is_dir() else src_path.parent)
278261
validate_component_configs(configs)
279262
for name, state in components.items():
@@ -289,9 +272,7 @@ def convert(
289272

290273
def main() -> None:
291274
parser = argparse.ArgumentParser(description=__doc__)
292-
parser.add_argument(
293-
"--src", required=True, help="HF repo id, local dir, or checkpoint path"
294-
)
275+
parser.add_argument("--src", required=True, help="HF repo id, local dir, or checkpoint path")
295276
parser.add_argument("--revision", help="HF branch, tag, or commit for repo sources")
296277
parser.add_argument(
297278
"--dst",

0 commit comments

Comments
 (0)