Default reuse-as-seg OFF; default expandable_segments on Linux/WSL

Two default flips for server-edition:

1. cross_check.reuse_as_seg now defaults to false (settings + default.yaml + CLI help): the dedicated segmenter keeps its own forward and the cross-check veto stays an independent second signal. The reuse remains available via --cross-check-as-seg / config; measured cost of off vs on: ~20 s/image on CPU, +0.1-0.25 s and +0.9-1.3 GB VRAM on GPU (13.3 vs 12.0 GB reserved under expandable segments -- still fits a 16 GB card).

2. bgfilter/__init__.py defaults PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True on non-Windows platforms, before torch loads (setdefault: an explicit env value wins; native Windows is excluded because torch warns and ignores it there). Measured: reserved 15.3 -> 12.0 GB and ~10% faster on the RTX 5070 Ti; no effect on CPU-only runs.

README/DEPLOY(_ZH) synced: reuse documented as opt-in, GPU profile numbers updated for both reuse states, perf table labeled with the config it was measured under.

Verified: defaults resolve off/set as intended on Windows and WSL; explicit PYTORCH_CUDA_ALLOC_CONF override wins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 20:40:19 +08:00
parent 6bf648cd64
commit 9b9d71cf82
7 changed files with 74 additions and 57 deletions
+19 -18
View File
@@ -161,17 +161,19 @@ Override the base directory with `BGFILTER_WEIGHTS_DIR`. `models/` is gitignored
The pipeline runs a second, high-resolution matting model
(`ZhengPeng7/BiRefNet_HR-matting`, ~425 MB) as a "second opinion" that clears
background residue trapped between hair strands. It is **ON by default** (both CLI
and HTTP service) and, with reuse-as-seg, that same forward doubles as the
segmentation mask on the birefnet backend — so it replaces the primary seg model
rather than adding to it. **You must provision this model** (Option A or B above):
and HTTP service). **You must provision this model** (Option A or B above):
- ⚠️ **On an offline server (`HF_HUB_OFFLINE=1`) it must be present before the
first request** — otherwise every default request fails, since it cannot
download the model at runtime.
- Turn it off service-wide with `BGFILTER_CROSS_CHECK=0`, or override per request
with the `cross_check` form field (`true`/`false`).
- The service preloads it at startup with the rest of the warm set; on the
birefnet backend the redundant primary segmenter is skipped.
- The service preloads it at startup with the rest of the warm set.
- Optional: `cross_check.reuse_as_seg: true` in the config (default **off**) makes
that same forward double as the segmentation mask on the birefnet backend —
replacing the primary seg model instead of adding to it (~20 s/image faster on
CPU, ~1 GB less VRAM; the redundant primary segmenter is then skipped at
startup). Off by default so the veto stays an independent signal.
### Downloading behind a firewall (CN networks)
@@ -289,19 +291,18 @@ service has **no authentication**. To reach it from other hosts:
- 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`).
- **GPU deployment (measured, RTX 5070 Ti 16 GB, full default pipeline —
cross-check on, reused as seg, bf16):** ~1–2 s/image (2 s at 4 MP), peak VRAM
~10.1 GB allocated. The number that must fit on the card is the allocator's
*reserved* footprint; set this in the service environment on Linux:
```ini
Environment=PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
```
Measured effect: reserved 15.3 GB → **12.0 GB** (fragmentation 5.2 → 1.9 GB) and
~10 % *faster* — with it, the full pipeline fits a 16 GB card with ~3.5 GB
headroom even next to a desktop session. Without it (or on native Windows, where
the option is silently unsupported), reserved is ~15.3 GB: a headless 16 GB card
still fits, but a desktop-attached one is borderline. Precision `bf16` is what
makes 16 GB viable at all — fp32 reserved ~17 GB overflows.
- **GPU deployment (measured, RTX 5070 Ti 16 GB, full pipeline — cross-check on,
bf16):** ~1–2 s/image (2 s at 4 MP), peak VRAM ~10.9 GB allocated (10.1 GB with
`reuse_as_seg: true`). The number that must fit on the card is the allocator's
*reserved* footprint. `bgfilter` defaults
`PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True` on Linux/WSL2 (set before
torch loads; native Windows does not support it, and an explicit env value
always wins). Measured effect: reserved 15.3 GB → **12.0 GB** with reuse
(13.3 GB without, the default) and ~10 % *faster* — the full pipeline fits a
16 GB card with ~2–3.5 GB headroom even next to a desktop session. Without
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.
- **Keeping RSS flat (glibc).** After each image the service calls glibc