Files
BGfilter/DEPLOY_ZH.md
T
lhk229 6232887ebd Pin opencv-python-headless in requirements
The GUI opencv-python build needs libGL.so.1 which headless Linux servers lack,
causing "ImportError: libGL.so.1" at first cv2 use. Pin the headless build so a
plain `pip install -r requirements.txt` works on servers out of the box (and
survives a git reset). BgFilter only uses cv2 for computation, so headless is a
drop-in on desktops too. Drop the now-unnecessary sed step from DEPLOY.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:45:51 +00:00

12 KiB
Raw Blame History

将 BgFilter 部署到 Linux 服务器

English version: DEPLOY.md

本指南涵盖在 Linux 服务器上运行 BgFilter HTTP 服务(POST /remove-background、 GET /healthz)所需的全部步骤。默认按 CPU 部署(推荐默认);涉及 GPU 的地方会单独标注。

服务入口是 app.py(uvicorn app:app)。API 契约和算法细节见 README.md。


1. 前置条件

  • Linux x86-64(在 Ubuntu 上验证过;其它主流发行版同理)。
  • 推荐 Python 3.11–3.13。更新的版本(如 3.14)也可能可用,但部分 ML 包可能还没发布对应 wheel——尽量选一个 torch / onnxruntime / opencv / pymatting 都有预编译 wheel 的版本。
  • git,以及 venv 模块(Debian/Ubuntu 上是 python3-venv)。
  • 磁盘空间:Python 环境约 3 GB + 模型权重约 1 GB。
  • 一次性联网即可(用于装依赖和下模型);服务跑起来后可完全离线。
sudo apt update
sudo apt install -y python3-venv python3-pip git

2. 获取代码

sudo mkdir -p /opt/genarrative-image-host/bgfilter-service
sudo chown "$USER" /opt/genarrative-image-host/bgfilter-service
cd /opt/genarrative-image-host/bgfilter-service
git clone <repo-url> .            # 或把仓库拷到这里;使用 server-edition 分支

3. Python 环境

python3 -m venv .venv
. .venv/bin/activate
python -m pip install -U pip

4. 安装依赖(CPU)

先从 CPU wheel 源装 PyTorch——否则 pip 会拉默认的 CUDA 构建,附带约 2–3 GB 的 nvidia-* 包,CPU 机器完全用不上:

pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu

requirements.txt 里已经固定用 opencv-python-headless(GUI 构建依赖 libGL.so.1 等无头服务器没有的库),所以无需改动。直接装其余依赖——此时 torch/torchvision 已满足,不会再拉 CUDA:

pip install -r requirements.txt

验证整套依赖可导入、且 torch 是 CPU 构建(cuda= None):

python -c "import torch,cv2,fastapi,transformers,pymatting,onnxruntime,kornia,timm; \
print('torch', torch.__version__, 'cuda=', torch.version.cuda)"

在墙内,给第二条 pip install 加上 -i https://pypi.tuna.tsinghua.edu.cn/simple 提速。

5. 准备模型权重

默认用到三个模型:hustvl/vitmatte-base-composition-1k(抠图)、 ZhengPeng7/BiRefNet(默认分割)、skytnt/anime-seg(可选分割)。 第四个模型 ZhengPeng7/BiRefNet_HR-matting(约 425 MB)只有在启用 cross-check(交叉校验) 否决时才需要——见本节末尾说明。下面两种放法二选一。

方案 A —— HuggingFace 缓存 + 离线模式(推荐)

先下载到一个缓存目录,之后离线运行:

export HF_HOME=/opt/genarrative-image-host/bgfilter-service/model-cache/hf
hf download hustvl/vitmatte-base-composition-1k
hf download ZhengPeng7/BiRefNet
hf download skytnt/anime-seg
hf download ZhengPeng7/BiRefNet_HR-matting   # 仅在使用 cross-check 时(见下)

运行时把 HF_HOME 指向同一路径,并设 HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1(见 §6)。 也可以在另一台机器下好,把 hub/ 目录整个拷过来。

方案 B —— 权重作为普通文件夹放进项目

把每个模型放进 models/<repo末段名>/,加载器会直接用它(不走 HF 缓存、不联网)。 没放对应文件夹时会回退到 repo id,所以这是可选功能。

文件夹名必须和 repo 末段名完全一致——加载器靠这个找到它 (ZhengPeng7/BiRefNet → models/BiRefNet)。各模型需要的文件:

