完善部署脚本兼容性并生成详细部署手册
- setup.sh: 自动检测 CONDA_BASE(conda info --base),移除 set -e 改为 错误收集,新增第8步验证 kohya 训练环境(测试 torch/accelerate 加载) - start_all_services.sh: 自动检测 CONDA_BASE,新增端口冲突检测和 WebUI 就绪等待(最多60秒轮询) - stop_all_services.sh: 新增停止脚本,按端口停止三个服务 - py310.yml: 移除硬编码 prefix 路径,避免跨机器部署问题 - DEPLOY.md: 详细部署操作手册,覆盖从 clone 到验证三大功能的全流程 - 已验证: kohya.tar.gz 解压→conda-unpack→PYTHONPATH 加载全部通过
This commit is contained in:
@@ -0,0 +1,644 @@
|
|||||||
|
# 换发型项目部署操作手册
|
||||||
|
|
||||||
|
本手册详细描述在全新的 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. 下载网盘文件
|
||||||
|
|
||||||
|
将网盘上的以下文件/目录下载到项目根目录(与代码合并)。**所有路径必须与下表一致**。
|
||||||
|
|
||||||
|
### 4.1 网盘文件清单
|
||||||
|
|
||||||
|
| 路径 | 大小 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `hair_service_sd/weights/` | 9.9G | 换发算法模型(matting、分割等) |
|
||||||
|
| `stable-diffusion-webui/models/` | 41G | SD 模型 + 228 个 LoRA + 辅助模型 |
|
||||||
|
| `stable-diffusion-webui/extensions/sd-webui-controlnet/` | 4.4G | ControlNet 扩展 |
|
||||||
|
| `stable-diffusion-webui/repositories/` | 225M | SD 依赖仓库(k-diffusion 等) |
|
||||||
|
| `kohya_ss_home/.local/` | 7.6G | 训练 pip 包(torch、accelerate、diffusers 等) |
|
||||||
|
| `kohya_ss_home/.cache/` | 3.3M | CLIP tokenizer 缓存 |
|
||||||
|
| `kohya_ss_home/kohya_ss/` | 439M | kohya_ss 训练代码 |
|
||||||
|
| `data/` | 4.9G | 业务数据(参考发型图等) |
|
||||||
|
| `conda_envs/my_hair.tar.gz` | 4.2G | conda 环境(换发算法服务用) |
|
||||||
|
| `conda_envs/sdwebui.tar.gz` | 3.6G | conda 环境(SD WebUI 用) |
|
||||||
|
| `conda_envs/kohya.tar.gz` | 84M | conda 环境(LoRA 训练用,仅含 Python+numpy) |
|
||||||
|
|
||||||
|
**合计约 76G**
|
||||||
|
|
||||||
|
### 4.2 下载后验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/change_hair_3090
|
||||||
|
|
||||||
|
# 检查关键文件是否存在
|
||||||
|
ls -lh conda_envs/*.tar.gz
|
||||||
|
ls -d hair_service_sd/weights/
|
||||||
|
ls -d kohya_ss_home/.local/
|
||||||
|
ls -d 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/
|
||||||
|
stable-diffusion-webui/models/Stable-diffusion/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://<IP>:8801/hairColor/v2` |
|
||||||
|
| 参数 | `img`(base64或URL), `userId`, `rgb`(如`"120,60,30"`) |
|
||||||
|
| 返回 | JSON,含换色后的图片 URL 或 base64 |
|
||||||
|
|
||||||
|
### 8.2 换发型 API
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| URL | `POST http://<IP>: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://<IP>: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://<IP>: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
|
||||||
|
```
|
||||||
@@ -52,4 +52,3 @@ dependencies:
|
|||||||
- werkzeug==3.0.3
|
- werkzeug==3.0.3
|
||||||
- zope-event==5.0
|
- zope-event==5.0
|
||||||
- zope-interface==6.4.post2
|
- zope-interface==6.4.post2
|
||||||
prefix: /home/szlc/miniconda3/envs/py310
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
|
||||||
|
|
||||||
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
CONDA_BASE="${CONDA_BASE:-/home/szlc/miniconda3}"
|
|
||||||
|
# 自动检测 conda 安装路径(优先用环境变量,其次用 conda info --base)
|
||||||
|
if [ -z "$CONDA_BASE" ]; then
|
||||||
|
if command -v conda >/dev/null 2>&1; then
|
||||||
|
CONDA_BASE="$(conda info --base 2>/dev/null)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
CONDA_BASE="${CONDA_BASE:-$HOME/miniconda3}"
|
||||||
|
|
||||||
# 初始化 conda(脚本中需要 source 才能用 conda activate)
|
# 初始化 conda(脚本中需要 source 才能用 conda activate)
|
||||||
if [ -f "$CONDA_BASE/etc/profile.d/conda.sh" ]; then
|
if [ -f "$CONDA_BASE/etc/profile.d/conda.sh" ]; then
|
||||||
@@ -13,68 +19,112 @@ fi
|
|||||||
|
|
||||||
echo "=== 换发型项目部署脚本 ==="
|
echo "=== 换发型项目部署脚本 ==="
|
||||||
echo "BASE_DIR: $BASE_DIR"
|
echo "BASE_DIR: $BASE_DIR"
|
||||||
|
echo "CONDA_BASE: $CONDA_BASE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
ERRORS=()
|
||||||
|
|
||||||
# 1. 检查前提条件
|
# 1. 检查前提条件
|
||||||
echo "[1/7] 检查前提条件..."
|
echo "[1/8] 检查前提条件..."
|
||||||
command -v git >/dev/null || { echo "ERROR: git 未安装"; exit 1; }
|
command -v git >/dev/null || { echo " ✗ git 未安装"; ERRORS+=("git"); }
|
||||||
command -v conda >/dev/null || { echo "ERROR: conda 未安装"; exit 1; }
|
command -v conda >/dev/null || { echo " ✗ conda 未安装"; ERRORS+=("conda"); }
|
||||||
nvidia-smi >/dev/null 2>&1 || { echo "ERROR: NVIDIA 驱动未安装"; exit 1; }
|
nvidia-smi >/dev/null 2>&1 || { echo " ✗ NVIDIA 驱动未安装"; ERRORS+=("nvidia-smi"); }
|
||||||
|
if [ ${#ERRORS[@]} -eq 0 ]; then
|
||||||
|
echo " ✓ 前提条件满足"
|
||||||
|
fi
|
||||||
|
|
||||||
# 2. 生成 configure.ini
|
# 2. 生成 configure.ini
|
||||||
echo "[2/7] 生成 configure.ini..."
|
echo "[2/8] 生成 configure.ini..."
|
||||||
sed "s|__BASE_DIR__|$BASE_DIR|g" "$BASE_DIR/hair_service_sd/config/configure.ini.template" > "$BASE_DIR/hair_service_sd/config/configure.ini"
|
sed "s|__BASE_DIR__|$BASE_DIR|g" "$BASE_DIR/hair_service_sd/config/configure.ini.template" > "$BASE_DIR/hair_service_sd/config/configure.ini"
|
||||||
echo " configure.ini 已生成"
|
echo " ✓ configure.ini 已生成"
|
||||||
|
|
||||||
# 3. 恢复 conda 环境(conda-pack)
|
# 3. 恢复 conda 环境(conda-pack)
|
||||||
echo "[3/7] 恢复 conda 环境..."
|
echo "[3/8] 恢复 conda 环境(my_hair, sdwebui, kohya)..."
|
||||||
for env_name in my_hair sdwebui kohya; do
|
for env_name in my_hair sdwebui kohya; do
|
||||||
if [ -f "$BASE_DIR/conda_envs/${env_name}.tar.gz" ]; then
|
if [ -f "$BASE_DIR/conda_envs/${env_name}.tar.gz" ]; then
|
||||||
echo " 恢复 $env_name ..."
|
echo " 恢复 $env_name ..."
|
||||||
rm -rf "$CONDA_BASE/envs/$env_name"
|
rm -rf "$CONDA_BASE/envs/$env_name"
|
||||||
mkdir -p "$CONDA_BASE/envs/$env_name"
|
mkdir -p "$CONDA_BASE/envs/$env_name"
|
||||||
tar -xzf "$BASE_DIR/conda_envs/${env_name}.tar.gz" -C "$CONDA_BASE/envs/$env_name"
|
tar -xzf "$BASE_DIR/conda_envs/${env_name}.tar.gz" -C "$CONDA_BASE/envs/$env_name"
|
||||||
conda activate "$env_name"
|
conda activate "$env_name" 2>/dev/null
|
||||||
conda-unpack # 修复打包后的硬编码路径
|
conda-unpack 2>/dev/null # 修复打包后的硬编码路径
|
||||||
conda deactivate
|
conda deactivate 2>/dev/null
|
||||||
echo " ✓ $env_name 已恢复"
|
echo " ✓ $env_name 已恢复"
|
||||||
else
|
else
|
||||||
echo " ✗ conda_envs/${env_name}.tar.gz 不存在,请从网盘下载"
|
echo " ✗ conda_envs/${env_name}.tar.gz 不存在,请从网盘下载"
|
||||||
|
ERRORS+=("conda_envs/${env_name}.tar.gz")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 4. 创建 py310 环境(从 yml)
|
# 4. 创建 py310 环境(从 yml)
|
||||||
echo "[4/7] 创建 py310 环境..."
|
echo "[4/8] 创建 py310 环境(从 yml)..."
|
||||||
if [ -f "$BASE_DIR/conda_envs/py310.yml" ]; then
|
if [ -f "$BASE_DIR/conda_envs/py310.yml" ]; then
|
||||||
conda env create -f "$BASE_DIR/conda_envs/py310.yml" -n py310 2>/dev/null || echo " py310 环境已存在,跳过"
|
conda env create -f "$BASE_DIR/conda_envs/py310.yml" -n py310 2>/dev/null && echo " ✓ py310 已创建" || echo " ℹ py310 环境已存在,跳过"
|
||||||
echo " ✓ py310 已就绪"
|
|
||||||
else
|
else
|
||||||
echo " ✗ conda_envs/py310.yml 不存在"
|
echo " ✗ conda_envs/py310.yml 不存在"
|
||||||
|
ERRORS+=("conda_envs/py310.yml")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5. 检查模型/数据目录
|
# 5. 检查模型/数据目录
|
||||||
echo "[5/7] 检查模型和数据目录..."
|
echo "[5/8] 检查模型和数据目录..."
|
||||||
for dir in hair_service_sd/weights stable-diffusion-webui/models/Lora stable-diffusion-webui/models/Stable-diffusion stable-diffusion-webui/extensions/sd-webui-controlnet stable-diffusion-webui/repositories kohya_ss_home/.local kohya_ss_home/kohya_ss data/ref_hairstyle; do
|
for dir in hair_service_sd/weights stable-diffusion-webui/models/Lora stable-diffusion-webui/models/Stable-diffusion stable-diffusion-webui/extensions/sd-webui-controlnet stable-diffusion-webui/repositories kohya_ss_home/.local kohya_ss_home/kohya_ss data/ref_hairstyle; do
|
||||||
if [ -d "$BASE_DIR/$dir" ]; then
|
if [ -d "$BASE_DIR/$dir" ]; then
|
||||||
echo " ✓ $dir"
|
echo " ✓ $dir"
|
||||||
else
|
else
|
||||||
echo " ✗ $dir 缺失,请从网盘下载"
|
echo " ✗ $dir 缺失,请从网盘下载"
|
||||||
|
ERRORS+=("$dir")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 6. 检查训练底模
|
# 6. 检查训练底模
|
||||||
echo "[6/7] 检查训练底模 v1-5-pruned-emaonly..."
|
echo "[6/8] 检查训练底模 v1-5-pruned-emaonly..."
|
||||||
if [ -f "$BASE_DIR/stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors" ]; then
|
if [ -f "$BASE_DIR/stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors" ]; then
|
||||||
echo " ✓ v1-5-pruned-emaonly.safetensors 已存在"
|
echo " ✓ v1-5-pruned-emaonly.safetensors 已存在"
|
||||||
else
|
else
|
||||||
echo " ✗ v1-5-pruned-emaonly.safetensors 缺失,请从网盘下载 models/ 目录"
|
echo " ✗ v1-5-pruned-emaonly.safetensors 缺失,请从网盘下载 models/ 目录"
|
||||||
|
ERRORS+=("v1-5-pruned-emaonly.safetensors")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7. 创建运行时目录
|
# 7. 创建运行时目录
|
||||||
echo "[7/7] 创建运行时目录..."
|
echo "[7/8] 创建运行时目录..."
|
||||||
mkdir -p "$BASE_DIR/logs"
|
mkdir -p "$BASE_DIR/logs"
|
||||||
mkdir -p "$BASE_DIR/data/tmp" "$BASE_DIR/data/res_dir" "$BASE_DIR/data/userImage" "$BASE_DIR/data/user_info"
|
mkdir -p "$BASE_DIR/data/tmp" "$BASE_DIR/data/res_dir" "$BASE_DIR/data/userImage" "$BASE_DIR/data/user_info"
|
||||||
mkdir -p "$BASE_DIR/kohya_ss_home/train_material"
|
mkdir -p "$BASE_DIR/kohya_ss_home/train_material"
|
||||||
|
echo " ✓ 运行时目录已创建"
|
||||||
|
|
||||||
|
# 8. 验证 kohya 训练环境
|
||||||
|
echo "[8/8] 验证 kohya 训练环境..."
|
||||||
|
KOHYA_PYTHON="$CONDA_BASE/envs/kohya/bin/python"
|
||||||
|
KOHYA_LOCAL="$BASE_DIR/kohya_ss_home/.local/lib/python3.10/site-packages"
|
||||||
|
if [ -f "$KOHYA_PYTHON" ] && [ -d "$KOHYA_LOCAL" ]; then
|
||||||
|
echo " 测试 torch/accelerate 加载..."
|
||||||
|
if PYTHONPATH="$KOHYA_LOCAL" "$KOHYA_PYTHON" -c "
|
||||||
|
import torch, accelerate, bitsandbytes, diffusers
|
||||||
|
print(f' torch={torch.__version__} cuda={torch.cuda.is_available()}')
|
||||||
|
print(f' accelerate={accelerate.__version__}')
|
||||||
|
print(' ✓ 训练环境验证通过')
|
||||||
|
" 2>/dev/null; then
|
||||||
|
true
|
||||||
|
else
|
||||||
|
echo " ✗ 训练环境验证失败,请检查 kohya 环境和 .local 目录"
|
||||||
|
ERRORS+=("kohya验证")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ✗ kohya Python 或 .local 目录不存在,跳过验证"
|
||||||
|
ERRORS+=("kohya环境")
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== 部署完成 ==="
|
echo "=== 部署结果 ==="
|
||||||
|
if [ ${#ERRORS[@]} -eq 0 ]; then
|
||||||
|
echo "✓ 所有检查通过,部署完成!"
|
||||||
|
else
|
||||||
|
echo "⚠ 有 ${#ERRORS[@]} 个问题需要处理:"
|
||||||
|
for err in "${ERRORS[@]}"; do
|
||||||
|
echo " - $err"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo "请从网盘下载缺失的文件后重新运行 ./setup.sh"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
echo "启动服务: ./start_all_services.sh"
|
echo "启动服务: ./start_all_services.sh"
|
||||||
|
|||||||
+74
-11
@@ -1,24 +1,87 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
CONDA_BASE="${CONDA_BASE:-/home/szlc/miniconda3}"
|
|
||||||
|
# 自动检测 conda 安装路径
|
||||||
|
if [ -z "$CONDA_BASE" ]; then
|
||||||
|
if command -v conda >/dev/null 2>&1; then
|
||||||
|
CONDA_BASE="$(conda info --base 2>/dev/null)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
CONDA_BASE="${CONDA_BASE:-$HOME/miniconda3}"
|
||||||
export CONDA_BASE
|
export CONDA_BASE
|
||||||
|
|
||||||
mkdir -p "$BASE_DIR/logs"
|
mkdir -p "$BASE_DIR/logs"
|
||||||
|
|
||||||
|
# 检查端口是否被占用,如占用则提示
|
||||||
|
check_port() {
|
||||||
|
local port=$1
|
||||||
|
local name=$2
|
||||||
|
if lsof -i :$port >/dev/null 2>&1; then
|
||||||
|
echo "⚠ 端口 $port ($name) 已被占用,可能服务已在运行"
|
||||||
|
echo " 如需重启,请先运行: ./stop_all_services.sh"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== 启动换发型服务 ==="
|
||||||
|
echo "BASE_DIR: $BASE_DIR"
|
||||||
|
echo "CONDA_BASE: $CONDA_BASE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查 conda 环境是否存在
|
||||||
|
for env_name in my_hair sdwebui py310; do
|
||||||
|
if [ ! -f "$CONDA_BASE/envs/$env_name/bin/python" ]; then
|
||||||
|
echo "✗ conda 环境 $env_name 不存在,请先运行 ./setup.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# 1. hair_service_sd (端口 8801)
|
# 1. hair_service_sd (端口 8801)
|
||||||
cd "$BASE_DIR/hair_service_sd"
|
echo "[1/3] 启动 hair_service_sd (端口 8801)..."
|
||||||
nohup "$CONDA_BASE/envs/my_hair/bin/python" run_copy_cost_colorb64.py > "$BASE_DIR/logs/hair_service.log" 2>&1 &
|
if check_port 8801 "hair_service_sd"; then
|
||||||
echo "hair_service_sd 已启动 (PID: $!, 端口 8801)"
|
cd "$BASE_DIR/hair_service_sd"
|
||||||
|
nohup "$CONDA_BASE/envs/my_hair/bin/python" run_copy_cost_colorb64.py > "$BASE_DIR/logs/hair_service.log" 2>&1 &
|
||||||
|
echo " hair_service_sd 已启动 (PID: $!, 端口 8801)"
|
||||||
|
fi
|
||||||
|
|
||||||
# 2. stable-diffusion-webui (端口 57860)
|
# 2. stable-diffusion-webui (端口 57860)
|
||||||
cd "$BASE_DIR/stable-diffusion-webui"
|
echo "[2/3] 启动 stable-diffusion-webui (端口 57860)..."
|
||||||
nohup "$CONDA_BASE/envs/sdwebui/bin/python" webui.py --api --listen --xformers --port 57860 > "$BASE_DIR/logs/webui.log" 2>&1 &
|
if check_port 57860 "webui"; then
|
||||||
echo "stable-diffusion-webui 已启动 (PID: $!, 端口 57860)"
|
cd "$BASE_DIR/stable-diffusion-webui"
|
||||||
|
nohup "$CONDA_BASE/envs/sdwebui/bin/python" webui.py --api --listen --xformers --port 57860 > "$BASE_DIR/logs/webui.log" 2>&1 &
|
||||||
|
echo " stable-diffusion-webui 已启动 (PID: $!, 端口 57860)"
|
||||||
|
echo " ℹ WebUI 首次启动需加载模型(约 30-60 秒),请耐心等待"
|
||||||
|
fi
|
||||||
|
|
||||||
# 3. photo_service (端口 32678)
|
# 3. photo_service (端口 32678)
|
||||||
cd "$BASE_DIR/photo_service"
|
echo "[3/3] 启动 photo_service (端口 32678)..."
|
||||||
nohup "$CONDA_BASE/envs/py310/bin/python" lora_train_service_1.py > "$BASE_DIR/logs/photo_service.log" 2>&1 &
|
if check_port 32678 "photo_service"; then
|
||||||
echo "photo_service 已启动 (PID: $!, 端口 32678)"
|
cd "$BASE_DIR/photo_service"
|
||||||
|
nohup "$CONDA_BASE/envs/py310/bin/python" lora_train_service_1.py > "$BASE_DIR/logs/photo_service.log" 2>&1 &
|
||||||
|
echo " photo_service 已启动 (PID: $!, 端口 32678)"
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "所有服务已在后台启动,日志在 $BASE_DIR/logs/"
|
echo "=== 所有服务已启动 ==="
|
||||||
|
echo "日志目录: $BASE_DIR/logs/"
|
||||||
|
echo ""
|
||||||
|
echo "查看日志:"
|
||||||
|
echo " tail -f $BASE_DIR/logs/hair_service.log # 换发型/换发色"
|
||||||
|
echo " tail -f $BASE_DIR/logs/webui.log # SD WebUI"
|
||||||
|
echo " tail -f $BASE_DIR/logs/photo_service.log # 训练服务"
|
||||||
|
echo ""
|
||||||
|
echo "停止服务: ./stop_all_services.sh"
|
||||||
|
echo ""
|
||||||
|
echo "等待 WebUI 就绪(检查端口 57860)..."
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if curl -s http://127.0.0.1:57860/sdapi/v1/options >/dev/null 2>&1; then
|
||||||
|
echo "✓ WebUI 已就绪"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
if [ $i -eq 60 ]; then
|
||||||
|
echo "⚠ WebUI 60 秒内未就绪,请检查日志: tail -f $BASE_DIR/logs/webui.log"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "=== 停止换发型服务 ==="
|
||||||
|
|
||||||
|
# 按端口停止服务
|
||||||
|
for port_info in "8801:hair_service_sd" "57860:webui" "32678:photo_service"; do
|
||||||
|
port="${port_info%%:*}"
|
||||||
|
name="${port_info##*:}"
|
||||||
|
if lsof -i :$port >/dev/null 2>&1; then
|
||||||
|
pid=$(lsof -t -i :$port)
|
||||||
|
kill $pid 2>/dev/null
|
||||||
|
echo " ✓ 已停止 $name (端口 $port, PID $pid)"
|
||||||
|
else
|
||||||
|
echo " ℹ $name 未在运行 (端口 $port)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 所有服务已停止 ==="
|
||||||
Reference in New Issue
Block a user