Spaces:
Paused
Paused
Umut Kocasari Claude Opus 4.8 commited on
Commit ·
10fa3d7
1
Parent(s): 4db294e
Pull checkpoint from a HF model repo at startup
Browse filesAdd 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>
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 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
### Environment variables
|
| 74 |
|
| 75 |
| Variable | Default | Purpose |
|
| 76 |
|---|---|---|
|
| 77 |
-
| `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 37 |
#
|
| 38 |
-
#
|
| 39 |
-
#
|
| 40 |
-
#
|
| 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
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 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 |
|