Umut Kocasari Claude Opus 4.8 commited on
Commit
10fa3d7
·
1 Parent(s): 4db294e

Pull checkpoint from a HF model repo at startup

Browse files

Add FACEANYTHING_CHECKPOINT_REPO (+ _FILE/_REPO_TYPE/_REVISION, HF_TOKEN) so the
~15 GB checkpoint lives in a separate HF model repo and is fetched once via
hf_hub_download on the CPU node at startup (never spending ZeroGPU seconds).
Falls back to an explicit local path or checkpoints/checkpoint.pt. README documents
the recommended storage + Persistent Storage / HF_HOME setup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (2) hide show
  1. README.md +47 -21
  2. app.py +57 -15
README.md CHANGED
@@ -49,32 +49,58 @@ tracks, output FPS, and a frame cap.
49
 
50
  The Gradio code (`app.py`) and the model source (`src/faceanything`,
51
  `src/depth_anything_3`) are included here. To make the Space runnable you still
52
- need the **checkpoint** (~15 GB), which is not committed:
53
-
54
- 1. Add the checkpoint with Git LFS at `checkpoints/checkpoint.pt`:
55
- ```bash
56
- git lfs install
57
- git lfs track "checkpoints/*.pt"
58
- mkdir -p checkpoints
59
- # copy or download checkpoint.pt into checkpoints/
60
- git add .gitattributes checkpoints/checkpoint.pt
61
- ```
62
- Or point the app elsewhere with the `FACEANYTHING_CHECKPOINT` env var (Space
63
- *Settings → Variables and secrets*), or fetch it at startup.
64
-
65
- 2. Pick the hardware. This needs a CUDA GPU. On **ZeroGPU**, `@spaces.GPU` is used
66
- automatically; raise `FACEANYTHING_GPU_DURATION` (seconds, default 180) if long
67
- clips time out. On a dedicated GPU Space, `spaces` degrades to a no-op.
68
-
69
- 3. The DA3 backbone config/architecture is pulled from the public model
70
- `depth-anything/DA3-GIANT-1.1` on first run (its weights are then overwritten by
71
- the checkpoint). Set `HF_HOME` to reuse a local cache.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  ### Environment variables
74
 
75
  | Variable | Default | Purpose |
76
  |---|---|---|
77
- | `FACEANYTHING_CHECKPOINT` | `checkpoints/checkpoint.pt` | path to the weights |
 
 
 
 
 
78
  | `FACEANYTHING_ROOT` | the app dir | root holding `src/` and `checkpoints/` |
79
  | `FACEANYTHING_BASE_MODEL` | `depth-anything/DA3-GIANT-1.1` | DA3 backbone id |
80
  | `FACEANYTHING_GPU_DURATION` | `180` | ZeroGPU seconds per request |
 
49
 
50
  The Gradio code (`app.py`) and the model source (`src/faceanything`,
51
  `src/depth_anything_3`) are included here. To make the Space runnable you still
52
+ need the **checkpoint** (~15 GB), which is not committed.
53
+
54
+ ### Checkpoint storage (recommended: a separate HF model repo)
55
+
56
+ Don't commit 15 GB into the Space repo. Upload the checkpoint to its own Hugging
57
+ Face **model** repo once, and let the app pull it at startup:
58
+
59
+ ```bash
60
+ # one-time upload (make the repo private and add an HF_TOKEN secret if you like)
61
+ hf upload UmutKocasari/FaceAnything-weights /path/to/checkpoint.pt checkpoint.pt --repo-type=model
62
+ ```
63
+
64
+ Then set on the Space (*Settings → Variables and secrets*):
65
+
66
+ ```
67
+ FACEANYTHING_CHECKPOINT_REPO = UmutKocasari/FaceAnything-weights
68
+ HF_TOKEN = hf_... # only if the repo is private
69
+ HF_HOME = /data/.huggingface # with Persistent Storage enabled (see below)
70
+ ```
71
+
72
+ `hf_hub_download` caches the file, so it transfers once (and is HF-internal, so
73
+ fast). The app resolves the checkpoint at **startup on the CPU node**, so the
74
+ download never eats into ZeroGPU compute time.
75
+
76
+ **Enable Persistent Storage** on the Space and point `HF_HOME` at it
77
+ (`/data/.huggingface`) so the 15 GB cache survives restarts instead of
78
+ re-downloading on every cold start.
79
+
80
+ *Alternatives:* commit it via Git LFS at `checkpoints/checkpoint.pt` (simplest,
81
+ but bloats the Space repo and slows clones — fine only if you accept that), or
82
+ set `FACEANYTHING_CHECKPOINT` to an already-present local path.
83
+
84
+ ### Hardware
85
+
86
+ This needs a CUDA GPU. On **ZeroGPU**, `@spaces.GPU` is used automatically; raise
87
+ `FACEANYTHING_GPU_DURATION` (seconds, default 180) if long clips time out. On a
88
+ dedicated GPU Space, `spaces` degrades to a no-op.
89
+
90
+ The DA3 backbone config/architecture is pulled from the public model
91
+ `depth-anything/DA3-GIANT-1.1` on first run (its weights are then overwritten by
92
+ the checkpoint); it lands in the same `HF_HOME` cache.
93
 
