Files
hair/docs/optimization_plans.md
2026-07-18 15:30:31 +08:00

326 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目标:所有接口 < 10 秒 — 三个优化方案
> 日期:2026-07-18
> 基准数据(优化1+2后轮换测试 5轮×4接口)
---
## 当前性能基线
| 接口 | 平均 | 最快 | 最慢 | 目标 | 差距 |
|------|------|------|------|------|------|
| 接口1-测量 | 0.1s | 0.1s | 0.1s | <10s | ✅ 已达标 |
| 接口2-女-椭圆 | 17.6s | 10.0s | 19.7s | <10s | -7.6s |
| 接口2-男-椭圆 | 8.1s | 7.9s | 8.4s | <10s | ✅ 已达标(余量小) |
| 接口3-B端生发 | 22.9s | 22.6s | 23.3s | <10s | -12.9s |
---
## 根因分析
### ComfyUI 模型反复换出(最大瓶颈)
ComfyUI 服务端日志(`journalctl -u comfyui`)揭示了根因:
```
12:17:14 model_type FLUX
12:17:16 loaded completely; 17421 MB usable, 15622 MB loaded ← 全量加载(15.6GB)
12:17:16 Requested to load Flux2
12:17:23 Unloaded partially: 11904 MB freed, 3718 MB remains ← 部分卸载
12:17:24 loaded completely; 11832 MB usable, 8996 MB loaded ← 重新加载(8.9GB)
12:17:27 VAE loaded
12:17:29 Requested to load Flux2 ← 男性复用(快)
12:17:31 loaded completely; 11671 MB usable, 8996 MB loaded ← 已加载,6s完成
12:17:43 Unloaded partially: 8996 MB freed, 0.04 MB remains ← 全部卸载!
12:17:45 loaded completely; 17567 MB usable, 15622 MB loaded ← 全量重载(15.6GB)
12:17:52 Unloaded partially: 11904 MB freed, 3718 MB remains ← 再次部分卸载
12:17:54 loaded completely; 11814 MB usable, 8996 MB loaded ← 再次重载(8.9GB)
12:17:58 接口3 完成(21.5s
```
**ComfyUI 在每次执行后都会卸载模型,下次执行时重新加载。** 模型加载耗时 ~8-15s,是接口3和接口2女超时的主因。
### 显存分布(32GB GPU
| 进程 | 显存 | 说明 |
|------|------|------|
| ComfyUI (Flux-2) | ~10-15 GB | 动态加载/卸载 |
| hair_service_sd | ~8 GB | GAN 模型常驻 |
| SD WebUI | ~3.2 GB | SD1.5 + ControlNet |
| Hair 服务 | ~0.7 GB | uvicorn + 模型 |
| **合计** | **~22-27 GB** | **仅剩 5-10 GB 可用** |
显存不足导致 ComfyUI 无法常驻完整的 Flux-2 模型(~15.6GB 全量或 ~9GB FP8)。
### 耗时拆解
**接口322.9s**
```
ComfyUI 模型加载: ~15s ← 根因
ComfyUI 推理(steps=6): ~6s
预处理(人脸+SegFormer+划线): ~1.6s
```
**接口2女(17.6s**
```
ComfyUI 模型加载: ~10s ← 根因(模型被接口3卸载后需重载)
ComfyUI 推理(steps=4): ~4s
swapHair HTTP: ~4.6s
预处理(extract_context): ~1.5s(优化2后 SegFormer 只跑一次)
```
**接口2男(8.1s**
```
ComfyUI 推理(steps=6): ~6s
预处理: ~2s
(模型常被前一个女性接口加载好,所以无重载开销)
```
---
## 方案 A:释放显存给 ComfyUI(最小改动)
### 核心思路
ComfyUI 需要 ~15.6GB 显存才能全量加载 Flux-2。当前被 hair_service_sd8GB)和 SD WebUI3.2GB)挤占。如果释放足够显存,ComfyUI 就能常驻模型,消除反复加载。
### 具体措施
#### A1. 接口3不依赖 hair_service_sd
接口3 **不调用** change_hair:8801 的 swapHair。但 hair_service_sd 的所有 GAN 模型(8GB)常驻显存只为接口2女服务。
**方案**:将 hair_service_sd 改为**按需启动/停止**
- 接口2女调用前启动 hair_service_sd
- 接口2女完成后停止 hair_service_sd(释放 8GB
- 接口3和接口2男不启动 hair_service_sd
**释放**8 GB → ComfyUI 可用显存从 ~5GB 增至 ~13GB
#### A2. 接口2女改为先启动 hair_service_sd → swapHair → 停止 → 再调 ComfyUI
```
接口2女流程:
1. 启动 hair_service_sd (8s) ← 可预热
2. swapHair (4.6s)
3. 停止 hair_service_sd → 释放 8GB
4. ComfyUI 重绘 (4-6s, 模型常驻)
总: ~17s → 仍有问题
```
**问题**hair_service_sd 启动需要 8s(加载全部 GAN),反而增加耗时。
#### A3. 停止 SD WebUI3.2GB
SD WebUI 只被 change_hair 的 swapHair 使用(接口2女)。如果接口2女改用其他方案(见方案B),可以完全停止 SD WebUI。
**释放**3.2 GB
#### A4. 总释放和预期效果
| 措施 | 释放 | ComfyUI 可用 |
|------|------|--------------|
| 当前 | — | ~5-10 GB |
| A1 (停 hair_service_sd) | +8 GB | ~13-18 GB |
| A3 (停 SD WebUI) | +3.2 GB | ~16-21 GB |
| **合计** | **+11.2 GB** | **~16-21 GB** |
Flux-2 全量 15.6GB,释放后 ComfyUI 可常驻模型。
### 预期耗时
| 接口 | 当前 | 优化后 | 达标 |
|------|------|--------|------|
| 接口1 | 0.1s | 0.1s | ✅ |
| 接口2-女 | 17.6s | ~11s (swapHair 4.6s + ComfyUI 4s + 预处理 1.5s + 启停 1s) | ❌ 差1s |
| 接口2-男 | 8.1s | ~8s | ✅ |
| 接口3 | 22.9s | ~8s (ComfyUI 6s + 预处理 1.6s) | ✅ |
### 优点
- 改动最小:主要改服务启停逻辑
- 不影响算法质量
- 不需要换 torch 版本
### 缺点
- 接口2女仍可能超 10sswapHair 4.6s 是硬瓶颈)
- hair_service_sd 启停增加系统复杂度
- 需要精确的显存管理
---
## 方案 B:统一工作流 + 降 steps(中等改动)
### 核心思路
两个工作流(0716add-hair-api.json 27节点 vs add_hair.json 29节点)加载相同模型但参数不同(steps=4 vs steps=6),切换时触发 ComfyUI 重新初始化。统一为一个工作流 + 降低 steps 可消除切换开销并加速推理。
### 具体措施
#### B1. 统一为单一工作流
`add_hair.json` 的 steps 从 6 降到 4,与 `0716add-hair-api.json` 一致。然后所有接口都用同一个工作流。
**改动**
- `add_hair.json`: KSampler steps 6 → 4
- 接口2男和接口3统一用修改后的 `add_hair.json`
- 接口2女也改用 `add_hair.json`(不再用 `0716add-hair-api.json`
**效果**:ComfyUI 不再在工作流间切换,模型可常驻。
#### B2. 进一步降低 steps 到 2
Flux-2 模型在 steps=2 时仍能生成合理结果(需质量验证)。
| steps | 单次推理 | 质量 |
|-------|---------|------|
| 6 | ~6s | 最好 |
| 4 | ~4s | 好 |
| 2 | ~2s | 可接受(需验证) |
#### B3. 接口2女去 swapHair(可选但关键)
swapHair 调 change_hair:8801 → webui:57860 SD1.5 img2img,耗时 4.6s。如果去掉 swapHair
- 女性直接用原图 + 遮罩 → ComfyUI Flux-2 重绘
- 省去 4.6s + 不需要启动 hair_service_sd + SD WebUI
- 释放 ~11.2GB 显存给 ComfyUI
**但**:swapHair 是换发型功能,去掉后女性发型会不同。需要确认产品是否接受。
### 预期耗时
| 接口 | 当前 | B1(steps=4) | B2(steps=2) | B3(去swapHair) |
|------|------|-------------|-------------|----------------|
| 接口2-女 | 17.6s | ~10s | ~8s | ~6s |
| 接口2-男 | 8.1s | ~6s | ~4s | ~4s |
| 接口3 | 22.9s | ~8s | ~6s | ~6s |
### 优点
- 消除工作流切换开销
- 降低推理时间
- 可与方案A叠加
### 缺点
- steps 降低可能影响质量(需验证)
- 去 swapHair 改变女性发型效果
- 需要修改工作流 JSON 和服务代码
---
## 方案 C:ComfyUI 预热 + 模型常驻(系统级优化)
### 核心思路
通过 ComfyUI API 和配置,让 Flux-2 模型在启动后常驻显存,不执行后自动卸载。结合预热请求,确保每次调用时模型已在显存。
### 具体措施
#### C1. 配置 ComfyUI 保持模型加载
ComfyUI 有 `--reserve-vram``--gpu-only` 参数控制 VRAM 管理:
```bash
# 启动 ComfyUI 时禁用模型卸载
python main.py --listen --gpu-only --reserve-vram 0
```
- `--gpu-only`:禁止将模型卸载到 CPU(保持 GPU 常驻)
- `--reserve-vram 0`:不预留 VRAM(最大化模型可用空间)
**前提**:需要释放足够显存(结合方案A的A1/A3)。
#### C2. ComfyUI 预热请求
在 hair 服务启动时,发送一个空请求给 ComfyUI,触发模型加载:
```python
# hair 服务启动后
comfyui.warmup() # 发送最小工作流,触发 Flux-2 加载到 VRAM
```
**效果**:第一次请求不再需要等待模型加载。
#### C3. 停止其他占用显存的服务
与方案A结合:
- 停止 hair_service_sd(释放 8GB
- 停止 SD WebUI(释放 3.2GB
- 仅保留 ComfyUI + Hair 服务
**总可用显存**32GB - 0.7GB(Hair) = ~31GB → 足以常驻 Flux-215.6GB
#### C4. ComfyUI 模型管理优化
设置环境变量:
```bash
export COMFYUI_MODEL_KEEP=true # 保持模型加载
```
或在 ComfyUI 的 `extra_model_paths.yaml``comfyui/config.yaml` 中配置模型缓存策略。
#### C5. 接口2女 swapHair 异步化
swapHair(4.6s)是接口2女的独立瓶颈。改为异步流水线:
```
1. 接收请求 → 异步调 swapHair
2. 同时开始预处理(extract_context + 遮罩)
3. swapHair 完成 + 预处理完成 → 合并
4. ComfyUI 重绘
```
**效果**swapHair 4.6s 与预处理 1.5s 并行,省 1.5s。
### 预期耗时
| 接口 | 当前 | C方案 |
|------|------|-------|
| 接口1 | 0.1s | 0.1s |
| 接口2-女 | 17.6s | ~9s (swapHair 4.6s ∥ 预处理 1.5s + ComfyUI 4s) |
| 接口2-男 | 8.1s | ~6s (ComfyUI 4s + 预处理 2s) |
| 接口3 | 22.9s | ~6s (ComfyUI 4s + 预处理 1.6s) |
### 优点
- 从根本上解决模型换出问题
- 效果最稳定(模型常驻后不再有抖动)
- 可与方案B叠加(steps 降到2则接口2女 ~6s
### 缺点
- 需要停掉 hair_service_sd 和 SD WebUI(影响其他功能)
- 接口2女仍依赖 swapHair4.6s
- ComfyUI 配置改动需验证不影响稳定性
- `--gpu-only` 在显存不足时可能导致 OOM 崩溃
---
## 三方案对比
| 维度 | 方案A(释放显存) | 方案B(统一工作流) | 方案C(模型常驻) |
|------|----------------|------------------|-----------------|
| 改动量 | 小 | 中 | 中-大 |
| 接口2女 | ~11s ❌ | ~8s ✅ | ~9s ✅ |
| 接口3 | ~8s ✅ | ~6s ✅ | ~6s ✅ |
| 接口2男 | ~8s ✅ | ~4s ✅ | ~6s ✅ |
| 质量 | 不变 | 需验证 | 不变 |
| 风险 | 低 | 中(质量) | 中(OOM) |
| 可叠加 | ✅ | ✅ | ✅ |
---
## 我的建议
**推荐:B + C 组合(统一工作流 + 模型常驻)**
理由:
1. **方案C** 从根本上解决模型换出(最大瓶颈),但需要停掉 hair_service_sd 和 SD WebUI
2. **方案B** 降低 steps 到 2-4,进一步减少推理时间
3. **方案B的B3(去swapHair** 是接口2女达标的关键:去掉 swapHair 后不再需要 hair_service_sd 和 SD WebUI,为方案C释放显存
4. 组合后所有接口都能稳定在 6-8s
**关键决策点**:接口2女是否可以去掉 swapHair(换发型)?如果可以,方案B+C组合是最佳选择。如果不行,需要方案A(hair_service_sd 按需启停)+ 方案C + swapHair 异步化。
需要你确认:
1. 接口2女是否可以去掉 swapHair(直接用原图+遮罩 → ComfyUI)?
2. 是否可以永久停止 SD WebUI 和 hair_service_sd
3. steps 从 6 降到 2 是否可接受(需要质量验证)?