# 换发型项目部署操作手册 本手册详细描述在全新的 Ubuntu 22.04 + NVIDIA 3090 机器上,从零开始部署并运行换发型、换发色、训练模型三大功能的完整步骤。 --- ## 目录 1. [环境前提](#1-环境前提) 2. [安装系统依赖](#2-安装系统依赖) 3. [Clone 代码](#3-clone-代码) 4. [下载网盘文件](#4-下载网盘文件) 5. [运行部署脚本](#5-运行部署脚本) 6. [启动服务](#6-启动服务) 7. [验证功能](#7-验证功能) 8. [API 接口参考](#8-api-接口参考) 9. [停止与重启服务](#9-停止与重启服务) 10. [常见问题排查](#10-常见问题排查) 11. [架构说明](#11-架构说明) --- ## 1. 环境前提 | 项目 | 要求 | |------|------| | 操作系统 | Ubuntu 22.04 LTS | | GPU | NVIDIA RTX 3090(或其他 10GB+ 显存的 NVIDIA GPU) | | NVIDIA 驱动 | ≥ 525.x(支持 CUDA 11.8) | | 磁盘空间 | ≥ 90GB(代码 + 模型 + 环境) | | 网络 | 需要访问 PyPI(创建 py310 环境时下载 pip 包) | | Python | 不需要预装(通过 conda 管理) | 验证 GPU 和驱动: ```bash nvidia-smi # 应显示 GPU 信息和 CUDA 版本(≥ 11.8) ``` --- ## 2. 安装系统依赖 ### 2.1 安装基础工具 ```bash sudo apt update sudo apt install -y git curl wget lsof ``` ### 2.2 安装 Miniconda(如未安装) ```bash # 下载并安装 Miniconda wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda3 # 初始化 conda $HOME/miniconda3/bin/conda init bash source ~/.bashrc # 验证 conda --version ``` ### 2.3 配置 conda 镜像(国内可选,加速 py310 创建) ```bash conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main conda config --set show_channel_urls yes ``` --- ## 3. Clone 代码 ```bash cd ~ git clone <仓库地址> change_hair_3090 cd change_hair_3090 ``` Clone 后的目录结构(仅代码,不含模型/环境): ``` change_hair_3090/ ├── hair_service_sd/ # 换发算法服务代码 ├── photo_service/ # 训练调度服务代码 ├── stable-diffusion-webui/ # SD WebUI 代码(不含 models/) ├── kohya_ss_home/ # kohya_ss 训练代码(不含 .local/) ├── conda_envs/ │ └── py310.yml # py310 环境定义文件 ├── setup.sh # 部署脚本 ├── start_all_services.sh # 启动脚本 ├── stop_all_services.sh # 停止脚本 └── README.md ``` --- ## 4. 下载网盘文件 将网盘上的 `cloud_packages/` 目录下载到项目根目录。网盘文件已分类打包为 14 个文件,便于上传和下载。 ### 4.1 网盘文件清单(已分类打包) | 文件 | 大小 | 说明 | |------|------|------| | `my_hair.tar.gz` | 4.2G | conda 环境(换发算法服务用) | | `sdwebui.tar.gz` | 3.6G | conda 环境(SD WebUI 用) | | `kohya.tar.gz` | 84M | conda 环境(LoRA 训练用,仅含 Python+numpy) | | `sd_base_models.tar.gz` | 3.6G | SD 底模(v1-5-pruned-emaonly.safetensors) | | `lora_0-9.tar.gz` | 29G | LoRA 模型(数字开头,约 228 个) | | `lora_h.tar.gz` | 132M | LoRA 模型(h 开头) | | `lora_n.tar.gz` | 132M | LoRA 模型(n 开头) | | `lora_t.tar.gz` | 791M | LoRA 模型(t 开头) | | `weights.tar.gz` | 9.2G | 换发算法模型(matting、分割等) | | `kohya_local.tar.gz` | 3.4G | 训练 pip 包(torch、accelerate、diffusers 等) | | `kohya_code.tar.gz` | 365M | kohya_ss 训练代码 + CLIP 缓存 | | `data.tar.gz` | 3.4G | 业务数据(参考发型图等) | | `webui_controlnet.tar.gz` | 4.1G | ControlNet 扩展 | | `webui_repositories.tar.gz` | 221M | SD 依赖仓库(k-diffusion 等) | **合计约 62G** ### 4.2 下载后解压 ```bash cd ~/change_hair_3090 # 创建 cloud_packages 目录并下载网盘文件到这里 mkdir -p cloud_packages # ... 将网盘上的 cloud_packages/ 目录下载到这里 ... # 解压所有包(按顺序执行) echo "=== 1. 解压 conda 环境 ===" tar -xzf cloud_packages/my_hair.tar.gz -C conda_envs/ tar -xzf cloud_packages/sdwebui.tar.gz -C conda_envs/ tar -xzf cloud_packages/kohya.tar.gz -C conda_envs/ echo "=== 2. 解压 SD 模型 ===" tar -xzf cloud_packages/sd_base_models.tar.gz -C stable-diffusion-webui/models/Stable-diffusion/ echo "=== 3. 解压 LoRA 模型 ===" tar -xzf cloud_packages/lora_0-9.tar.gz -C stable-diffusion-webui/models/Lora/ tar -xzf cloud_packages/lora_h.tar.gz -C stable-diffusion-webui/models/Lora/ tar -xzf cloud_packages/lora_n.tar.gz -C stable-diffusion-webui/models/Lora/ tar -xzf cloud_packages/lora_t.tar.gz -C stable-diffusion-webui/models/Lora/ echo "=== 4. 解压换发算法权重 ===" tar -xzf cloud_packages/weights.tar.gz -C hair_service_sd/ echo "=== 5. 解压 kohya 训练环境 ===" tar -xzf cloud_packages/kohya_local.tar.gz -C kohya_ss_home/ tar -xzf cloud_packages/kohya_code.tar.gz -C kohya_ss_home/ echo "=== 6. 解压业务数据 ===" tar -xzf cloud_packages/data.tar.gz -C . echo "=== 7. 解压 WebUI 扩展 ===" tar -xzf cloud_packages/webui_controlnet.tar.gz -C stable-diffusion-webui/extensions/ tar -xzf cloud_packages/webui_repositories.tar.gz -C stable-diffusion-webui/ ``` ### 4.3 解压后验证 ```bash cd ~/change_hair_3090 # 检查关键文件是否存在 ls -lh conda_envs/*.tar.gz ls -d hair_service_sd/weights/ ls -d kohya_ss_home/.local/ ls -lh stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors ``` 期望输出: ``` -rw------- ... 84M ... conda_envs/kohya.tar.gz -rw------- ... 4.2G ... conda_envs/my_hair.tar.gz -rw------- ... 3.6G ... conda_envs/sdwebui.tar.gz hair_service_sd/weights/ kohya_ss_home/.local/ -rw-rw-r-- ... 4.0G ... v1-5-pruned-emaonly.safetensors ``` ### 4.3 关于 kohya 训练环境的架构说明 LoRA 训练环境由两部分组成,缺一不可: ``` conda_envs/kohya.tar.gz (84M) kohya_ss_home/.local/ (7.6G) ┌─────────────────────────┐ ┌──────────────────────────────────┐ │ Python 3.10 解释器 │ │ torch 2.0.1+cu118 │ │ numpy 1.24.4 │ +PYTHONPATH→ │ accelerate 0.23.0 │ │ tqdm │ │ bitsandbytes 0.41.1 │ │ setuptools 69.5.1 │ │ diffusers 0.21.4 │ │ (conda-pack 打包) │ │ transformers 4.30.2 │ │ │ │ xformers 0.0.21 │ │ │ │ safetensors, pytorch_lightning │ │ │ │ (从 Docker 容器复制的 pip 包) │ └─────────────────────────┘ └──────────────────────────────────┘ ``` `kohya.tar.gz` 仅包含 Python 解释器和 numpy(解决版本兼容性),通过 `PYTHONPATH` 环境变量指向 `.local/` 目录来加载 torch 等大包。这样避免重新下载 7.6G 的训练依赖。 --- ## 5. 运行部署脚本 ```bash cd ~/change_hair_3090 chmod +x setup.sh start_all_services.sh stop_all_services.sh ./setup.sh ``` ### 5.1 setup.sh 执行的 8 个步骤 | 步骤 | 说明 | |------|------| | 1/8 | 检查前提条件(git、conda、NVIDIA 驱动) | | 2/8 | 生成 `configure.ini`(自动替换 `__BASE_DIR__` 为实际路径) | | 3/8 | 从 conda-pack 恢复 my_hair、sdwebui、kohya 三个 conda 环境 | | 4/8 | 从 `py310.yml` 创建 py310 环境(需联网下载 pip 包) | | 5/8 | 检查模型和数据目录完整性 | | 6/8 | 检查训练底模 `v1-5-pruned-emaonly.safetensors` | | 7/8 | 创建运行时目录(logs、data/tmp 等) | | 8/8 | 验证 kohya 训练环境(测试 torch/accelerate 能否加载) | ### 5.2 成功输出 ``` === 换发型项目部署脚本 === BASE_DIR: /home/xxx/change_hair_3090 CONDA_BASE: /home/xxx/miniconda3 [1/8] 检查前提条件... ✓ 前提条件满足 [2/8] 生成 configure.ini... ✓ configure.ini 已生成 [3/8] 恢复 conda 环境(my_hair, sdwebui, kohya)... ✓ my_hair 已恢复 ✓ sdwebui 已恢复 ✓ kohya 已恢复 [4/8] 创建 py310 环境(从 yml)... ✓ py310 已创建 [5/8] 检查模型和数据目录... ✓ hair_service_sd/weights ✓ stable-diffusion-webui/models/Lora ...(全部 ✓) [6/8] 检查训练底模 v1-5-pruned-emaonly... ✓ v1-5-pruned-emaonly.safetensors 已存在 [7/8] 创建运行时目录... ✓ 运行时目录已创建 [8/8] 验证 kohya 训练环境... 测试 torch/accelerate 加载... torch=2.0.1+cu118 cuda=True accelerate=0.23.0 ✓ 训练环境验证通过 === 部署结果 === ✓ 所有检查通过,部署完成! ``` ### 5.3 如果 CONDA_BASE 不在默认路径 ```bash # 方法1:设置环境变量 export CONDA_BASE=/your/conda/path ./setup.sh # 方法2:脚本会自动通过 `conda info --base` 检测 # 只要 conda 在 PATH 中即可自动找到 ``` --- ## 6. 启动服务 ```bash ./start_all_services.sh ``` ### 6.1 启动的三个服务 | 服务 | 端口 | conda 环境 | 功能 | |------|------|-----------|------| | hair_service_sd | 8801 | my_hair | 换发型/换发色核心算法 | | stable-diffusion-webui | 57860 | sdwebui | SD 图生图推理 | | photo_service | 32678 | py310 | LoRA 训练调度(训练子进程使用 kohya 环境) | ### 6.2 成功输出 ``` === 启动换发型服务 === [1/3] 启动 hair_service_sd (端口 8801)... hair_service_sd 已启动 (PID: xxxx, 端口 8801) [2/3] 启动 stable-diffusion-webui (端口 57860)... stable-diffusion-webui 已启动 (PID: xxxx, 端口 57860) ℹ WebUI 首次启动需加载模型(约 30-60 秒),请耐心等待 [3/3] 启动 photo_service (端口 32678)... photo_service 已启动 (PID: xxxx, 端口 32678) === 所有服务已启动 === 等待 WebUI 就绪(检查端口 57860)... ✓ WebUI 已就绪 ``` ### 6.3 查看日志 ```bash # 换发型/换发色服务日志 tail -f logs/hair_service.log # SD WebUI 日志 tail -f logs/webui.log # 训练服务日志 tail -f logs/photo_service.log ``` --- ## 7. 验证功能 ### 7.1 验证服务状态 ```bash # 检查三个端口是否在监听 curl -s http://127.0.0.1:8801/ | head -5 curl -s http://127.0.0.1:57860/sdapi/v1/options | head -5 curl -s http://127.0.0.1:32678/ | head -5 ``` ### 7.2 验证换发色功能 ```bash # 准备一张人像照片(base64 编码) IMG_B64=$(base64 -w0 test_photo.jpg) curl -X POST http://127.0.0.1:8801/hairColor/v2 \ -H "Content-Type: application/json" \ -d "{ \"img\": \"data:image/jpeg;base64,${IMG_B64}\", \"userId\": \"test_user\", \"rgb\": \"120,60,30\" }" ``` 参数说明: - `img`:用户照片,支持 base64(`data:image/jpeg;base64,...`)或 URL - `userId`:用户标识 - `rgb`:目标发色 RGB 值(如 `120,60,30` 表示棕色) ### 7.3 验证换发型功能 ```bash curl -X POST http://127.0.0.1:8801/api/swapHair/v1 \ -H "Content-Type: application/json" \ -d "{ \"hair_id\": \"<发型ID>\", \"task_id\": \"test_001\", \"is_hr\": \"false\", \"user_img_path\": \"data:image/jpeg;base64,${IMG_B64}\" }" ``` 参数说明: - `hair_id`:发型 ID(对应 `data/ref_hairstyle/` 目录下的发型) - `task_id`:任务唯一标识 - `is_hr`:是否高清模式(`"true"` 或 `"false"`) - `user_img_path`:用户照片,支持 base64 或 URL ### 7.4 验证训练功能 训练需要准备训练素材(10+ 张同一发型的照片),组织成指定目录结构: ``` hair_material_dir/ ├── images/ │ └── 1_hairstyle/ # 数字开头的文件夹 │ ├── 001.png # 训练图片(≥10张) │ ├── 001.txt # 标签文件(自动生成) │ ├── 002.png │ ├── 002.txt │ └── ... └── model/ # 训练输出目录(需提前创建) ``` 发起训练请求: ```bash curl -X POST http://127.0.0.1:32678/api/hair/train \ -H "Content-Type: application/json" \ -d "{ \"task_id\": \"train_001\", \"hair_id\": \"test_hair\", \"hair_material_dir\": \"/home/xxx/change_hair_3090/data/tmp/test_material\" }" ``` 训练日志查看: ```bash tail -f logs/photo_service.log # 训练开始后会看到 cmd_train 输出 # 训练完成后会在 hair_material_dir/model/ 下生成 hairstyle_hd_lora.safetensors ``` 训练参数(已在代码中固定): - 底模:`v1-5-pruned-emaonly.safetensors` - 训练步数:1500 步 - 分辨率:2000x2000 - LoRA dim:128,alpha:64 - 优化器:AdamW8bit - 精度:fp16 --- ## 8. API 接口参考 ### 8.1 换发色 API | 项目 | 值 | |------|-----| | URL | `POST http://:8801/hairColor/v2` | | 参数 | `img`(base64或URL), `userId`, `rgb`(如`"120,60,30"`) | | 返回 | JSON,含换色后的图片 URL 或 base64 | ### 8.2 换发型 API | 项目 | 值 | |------|-----| | URL | `POST http://:8801/api/swapHair/v1` | | 参数 | `hair_id`, `task_id`, `is_hr`, `user_img_path`(base64或URL), `output_format`(可选) | | 返回 | JSON,含换发后的图片 URL 或 base64 | ### 8.3 训练 API | 项目 | 值 | |------|-----| | URL | `POST http://:32678/api/hair/train` | | 参数 | `task_id`, `hair_id`, `hair_material_dir`(训练素材目录绝对路径) | | 返回 | `{"state": 0, "msg": "头发lora训练开始", "task_id": "..."}` | | 训练回调 | 训练完成/失败后 POST 到 `http://127.0.0.1:8801/api/hair/trainCallBack` | ### 8.4 推理 API | 项目 | 值 | |------|-----| | URL | `POST http://:32678/api/hair/inference` | | 参数 | `hair_id`, `inference_port`, `hair_material_dir`, `request_json`(SD WebUI img2img 请求体) | --- ## 9. 停止与重启服务 ### 9.1 停止所有服务 ```bash ./stop_all_services.sh ``` 输出: ``` === 停止换发型服务 === ✓ 已停止 hair_service_sd (端口 8801, PID xxxx) ✓ 已停止 webui (端口 57860, PID xxxx) ✓ 已停止 photo_service (端口 32678, PID xxxx) ``` ### 9.2 重启服务 ```bash ./stop_all_services.sh ./start_all_services.sh ``` ### 9.3 手动停止单个服务 ```bash kill $(lsof -t -i:8801) # 停止换发服务 kill $(lsof -t -i:57860) # 停止 WebUI kill $(lsof -t -i:32678) # 停止训练服务 ``` --- ## 10. 常见问题排查 ### 10.1 setup.sh 报错 "conda 未安装" ```bash # 确认 conda 已安装 which conda # 如果没有,参考第2.2节安装 Miniconda ``` ### 10.2 setup.sh 报错 "CONDA_BASE 不正确" ```bash # 查找 conda 安装路径 which conda # 或 conda info --base # 设置后重新运行 export CONDA_BASE=$(conda info --base) ./setup.sh ``` ### 10.3 py310 环境创建失败(网络问题) py310 环境需要从 PyPI 下载 pip 包(flask、gevent、opencv-python 等)。如果网络不通: ```bash # 使用国内 PyPI 镜像 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # 手动创建 conda create -n py310 python=3.10 -y conda activate py310 pip install flask==3.0.3 gevent==24.2.1 opencv-python==4.10.0.84 numpy==2.0.0 scipy==1.14.0 scikit-image==0.24.0 pillow==10.4.0 requests==2.32.3 ``` ### 10.4 start_all_services.sh 报 "端口已被占用" ```bash # 先停止已有服务 ./stop_all_services.sh # 确认端口已释放 lsof -i :8801 lsof -i :57860 lsof -i :32678 # 重新启动 ./start_all_services.sh ``` ### 10.5 WebUI 启动失败 ```bash # 查看详细日志 tail -100 logs/webui.log # 常见原因: # 1. 模型文件缺失 → 检查 stable-diffusion-webui/models/Stable-diffusion/ # 2. 显存不足 → 检查 nvidia-smi # 3. xformers 兼容性 → 尝试去掉 --xformers 参数 ``` ### 10.6 训练失败 ```bash # 查看训练日志 tail -100 logs/photo_service.log # 常见原因: # 1. 训练素材目录结构不对 → 参考 7.4 节 # 2. 底模缺失 → 检查 v1-5-pruned-emaonly.safetensors # 3. .local 包损坏 → 重新从网盘下载 kohya_ss_home/.local/ # 4. kohya 环境问题 → 重新运行 setup.sh ``` ### 10.7 GPU 不可用(CUDA error) ```bash # 检查驱动 nvidia-smi # 检查 CUDA nvcc --version # 测试 torch CUDA CONDA_BASE=$(conda info --base) PYTHONPATH=$PWD/kohya_ss_home/.local/lib/python3.10/site-packages \ $CONDA_BASE/envs/kohya/bin/python -c "import torch; print(torch.cuda.is_available())" # 应输出 True ``` ### 10.8 内存不足(OOM) 3090 有 24GB 显存。如果同时运行三个服务出现 OOM: ```bash # 先停止不需要的服务 ./stop_all_services.sh # 只启动需要的服务(如只换发型) $CONDA_BASE/envs/my_hair/bin/python hair_service_sd/run_copy_cost_colorb64.py & $CONDA_BASE/envs/sdwebui/bin/python stable-diffusion-webui/webui.py --api --listen --xformers --port 57860 & ``` --- ## 11. 架构说明 ### 11.1 系统架构 ``` 用户请求 │ ┌─────────────┼─────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │hair_service│ │photo_service│ │stable-diffusion│ │ _sd │ │ │ │ -webui │ │ (8801) │ │ (32678) │ │ (57860) │ └────┬─────┘ └─────┬─────┘ └───────┬────────┘ │ │ │ │ 训练子进程 │ │ │ │ │ ┌────────┴────────┐ │ │ │ kohya conda env │ │ │ │ + .local/ 包 │ │ │ │ accelerate │ │ │ │ train_network │ │ │ └─────────────────┘ │ │ │ ▼ ▼ weights/ models/Stable-diffusion/ (换发模型) v1-5-pruned-emaonly.safetensors models/Lora/ (228个LoRA) ``` ### 11.2 数据流 **换发型/换发色**: ``` 用户图片 → hair_service_sd(8801) → 调用 WebUI(57860) img2img → 返回结果 ``` **训练 LoRA**: ``` 训练素材 → photo_service(32678) → kohya环境+accelerate → train_network.py → 生成 LoRA ``` **训练后推理**: ``` 用户图片 + LoRA → photo_service(32678) → 复制LoRA到webui/models/Lora/ → WebUI img2img → 返回 ``` ### 11.3 conda 环境说明 | 环境 | 用途 | 包含内容 | 大小 | |------|------|---------|------| | my_hair | 换发算法服务 | torch, cv2, flask, 换发依赖 | 4.2G | | sdwebui | SD WebUI | torch, xformers, webui 依赖 | 3.6G | | py310 | 训练调度服务 | flask, gevent, cv2, numpy 2.0 | ~500M | | kohya | LoRA 训练 | Python 3.10, numpy 1.24 | 84M | | .local/ | 训练大包(非conda) | torch 2.0.1, accelerate, diffusers | 7.6G | kohya 环境通过 `PYTHONPATH` 指向 `.local/` 目录来复用训练大包,避免重复下载。 --- ## 附录:完整部署速查 ```bash # 1. 安装 conda(如未安装) wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda3 source ~/.bashrc # 2. Clone 代码 cd ~ git clone <仓库地址> change_hair_3090 cd change_hair_3090 # 3. 下载网盘文件(合并到项目根目录) # ... 手动下载 ... # 4. 部署 chmod +x setup.sh start_all_services.sh stop_all_services.sh ./setup.sh # 5. 启动 ./start_all_services.sh # 6. 验证 curl http://127.0.0.1:8801/ curl http://127.0.0.1:57860/sdapi/v1/options curl http://127.0.0.1:32678/ # 7. 停止 ./stop_all_services.sh ```