add DEPLOY.md

This commit is contained in:
2026-07-05 09:04:22 +00:00
parent edcef6e34d
commit d3f19ddcc7
2 changed files with 295 additions and 1 deletions
+34 -1
View File
@@ -1,5 +1,7 @@
# Deploying BgFilter to a Linux server
> 中文版:[DEPLOY_ZH.md](DEPLOY_ZH.md)
This guide covers everything needed to run the BgFilter HTTP service
(`POST /remove-background`, `GET /healthz`) on a Linux server. It assumes a CPU
deployment (the default); GPU notes are called out where relevant.
@@ -99,7 +101,38 @@ the `hub/` folder over.
### Option B — plain folders inside the project
Drop each model into `models/<repo-basename>/` and the loader uses it directly (no
HF cache, no network). Absent folders fall back to the repo id, so this is opt-in:
HF cache, no network). Absent folders fall back to the repo id, so this is opt-in.
**The folder name must match the repo basename exactly** — that is how the loader
finds it (`ZhengPeng7/BiRefNet` → `models/BiRefNet`). Required files per model:
```text
<project-root>/
└── models/
├── vitmatte-base-composition-1k/ # ViTMatte matting model
│ ├── config.json
│ ├── preprocessor_config.json
│ └── pytorch_model.bin # ~369 MB
├── BiRefNet/ # default segmenter (trust_remote_code)
│ ├── config.json
│ ├── BiRefNet_config.py # custom code — required by trust_remote_code
│ ├── birefnet.py # custom code — required by trust_remote_code
│ └── model.safetensors # ~424 MB
└── anime-seg/ # optional segmenter (seg_model=anime-seg)
└── isnetis.onnx # ~168 MB
```
Notes:
- **ViTMatte**: needs `config.json`, `preprocessor_config.json`, and the weights
(`pytorch_model.bin`; `model.safetensors` also works if present).
- **BiRefNet**: the two `.py` files are mandatory — `trust_remote_code` executes them
to build the model. Keep `config.json` + `model.safetensors` alongside them. (The
repo's `handler.py` / `requirements.txt` / `README.md` are not needed.)
- **anime-seg**: only `isnetis.onnx` is read; nothing else is required.
- `anime-seg` is optional — omit its folder if you never use `seg_model=anime-seg`.
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):
```bash
hf download hustvl/vitmatte-base-composition-1k --local-dir models/vitmatte-base-composition-1k
+261
View File
@@ -0,0 +1,261 @@
# 将 BgFilter 部署到 Linux 服务器
> English version: [DEPLOY.md](DEPLOY.md)
本指南涵盖在 Linux 服务器上运行 BgFilter HTTP 服务(`POST /remove-background`、
`GET /healthz`)所需的全部步骤。默认按 **CPU** 部署(推荐默认);涉及 GPU 的地方会单独标注。
服务入口是 `app.py`(`uvicorn app:app`)。API 契约和算法细节见 [README.md](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。
- **一次性**联网即可(用于装依赖和下模型);服务跑起来后可完全离线。
```bash
sudo apt update
sudo apt install -y python3-venv python3-pip git
```
## 2. 获取代码
```bash
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 环境
```bash
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 机器完全用不上:
```bash
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
```
无 GUI 的服务器请用 **`opencv-python-headless`** 代替 `opencv-python`(GUI 构建依赖
`libGL.so.1` 等服务器通常没有的库):
```bash
sed -i 's/^opencv-python$/opencv-python-headless/' requirements.txt
```
再装其余依赖。此时 `torch`/`torchvision` 已满足,不会再拉 CUDA:
```bash
pip install -r requirements.txt
```
验证整套依赖可导入、且 torch 是 CPU 构建(`cuda= None`):
```bash
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`(可选分割)。
下面两种放法**二选一**。
### 方案 A —— HuggingFace 缓存 + 离线模式(推荐)
先下载到一个缓存目录,之后离线运行:
```bash
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_HOME` 指向同一路径,并设 `HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1`(见 §6)。
也可以在另一台机器下好,把 `hub/` 目录整个拷过来。
### 方案 B —— 权重作为普通文件夹放进项目
把每个模型放进 `models/<repo末段名>/`,加载器会直接用它(不走 HF 缓存、不联网)。
没放对应文件夹时会回退到 repo id,所以这是可选功能。
**文件夹名必须和 repo 末段名完全一致**——加载器靠这个找到它
(`ZhengPeng7/BiRefNet` → `models/BiRefNet`)。各模型需要的文件:
```text
<项目根目录>/
└── 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
```
说明:
- **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` 是可选的——若从不使用 `seg_model=anime-seg`,可以不放这个文件夹。
最省事的填充方式是用 `hf download`(它也会顺带拉几个用不到的文件如 `README.md`,无害):
```bash
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
```
用 `BGFILTER_WEIGHTS_DIR` 可改基目录。`models/` 已被 gitignore。
### 墙内下载(国内网络)
若直连 HuggingFace 被墙,用镜像 **并绕过本地代理、禁用 Xet**——这是稳定可用的组合:
```bash
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_WEIGHTS_DIR` | `models` | 本地权重文件夹的查找目录(方案 B)|
| `HF_HOME` | — | HF 缓存位置(方案 A)|
| `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` | — | 权重缓存好后,生产设为 `1` |
| `OMP_NUM_THREADS` / `MKL_NUM_THREADS` | — | 限制 CPU 线程数(如 `4`)|
## 7. 运行服务
```bash
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`:
```ini
[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` 和离线那几行——
那种权重不需要缓存也不联网。
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now genarrative-bgfilter
sudo systemctl status genarrative-bgfilter
journalctl -u genarrative-bgfilter -f # 等到 "Application startup complete"
```
## 9. 验证
```bash
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"。 |
| 负载下 OOM / 被 kill | worker 多于一个,或 `MemoryMax` 太低。保持 `--workers 1`。 |
| `400 could not auto-detect background colour` | 输入没有干净的纯色边框;传 `screen_color=#RRGGBB`。 |