news 2026/9/10 0:36:14

Diffusers 实战:用 InstructPix2Pix 微调 Stable Diffusion 实现指令驱动图像编辑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Diffusers 实战:用 InstructPix2Pix 微调 Stable Diffusion 实现指令驱动图像编辑

Diffusers 实战:用 InstructPix2Pix 微调 Stable Diffusion 实现指令驱动图像编辑

【免费下载链接】diffusers🤗 Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers

本文基于 diffusers 仓库中的 train_instruct_pix2pix.py 训练脚本,系统讲解如何对 Stable Diffusion 进行 InstructPix2Pix 微调,使其能根据一句自然语言编辑指令修改输入图片。读完本文,你将掌握从依赖安装、数据准备、单卡与多卡训练,到参数调优与推理部署的完整闭环,并能理解训练脚本与推理管线背后的关键实现原理。

InstructPix2Pix 方法概述

InstructPix2Pix(对应论文 arXiv 2211.09800)是一种对文本条件扩散模型进行微调的方法,目标是让模型能够遵循针对单张输入图像的编辑指令完成图像编辑。经过该方法微调后的模型,其输入由两部分组成:

  • 原始输入图像:待编辑的目标图片;
  • 编辑指令(edit prompt):一段描述期望编辑效果的自然语言,例如 "把雪山变成草地"、"擦除湖面"。

模型的输出则是应用了该编辑指令后的"已编辑"图像,即输入图像与编辑指令语义对齐的新图片。

在该训练框架中,训练数据由三元组构成:input_image(原始图)、edit_prompt(编辑指令)、edited_image(编辑后的目标图)。训练目标是让模型学会从"原始图 + 指令"出发去噪出"编辑后的图",从而实现指令驱动(instruction-driven)的编辑能力。

环境准备与依赖安装

从源码安装 diffusers

官方强烈建议从源码(source)安装 diffusers,因为示例脚本更新频繁,且带有示例专属依赖。请在全新虚拟环境中执行:

git clone https://github.com/huggingface/diffusers cd diffusers pip install -e .

说明:上述命令将仓库克隆到本地并以可编辑模式安装。本文所分析的当前仓库即为该示例脚本的所在项目,训练脚本位于 examples/instruct_pix2pix/train_instruct_pix2pix.py。

安装示例专属依赖

进入示例目录并安装 requirements.txt 中声明的依赖:

cd examples/instruct_pix2pix pip install -r requirements.txt

该文件声明的核心依赖如下:

依赖版本要求用途
accelerate>=0.16.0分布式训练、混合精度与训练基础设施
torchvision图像变换(transforms)与数据增强
transformers>=4.25.1CLIP 文本编码器与分词器
datasets加载 Hugging Face Hub 数据集或本地imagefolder
ftfy文本清洗(修正 Unicode 编码问题)
tensorboard默认训练日志记录

如需在训练中启用验证推理可视化(report_to="wandb"),还需额外安装pip install wandb

初始化 Accelerate 环境

训练依赖 🤗 Accelerate 管理设备、混合精度与分布式环境。三种初始化方式任选其一:

交互式配置(推荐,可按环境定制):

accelerate config

使用默认配置(无需回答环境问题):

accelerate config default

非交互式环境(如 notebook 无法使用交互式 shell):

from accelerate.utils import write_basic_config write_basic_config()

从源码实现看,脚本通过Accelerator统一管理梯度累积步数、混合精度与日志后端(见 train_instruct_pix2pix.py 中accelerator = Accelerator(gradient_accumulation_steps=..., mixed_precision=..., log_with=..., project_config=...)的初始化逻辑)。

数据集准备

使用公开玩具数据集快速验证

脚本作者已声明:train_instruct_pix2pix.py忠实实现了 InstructPix2Pix 的训练流程,但仅在小型数据集上测试过,这可能会影响最终效果。为了更好的结果,建议使用更大的数据集、训练更长时间。

本文示例使用小型玩具数据集fusing/instructpix2pix-1000-samples,它是论文原始数据集(CLIP 过滤版)的缩小版本。脚本内置了该数据集的三元组列名映射:

DATASET_NAME_MAPPING = { "fusing/instructpix2pix-1000-samples": ("input_image", "edit_prompt", "edited_image"), }