<项目根目录>/
└── models/
    ├── vitmatte-base-composition-1k/     # ViTMatte 抠图模型
    │   ├── config.json
    │   ├── preprocessor_config.json
    │   └── pytorch_model.bin             # 约 369 MB
    ├── BiRefNet/                         # 默认分割模型(trust_remote_code)
    │   ├── config.json
    │   ├── BiRefNet_config.py            # 自定义代码——trust_remote_code 必需
    │   ├── birefnet.py                   # 自定义代码——trust_remote_code 必需
    │   └── model.safetensors             # 约 424 MB
    ├── anime-seg/                        # 可选分割模型(seg_model=anime-seg)
    │   └── isnetis.onnx                  # 约 168 MB
    └── BiRefNet_HR-matting/              # 可选——仅用于 cross-check 否决
        ├── config.json
        ├── BiRefNet_config.py            # 自定义代码——trust_remote_code 必需
        ├── birefnet.py                   # 自定义代码——trust_remote_code 必需
        └── model.safetensors             # 约 425 MB

说明:

  • ViTMatte:需要 config.json、preprocessor_config.json 和权重 (pytorch_model.bin;若有 model.safetensors 也可)。
  • BiRefNet:两个 .py 文件是必需的——trust_remote_code 会执行它们来构建模型。 和 config.json + model.safetensors 放在一起。(repo 里的 handler.py / requirements.txt / README.md 用不到。)
  • anime-seg:只读 isnetis.onnx,其它都不需要。
  • anime-seg 和 BiRefNet_HR-matting 都是可选的——不用 seg_model=anime-seg / cross-check 否决时,各自的文件夹可以不放。

最省事的填充方式是用 hf download(它也会顺带拉几个用不到的文件如 README.md,无害):

hf download hustvl/vitmatte-base-composition-1k --local-dir models/vitmatte-base-composition-1k
hf download ZhengPeng7/BiRefNet                 --local-dir models/BiRefNet
hf download skytnt/anime-seg                     --local-dir models/anime-seg
hf download ZhengPeng7/BiRefNet_HR-matting       --local-dir models/BiRefNet_HR-matting  # 仅 cross-check

用 BGFILTER_WEIGHTS_DIR 可改基目录。models/ 已被 gitignore。

cross-check 否决(可选,服务里默认关闭)

管线可以再跑一个高分辨率 matting 模型(ZhengPeng7/BiRefNet_HR-matting,约 425 MB) 作为"第二意见",专门清理发丝间残留的背景色。在 HTTP 服务里默认是关的、且懒加载, 所以不开启就不需要这个模型:

  • 服务级开启:BGFILTER_CROSS_CHECK=1;或按请求:表单字段 cross_check=true。
  • ⚠️ 离线服务器(HF_HUB_OFFLINE=1)必须先备好 BiRefNet_HR-matting(上面方案 A 或 B), 否则第一个 cross-check 请求会失败——运行时它无法联网下载模型。
  • 每张图多一次 2048 分辨率推理(CPU 上约 35s/张),延迟大约翻倍。
  • 注意:配置默认(configs/default.yaml)里 cross_check.enabled: true,CLI 会遵循它; 只有 HTTP 服务强制关闭,除非设了 BGFILTER_CROSS_CHECK=1。

墙内下载(国内网络)

若直连 HuggingFace 被墙,用镜像 并绕过本地代理、禁用 Xet——这是稳定可用的组合:

export HF_ENDPOINT=https://hf-mirror.com   # 国内镜像
export NO_PROXY='*'                        # 绕过代理;镜像是国内直连
export HF_HUB_DISABLE_XET=1                 # 这些 repo 是 Xet 存储;强制走经典 HTTP

这样能避开两个坑:(1) 镜像 + 走海外的代理会让镜像把 resolve 又重定向回 huggingface.co,新版 huggingface_hub 会因此报 FileMetadataError; (2) 装了 hf-xet 时 Xet 下载路径在此环境下会瞬间失败。

6. 配置(环境变量)

变量 默认 作用
BGFILTER_CONFIG configs/default.yaml 管线配置文件
BGFILTER_DEVICE cpu 同时覆盖 model 和 segmentation 的 device(GPU 用 cuda)
BGFILTER_MAX_IMAGE_PIXELS 4194304 超过则返回 413(约 4 MP)
BGFILTER_PRELOAD 1 启动时预加载默认模型(首个请求不用冷加载)
BGFILTER_CROSS_CHECK 0 启用 cross-check 否决(需 BiRefNet_HR-matting;延迟约 ×2)
BGFILTER_WEIGHTS_DIR models 本地权重文件夹的查找目录(方案 B)
HF_HOME — HF 缓存位置(方案 A)
HF_HUB_OFFLINE / TRANSFORMERS_OFFLINE — 权重缓存好后,生产设为 1
OMP_NUM_THREADS / MKL_NUM_THREADS — 限制 CPU 线程数(如 4)

