2026-07-08 20:35:12 +08:00
2026-07-07 22:04:10 +08:00
2026-07-08 20:35:12 +08:00

换发型服务 - 本地部署文档

本文档说明换发型服务(hair_service_sd)在本机的部署架构、接口用法、训练功能与日常运维操作。 该服务从 szlc@192.168.101.63:/home/szlc/project 克隆部署至本机 /home/xsl/change_hair


一、总体架构

服务由三个独立进程组成,存在调用依赖关系:

                        ┌─────────────────────────────┐
   客户端 ──HTTP──▶     │   hair_service_sd  (:8801)   │   主服务,对外提供所有接口
                        │   conda env: my_hair         │
                        └──────────┬──────────────────┘
                                   │ 换发型/训练时内部调用
                    ┌──────────────┴───────────────┐
                    ▼                              ▼
        ┌──────────────────────┐       ┌──────────────────────┐
        │ photo_service (:32678)│       │   webui (:57860)      │
        │ conda env: py310     │       │   conda env: sdwebui  │
        │ LoRA加载/训练调度     │────▶  │   SD模型 + ControlNet │
        │ 训练: conda env:kohya│ 推理   │   LoRA权重            │
        └──────────────────────┘       └──────────────────────┘
进程 端口 conda 环境 职责
hair_service_sd 8801 my_hair 主服务,对外提供换发色/换发型/上传发型/训练回调接口
photo_service 32678 py310 (推理) / kohya (训练) LoRA 权重加载、webui 推理调度、LoRA 训练执行
webui 57860 sdwebui Stable Diffusion img2img 推理(SD模型 + ControlNet + LoRA

启动顺序(存在依赖):webui → photo_service → hair_service_sd


二、目录结构

所有数据部署在 /home/xsl/change_hair(对应原服务器 /home/szlc/project + /data):

/home/xsl/change_hair/
├── README.md                    # 本文档
├── start_all.sh                 # 统一启动/停止/状态脚本
├── start_photo.sh               # photo_service 启动包装脚本
├── start_hair.sh                # hair_service_sd 启动包装脚本
├── adapt_paths.sh               # 路径适配脚本(部署时一次性执行)
├── fix_conda_paths.py           # conda 环境路径修复脚本(部署时一次性执行)
├── test_haircolor.py            # 换发色接口测试脚本
├── test_swaphair.py             # 换发型接口测试脚本
├── test_train_api.py            # 训练接口测试脚本
│
├── project/                     # ← 原服务器 /home/szlc/project
│   ├── hair_service_sd/         # 主服务(9.9G,含 weights 模型权重)
│   ├── onediff/                 # webui49G,含SD模型+228个LoRA+ControlNet
│   │   └── stable-diffusion-webui/
│   ├── photo_service/           # LoRA调度+训练服务(4.1M
│   ├── kohya_ss_home/           # kohya LoRA训练框架(13G
│   │   └── kohya_ss/            # train_network.py 所在目录
│   ├── data/                    # 发型素材(4.9G
│   │   ├── ref_hairstyle/       # 换发型发型材质(183个发型)
│   │   ├── ref_haircolor/       # 换发色参考
│   │   ├── hair_template_material/  # 发型模板(matting+pkl
│   │   ├── upload_train_imgs/   # 上传发型训练图
│   │   ├── ref_user_imgs/       # ⚠️ 训练素材生成用的参考图(当前为空,见下文说明)
│   │   └── ...
│   └── logs/                    # 所有服务日志
│
└── data/                        # ← 原服务器 /data
    └── train_material/          # 338个发型的LoRA训练素材(121G
        └── <hair_id>/
            ├── images/<N>_hairstyle/*.png   # 训练图片
            └── model/hairstyle_hd_lora.safetensors  # 训练产出的LoRA权重

conda 环境位于 /home/xsl/miniconda3/envs/

环境 Python 用途
my_hair 3.10.13 hair_service_sd 主服务
sdwebui 3.10.19 webui SD 推理
py310 3.10.14 photo_service LoRA调度
kohya 3.10.20 LoRA 训练(本次部署新建,原服务用 Docker

三、日常运维操作

启动 / 停止 / 查看状态

cd /home/xsl/change_hair

bash start_all.sh start     # 启动全部服务(按依赖顺序)
bash start_all.sh stop      # 停止全部服务
bash start_all.sh restart   # 重启全部服务
bash start_all.sh status    # 查看运行状态与端口

启动后 webui 加载 SD 模型需约 1-2 分钟,status 显示端口就绪即表示可用。

查看日志

tail -f project/logs/webui.log           # webui 日志
tail -f project/logs/photo_service.log   # photo_service 日志
tail -f project/logs/hair_service.log    # 主服务日志

运行接口测试

# 换发色测试(生成红色头发)
/home/xsl/miniconda3/envs/my_hair/bin/python test_haircolor.py

# 换发型测试(用已有发型)
/home/xsl/miniconda3/envs/my_hair/bin/python test_swaphair.py

测试结果图保存在 project/logs/test_*_result.jpg


四、接口文档

主服务地址:http://127.0.0.1:8801

1. 换发色 POST /hairColor/v2

把照片中头发的颜色改为指定 RGB。

请求参数JSON):

参数 类型 必填 说明
img string 图片 base64,需带 data:image/jpeg;base64, 前缀
userId string 用户标识
rgb [int,int,int] 目标颜色,长度3的数组,如 [255,0,0] 红色
output_format string base64(返回base64图片)或 url(上传OSS返回链接,默认)

请求示例

import base64, requests

with open("photo.jpg", "rb") as f:
    img_b64 = "data:image/jpeg;base64," + base64.b64encode(f.read()).decode()

resp = requests.post("http://127.0.0.1:8801/hairColor/v2", json={
    "img": img_b64,
    "userId": "user001",
    "rgb": [255, 0, 0],        # 红色
    "output_format": "base64"
})
result = resp.json()
# {"msg": "success", "state": 0, "result": "<base64图片>", "umd": ""}

2. 换发型 POST /api/swapHair/v1

把照片中人物的发型换成指定发型(需该发型已训练好 LoRA)。

请求参数JSON):

参数 类型 必填 说明
hair_id string 发型ID(对应 train_material 和 ref_hairstyle 中的目录名)
task_id string 任务ID(任意唯一字符串)
is_hr string "true" 高清版 / "false" 普通版
user_img_path string 用户照片 base64,需带 data:image/jpeg;base64, 前缀
output_format string base64url(默认)

请求示例

resp = requests.post("http://127.0.0.1:8801/api/swapHair/v1", json={
    "hair_id": "1907641420518580226",
    "task_id": "task_001",
    "is_hr": "true",
    "user_img_path": img_b64,   # data:image/jpeg;base64,...
    "output_format": "base64"
})
result = resp.json()
# {"state": 0, "msg": "success", "data": "<base64图片>", "task_id": "task_001"}

可用发型:发型需同时具备 ref_hairstyle/<hair_id> 材质 + train_material/<hair_id>/model/hairstyle_hd_lora.safetensors 权重。查看可用发型:

# 列出材质+权重都齐全的发型
for hid in $(ls project/data/ref_hairstyle); do
  [ -f data/train_material/$hid/model/hairstyle_hd_lora.safetensors ] && echo "$hid"
done

3. 新增发型训练 POST /api/uploadHair/v1

上传新发型图片,异步训练 LoRA。训练完成后发型即可用于换发型。

请求参数JSON):

参数 类型 必填 说明
hair_id string 新发型ID(自定义唯一ID
img_lists [string] 发型图片 URL 列表(至少1张,需 HTTP 可访问的URL)

注意:此接口 img_lists 必须是 HTTP URL(内部用 requests 下载),不支持 base64。如用本地图片,需先启动一个 HTTP 服务托管。

响应:立即返回 {"msg": "OK", "state": 0},训练在后台异步进行(约 30-40 分钟)。

4. 训练回调 POST /api/hair/trainCallBack

photo_service 训练完成后自动调用此接口通知主服务,一般不由外部直接调用。


五、新增发型训练(LoRA Training

工作原理

原服务通过 Docker 容器(chinatszrn/ubuntu:kohya_ss)运行 kohya 的 train_network.py 训练 LoRA。本机部署已改为本地 conda 环境直接执行,无需 Docker。

完整链路:

uploadHair → 下载图片 → 生成训练素材(matting/pkl/训练图)
          → photo_service 入队
          → 后台 train_thread 执行:
              accelerate launch train_network.py (1500步, 约30-40分钟)
          → 产出 hairstyle_hd_lora.safetensors
          → 回调 trainCallBack
          → 该发型即可用于换发型

训练配置(已适配本机)

photo_service 的训练命令(lora_train_service_1.pytrain_thread 函数)关键参数:

配置项 说明
训练脚本 kohya_ss_home/kohya_ss/train_network.py kohya LoRA 训练
conda 环境 /home/xsl/miniconda3/envs/kohya torch 2.0.1+cu118
基础模型 v1-5-pruned-emaonly.safetensors SD底模(原为 majicmix,本机不存在,已替换)
优化器 AdamW 原为 AdamW8bit(依赖 bitsandbytes,有兼容问题,已改)
训练步数 1500
LoRA维度 128 (network_dim)
GPU device 0 单卡

手动触发训练(不经过 uploadHair)

如果已有训练素材(train_material/<hair_id>/images/<N>_hairstyle/*.png),可直接调用 photo_service 训练:

curl -X POST http://127.0.0.1:32678/api/hair/train \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "manual_train_001",
    "hair_id": "1905785164224868354",
    "hair_material_dir": "/home/xsl/change_hair/data/train_material/1905785164224868354",
    "is_tj": "1",
    "device_id": "0",
    "webui_addr": "http://0.0.0.0:32678/"
  }'

训练进度查看:tail -f project/logs/photo_service.log(搜索 steps:

⚠️ 训练素材生成依赖说明

uploadHair 的完整流程中,生成训练素材这一步依赖 project/data/ref_user_imgs/ 参考图目录(用于人脸对齐生成训练对)。该目录在原服务器上即为空(这是原项目状态)。

  • ref_user_imgs 为空,uploadHair 能下载图片并触发 LoRA 训练,但生成的新训练素材质量会受限
  • 要完整使用 uploadHair 上传全新发型训练,需往 ref_user_imgs/ 补充参考人像图 + 对应的 .pkl 关键点文件

六、部署改动记录

以下是对原服务代码/配置的改动,供维护参考:

1. 路径适配(所有配置和代码)

原服务器路径 → 本机路径的映射:

原路径 本机路径
/home/szlc/project/... /home/xsl/change_hair/project/...
/data/train_material /home/xsl/change_hair/data/train_material
/home/szlc/miniconda3 /home/xsl/miniconda3

涉及文件:hair_service_sd/config/configure.inihair_service_sd/*.pyphoto_service/*.pyonediff/.../config.json 等。 执行脚本:adapt_paths.sh(业务代码)+ fix_conda_paths.pyconda环境)。

2. webui 配置改动

改动 说明
config.json 的 onediff compiler 路径 指向本机 onediff 目录
启动加 HF_HUB_OFFLINE=1 本机无法访问 huggingface.co,用本地缓存离线加载 CLIP
SD 模型 实际加载 v1-5-pruned-emaonlyconfig 里写的 majicmix 不存在,webui 自动 fallback

3. 换发型推理改动(hair_service_sd/gen_super_image.py

refiner_checkpoint 从不存在的 majicmixRealistic_v7.safetensors 改为 v1-5-pruned-emaonly.safetensors(第185、213行)。否则 webui 报 Could not find checkpoint 错误。

4. photo_service 训练改动(photo_service/lora_train_service_1.py

改动 原值 新值
LoRA 输出目录 /gz-fs/Lora webui 的 models/Lora 目录(实际路径)
kohya 训练目录 /root/project/kohya_ss_home 本机 kohya_ss_home
训练方式 sudo docker run chinatszrn/ubuntu:kohya_ss accelerate launch ... 本地 accelerate launch ...conda kohya 环境)
基础模型 /mnt/nas_hdd/.../majicmixRealistic_v7.safetensors 本机 v1-5-pruned-emaonly.safetensors
优化器 AdamW8bitbitsandbytes AdamWtorch 原生)
tokenizer --tokenizer_cache_dir=/home/chinatszrn/.cache/clip 删除(用 HF 缓存 + 离线模式)

七、已知限制与注意事项

  1. OSS 上传:换发色/换发型默认 output_format=url 会把结果图上传到生产阿里云 OSS(密钥硬编码在代码中)。仅本地测试时建议用 output_format=base64 避免污染生产环境。

  2. 网络限制:本机无法访问 huggingface.co。webui 和训练都依赖本地 HF 缓存(~/.cache/huggingface),已配置离线模式。如需新增 HF 模型需手动准备缓存。

  3. ref_user_imgs 为空:影响 uploadHair 生成训练素材的完整性(见第五节说明)。

  4. 单卡部署GPU 固定使用 device 0。CUDA_VISIBLE_DEVICES=0 已写入启动脚本。如有多卡需求需调整配置。

  5. 服务进程保活:服务通过 nohup + wrapper 脚本启动。切勿直接 python xxx.py & 启动,会被 shell 会话退出时清理。请始终用 start_all.sh startstart_*.sh 脚本。

  6. webui 启动较慢:加载 SD 模型需 1-2 分钟,启动后需等待 start_all.sh status 显示端口就绪才能正常服务。


八、快速排障

现象 可能原因 解决
换发型报 推理发型失败 webui 未就绪或 LoRA 缺失 start_all.sh status 检查 webui 端口;确认发型 LoRA 存在
webui 报 Could not find checkpoint refiner 模型名不对 确认 gen_super_image.py 的 refiner_checkpoint 为 v1-5-pruned-emaonly.safetensors
训练报 bitsandbytes 错误 bnb 版本/优化器问题 确认用 AdamW(非 AdamW8bit
webui 卡在 huggingface 重试 HF 离线模式未启用 启动脚本已设 HF_HUB_OFFLINE=1,确认未丢失
服务启动后立即退出 未用 wrapper 脚本启动 start_all.sh start 启动
conda 环境 python 段错误 环境二进制损坏 重新 rsync 环境并用 fix_conda_paths.py 修复(勿用 sed
S
Description
No description provided
Readme
20 MiB
Languages
Python 94.7%
HTML 4.2%
Shell 0.6%
C++ 0.5%