即默认约定:input_image列为原始图、edit_prompt列为编辑指令、edited_image列为编辑后的目标图。若使用自定义数据集,可通过--original_image_column--edit_prompt_column--edited_image_column三个参数覆盖默认列名;数据加载支持两种方式:

  • --dataset_name:Hugging Face Hub 上的数据集标识符,或本地数据集路径;
  • --train_data_dir:本地文件夹(需遵循imagefolder结构,含metadata.jsonl提供标注)。

关于如何构建自己的训练数据集,可参考仓库中的 create_dataset 指南。

设置环境变量

export MODEL_NAME="stable-diffusion-v1-5/stable-diffusion-v1-5" export DATASET_ID="fusing/instructpix2pix-1000-samples"
  • MODEL_NAME作为--pretrained_model_name_or_path传入,可以是 Hub 上的模型仓库标识符,也可以是包含模型权重的本地文件夹路径;
  • DATASET_ID作为--dataset_name传入,指定训练数据集。

启动训练:完整命令与参数解析

执行以下命令启动训练。脚本会把所有组件(feature_extractorschedulertext_encoderunetvae等)以 diffusers 格式保存到输出目录的子文件夹中:

accelerate launch --mixed_precision="fp16" train_instruct_pix2pix.py \ --pretrained_model_name_or_path=$MODEL_NAME \ --dataset_name=$DATASET_ID \ --enable_xformers_memory_efficient_attention \ --resolution=256 --random_flip \ --train_batch_size=4 --gradient_accumulation_steps=4 --gradient_checkpointing \ --max_train_steps=15000 \ --checkpointing_steps=5000 --checkpoints_total_limit=1 \ --learning_rate=5e-05 --max_grad_norm=1 --lr_warmup_steps=0 \ --conditioning_dropout_prob=0.05 \ --mixed_precision=fp16 \ --seed=42 \ --push_to_hub

关键参数详解

结合 train_instruct_pix2pix.py 中的参数定义,逐项说明:

参数示例值说明
--pretrained_model_name_or_path必填预训练模型路径或 Hub 标识符,脚本会分别加载schedulertokenizertext_encodervaeunet子目录
--revision/--variant模型仓库的分支/标签版本(如fp16variant)
--dataset_namefusing/instructpix2pix-1000-samples训练数据集;与--train_data_dir二选一,二者皆空会直接报错
--resolution256输入图像统一缩放分辨率;论文作者观察到 256 分辨率训练的模型可良好泛化到 512 等更大分辨率(得益于其大训练数据集)
--center_crop/--random_flip中心裁剪(默认随机裁剪)/ 随机水平翻转增强
--train_batch_size4每设备 batch 大小(默认 16)
--gradient_accumulation_steps4累积多少步后再执行一次参数更新(默认 1)
--gradient_checkpointing以更慢的反向传播换取显存节省
--max_train_steps15000总训练步数,指定后覆盖--num_train_epochs(默认 100 轮)
--checkpointing_steps5000每多少步保存一次训练状态(默认 500),可用于--resume_from_checkpoint恢复训练
--checkpoints_total_limit1最多保留的 checkpoint 数量,超限时自动删除最旧的
--learning_rate5e-05学习率(默认1e-4),可用--scale_lr按 GPU 数、batch、累积步数缩放
--lr_scheduler/--lr_warmup_stepsconstant/0调度器类型(支持linearcosinecosine_with_restartspolynomialconstantconstant_with_warmup)与预热步数(默认 500)
--max_grad_norm1梯度裁剪范数上限
--conditioning_dropout_prob0.05条件丢弃概率,见下文原理章节
--mixed_precisionfp16混合精度,可选no/fp16/bf16(bf16 需 PyTorch >= 1.10 与 Ampere GPU)
--seed42训练随机种子
--push_to_hub训练结束后把模型推送至 Hub
--use_ema为 UNet 维护指数移动平均(EMA)模型,通常可提升生成质量
--use_8bit_adam使用 bitsandbytes 的 8-bit AdamW 节省显存
--allow_tf32在 Ampere GPU 上允许 TF32 加速训练
--report_totensorboard日志后端,支持tensorboard(默认)、wandbcomet_mlall
--resume_from_checkpoint传入 checkpoint 路径或"latest"自动恢复最近一次训练状态

训练数据预处理要点