94
  ### Environment variables
95
 
96
  | Variable | Default | Purpose |
97
  |---|---|---|
98
+ | `FACEANYTHING_CHECKPOINT_REPO` | | HF repo id to download the checkpoint from |
99
+ | `FACEANYTHING_CHECKPOINT_FILE` | `checkpoint.pt` | filename within that repo |
100
+ | `FACEANYTHING_CHECKPOINT_REPO_TYPE` | `model` | `model` / `dataset` / `space` |
101
+ | `FACEANYTHING_CHECKPOINT_REVISION` | — | branch/tag/commit to pin |
102
+ | `HF_TOKEN` | — | token for a private checkpoint repo |
103
+ | `FACEANYTHING_CHECKPOINT` | `checkpoints/checkpoint.pt` | explicit local path (overrides the repo download if it exists) |
104
  | `FACEANYTHING_ROOT` | the app dir | root holding `src/` and `checkpoints/` |
105
  | `FACEANYTHING_BASE_MODEL` | `depth-anything/DA3-GIANT-1.1` | DA3 backbone id |
106
  | `FACEANYTHING_GPU_DURATION` | `180` | ZeroGPU seconds per request |
app.py CHANGED
@@ -33,12 +33,11 @@ import numpy as np
33
 
34
 
35
  # --------------------------------------------------------------------------- #
36
- # Locate the published FaceAnything source + checkpoint.
37
  #
38
- # For a real deployment, vendor the model code and weights into this Space:
39
- # * copy the source repo's `src/` here (or `pip install` the package), and
40
- # * place the checkpoint at `checkpoints/checkpoint.pt` (Git LFS).
41
- # For local testing against the source checkout, point FACEANYTHING_ROOT at it:
42
  # export FACEANYTHING_ROOT=/cluster/eriador/ukocasari/projects/FaceAnything
43
  # --------------------------------------------------------------------------- #
44
  APP_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -59,14 +58,59 @@ def _ensure_faceanything_importable():
59
 
60
  _ensure_faceanything_importable()
61
 
62
- CHECKPOINT = os.environ.get(
63
- "FACEANYTHING_CHECKPOINT", os.path.join(FA_ROOT, "checkpoints", "checkpoint.pt")
64
- )
65
  BASE_MODEL = os.environ.get("FACEANYTHING_BASE_MODEL", "depth-anything/DA3-GIANT-1.1")
66
  GPU_DURATION = int(os.environ.get("FACEANYTHING_GPU_DURATION", "180"))
67
  MAX_IMAGES = int(os.environ.get("FACEANYTHING_MAX_IMAGES", "40"))
68
 
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  # --------------------------------------------------------------------------- #
71
  # ZeroGPU decorator — falls back to a no-op when `spaces` is unavailable
72
  # (e.g. running on a plain GPU box / cluster), so the same file runs anywhere.
@@ -98,17 +142,15 @@ _MODEL_DEVICE = None
98
 
99
 
100
  def _get_model(device: str):
101
- global _MODEL, _MODEL_DEVICE
102
  if _MODEL is not None and _MODEL_DEVICE == device:
103
  return _MODEL
104
  from faceanything.model import load_model
105
 
106
- if not os.path.exists(CHECKPOINT):
107
- raise FileNotFoundError(
108
- f"Checkpoint not found at '{CHECKPOINT}'. Set FACEANYTHING_CHECKPOINT or "
109
- f"place checkpoint.pt under checkpoints/ (see README)."
110
- )
111
- _MODEL = load_model(CHECKPOINT, base_model=BASE_MODEL, device=device)
112
  _MODEL_DEVICE = device
113
  return _MODEL
114
 
 
33
 
34
 
35
  # --------------------------------------------------------------------------- #
36
+ # Locate the published FaceAnything source.
37
  #
