stable diffusion文生图模型解析模型
一 、Stable Diffusion XL Base 1.0 完整文件与代码映射树形图
stable-diffusion-xl-base-1.0/ │ ├── .gitattributes # [Git配置]用于Git LFS大文件存储的跟踪设置 (非模型代码) ├── README.md # [说明文档] 模型的介绍、引用和使用说明 (非模型代码) ├── LICENSE.md # [版权许可] OpenRAIL++ 许可证文件 (非模型代码) │ ├── model_index.json # [总控配置文件] │ # 对应代码: diffusers.StableDiffusionXLPipeline │ # 作用: 定义了各个子文件夹对应加载哪个 Python 类。 │ ├── sd_xl_base_1.0.safetensors # [WebUI/ComfyUI 专用整合包] │ # 这是一个包含下列所有权重的单个大文件 (约 6.94 GB)。 │ # 对应代码: 如果用 diffusers 加载单个文件,使用 .from_single_file() 方法。 │ ├── unet/ # [核心生成网络] │ │ # 对应 Python 类: diffusers.UNet2DConditionModel │ ├── config.json # [网络架构参数] │ │ # 内容: 定义 layers=3, channels=320, attention_head_dim=[5, 10, 20] 等 │ │ # 作用: 告诉 Python 如何构建神经网络的“骨架”。 │ └── diffusion_pytorch_model.safetensors # [核心权重] (约 10.3 GB) │ # 内容: 40亿个参数的浮点数矩阵。 │ # 作用: 填充骨架的“肌肉”,负责具体的图像去噪生成。 │ ├── vae/ # [变分自编码器] │ │ # 对应 Python 类: diffusers.AutoencoderKL │ ├── config.json # [架构参数] │ │ # 内容: 定义 latent_channels=4, block_out_channels=[128, 256, 512] 等 │ └── diffusion_pytorch_model.safetensors # [权重文件] (约 335 MB) │ # 作用: 负责将 1024x1024 的像素图压缩为 128x128 的 Latent 特征。 │ ├── text_encoder/ # [文本编码器 1] (CLIP ViT-L/14) │ │ # 对应 Python 类: transformers.CLIPTextModel │ ├── config.json # [架构参数] │ │ # 内容: hidden_size=768, num_hidden_layers=12 等 │ └── model.safetensors # [权重文件] (约 492 MB) │ # 作用: 提取基础的文本语义特征。 │ ├── text_encoder_2/ # [文本编码器 2] (OpenCLIP ViT-bigG/14) │ │ # 对应 Python 类: transformers.CLIPTextModelWithProjection │ ├── config.json # [架构参数] │ │ # 内容: hidden_size=1280, num_hidden_layers=32 (比上面那个大很多) │ └── model.safetensors # [权重文件] (约 2.78 GB) │ # 作用: 提取更深层、更复杂的文本语义和风格特征。 │ ├── tokenizer/ # [分词器 1] (配合 text_encoder) │ │ # 对应 Python 类: transformers.CLIPTokenizer │ ├── tokenizer_config.json # [分词配置] 定义截断长度 (77 tokens)、填充策略等。 │ ├── vocab.json # [词表] 单词到 ID 的映射表 (例如 "cat": 2345)。 │ ├── merges.txt # [合并规则] BPE 算法的子词合并规则。 │ └── special_tokens_map.json # [特殊符] 定义 <start>, <end>, <pad> 等特殊标记。 │ ├── tokenizer_2/ # [分词器 2] (配合 text_encoder_2) │ │ # 对应 Python 类: transformers.CLIPTokenizer │ │ # 注意: 这里的词表可能与 tokenizer_1 不同,因为模型来源不同。 │ ├── tokenizer_config.json # [分词配置] │ ├── vocab.json # [词表] │ ├── merges.txt # [合并规则] │ └── special_tokens_map.json # [特殊符] │ └── scheduler/ # [噪声调度器] │ # 对应 Python 类: diffusers.EulerDiscreteScheduler (默认) └── scheduler_config.json # [算法参数]# 内容: beta_start=0.00085, beta_end=0.012, num_train_timesteps=1000# 作用: 定义去噪过程的数学公式参数。第一部分:文件结构深度解析
这个仓库中的文件并非即使可以运行的 Python 脚本,而是模型的“配置文件”和“权重参数”。可以将这些文件理解为一个个“零件”,通过特定的代码(如 diffusers 库)组装起来才能运行。
1. 核心引导文件
model_index.json- 用途:这是整个模型的“总指挥”或“目录”。
- 解析:它告诉程序:“如果要加载这个模型,请去
text_encoder文件夹找文本编码器,去unet文件夹找生成模型,去scheduler文件夹找调度算法”。 - 为什么有它:
diffusers库在加载模型时(DiffusionPipeline.from_pretrained),首先读取这个文件来初始化各个组件。
2. 文本理解组件 (Text Encoders)
SDXL 的一大创新是使用了两个不同的文本编码器来更好地理解提示词(Prompt)。
- 文件夹
text_encoder(对应 OpenAI CLIP ViT-L/14) - 文件夹
text_encoder_2(对应 OpenCLIP ViT-bigG/14)config.json:定义了神经网络的架构(例如有多少层、隐藏层大小是多少)。代码是根据 Transformer 架构编写的。model.safetensors(或 pytorch_model.bin):这是权重文件。里面存储了模型在数亿张图片和文本对上训练出来的参数(也就是“知识”)。- 作用:将你输入的文字(如 “a cat”)转换成计算机能理解的数学向量(Embeddings)。
3. 文本处理组件 (Tokenizers)
- 文件夹
tokenizer&tokenizer_2vocab.json/merges.txt:这是字典。它定义了模型认识哪些单词或字根。tokenizer_config.json:分词器的配置,比如最大长度限制。- 作用:在把文字送入上面的 Text Encoder 之前,需要先切分成一个个 Token(标记)。
4. 核心生成组件 (UNet)
- 文件夹
unetconfig.json:定义了 UNet 的网络结构。SDXL 的 UNet 极其庞大,参数量是旧版 SD 1.5 的 3 倍。diffusion_pytorch_model.safetensors:这是最核心的文件,体积最大(约 5GB-10GB)。- 作用:它是“画师”。它接收由 VAE 压缩的图像信息和 Text Encoder 提供的文本信息,通过“去噪”的过程一步步生成图像。它是根据 Latent Diffusion Models (LDM) 的论文算法编写和训练的。
5. 图像压缩组件 (VAE)
- 文件夹
vae(Variational Auto-Encoder)config.json&diffusion_pytorch_model.safetensors- 作用:它是“翻译官”。UNet 不直接在像素级画图(因为太慢),而是在一个压缩的“潜空间”里画。
- 编码:把像素图片压缩成潜空间数据。
- 解码:把 UNet 画好的潜空间数据“翻译”回我们可以看到的彩色图片。
6. 调度器 (Scheduler)
- 文件夹
schedulerscheduler_config.json- 作用:决定去噪的节奏。比如是用 Euler 算法还是 DPM 算法,每一步去多少噪点。这决定了画图的速度和质量。
7. 单一大文件 (用于 WebUI)
sd_xl_base_1.0.safetensors(通常在根目录)- 用途:这是一个打包文件。它把上面提到的 UNet、VAE、Text Encoder 等所有权重合并不在一个文件里。
- 为什么有它:方便使用 Stable Diffusion WebUI (A1111) 或 ComfyUI 的用户直接下载这一个文件就能用,不需要下载那么多文件夹。
二、这些文件是如何协作的?
SDXL 生成流程总览 (Inference Pipeline) │ ├── 【用户输入】 │ └── 提示词 (Prompt): "a cat" │ ▼ [1. 预处理阶段 (Tokenization)] ──────────────────────────┐ │ │ ├── <调用的代码>: CLIPTokenizer │ ├── <读取的文件>: tokenizer/vocab.json (词表) │ │ tokenizer/merges.txt (合并规则) │ │ │ └── > 输出结果: Token IDs [49406, 320, ...](数字序列) ──┘ │ ▼ [2. 文本编码阶段 (Text Encoding)] ───────────────────────┐ │ │ ├── <调用的代码>: CLIPTextModel (x2) │ ├── <读取的文件>: text_encoder/model.safetensors │ │ text_encoder_2/model.safetensors │ │ │ └── > 输出结果: Prompt Embeddings (文本特征向量矩阵) ────┘ │ │ (等待与 Latents 结合...) │ ▼ [3. 初始噪声生成 (Latent Initialization)] ───────────────┐ │ │ ├── <调用的代码>: Gaussian Noise Generator │ ├── <读取的文件>: scheduler/scheduler_config.json │ │ (决定噪声分布和形状) │ │ │ └── > 输出结果: Noisy Latents (纯噪声张量 128x128) ──────┘ │ ▼ [4. 循环去噪阶段 (The Denoising Loop)]<★ 核心/最耗时> ──┐ │ │ ├── 输入数据: Noisy Latents + Prompt Embeddings │ │ │ ├── ↻ 循环开始 (例如 30 Steps) │ │ │ │ │ ├── <调用的代码>: UNet2DConditionModel │ │ ├── <读取的文件>: unet/diffusion_pytorch_model.safetensors │ │ (加载 10GB 的核心权重) │ │ │ │ │ ├── 动作: UNet 预测噪声 -> Scheduler 减去噪声 │ │ └── 更新: Latents 变得稍微清晰一点 │ │ │ │ └── [回到循环顶部,直到完成所有 Steps] │ │ │ └── > 输出结果: Clean Latents (干净的潜空间图像) ────────┘ │ ▼ [5. 图像解码阶段 (Image Decoding)] ──────────────────────┐ │ │ ├── <调用的代码>: AutoencoderKL (VAE) │ ├── <读取的文件>: vae/diffusion_pytorch_model.safetensors│ │ (加载 VAE 权重) │ │ │ ├── 动作: 将 4通道 Latents 解压为 3通道 RGB 图像 │ └── > 输出结果: Final Image (1024x1024 最终图片) ────────┘ │ ▼ 【流程结束】 这是一个标准的 数据流(Data Flow) 过程:
1. 预处理阶段 (对应 tokenizer & tokenizer_2)
- 输入: 字符串 “a cat”
- 操作: Python 代码加载
vocab.json,把 “a cat” 切割并查表。 - 输出: 一串数字 ID,例如
[49406, 320, 2368, 49407]。
2. 文本编码阶段 (对应 text_encoder & text_encoder_2)
- 输入: 上一步的数字 ID。
- 操作: Python 代码实例化
CLIPTextModel类,加载model.safetensors中的权重矩阵,进行矩阵乘法运算。 - 输出: Prompt Embeddings (提示词向量)。这是两组高维向量,代表了"a cat"的数学含义。SDXL 会把这两组向量拼接在一起。
3. 初始噪声生成 (对应 scheduler)
- 操作: 读取
scheduler_config.json中的num_train_timesteps。 - 输出: 创建一个纯噪声的张量(Latents),大小通常是
128x128(对应 1024x1024 的图)。
4. 循环去噪阶段 (对应 unet) ★最耗时的步骤
- 输入: 纯噪声 Latents + 提示词向量 + 时间步 (TimeStep)。
- 操作: Python 实例化
UNet2DConditionModel。这是代码的核心循环。- UNet 接收噪声图和文字向量。
- 利用
diffusion_pytorch_model.safetensors里的权重,预测图里的“噪音”是什么。 Scheduler根据预测结果,从图中减去一点噪音。- 这个过程重复 20-50 次(也就是我们在 WebUI 里看到的 Steps)。
- 输出: 一个去噪完成的、干净的 Latent 张量。
5. 图像解码阶段 (对应 vae)
- 输入: 干净的 Latent 张量 (128x128)。
- 操作: Python 实例化
AutoencoderKL,加载 VAE 的权重。 - 输出: 将潜空间数据放大并“翻译”回 RGB 像素空间 (1024x1024)。
第一部分:文件结构深度解析
这个仓库中的文件并非即使可以运行的 Python 脚本,而是模型的“配置文件”和“权重参数”。可以将这些文件理解为一个个“零件”,通过特定的代码(如 diffusers 库)组装起来才能运行。
1. 核心引导文件
model_index.json- 用途:这是整个模型的“总指挥”或“目录”。
- 解析:它告诉程序:“如果要加载这个模型,请去
text_encoder文件夹找文本编码器,去unet文件夹找生成模型,去scheduler文件夹找调度算法”。 - 为什么有它:
diffusers库在加载模型时(DiffusionPipeline.from_pretrained),首先读取这个文件来初始化各个组件。
2. 文本理解组件 (Text Encoders)
SDXL 的一大创新是使用了两个不同的文本编码器来更好地理解提示词(Prompt)。
- 文件夹
text_encoder(对应 OpenAI CLIP ViT-L/14) - 文件夹
text_encoder_2(对应 OpenCLIP ViT-bigG/14)config.json:定义了神经网络的架构(例如有多少层、隐藏层大小是多少)。代码是根据 Transformer 架构编写的。model.safetensors(或 pytorch_model.bin):这是权重文件。里面存储了模型在数亿张图片和文本对上训练出来的参数(也就是“知识”)。- 作用:将你输入的文字(如 “a cat”)转换成计算机能理解的数学向量(Embeddings)。
3. 文本处理组件 (Tokenizers)
- 文件夹
tokenizer&tokenizer_2vocab.json/merges.txt:这是字典。它定义了模型认识哪些单词或字根。tokenizer_config.json:分词器的配置,比如最大长度限制。- 作用:在把文字送入上面的 Text Encoder 之前,需要先切分成一个个 Token(标记)。
4. 核心生成组件 (UNet)
- 文件夹
unetconfig.json:定义了 UNet 的网络结构。SDXL 的 UNet 极其庞大,参数量是旧版 SD 1.5 的 3 倍。diffusion_pytorch_model.safetensors:这是最核心的文件,体积最大(约 5GB-10GB)。- 作用:它是“画师”。它接收由 VAE 压缩的图像信息和 Text Encoder 提供的文本信息,通过“去噪”的过程一步步生成图像。它是根据 Latent Diffusion Models (LDM) 的论文算法编写和训练的。
5. 图像压缩组件 (VAE)
- 文件夹
vae(Variational Auto-Encoder)config.json&diffusion_pytorch_model.safetensors- 作用:它是“翻译官”。UNet 不直接在像素级画图(因为太慢),而是在一个压缩的“潜空间”里画。
- 编码:把像素图片压缩成潜空间数据。
- 解码:把 UNet 画好的潜空间数据“翻译”回我们可以看到的彩色图片。
6. 调度器 (Scheduler)
- 文件夹
schedulerscheduler_config.json- 作用:决定去噪的节奏。比如是用 Euler 算法还是 DPM 算法,每一步去多少噪点。这决定了画图的速度和质量。
7. 单一大文件 (用于 WebUI)
sd_xl_base_1.0.safetensors(通常在根目录)- 用途:这是一个打包文件。它把上面提到的 UNet、VAE、Text Encoder 等所有权重合并不在一个文件里。
- 为什么有它:方便使用 Stable Diffusion WebUI (A1111) 或 ComfyUI 的用户直接下载这一个文件就能用,不需要下载那么多文件夹。
三、Stable Diffusion“微调”和“API化部署”
以下我将分为三个部分详细解答:微调策略与场景、本地部署操作步骤、以及应用程序接口(API)封装与调用。
第一部分:微调 (Fine-tuning) —— 如何定制模型?
所谓的“微调”,通常不是修改 Python 代码逻辑(即不是改 unet/config.json 或 py 文件),而是通过新的训练数据更新 .safetensors 里的权重参数。
1. 微调的常见场景与方案
| 场景 | 目标 | 推荐技术 | 修改了哪里? | 例子 |
|---|---|---|---|---|
| 特定物体/人像 | 让模型学会画“你家的猫”或“某个特定的产品” | Dreambooth | 更新 UNet 和 Text Encoder 的整体权重。 | 把所有生成的“dog”都变成你家宠物的样子。 |
| 特定画风/风格 | 让模型学会“水墨画风格”或“皮克斯风格” | LoRA (Low-Rank Adaptation) | 不修改原模型权重,而是挂载一个小的“外挂权重包”到 UNet 上。 | 生成的所有图片都带有赛博朋克滤镜。 |
| 结构控制 | 让模型严格遵循线条稿或姿势 | ControlNet | 训练一个全新的“旁路网络”来控制 UNet。 | 根据装修线稿生成室内设计图。 |
Stable Diffusion XL 微调技术深度技术对照表
| 技术名称 | 核心逻辑 & 文件修改深度解析 | 数据集准备 & 训练需求 | 典型场景 & 产出 |
|---|---|---|---|
| 1. Dreambooth(全量微调) | 逻辑: 覆写底层参数 (脑科手术)。 强制将特定 Token (如 sks) 绑定到特定图像特征。 文件修改: 1. 直接修改unet/diffusion_pytorch_model.safetensors (UNet) 和 Text Encoder 权重。 2. 不新增 模块,而是生成一个全新的、巨大的 Checkpoint 文件。 | 数据集: • 少而精: 20-30 张特定物体/人像图。 • 正则化数据 (Class Data): 需几百张通用图 (如普通狗) 防止“灾难性遗忘”。 训练: • 全量训练。计算量大,耗时长。 | 场景: 特定产品植入 (如特定款香水瓶)、个人写真。 产出: 独立大模型 (6GB+)。 调用时替换原模型。 |
| 2. LoRA(低秩适应) | 逻辑: 旁路矩阵注入 (滤镜外挂)。 在 Cross-Attention 层插入低秩矩阵 AAA 和 BBB ( W′=W+A×BW' = W + A \times BW′=W+A×B )。 文件修改: 1. 冻结 原模型 UNet 权重 (只读)。 2. 新增 包含 A,BA, BA,B 矩阵的小型 .safetensors 文件。 | 数据集: • 中等规模: 50+ 张风格统一的图片。 • 详细打标: 需对每张图进行精准文本描述。 训练: • 增量训练。仅训练 A,BA, BA,B 矩阵,速度快,显存占用低。 | 场景: 画风迁移 (赛博朋克、水墨风)、概念学习。 产出: 轻量权重包 (100MB)。 调用时挂载在原模型上。 |
| 3. ControlNet(结构控制) | 逻辑: 编码器克隆 (临摹描图)。 利用“零卷积”接入额外的视觉条件 (线稿/深度图)。 文件修改: 1. 克隆 UNet 的 Encoder Block (一份锁定,一份可训练)。 2. 新增 独立的 ControlNet 模块文件。 | 数据集: • 成对数据: 输入条件图 (线稿) + 对应真值图 (彩图)。 • 规模大: 通常需数千至上万张成对数据。 训练: • 模块训练。仅训练 ControlNet 部分,主模型冻结。 | 场景: 线稿上色、建筑设计 (草图变渲染图)、姿势控制。 产出: 独立控制模型 (1-2GB)。 调用时与主模型并行工作。 |
2. 微调操作简述 (以 LoRA 为例)
- 准备数据:准备 20-50 张高质量图片,放在一个文件夹里。
- 打标:给每张图写一个描述文件(如
a girl, blue eyes, white hair)。 - 训练工具:
- GUI 推荐:
kohya_ss(目前最流行的可视化训练工具)。 - 代码推荐:HuggingFace Diffusers 的
train_text_to_image_lora.py脚本。
- GUI 推荐:
- 产出:训练结束后,你会得到一个
.safetensors文件(比如my_style.safetensors,大小约 100MB)。
第二部分:本地代码部署的操作步骤
假设你已经有了基础模型(SDXL Base 1.0),现在要在本地服务器(Linux/Windows)上把代码跑起来。
1. 硬件与环境准备
- 硬件:NVIDIA 显卡(建议显存 16GB 以上,最低 12GB)。
- 驱动:安装好 NVIDIA Driver 和 CUDA Toolkit (推荐 11.8 或 12.1)。
2. 安装依赖
打开终端(Terminal/CMD),执行以下命令:
# 1. 创建虚拟环境 (强烈建议) conda create -n sdxl python=3.10 conda activate sdxl # 2. 安装 PyTorch (根据你的 CUDA 版本选择,这里以 CUDA 12.1 为例) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 3. 安装 Diffusers 和相关库 pip install diffusers transformers accelerate safetensors invisible-watermark # 如果你要做 API 服务,还需要安装 FastAPI pip install fastapi uvicorn python-multipart 3. 编写推理代码 (inference.py)
这是最基础的加载与运行代码:
import torch from diffusers import DiffusionPipeline # 初始化路径 (可以是本地文件夹路径,也可以是 HuggingFace ID) model_path ="./stable-diffusion-xl-base-1.0"# 假设你已经下载到了本地print("正在加载模型到内存...") pipe = DiffusionPipeline.from_pretrained( model_path, torch_dtype=torch.float16, use_safetensors=True, variant="fp16")# 关键:移入显存 pipe.to("cuda")# (可选) 如果你训练了 LoRA,在这里加载# pipe.load_lora_weights("./my_lora.safetensors")defgenerate_image(prompt):print(f"正在生成: {prompt}") image = pipe(prompt=prompt).images[0]return image if __name__ =="__main__": img = generate_image("A futuristic city on Mars, 8k resolution") img.save("output.png")print("生成完成!")第三部分:其他应用程序如何调用? (API 封装)
其他的应用程序(比如微信小程序、公司官网、Java 后端、iOS App)不能直接运行 Python 代码。它们通常通过 HTTP 请求 (REST API) 来与你的模型服务器对话。
我们需要把上面的 Python 代码包装成一个 Web 服务。最通用的做法是使用 FastAPI。
1. 编写服务端代码 (server.py)
import torch import uvicorn import base64 from io import BytesIO from fastapi import FastAPI, HTTPException from pydantic import BaseModel from diffusers import DiffusionPipeline # === 1. 初始化 FastAPI === app = FastAPI(title="SDXL Image Generation API")# === 2. 全局加载模型 (只在启动时加载一次) ===print("Server starting, loading model...") pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0",# 或者本地路径 torch_dtype=torch.float16, use_safetensors=True, variant="fp16") pipe.to("cuda")print("Model loaded successfully!")# === 3. 定义请求的数据格式 ===classGenerateRequest(BaseModel): prompt:str negative_prompt:str="low quality, bad anatomy" steps:int=30# === 4. 定义接口 (API Endpoint) [email protected]("/generate")asyncdefgenerate(req: GenerateRequest):try:# 调用模型生成 image = pipe( prompt=req.prompt, negative_prompt=req.negative_prompt, num_inference_steps=req.steps ).images[0]# 将图片转换为 Base64 字符串以便网络传输 buffered = BytesIO() image.save(buffered,format="PNG") img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")return{"status":"success","image_base64": img_str}except Exception as e:raise HTTPException(status_code=500, detail=str(e))# === 5. 启动服务 ===if __name__ =="__main__":# 监听 8000 端口 uvicorn.run(app, host="0.0.0.0", port=8000)2. 启动服务器
在终端运行:
python server.py 此时,你的电脑变成了一台AI 绘画服务器。
3. 客户端调用 (其他 APP 怎么连进来?)
无论是 Java, JavaScript, 还是 Python,只需要发送一个 HTTP POST 请求即可。
示例:另一个 Python 程序调用你的接口
import requests import base64 # 目标地址 url ="http://localhost:8000/generate"# 发送数据 payload ={"prompt":"A cute robot eating an apple","steps":25} response = requests.post(url, json=payload)if response.status_code ==200: data = response.json()# 解码图片 img_data = base64.b64decode(data["image_base64"])withopen("result.png","wb")as f: f.write(img_data)print("图片已接收并保存!")else:print("调用失败", response.text)SDXL 生产环境完整全链路架构图
[生产环境全链路架构图 - Production Environment] 1. 用户终端层 (Client Layer) - [发起者] │ ├── 微信小程序 / Web前端 / App │ │ │ ├── [动作 A] 用户配置参数 │ │ ├── 提示词: "A cyberpunk cat, neon lights" │ │ ├── 风格选择: "Cyberpunk LoRA" (下拉菜单选择) │ │ ├── 尺寸: 1024x1024 │ │ └── 图片(可选): 上传线稿 (如果是 ControlNet 模式) │ │ │ └── [动作 B] 构造 HTTP POST 请求 (Payload) │ └── 发送 JSON 数据包 -> https://api.your-domain.com/generate │ ▼ 2. API 网关与服务层 (Service Layer) - [调度者] │ ├── Nginx (反向代理服务器) │ ├── 负责 SSL 加密 (Https) │ ├── 负载均衡 (如果有排多台 GPU 服务器) │ └── 转发请求 -> 本地 8000 端口 │ └── FastAPI 服务端 (server.py) │ ├── [步骤 1: 数据验证 (Pydantic)] │ └── 检查 JSON 格式是否合法 (比如 steps 不能超过 50,防止显存爆炸) │ ├── [步骤 2: 并发锁 (Asyncio Lock)] ★关键 │ └── 作用: 即使 10 人同时点击,GPU 同一时间只能画一张。 │ 这就需要排队,防止显存 OOM (Out of Memory)。 │ ├── [步骤 3: 图像预处理] │ └── 如果有上传图片,将 Base64 字符串解码为 PIL Image 对象。 │ └── [步骤 4: 任务下发] └── 调用 pipe() 函数,传入参数。 ▼ 3. AI 模型引擎层 (Model Layer) - [执行者] │ ├── 显存 (VRAM - 显卡内存) ★寸土寸金 │ │ │ ├── [常驻内存区域] (约 12GB) │ │ ├── UNet (SDXL Base FP16) - 核心画师 │ │ ├── VAE (解码器) - 翻译官 │ │ └── Text Encoders (CLIP) - 语义理解 │ │ │ └── [动态交换区域] (约 200MB) ★微调的核心 │ ├── 动作: 根据用户请求,实时挂载/卸载 LoRA │ │ ├── 用户A要赛博风 -> load_lora("cyberpunk.safetensors") │ │ ├── 画完 -> unload_lora() │ │ └── 用户B要水墨风 -> load_lora("ink.safetensors") │ └── 优势: 不需要为了不同风格启动多个模型,节省显存。 │ └── 运算单元 (GPU Core) └── 执行去噪循环 (Denoising Loop 30次) ▼ 4. 结果返回链路 (Response Loop) │ ├── [模型层] 产出 PIL Image 对象 ├── [API 层] Image -> 压缩为 JPEG/PNG -> 转 Base64 字符串 └── [网络层] 返回 JSON response {"status": "success", "image": "data:image/png;base64..."}