脚本对数据集的预处理逻辑值得注意(对应preprocess_images/preprocess_train函数):

  • 原始图与编辑后的目标图会被拼接在一起后施加相同的数据增强(随机裁剪或中心裁剪、随机水平翻转),以保证两张图经过完全一致的几何变换;
  • 像素值归一化到[-1, 1]区间(2 * (images / 255) - 1);
  • 编辑指令通过 CLIP tokenizer 以max_length填充并截断为定长序列。

用 Weights & Biases 监控训练与验证推理

脚本额外支持在训练过程中执行验证推理,将"原始图 + 验证提示词"送入当前训练状态的模型,生成编辑结果并上传到 W&B,便于实时观察模型是否在学会遵循指令(对模型调试非常有用)。启用方式为--report_to="wandb"

accelerate launch --mixed_precision="fp16" train_instruct_pix2pix.py \ --pretrained_model_name_or_path=$MODEL_NAME \ --dataset_name=$DATASET_ID \ --enable_xformers_memory_efficient_attention \ --resolution=256 --random_flip \ --train_batch_size=4 --gradient_accumulation_steps=4 --gradient_checkpointing \ --max_train_steps=15000 \ --checkpointing_steps=5000 --checkpoints_total_limit=1 \ --learning_rate=5e-05 --max_grad_norm=1 --lr_warmup_steps=0 \ --conditioning_dropout_prob=0.05 \ --mixed_precision=fp16 \ --val_image_url="https://hf.co/datasets/diffusers/diffusers-images-docs/resolve/main/mountain.png" \ --validation_prompt="make the mountains snowy" \ --seed=42 \ --report_to=wandb \ --push_to_hub

相关参数:

  • --val_image_url:验证用的原始图片 URL(用于调试推理);
  • --validation_prompt:验证提示词,例如上例的 "make the mountains snowy"(让山脉积雪);
  • --num_validation_images:验证生成张数(默认 4);
  • --validation_epochs:每多少轮执行一次验证(默认 1)。

从源码看,验证在log_validation函数中实现:每轮结束时(若指定了验证 URL 与提示词),脚本会用当前(或 EMA 的)UNet 重建StableDiffusionInstructPix2PixPipeline,以num_inference_steps=20image_guidance_scale=1.5guidance_scale=7的参数生成编辑图,并将"原始图、编辑图、编辑指令"以 W&B Table 的形式记录。注意:--report_to=wandb--hub_token不能同时使用(存在 token 泄露风险),Hub 认证请使用hf auth login

注:论文作者发现,用 256×256 分辨率训练得到的模型可以很好地泛化到 512×512 等更高分辨率,这主要归功于其训练所用的大规模数据集。

多 GPU 分布式训练

accelerate提供了无缝的多 GPU 训练支持。先通过accelerate config完成分布式环境配置(或阅读 Accelerate 的 launch 教程),再使用--multi_gpu启动。示例命令:

accelerate launch --mixed_precision="fp16" --multi_gpu train_instruct_pix2pix.py \ --pretrained_model_name_or_path=stable-diffusion-v1-5/stable-diffusion-v1-5 \ --dataset_name=sayakpaul/instructpix2pix-1000-samples \ --use_ema \ --enable_xformers_memory_efficient_attention \ --resolution=512 --random_flip \ --train_batch_size=4 --gradient_accumulation_steps=4 --gradient_checkpointing \ --max_train_steps=15000 \ --checkpointing_steps=5000 --checkpoints_total_limit=1 \ --learning_rate=5e-05 --lr_warmup_steps=0 \ --conditioning_dropout_prob=0.05 \ --mixed_precision=fp16 \ --seed=42 \ --push_to_hub

与单卡命令相比,此例额外开启了--use_ema并将分辨率提升至 512。脚本内部对分布式做了多处适配,例如:

  • accelerator.prepare统一包装 UNet、优化器、数据加载器与 LR 调度器;
  • 学习率调度器的 warmup 步数与总步数会乘以进程数(num_warmup_steps_for_scheduler = args.lr_warmup_steps * accelerator.num_processes);
  • checkpoint 的保存与加载通过save_model_hook/load_model_hook以 diffusers 格式序列化 UNet 与 EMA 权重;
  • 损失值通过accelerator.gather跨进程聚合后用于日志记录。

训练核心实现原理(源码级解析)

8 通道 UNet:为双条件输入扩展输入层

InstructPix2Pix 使用额外的图像(原始图)作为条件。为此,UNet 第一个卷积层的输入通道数从 4 扩为8:其中 4 个通道承载加噪后的编辑目标图潜在表示,另外 4 个通道承载原始输入图的潜在表示。脚本的关键初始化代码如下:

