Download scripts/apply_mae_patch.py from quinnlue/mae-cross-objective: direct link, hf CLI and curl.
- Browser
- Download file 4.63 kB
-
https://huggingface.co/quinnlue/mae-cross-objective/resolve/main/scripts/apply_mae_patch.py
- Command line
-
hf download hf://quinnlue/mae-cross-objective/scripts/apply_mae_patch.py
-
curl -L -o apply_mae_patch.py https://huggingface.co/quinnlue/mae-cross-objective/resolve/main/scripts/apply_mae_patch.py
4.63 kB
| """Idempotently graft the MAE objective into the eatmap tree on the VM. | |
| Kept here rather than applied by hand because /workspace is not a volume on this | |
| instance -- workspace_is_volume is False, so a recycle wipes the container | |
| filesystem. This script plus mae.py is the whole change; re-running it on a | |
| fresh box reproduces the tree. | |
| Edits are surgical and leave every EAT code path byte-identical: the objective | |
| dispatch defaults to "ufo", and the two structural fixes (teacher-optional | |
| export, teacher-aware parameter count) are no-ops when a teacher is present. | |
| """ | |
| import sys | |
| from pathlib import Path | |
| ROOT = Path(sys.argv[1] if len(sys.argv) > 1 else "/workspace/code/eat-map-regmix/eatmap") | |
| def patch(path: Path, old: str, new: str, label: str) -> None: | |
| text = path.read_text() | |
| if new in text: | |
| print(f" [skip] {label} (already applied)") | |
| return | |
| if old not in text: | |
| raise SystemExit(f" [FAIL] {label}: anchor not found in {path}") | |
| path.write_text(text.replace(old, new, 1)) | |
| print(f" [ok] {label}") | |
| print(f"patching {ROOT}") | |
| # ---- 1. ObjectiveConfig: objective selector + MAE decoder geometry ---------- | |
| patch( | |
| ROOT / "config.py", | |
| """ # null/0 means "anneal over total_steps" -- never leave this at a value | |
| # larger than the budget or the EMA never reaches its end decay. | |
| ema_anneal_steps: int | None = None""", | |
| """ # null/0 means "anneal over total_steps" -- never leave this at a value | |
| # larger than the budget or the EMA never reaches its end decay. | |
| ema_anneal_steps: int | None = None | |
| # "ufo" is EAT's EMA-teacher objective and the default, so every existing | |
| # config keeps its meaning. "mae" swaps in masked log-mel reconstruction | |
| # over the same encoder -- see eatmap/mae.py for why that sharing matters. | |
| type: str = "ufo" | |
| # Decoder geometry, MAE only. Asymmetric by design: the decoder is thrown | |
| # away after pretraining, so it is narrow and shallow relative to the | |
| # encoder. Defaults are sized for the 384-dim 15M proxy. | |
| mae_decoder_dim: int = 256 | |
| mae_decoder_depth: int = 4 | |
| mae_decoder_heads: int = 8 | |
| # Per-patch target standardization (He et al.'s norm_pix_loss). Off makes | |
| # the loss track patch loudness rather than structure. | |
| mae_norm_pix: bool = True""", | |
| "ObjectiveConfig: type + MAE decoder fields", | |
| ) | |
| # ---- 2. export_weights: teacher is optional -------------------------------- | |
| patch( | |
| ROOT / "runner.py", | |
| """ tensors = {} | |
| for name, tensor in model.student.state_dict().items(): | |
| tensors[f"student.{name}"] = tensor.detach().cpu().contiguous() | |
| for name, tensor in model.teacher.state_dict().items(): | |
| tensors[f"teacher.{name}"] = tensor.detach().cpu().contiguous() | |
| for name, tensor in model.decoder.state_dict().items(): | |
| tensors[f"decoder.{name}"] = tensor.detach().cpu().contiguous()""", | |
| """ tensors = {} | |
| # MAE has no teacher, so the parts are discovered rather than assumed. The | |
| # student is written under the same "student." prefix either way, which is | |
| # what probe.load_encoder keys on -- an MAE export and an EAT export are | |
| # interchangeable to every readout. | |
| for part in ("student", "teacher", "decoder"): | |
| module = getattr(model, part, None) | |
| if module is None: | |
| continue | |
| for name, tensor in module.state_dict().items(): | |
| tensors[f"{part}.{name}"] = tensor.detach().cpu().contiguous()""", | |
| "export_weights: teacher-optional", | |
| ) | |
| # ---- 3. objective dispatch ------------------------------------------------- | |
| patch( | |
| ROOT / "runner.py", | |
| "from .model import EATPretrainer, parameter_counts", | |
| "from .mae import MAEPretrainer\nfrom .model import EATPretrainer, parameter_counts", | |
| "runner: import MAEPretrainer", | |
| ) | |
| patch( | |
| ROOT / "runner.py", | |
| " model = EATPretrainer(config).to(device)", | |
| """ pretrainer = {"ufo": EATPretrainer, "mae": MAEPretrainer}.get(config.objective.type) | |
| if pretrainer is None: | |
| raise ValueError(f"unknown objective.type {config.objective.type!r}") | |
| model = pretrainer(config).to(device)""", | |
| "runner: objective dispatch", | |
| ) | |
| # ---- 4. parameter_counts: only EAT carries a frozen twin ------------------- | |
| patch( | |
| ROOT / "model.py", | |
| """ "total_params": student * 2 + decoder, # teacher is a frozen copy""", | |
| """ # EAT carries a frozen EMA twin of the student; MAE does not. | |
| "total_params": student * (2 if getattr(model, "teacher", None) is not None else 1) + decoder,""", | |
| "parameter_counts: teacher-aware total", | |
| ) | |
| print("done") | |