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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
Executable
+172
@@ -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 <TOKEN>] [--port <PORT>] [--config <cfg>]
|
||||
# --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" <<WRAP
|
||||
#!/bin/bash
|
||||
cd "$APP_DIR" || exit 1
|
||||
export BGFILTER_CONFIG="$CONFIG"
|
||||
[ -f "$TOKEN_FILE" ] && export BGFILTER_AUTH_TOKEN="\$(cat "$TOKEN_FILE")"
|
||||
exec "$PY" -m uvicorn app:app --host 0.0.0.0 --port $PORT --workers 1
|
||||
WRAP
|
||||
chmod +x "$RUN_WRAPPER"
|
||||
|
||||
# ---- 6. supervisord config ----
|
||||
cat > "$SUP_CONF" <<SUP
|
||||
[unix_http_server]
|
||||
file=$SUP_SOCK
|
||||
chmod=0700
|
||||
|
||||
[supervisord]
|
||||
logfile=$HOME/supervisord.log
|
||||
pidfile=$HOME/supervisord.pid
|
||||
childlogdir=$HOME
|
||||
nodaemon=false
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix://$SUP_SOCK
|
||||
|
||||
[program:bgfilter]
|
||||
command=/bin/bash $RUN_WRAPPER
|
||||
directory=$APP_DIR
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=20
|
||||
startretries=5
|
||||
stopwaitsecs=25
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=$LOG
|
||||
stdout_logfile_maxbytes=10MB
|
||||
stdout_logfile_backups=2
|
||||
SUP
|
||||
|
||||
# ---- 7. interactive-login autostart in ~/.bashrc (idempotent) ----
|
||||
if ! grep -q "supervisord -c $SUP_CONF" "$HOME/.bashrc" 2>/dev/null; then
|
||||
cat >> "$HOME/.bashrc" <<BRC
|
||||
|
||||
# --- BGfilter supervisord auto-start (idempotent; added by deploy_autodl.sh) ---
|
||||
if ! pgrep -f "supervisord -c $SUP_CONF" >/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"
|
||||
Reference in New Issue
Block a user