in_channels = 8 out_channels = unet.conv_in.out_channels unet.register_to_config(in_channels=in_channels) with torch.no_grad(): new_conv_in = nn.Conv2d( in_channels, out_channels, unet.conv_in.kernel_size, unet.conv_in.stride, unet.conv_in.padding ) new_conv_in.weight.zero_() new_conv_in.weight[:, :4, :, :].copy_(unet.conv_in.weight) unet.conv_in = new_conv_in

新增的 4 个通道权重初始化为零,前 4 个通道则从预训练 checkpoint 复制,从而在保留预训练能力的同时引入图像条件输入。其余组件保持冻结:vaetext_encoderrequires_grad_(False),只有 UNet 参与训练(EMA 可选地维护 UNet 权重副本)。

前向扩散与损失计算

每个训练步的核心流程(对应主训练循环):

  1. 将编辑目标图编码到潜在空间并采样:latents = vae.encode(edited_pixel_values).latent_dist.sample(),再乘以vae.config.scaling_factor
  2. 为每个样本采样随机时间步,按 DDPM 调度器执行前向加噪:noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps)
  3. 文本条件:encoder_hidden_states = text_encoder(input_ids)[0]
  4. 图像条件:取原始图潜在表示的**众数(mode)**而非随机采样:original_image_embeds = vae.encode(original_pixel_values).latent_dist.mode()
  5. 将加噪潜在表示与原始图条件在通道维拼接:torch.cat([noisy_latents, original_image_embeds], dim=1)
  6. 依据prediction_type确定回归目标:epsilon类型直接以噪声为 target,v_prediction类型则用get_velocity计算;
  7. UNet 前向得到预测值,与目标计算 MSE 损失:F.mse_loss(model_pred.float(), target.float(), reduction="mean")
  8. 梯度裁剪(max_grad_norm)、优化器与调度器步进、EMA 更新(若启用)。

Conditioning Dropout:支撑推理时的 Classifier-Free Guidance

训练中的--conditioning_dropout_prob(论文第 3.2.1 节)是让模型在推理时支持无分类器引导的关键。实现逻辑为:以2 * conditioning_dropout_prob的概率把文本条件替换为空文本嵌入(用空字符串 tokenize 得到),以conditioning_dropout_prob的概率把图像条件置零:

if args.conditioning_dropout_prob is not None: random_p = torch.rand(bsz, device=latents.device, generator=generator) # 文本条件 mask:以 2*p 概率替换为空条件 prompt_mask = random_p < 2 * args.conditioning_dropout_prob encoder_hidden_states = torch.where(prompt_mask, null_conditioning, encoder_hidden_states) # 图像条件 mask:以 p 概率置零 image_mask = 1 - ((random_p >= p) * (random_p < 3 * p)) original_image_embeds = image_mask * original_image_embeds

这样训练出的模型同时见过"有/无"文本条件与"有/无"图像条件,推理时即可通过引导尺度在"忠实指令"与"忠实原图"之间自由权衡。

推理:加载模型并编辑图像

训练完成后即可用StableDiffusionInstructPix2PixPipeline进行推理:

import PIL import requests import torch from diffusers import StableDiffusionInstructPix2PixPipeline model_id = "your_model_id" # <- 替换为你的模型 ID pipe = StableDiffusionInstructPix2PixPipeline.from_pretrained(model_id, dtype=torch.float16).to("cuda") generator = torch.Generator("cuda").manual_seed(0) url = "https://huggingface.co/datasets/sayakpaul/sample-datasets/resolve/main/test_pix2pix_4.png" def download_image(url): image = PIL.Image.open(requests.get(url, stream=True).raw) image = PIL.ImageOps.exif_transpose(image) image = image.convert("RGB") return image image = download_image(url) prompt = "wipe out the lake" num_inference_steps = 20 image_guidance_scale = 1.5 guidance_scale = 10 edited_image = pipe( prompt, image=image, num_inference_steps=num_inference_steps, image_guidance_scale=image_guidance_scale, guidance_scale=guidance_scale, generator=generator, ).images[0] edited_image.save("edited_image.png")

注意model_id需要替换为你自己的模型标识符;该训练脚本产出的示例模型仓库可参考社区公开示例(sayakpaul/instruct-pix2pix)。

三个关键推理参数

官方建议重点调节以下三个参数来控制生成速度与质量:

