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

11 KiB
Raw Permalink Blame History

目标:所有接口 < 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 管理:

# 启动 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,触发模型加载:

# 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 模型管理优化

设置环境变量:

export COMFYUI_MODEL_KEEP=true  # 保持模型加载

或在 ComfyUI 的 extra_model_paths.yamlcomfyui/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 是否可接受(需要质量验证)?