From 28d3fe8842526d68c61a8fd6f1a42fd2f0478f6c Mon Sep 17 00:00:00 2001 From: Linghong Date: Mon, 13 Jul 2026 03:42:05 +0000 Subject: [PATCH] Add one-click AutoDL deploy script and GPU lane config scripts/deploy_autodl.sh: idempotent setup for an AutoDL box -- installs app deps (keeping the image's CUDA torch), picks the cupy wheel from torch's CUDA version for GPU foreground, fetches weights, writes the auth token, renders a supervisord instance (crash auto-restart) + a ~/.bashrc login autostart, then starts the service and waits for /healthz. Args: --token, --port (default 6006), --config (default configs/gpu.yaml). configs/gpu.yaml: the GPU lane (CUDA + bf16, full pipeline with cross-check, despill off) promoted from a box-local file into the repo so the deploy is reproducible. The public port mapping and the "no auto-start without an interactive login" gap are AutoDL platform limits, documented at the top of the script. Co-Authored-By: Claude Opus 4.8 --- configs/gpu.yaml | 61 ++++++++++++++ scripts/deploy_autodl.sh | 172 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 configs/gpu.yaml create mode 100755 scripts/deploy_autodl.sh diff --git a/configs/gpu.yaml b/configs/gpu.yaml new file mode 100644 index 0000000..1b17b7c --- /dev/null +++ b/configs/gpu.yaml @@ -0,0 +1,61 @@ +# GPU lane: CUDA + bf16 across all three models. Full pipeline (BiRefNet seg + +# ViTMatte + HR-matting cross-check). Foreground estimation auto-uses the CuPy GPU +# backend when cupy is installed (see foreground.use_gpu, default on). despill is +# off (it false-positives on subjects sharing the background hue). +screen_color: null + +model: + model_name: hustvl/vitmatte-base-composition-1k + device: cuda + matting_method: vitmatte + fallback_to_chroma_alpha: false + precision: bf16 + attn_query_chunk: 2048 + +segmentation: + enabled: true + backend: birefnet + model_name: ZhengPeng7/BiRefNet + device: cuda + input_size: 1024 + precision: bf16 + +trimap: + sure_bg_threshold: 0.92 + sure_fg_threshold: 0.12 + unknown_radius_ratio: 0.012 + fg_safe_radius_ratio: 0.006 + seg_core_threshold: 0.60 + seg_loose_threshold: 0.08 + mode: directional + seg_low: 0.15 + bg_hue_proj_min: 4.0 + seg_force_fg: 0.98 + +alpha_post: + chroma_suppress: true + chroma_suppress_bg_low: 0.35 + chroma_suppress_bg_high: 0.80 + chroma_suppress_strength: 1.0 + suppress_raw_lo: 0.85 + suppress_raw_hi: 0.98 + +cross_check: + enabled: true + model_name: ZhengPeng7/BiRefNet_HR-matting + input_size: 2048 + reuse_as_seg: false + precision: bf16 + proj_min: 3.0 + l_min: 45.0 + feather_sigma: 2.0 + gate_lo: 0.70 + gate_hi: 0.95 + +foreground: + enabled: true + method: ml + ml_regularization: 0.00001 + +despill: + enabled: false diff --git a/scripts/deploy_autodl.sh b/scripts/deploy_autodl.sh new file mode 100755 index 0000000..4ddb766 --- /dev/null +++ b/scripts/deploy_autodl.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# One-click AutoDL deploy for the BGfilter HTTP service. +# +# Sets up (idempotently): app deps + model weights + optional CuPy GPU foreground +# + a supervisord instance (crash auto-restart) + an interactive-login autostart, +# then starts the service and verifies /healthz. +# +# Usage: +# scripts/deploy_autodl.sh [--token ] [--port ] [--config ] +# --token auth token; sets the X-Genarrative-Image-Token requirement. +# Omit to run OPEN (no auth) -- a warning is printed. +# --port public-mapped container port (default 6006). +# --config pipeline config (default configs/gpu.yaml). +# +# Assumes: the repo is already checked out (this script does NOT git pull), root +# user, torch/CUDA provided by the AutoDL image, python at /root/miniconda3. +# +# Out of scope (AutoDL limitations, not fixable here): +# * The public URL mapping (e.g. 6006 -> https://...:8443) is set in the AutoDL +# web console, not by this script. +# * After a container restart the service only comes back when you open an +# interactive shell (SSH / JupyterLab terminal) -- AutoDL has no systemd/boot +# hook, so the autostart lives in ~/.bashrc. +set -euo pipefail + +# ---- args ---- +TOKEN="" +PORT=6006 +CONFIG="configs/gpu.yaml" +while [ $# -gt 0 ]; do + case "$1" in + --token) TOKEN="${2:-}"; shift 2;; + --port) PORT="${2:-}"; shift 2;; + --config) CONFIG="${2:-}"; shift 2;; + -h|--help) sed -n '2,30p' "$0" | sed 's/^# \?//'; exit 0;; + *) echo "unknown arg: $1" >&2; exit 1;; + esac +done + +# ---- paths ---- +APP_DIR="$(cd "$(dirname "$0")/.." && pwd)" +PY=/root/miniconda3/bin/python +[ -x "$PY" ] || PY="$(command -v python)" +BINDIR="$(dirname "$PY")" +SUPERVISORD="$BINDIR/supervisord" +SUPERVISORCTL="$BINDIR/supervisorctl" +TOKEN_FILE="$HOME/.bgfilter_token" +RUN_WRAPPER="$HOME/bgfilter_run.sh" +SUP_CONF="$HOME/supervisord.conf" +SUP_SOCK="$HOME/bgfilter-supervisor.sock" +LOG=/tmp/bgfilter.log + +echo "[deploy] app_dir=$APP_DIR python=$PY port=$PORT config=$CONFIG" + +# ---- 1. detect CUDA -> pick the matching cupy wheel (GPU foreground) ---- +CUDA_VER="$("$PY" -c 'import torch;print(torch.version.cuda or "")' 2>/dev/null || echo "")" +echo "[deploy] torch CUDA = ${CUDA_VER:-none}" +CUPY_PKG="" +case "$CUDA_VER" in + 13.*) CUPY_PKG="cupy-cuda13x";; + 12.*) CUPY_PKG="cupy-cuda12x";; + 11.*) CUPY_PKG="cupy-cuda11x";; +esac + +# ---- 2. deps (keep the image's CUDA torch: never let pip replace torch/torchvision) ---- +echo "[deploy] installing requirements (excluding torch/torchvision)..." +grep -vE '^(torch|torchvision)$' "$APP_DIR/requirements.txt" > /tmp/bgfilter-reqs.txt +"$PY" -m pip install -q -r /tmp/bgfilter-reqs.txt +if [ -n "$CUPY_PKG" ]; then + echo "[deploy] installing $CUPY_PKG (GPU foreground)..." + "$PY" -m pip install -q "$CUPY_PKG" || echo "[deploy] WARN: $CUPY_PKG failed; foreground falls back to CPU" +else + echo "[deploy] no CUDA -> skip cupy (foreground stays on CPU)" +fi + +# ---- 3. weights (hf-mirror; the script skips ones already on disk) ---- +echo "[deploy] fetching weights..." +( cd "$APP_DIR" && "$PY" scripts/fetch_weights.py ) + +# ---- 4. auth token ---- +if [ -n "$TOKEN" ]; then + printf '%s' "$TOKEN" > "$TOKEN_FILE"; chmod 600 "$TOKEN_FILE" + echo "[deploy] auth ENABLED (token -> $TOKEN_FILE, chmod 600)" +else + rm -f "$TOKEN_FILE" + echo "[deploy] WARN: no --token -> service is OPEN (no auth)" +fi + +# ---- 5. launch wrapper (exec so supervisord tracks the uvicorn PID) ---- +cat > "$RUN_WRAPPER" < "$SUP_CONF" </dev/null; then + cat >> "$HOME/.bashrc" </dev/null 2>&1; then + rm -f "$SUP_SOCK" "$HOME/supervisord.pid" 2>/dev/null + "$SUPERVISORD" -c "$SUP_CONF" >/dev/null 2>&1 +fi +BRC + echo "[deploy] added autostart to ~/.bashrc" +else + echo "[deploy] autostart already in ~/.bashrc" +fi + +# ---- 8. start (or reload) supervisord ---- +if pgrep -f "supervisord -c $SUP_CONF" >/dev/null 2>&1; then + echo "[deploy] supervisord already running -> reload + restart bgfilter" + "$SUPERVISORCTL" -c "$SUP_CONF" reread || true + "$SUPERVISORCTL" -c "$SUP_CONF" update || true + "$SUPERVISORCTL" -c "$SUP_CONF" restart bgfilter || true +else + rm -f "$SUP_SOCK" "$HOME/supervisord.pid" 2>/dev/null + "$SUPERVISORD" -c "$SUP_CONF" + echo "[deploy] supervisord started" +fi + +# ---- 9. wait for readiness + report ---- +echo "[deploy] waiting for /healthz on port $PORT (models load ~10-15s)..." +for _ in $(seq 1 40); do + if [ "$(curl -s -o /dev/null -w '%{http_code}' -m 5 "http://127.0.0.1:$PORT/healthz" || true)" = "200" ]; then + echo "[deploy] READY: healthz 200" + break + fi + sleep 2 +done +"$SUPERVISORCTL" -c "$SUP_CONF" status || true +echo +echo "[deploy] done. Manage the service with:" +echo " $SUPERVISORCTL -c $SUP_CONF status|restart|stop|tail bgfilter"