Merge remote server-edition: cpu-fast lane deploy docs

Both sides extended DEPLOY(_ZH): remote documented the cpu-fast lane (weights subset, config comparison, systemd note, OOM troubleshooting), local added the measured GPU profile and the reuse-off default. Conflict was the capacity-section memory bullet: kept the GPU deployment bullet and remote's cpu-fast-aware memory bullet (which supersedes the old three-models line).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 20:52:57 +08:00
2 changed files with 82 additions and 9 deletions
+44 -5
View File
@@ -143,6 +143,9 @@ Notes:
- **anime-seg**: only `isnetis.onnx` is read; nothing else is required.
- `anime-seg` and `BiRefNet_HR-matting` are optional — omit their folders unless you
use `seg_model=anime-seg` / the cross-check veto respectively.
- The **`cpu-fast` lane** (§6) loads only **ViTMatte + BiRefNet**; on an 8 GB box
using that lane you can skip `anime-seg` and `BiRefNet_HR-matting` entirely.
(`scripts/fetch_weights.py` still fetches all four for full functionality.)
The easiest way to populate the folders is to let `hf download` fetch them (it also
pulls a couple of unused files like `README.md`, which is harmless):
@@ -204,6 +207,32 @@ redirect back to `huggingface.co`, which recent `huggingface_hub` rejects with
| `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` | — | Set to `1` in production once weights are cached |
| `OMP_NUM_THREADS` / `MKL_NUM_THREADS` | — | Cap CPU threads (e.g. `4`) |
### Config file: `default.yaml` vs the `cpu-fast` lane
`BGFILTER_CONFIG` selects the pipeline config. Two are shipped:
- **`configs/default.yaml`** — full quality. Cross-check veto **on** (loads the extra
`BiRefNet_HR-matting` at 2048 as a second opinion), best edges. Heavier: on large
inputs the peak working set runs well into double-digit GB, so it wants a roomy box
(or a GPU).
- **`configs/cpu-fast.yaml`** — the lean CPU lane, tuned for an **8 GB box**. fp32,
BiRefNet segmentation only, **no cross-check, no anime-seg**, chunked attention
(`attn_query_chunk: 512`). Loads only **two** weights (base ViTMatte + BiRefNet).
Measured peak working set: **~5.6 GB @ 2048×1152 (2.4 MP)**, ~7.1 GB @ 2048×2048
(4.2 MP); ~14–15 s per 1.5 MP image.
> **On a ≤8 GB server, set `BGFILTER_CONFIG=configs/cpu-fast.yaml`.** The default lane
> plus a large input is exactly what drives ViTMatte's attention transient into an
> OOM — the worker is killed (SIGKILL) and a fronting nginx returns **502** while the
> app log shows `DefaultCPUAllocator: can't allocate memory`.
Two model knobs live in the **config file** (`model:` section), not env vars:
| Config key | Default | Purpose |
| --- | --- | --- |
| `model.precision` | `fp32` | `fp32` or `bf16`. bf16 is used **only** on hardware with native kernels (CUDA, or a CPU with AVX512-BF16/AMX); otherwise it warns and falls back to fp32. Also settable per model under `segmentation:` / `cross_check:`. |
| `model.attn_query_chunk` | `2048` | Query-row chunk for ViTMatte's global attention. Smaller (e.g. `512`) caps the O(N²) memory transient for a few % more compute; output is bit-for-bit identical. `0` disables chunking (stock one-shot attention). |
## 7. Run the service
```bash
@@ -252,6 +281,10 @@ ReadWritePaths=/opt/genarrative-image-host
WantedBy=multi-user.target
```
On a ≤8 GB box, change the config line to the lean lane:
`Environment=BGFILTER_CONFIG=configs/cpu-fast.yaml` (see §6) — the default lane can
OOM on large inputs.
If you use Option B (local `models/` folders) instead of the HF cache, drop the
`HF_HOME`/offline lines — those weights need no cache or network.
@@ -285,9 +318,10 @@ service has **no authentication**. To reach it from other hosts:
## 11. Capacity & performance
- CPU throughput is ~**45 s per 1.5 MP image** with the default (base ViTMatte +
BiRefNet); requests are serialized by the global lock, so ~1–2 images/min per
instance. Bottleneck is full-resolution ViTMatte + pymatting foreground estimation.
- CPU throughput: the **`cpu-fast` lane** does ~**14–15 s per 1.5 MP image** (base
ViTMatte + one BiRefNet@1024, chunked attention). The **default lane** is slower —
the cross-check adds a second HR-matting@2048 forward. Requests are serialized by
the global lock, so plan for a handful of images/min per instance.
- For throughput: use a GPU (`BGFILTER_DEVICE=cuda`, install a CUDA torch build) —
roughly an order of magnitude faster — and/or run multiple instances behind a load
balancer (each with `--workers 1`).
@@ -303,8 +337,11 @@ service has **no authentication**. To reach it from other hosts:
expandable segments (e.g. native Windows) reserved is ~15.3–16.2 GB:
borderline-to-overflow on a 16 GB card. Precision `bf16` is what makes 16 GB
viable at all — fp32 reserved ~17 GB overflows.
- Memory: one worker holds all three models (~1 GB weights + runtime). `MemoryMax=8G`
is a safe ceiling for a single CPU worker.
- Memory: chunked attention (`attn_query_chunk`) caps ViTMatte's O(N²) transient, so
the peak is set by dense compute, not the attention map. On the `cpu-fast` lane the
measured peak is **~5.6 GB @ 2.4 MP / ~7.1 GB @ 4.2 MP** — `MemoryMax=8G` with the
default 4 MP input cap is a safe ceiling for a single CPU worker. The default lane
(cross-check on) needs more headroom.
- **Keeping RSS flat (glibc).** After each image the service calls glibc
`malloc_trim(0)` (`bgfilter/memtune.py`) to hand a large BiRefNet@2048 forward's
freed activations back to the OS — without it, ptmalloc keeps them in the arena
@@ -333,4 +370,6 @@ service has **no authentication**. To reach it from other hosts:
| `503 service not ready` | Models still loading at startup; wait for "Application startup complete". |
| `500 inference failed` right after enabling `BGFILTER_CROSS_CHECK` (offline) | `BiRefNet_HR-matting` not provisioned; download it into the cache/`models/` (§5). |
| OOM / killed under load | More than one worker, or `MemoryMax` too low. Keep `--workers 1`. |
| Worker `killed` (SIGKILL) / `502` on a large image; log shows `DefaultCPUAllocator: can't allocate memory` | ViTMatte OOM on a big input. Use `BGFILTER_CONFIG=configs/cpu-fast.yaml` (§6), and/or lower `BGFILTER_MAX_IMAGE_PIXELS`. |
| `413`/large upload rejected at the proxy | nginx `client_max_body_size` (default 1 MB) — raise it in the server block (e.g. `client_max_body_size 12m;`); this is separate from the app's `BGFILTER_MAX_IMAGE_PIXELS`. |
| `400 could not auto-detect background colour` | Input has no clean flat border; pass `screen_color=#RRGGBB`. |