38
+ # The model code (`src/faceanything`, `src/depth_anything_3`) is vendored into
39
+ # this Space. For local testing against a source checkout, point FACEANYTHING_ROOT
40
+ # at it instead:
 
41
  # export FACEANYTHING_ROOT=/cluster/eriador/ukocasari/projects/FaceAnything
42
  # --------------------------------------------------------------------------- #
43
  APP_DIR = os.path.dirname(os.path.abspath(__file__))
 
58
 
59
  _ensure_faceanything_importable()
60
 
 
 
 
61
  BASE_MODEL = os.environ.get("FACEANYTHING_BASE_MODEL", "depth-anything/DA3-GIANT-1.1")
62
  GPU_DURATION = int(os.environ.get("FACEANYTHING_GPU_DURATION", "180"))
63
  MAX_IMAGES = int(os.environ.get("FACEANYTHING_MAX_IMAGES", "40"))
64
 
65
 
66
+ # --------------------------------------------------------------------------- #
67
+ # Checkpoint (~15 GB). Recommended storage: a separate HF *model* repo, pulled
68
+ # once with `hf_hub_download` and cached (point HF_HOME at persistent storage,
69
+ # e.g. /data/.huggingface, so it survives restarts). Resolution order:
70
+ # 1. FACEANYTHING_CHECKPOINT — an explicit local file (used if it exists)
71
+ # 2. FACEANYTHING_CHECKPOINT_REPO — download <FILE> from this HF repo
72
+ # (private repos: set the HF_TOKEN secret)
73
+ # 3. checkpoints/checkpoint.pt next to the app (e.g. committed via Git LFS)
74
+ # --------------------------------------------------------------------------- #
75
+ def _resolve_checkpoint():
76
+ explicit = os.environ.get("FACEANYTHING_CHECKPOINT")
77
+ if explicit and os.path.exists(explicit):
78
+ return explicit
79
+
80
+ repo = os.environ.get("FACEANYTHING_CHECKPOINT_REPO")
81
+ if repo:
82
+ from huggingface_hub import hf_hub_download
83
+
84
+ return hf_hub_download(
85
+ repo_id=repo,
86
+ filename=os.environ.get("FACEANYTHING_CHECKPOINT_FILE", "checkpoint.pt"),
87
+ repo_type=os.environ.get("FACEANYTHING_CHECKPOINT_REPO_TYPE", "model"),
88
+ revision=os.environ.get("FACEANYTHING_CHECKPOINT_REVISION") or None,
89
+ token=os.environ.get("HF_TOKEN") or None,
90
+ )
91
+
92
+ default = os.path.join(FA_ROOT, "checkpoints", "checkpoint.pt")
93
+ if os.path.exists(default):
94
+ return default
95
+
96
+ raise FileNotFoundError(
97
+ "No checkpoint found. Set FACEANYTHING_CHECKPOINT to a local file, or "
98
+ "FACEANYTHING_CHECKPOINT_REPO to a Hugging Face repo id (add the HF_TOKEN "
99
+ "secret if it is private), or place checkpoint.pt under checkpoints/."
100
+ )
101
+
102
+
103
+ # Resolve (and download, if from a repo) at startup — on the CPU node, so the
104
+ # 15 GB transfer never counts against ZeroGPU compute time. A failure here is
105
+ # non-fatal: the UI still builds and the clear error surfaces on first run.
106
+ try:
107
+ CHECKPOINT = _resolve_checkpoint()
108
+ print(f"[faceanything] checkpoint ready: {CHECKPOINT}", flush=True)
109
+ except Exception as _ckpt_err: # noqa: BLE001
110
+ CHECKPOINT = None
111
+ print(f"[faceanything] checkpoint not ready yet: {_ckpt_err}", flush=True)
112
+
113
+
114
  # --------------------------------------------------------------------------- #
115
  # ZeroGPU decorator — falls back to a no-op when `spaces` is unavailable
116
  # (e.g. running on a plain GPU box / cluster), so the same file runs anywhere.
 
142
 
143
 
144
  def _get_model(device: str):
145
+ global _MODEL, _MODEL_DEVICE, CHECKPOINT
146
  if _MODEL is not None and _MODEL_DEVICE == device:
147
  return _MODEL
148
  from faceanything.model import load_model
149
 
150
+ # Re-resolve if the startup attempt failed (e.g. env was set afterwards).
151
+ ckpt = CHECKPOINT or _resolve_checkpoint()
152
+ CHECKPOINT = ckpt
153
+ _MODEL = load_model(ckpt, base_model=BASE_MODEL, device=device)
 
 
154
  _MODEL_DEVICE = device
155
  return _MODEL
156