7. 运行服务

python -m uvicorn app:app --host 127.0.0.1 --port 18083 --workers 1
  • 必须保留 --workers 1。 每个 worker 各加载一整套模型,多 worker 会成倍占内存 (8 GB 机器会 OOM)。服务已用全局锁串行化推理。
  • --host 127.0.0.1 只对本机开放(面向同机调用方)。跨机访问见 §10。

8. 作为 systemd 服务运行

/etc/systemd/system/genarrative-bgfilter.service:

[Unit]
Description=Genarrative BgFilter background removal service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/genarrative-image-host/bgfilter-service
Environment=HF_HOME=/opt/genarrative-image-host/bgfilter-service/model-cache/hf
Environment=HF_HUB_OFFLINE=1
Environment=TRANSFORMERS_OFFLINE=1
Environment=HF_HUB_DISABLE_XET=1
Environment=BGFILTER_CONFIG=configs/default.yaml
Environment=BGFILTER_DEVICE=cpu
Environment=BGFILTER_MAX_IMAGE_PIXELS=4194304
Environment=BGFILTER_PRELOAD=1
Environment=OMP_NUM_THREADS=4
Environment=MKL_NUM_THREADS=4
ExecStart=/opt/genarrative-image-host/bgfilter-service/.venv/bin/uvicorn app:app --host 127.0.0.1 --port 18083 --workers 1
Restart=on-failure
RestartSec=5
MemoryMax=8G
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/opt/genarrative-image-host

[Install]
WantedBy=multi-user.target

若用方案 B(本地 models/ 文件夹)而非 HF 缓存,去掉 HF_HOME 和离线那几行—— 那种权重不需要缓存也不联网。

sudo systemctl daemon-reload
sudo systemctl enable --now genarrative-bgfilter
sudo systemctl status genarrative-bgfilter
journalctl -u genarrative-bgfilter -f          # 等到 "Application startup complete"

9. 验证

curl -s http://127.0.0.1:18083/healthz
# {"ok":true,"service":"bgfilter","version":"0.1.0","defaultSegModel":"birefnet","device":"cpu"}

curl -sS -F "file=@input.png" -F "screen_color=#CFEFFF" \
  http://127.0.0.1:18083/remove-background -o out.png

10. 对外暴露

单元里绑的是 127.0.0.1——面向同机调用方(例如 Genarrative Rust BFF,通过 GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL 调用)。服务本身没有鉴权。 要从其它主机访问:

  • 反向代理(推荐): 前面放 nginx/caddy,终止 TLS、加鉴权/限流,转发到 127.0.0.1:18083。
  • 直接暴露: 把 --host 改成 0.0.0.0,并用防火墙限制来源 IP。 切勿把无鉴权的服务裸暴露到公网。

11. 容量与性能

  • CPU 吞吐约 45 秒/张(1.5 MP),用默认配置(base ViTMatte + BiRefNet);请求被全局锁 串行,所以单实例约 1–2 张/分钟。瓶颈是全分辨率的 ViTMatte 和 pymatting 前景估计。
  • 要提吞吐:上 GPU(BGFILTER_DEVICE=cuda,装 CUDA 版 torch),大约快一个数量级; 和/或多实例 + 负载均衡(每个都 --workers 1)。
  • 内存:单个 worker 持有全部三个模型(约 1 GB 权重 + 运行时)。单 CPU worker 用 MemoryMax=8G 作上限比较稳妥。

12. 故障排查

现象 原因 / 解决
pip 拉了 nvidia-*/cuda-*(巨大) §4 里漏了 CPU 源。用 --index-url https://download.pytorch.org/whl/cpu 装 torch。
import cv2 报 ImportError: libGL.so.1 在无 GUI 机器上用了 opencv-python。换成 opencv-python-headless(§4)。
建 venv 时 ensurepip is not available 装 python3-venv(§1)。
下载时 FileMetadataError: ... not on huggingface.co 镜像与代理冲突。绕过代理(NO_PROXY='*')并设 HF_HUB_DISABLE_XET=1(§5)。
LocalEntryNotFoundError、0 字节 Xet 下载路径失败;设 HF_HUB_DISABLE_XET=1。
503 service not ready 启动时模型还在加载;等 "Application startup complete"。
刚设 BGFILTER_CROSS_CHECK 后(离线)报 500 inference failed BiRefNet_HR-matting 没备好;下到缓存/models/(§5)。
负载下 OOM / 被 kill worker 多于一个,或 MemoryMax 太低。保持 --workers 1。
400 could not auto-detect background colour 输入没有干净的纯色边框;传 screen_color=#RRGGBB。