参数默认值作用
num_inference_steps20(示例)去噪步数,步数越多质量越高但耗时越长
guidance_scale10(示例)文本指令引导强度,越大越忠实于指令文本
image_guidance_scale1.5(示例)原图引导强度,越大越接近输入原图

其中image_guidance_scaleguidance_scale对生成的("已编辑")图像影响尤为显著,值得重点调参。

双引导的数学实现

在 pipeline_stable_diffusion_instruct_pix2pix.py 的推理循环中,无分类器引导被同时应用于文本输入图像两个条件。因为存在两类条件,潜变量被复制为 3 份,分别得到:纯文本引导预测noise_pred_text、文本+图像引导预测noise_pred_image、无条件预测noise_pred_uncond,最终融合公式为:

noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_image) + image_guidance_scale * (noise_pred_image - noise_pred_uncond)

该公式(见管线源码第 441-448 行)直观体现了两个尺度的语义:guidance_scale控制"编辑指令"的影响力,image_guidance_scale控制"原图"的保持程度。管线还通过do_classifier_free_guidance属性(guidance_scale > 1.0 且 image_guidance_scale >= 1.0时为真)判断是否启用双引导,并对 UNet 输入通道进行校验:加噪潜变量通道数与原图潜变量通道数之和必须等于 UNet 配置的in_channels(即 8),否则报错提示配置不一致。

进阶:Stable Diffusion XL 变体

仓库还提供了等价的 train_instruct_pix2pix_sdxl.py 脚本(针对 Stable Diffusion XL),详见 README_sdxl.md。SDXL 变体的训练范式与本例一致,仅在基础模型与部分组件上有所差异。

常见问题与实用建议

  • 效果不佳时优先增大数据与训练时长:脚本仅在 1000 样本的小数据集上验证过,官方明确提示小数据集会直接影响最终效果;论文原版使用 CLIP 过滤的大规模数据集,建议获取更大数据集并延长训练;
  • 显存紧张:组合使用--gradient_checkpointing--use_8bit_adam--mixed_precision=fp16--enable_xformers_memory_efficient_attention(需安装 xformers,注意 0.0.16 版本在部分 GPU 上有已知问题,建议升级到 0.0.17+)可显著降低占用;
  • 想要更稳定的生成质量:开启--use_ema维护 EMA 权重,验证与最终保存时脚本会自动把 EMA 参数复制回 UNet;
  • 断点续训:用--checkpointing_steps定期保存、--resume_from_checkpoint="latest"自动恢复最近一次训练进度;
  • 灵活的实验数据集:如需快速验证脚本流程,可用--max_train_samples截断训练样本数进行小规模调试。

如果希望探索 InstructPix2Pix 训练方法论在更多场景中的应用,可进一步阅读社区关于"Instruction-tuning Stable Diffusion with InstructPix2Pix"的相关技术文章(官方博客与社区示例均有讨论)。

【免费下载链接】diffusers🤗 Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 0:32:19

实时信号处理库架构设计与流式算法工程实践

1. 项目定位与整体设计思路 做实时信号处理库这件事&#xff0c;说白了就是解决一个核心矛盾&#xff1a; 信号采进来的速度和处理它的速度必须匹配&#xff0c;否则数据就会堆积、丢帧&#xff0c;整个系统就失去“实时”的意义 。我自己在做振动监测项目时被这个问题卡过很…

作者头像 李华
网站建设 2026/9/10 0:28:24

COSCon‘25 RISC-V开源论坛深度解读:软件生态加速落地

各位做架构、做编译器、做系统软件的同行&#xff0c;还有关注指令集和开源社区的朋友们&#xff0c;这几天圈里讨论度最高的消息之一&#xff0c;应该就是 COSCon‘25 的 RISC-V 开源论坛议程正式放出来了。作为从 ARM 时代一路看到 RISC-V 在国内落地的人&#xff0c;我第一时…

作者头像 李华
网站建设 2026/9/10 0:23:21

SerenityOS posix_spawnattr 指南:配置 posix_spawn 子进程属性

SerenityOS posix_spawnattr 指南&#xff1a;配置 posix_spawn 子进程属性 【免费下载链接】serenity The Serenity Operating System &#x1f41e; 项目地址: https://gitcode.com/GitHub_Trending/se/serenity 导读 本指南基于 SerenityOS 仓库中的 posix_spawnatt…

作者头像 李华