[特殊字符] Diffusers 文本引导图像修复(Inpainting)完全指南:从 StableDiffusionInpaintPipeline 到 AutoPipeline 实战
2026/9/10 3:26:42 网站建设 项目流程

🤗 Diffusers 文本引导图像修复(Inpainting)完全指南:从 StableDiffusionInpaintPipeline 到 AutoPipeline 实战

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

导读

本文基于 🤗 Diffusers 官方文档(韩文版 inpaint.md 及同主题英文文档 inpaint.md),系统讲解**文本引导的图像修复(text-guided inpainting)**技术:给定一张原图与一张掩码(mask),用文本提示词把掩码覆盖的区域重新绘制成想要的内容。你将学会如何加载StableDiffusionInpaintPipeline、如何准备原图与掩码、如何用AutoPipelineForInpainting自动选择合适的修复管线、如何通过strengthguidance_scalepadding_mask_crop等参数精细控制生成效果,以及如何将修复管线与其他管线链式组合、并用 ControlNet 获得更强的可控性。

什么是文本引导图像修复

修复(inpainting)是图像编辑领域的一项经典任务:它替换或编辑图像的指定区域。与"整图重绘"的 img2img 不同,inpainting只改变掩码覆盖的区域,其余部分保持原样。这使得它非常适合:

  • 图像修复:去除划痕、噪点、伪影等缺陷;
  • 物体替换:把图中的某个对象换成全新的内容;
  • 局部重绘:只重绘指定区域,保留背景和其余细节。

修复的核心是掩码:掩码中白色像素代表要重绘的区域黑色像素代表保留的区域。模型会根据文本提示词填充白色区域。在 🤗 Diffusers 中,这一能力由专门针对修复任务训练的 Stable Diffusion 检查点(如stable-diffusion-v1-5/stable-diffusion-inpainting)配合 StableDiffusionInpaintPipeline 实现。

快速上手:加载管线并完成一次修复

加载 StableDiffusionInpaintPipeline

首先从 diffusers 导入管线类,加载专门为修复任务微调的 Stable Diffusion 检查点:

import PIL import requests import torch from io import BytesIO from diffusers import StableDiffusionInpaintPipeline pipeline = StableDiffusionInpaintPipeline.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, ) pipeline = pipeline.to("cuda")

说明:代码中的dtype=torch.float16是本文档所采用的历史写法,diffusers 官方推荐的等效参数名是torch_dtype=torch.float16(在源码 docstring 示例中即使用torch_dtype,见 pipeline_stable_diffusion_inpaint.py)。半精度推理能显著降低显存占用并加速推理。

下载原图与掩码

接下来准备一张待修复的图片(例如一张在公园长椅上休息的小狗照片)以及对应的掩码图:

def download_image(url): response = requests.get(url) return PIL.Image.open(BytesIO(response.content)).convert("RGB") img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png" mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png" init_image = download_image(img_url).resize((512, 512)) mask_image = download_image(mask_url).resize((512, 512))

注意这里把原图和掩码都resize到 512×512,以匹配修复检查点的训练分辨率。

执行修复

现在用一句提示词告诉模型要把掩码区域画成什么:

prompt = "Face of a yellow cat, high resolution, sitting on a park bench" image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]

完整流程可以概括为:原图 + 掩码 + 提示词 = 新图。掩码覆盖的小狗区域会被重绘成一只坐在公园长椅上的黄色猫咪。

掩码与提示词的作用关系

输入作用
image待修复的原始图像,掩码外的区域会被原样保留
mask_image决定重绘区域:白色像素区域被重绘,黑色像素区域被保留
prompt描述掩码区域应该生成的内容,直接决定重绘结果

关于历史实现的重要警告

⚠️兼容性警告:早期实验性的修复实现使用了质量较低的另一种处理流程。为了保持向后兼容,当加载不包含新模型的预训练管线时,仍会继续沿用旧的修复方法。也就是说,只有加载了带新版修复模型(UNet 输入通道为 9 的修复专用检查点)的管线,才会走新的高质量修复路径。

这一点在源码中可以得到印证:StableDiffusionInpaintPipeline.__init__中会对unet.config.in_channels做检查,如果 UNet 输入通道数不是 9,会打印提示日志(见 pipeline_stable_diffusion_inpaint.py)。修复专用模型(如stable-diffusion-v1-5/stable-diffusion-inpainting)的 UNet 输入为 9 通道(4 通道潜变量 + 1 通道掩码 + 4 通道被掩码图像潜变量),而普通文生图模型的 UNet 输入为 4 通道。

用 AutoPipelineForInpainting 自动选择合适的管线

现代 diffusers 推荐使用自动管线(AutoPipeline)来加载模型:它会根据检查点的配置自动检测并实例化最合适的管线类,省去手动指定具体类的麻烦。

import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import load_image, make_image_grid pipeline = AutoPipelineForInpainting.from_pretrained( "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16 ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention()

加载原图与掩码:

init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png") mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png")

传入提示词、负向提示词与原图、掩码:

prompt = "a black cat with glowing eyes, cute, adorable, disney, pixar, highly detailed, 8k" negative_prompt = "bad anatomy, deformed, ugly, disfigured" image = pipeline(prompt=prompt, negative_prompt=negative_prompt, image=init_image, mask_image=mask_image).images[0] make_image_grid([init_image, mask_image, image], rows=1, cols=3)

AutoPipeline 的底层映射

AutoPipelineForInpainting并非一个具体实现类,而是根据检查点类型在AUTO_INPAINT_PIPELINES_MAPPING中进行模式匹配(见 auto_pipeline.py)。当前仓库支持自动映射的修复管线包括:

检查点类型自动匹配的管线类
stable-diffusionStableDiffusionInpaintPipeline
stable-diffusion-xlStableDiffusionXLInpaintPipeline
stable-diffusion-3StableDiffusion3InpaintPipeline
ifIFInpaintingPipeline
kandinsky / kandinsky22KandinskyInpaintCombinedPipeline/KandinskyV22InpaintCombinedPipeline
stable-diffusion-controlnet 系列StableDiffusionControlNetInpaintPipeline
flux / flux-controlnet / flux-controlFluxInpaintPipeline/FluxControlNetInpaintPipeline/FluxControlInpaintPipeline
qwenimage / qwenimage-editQwenImageInpaintPipeline/QwenImageEditInpaintPipeline
z-imageZImageInpaintPipeline

因此在大多数场景下,你只需要写一行AutoPipelineForInpainting.from_pretrained(...),diffusers 就会为你选好正确的管线。

创建掩码:掩码模糊与掩码裁剪

如何生成掩码

官方文档给出的所有示例都直接提供了现成的掩码图,方便演示。如果要修复自己的图片,需要自己制作掩码。制作方法通常是在图像编辑软件中用笔刷把待重绘区域涂成白色、其余区域涂成黑色。

掩码模糊(Mask blur)

VaeImageProcessor.blur方法提供了控制原图与修复区域之间融合方式的选项。模糊程度由blur_factor参数决定:blur_factor越大,掩码边缘被模糊得越厉害,原图与修复区之间的过渡越柔和;blur_factor越小(或为 0),掩码边缘越锐利。

import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import load_image from PIL import Image pipeline = AutoPipelineForInpainting.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16).to('cuda') # 也可用 "mps"、"xpu"、"cpu" mask = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore_mask.png") blurred_mask = pipeline.mask_processor.blur(mask, blur_factor=33) blurred_mask

从源码看,blur方法是VaeImageProcessor的静态方法,默认blur_factor=4,内部通过 PIL 的ImageFilter.GaussianBlur对掩码做高斯模糊(见 image_processor.py)。

掩码裁剪(padding_mask_crop)

当掩码区域很小而整张图很大时,直接对全图做修复会浪费大量计算资源在无关的背景信息上。padding_mask_crop参数就是为了解决这个问题:它会先找到包含全部掩码区域的最小矩形,再按padding_mask_crop指定的边距向外扩展,把该区域(以及原图的对应区域)裁出来,放大到更高分辨率做修复,最后再叠加回原图。

import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import load_image from PIL import Image generator = torch.Generator(device='cuda').manual_seed(0) # 或 "mps"、"xpu"、"cpu" pipeline = AutoPipelineForInpainting.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16).to('cuda') base = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore.png") mask = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/seashore_mask.png") image = pipeline("boat", image=base, mask_image=mask, strength=0.75, generator=generator, padding_mask_crop=32).images[0] image

源码中对应的裁剪逻辑位于mask_processor.get_crop_region(见 image_processor.py),在管线__call__中当padding_mask_crop不为None时计算crops_coords,修复完成后通过apply_overlay把修复结果贴回原图(见 pipeline_stable_diffusion_inpaint.py 与 image_processor.py)。

常用修复模型与选择建议

Stable Diffusion Inpainting

stable-diffusion-v1-5/stable-diffusion-inpainting是在 512×512 图像上针对修复任务微调的潜在扩散模型。它速度快、质量不错,是上手修复任务的理想起点。

import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import load_image, make_image_grid pipeline = AutoPipelineForInpainting.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16" ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() # 加载原图和掩码 init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png") mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png") generator = torch.Generator("cuda").manual_seed(92) prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k" image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, generator=generator).images[0] make_image_grid([init_image, mask_image, image], rows=1, cols=3)

Stable Diffusion XL(SDXL)Inpainting

SDXL 是比 v1.5 更大更强的版本,典型情况下能生成更高分辨率的图像。SDXL 还支持两阶段流程:基础模型生成图像,refiner 模型进一步增强细节。SDXL 修复检查点示例为diffusers/stable-diffusion-xl-1.0-inpainting-0.1,使用方式与上面基本一致,只需替换模型 ID:

pipeline = AutoPipelineForInpainting.from_pretrained( "diffusers/stable-diffusion-xl-1.0-inpainting-0.1", dtype=torch.float16, variant="fp16" )

Kandinsky 2.2 Inpainting

Kandinsky 模型家族与 SDXL 类似,同样由两个模型组成:image prior 模型创建图像嵌入,扩散模型据此生成图像。最简单的使用方式是通过AutoPipelineForInpainting加载kandinsky-community/kandinsky-2-2-decoder-inpaint,它在底层自动使用KandinskyV22InpaintCombinedPipeline

pipeline = AutoPipelineForInpainting.from_pretrained( "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16 )

选择建议:SDXL 通常比 Stable Diffusion v1.5 生成更高分辨率的图像,Kandinsky 2.2 也能生成高质量图像;Stable Diffusion Inpainting 则以其速度和易用性适合作为起点。

普通检查点也能修复:权衡与 overlay 技巧

前面介绍的都是修复专用检查点,但你同样可以使用普通检查点(如stable-diffusion-v1-5/stable-diffusion-v1-5)来做修复。两者的差异值得注意:

  • 普通检查点:整体图像质量可能略低,掩码边缘的过渡不够自然,甚至能看到掩码轮廓,但它倾向于更好地保留未掩码区域
  • 修复专用检查点:专门训练来生成更高质量的修复结果,包括更自然的掩码/非掩码过渡,但也更可能改变未掩码区域

强制保留未掩码区域:apply_overlay

如果"未掩码区域必须保持不变"是你的硬性要求,可以用VaeImageProcessor.apply_overlay强制让未掩码区域保持原样(代价是掩码边缘过渡可能不太自然):

import PIL import numpy as np import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import load_image, make_image_grid device = "cuda" # 或 "mps"、"xpu"、"cpu" pipeline = AutoPipelineForInpainting.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16" ) pipeline = pipeline.to(device) img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png" mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png" init_image = load_image(img_url).resize((512, 512)) mask_image = load_image(mask_url).resize((512, 512)) prompt = "Face of a yellow cat, high resolution, sitting on a park bench" repainted_image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image).images[0] repainted_image.save("repainted_image.png") unmasked_unchanged_image = pipeline.image_processor.apply_overlay(mask_image, init_image, repainted_image) unmasked_unchanged_image.save("force_unmasked_unchanged.png") make_image_grid([init_image, mask_image, repainted_image, unmasked_unchanged_image], rows=2, cols=2)

核心参数详解:精确控制修复效果

图像的质量与"创意程度"高度依赖管线参数。以下参数是修复任务中最关键、最常用的。

strength:控制与原图的相似度

strength衡量向原图添加噪声的多少,直接影响输出与原图的相似程度:

  • strength:添加更多噪声,去噪过程更长,生成质量更高,但结果与原图差异更大;
  • strength:添加噪声更少,去噪更快,但质量可能下降,结果更接近原图。
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, strength=0.6).images[0]

源码中strength的取值范围被约束在[0.0, 1.0],超出会直接抛出ValueError(见 pipeline_stable_diffusion_inpaint.py)。实现上,实际去噪步数由get_timesteps根据init_timestep = min(int(num_inference_steps * strength), num_inference_steps)计算;strength=1.0时初始潜变量为纯噪声,strength<1时初始潜变量为"图像潜变量 + 噪声"的组合(见 pipeline_stable_diffusion_inpaint.py 与 get_timesteps)。

guidance_scale:控制提示词对齐程度

guidance_scale(默认 7.5)决定生成图像与文本提示词的对齐程度:

  • guidance_scale:输出与提示词高度对齐,是提示词的"严格诠释";
  • guidance_scale:输出与提示词较松散,可能更多样化。

strengthguidance_scale可以组合使用以更精细地控制模型的表达力,例如strength+ 高guidance_scale会给模型最大的创作自由度。

image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, guidance_scale=2.5).images[0]

源码层面,当guidance_scale > 1时启用无分类器引导(classifier-free guidance,CFG):去噪循环中会对无条件嵌入与文本嵌入各做一次前向,然后按公式noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)融合两个预测(见 pipeline_stable_diffusion_inpaint.py)。当guidance_scale <= 1时,do_classifier_free_guidance属性返回False(见 L864-L866),跳过 CFG。

negative_prompt:负向提示词

负向提示词与正向提示词作用相反:它引导模型避免生成某些内容,常用于快速提升图像质量、排除不想要的元素。

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k" negative_prompt = "bad architecture, unstable, poor details, blurry" image = pipeline(prompt=prompt, negative_prompt=negative_prompt, image=init_image, mask_image=mask_image).images[0]

其他常用参数一览

结合__call__的完整签名(见 pipeline_stable_diffusion_inpaint.py),以下参数也值得掌握:

参数默认值作用
num_inference_steps50去噪步数,越多质量通常越高、速度越慢;受strength调制
height/widthUNet 配置决定(512×512)输出尺寸,必须能被vae_scale_factor(8)整除
num_images_per_prompt1每个提示词生成的图片数量
generatorNonetorch.Generator,传入固定种子可复现结果
eta0.0仅对DDIMScheduler生效的随机性参数,对应 DDIM 论文中的 η
latentsNone预生成的噪声潜变量,可用同一组潜变量搭配不同提示词
prompt_embeds/negative_prompt_embedsNone预计算好的文本嵌入,可替代prompt传入
output_type"pil"输出格式,可选 "pil"、"np"、"latent"
clip_skipNone跳过 CLIP 末尾若干层再取嵌入(1 表示取倒数第二层输出)
callback_on_step_endNone每步去噪结束时的回调函数

管线链式组合:让修复融入更复杂的生成流程

AutoPipelineForInpainting可以与其他 diffusers 管线链式使用,用来优化其他管线的输出。多管线串联时,在潜空间(latent space)中传递中间结果并复用相同组件可以显著节省显存。

文生图 → 修复(Text-to-image-to-inpaint)

先文生图生成一座城堡,再用修复管线在指定掩码区域画一条瀑布,全程无需额外提供底图:

import torch from diffusers import AutoPipelineForText2Image, AutoPipelineForInpainting from diffusers.utils import load_image, make_image_grid pipeline = AutoPipelineForText2Image.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-v1-5", dtype=torch.float16, variant="fp16", use_safetensors=True ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() text2image = pipeline("concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k").images[0]

加载掩码并对掩码区域进行修复:

mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_text-chain-mask.png") pipeline = AutoPipelineForInpainting.from_pretrained( "kandinsky-community/kandinsky-2-2-decoder-inpaint", dtype=torch.float16 ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() prompt = "digital painting of a fantasy waterfall, cloudy" image = pipeline(prompt=prompt, image=text2image, mask_image=mask_image).images[0] make_image_grid([text2image, mask_image, image], rows=1, cols=3)

修复 → img2img(Inpaint-to-image-to-image)

也可以把修复放在前面,后面接 img2img 或超分管线进一步提升质量。先用修复管线得到结果,再用 SDXL refiner 增强细节:

# 第一步:修复 pipeline = AutoPipelineForInpainting.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, variant="fp16" ) pipeline.enable_model_cpu_offload() init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png") mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png") prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k" image_inpainting = pipeline(prompt=prompt, image=init_image, mask_image=mask_image).images[0] # 为 SDXL 调整尺寸到 1024x1024 image_inpainting = image_inpainting.resize((1024, 1024)) # 第二步:用 SDXL refiner 增强细节 pipeline = AutoPipelineForInpainting.from_pretrained( "stabilityai/stable-diffusion-xl-refiner-1.0", dtype=torch.float16, variant="fp16" ) pipeline.enable_model_cpu_offload() image = pipeline(prompt=prompt, image=image_inpainting, mask_image=mask_image, output_type="latent").images[0]

💡提示:指定output_type="latent"可以让所有输出保持在潜空间,避免一次不必要的"解码-再编码"。但这仅在链式管线使用同一个 VAE 类时有效。例如上文中 Kandinsky 2.2 与 Stable Diffusion 使用的 VAE 类不同,就无法跨管线保持潜空间;而两个 Stable Diffusion v1.5 管线都使用AutoencoderKL,则可以全程停留在潜空间。

最后用from_pipe复用已有组件,把结果交给 img2img 管线做收尾,避免重复加载全部组件到内存:

pipeline = AutoPipelineForImage2Image.from_pipe(pipeline) # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() image = pipeline(prompt=prompt, image=image).images[0] make_image_grid([init_image, mask_image, image_inpainting, image], rows=2, cols=2)

AutoPipelineForInpainting.from_pipe会通过_get_task_class在当前管线的类名上做模式匹配,找出对应的修复管线类并复用原管线的组件(见 auto_pipeline.py)。

img2img 与 inpainting 的关系:img2img 生成一张与给定图片相似的新图;inpainting 做的事相同,但只变换掩码定义的区域,其余部分不变。可以把 inpainting 理解为"做局部精确修改的精细工具",把 img2img 理解为"做大幅改造的宏观工具"。

更强的控制:提示词加权与 ControlNet

去噪过程具有随机性,仅靠negative_prompt等参数难以让图像"完全符合预期"。下面两种方法能提供更强、更精确的控制。

提示词加权(Prompt weighting)

提示词加权为提示词中每个概念的表示提供可量化的缩放手段:通过放大/缩小各概念的文本嵌入向量幅度,控制每个概念在图像中的呈现程度。可用 Compel。

生成嵌入后,通过prompt_embeds(以及使用负向提示词时的negative_prompt_embeds)参数传入管线,替代prompt参数:

import torch from diffusers import AutoPipelineForInpainting from diffusers.utils import make_image_grid pipeline = AutoPipelineForInpainting.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", dtype=torch.float16, ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() image = pipeline(prompt_embeds=prompt_embeds, # 由 Compel 生成 negative_prompt_embeds=negative_prompt_embeds, # 由 Compel 生成 image=init_image, mask_image=mask_image ).images[0] make_image_grid([init_image, mask_image, image], rows=1, cols=3)

使用 ControlNet 修复

ControlNet 与其他扩散模型(如 Stable Diffusion)配合使用,提供更灵活、更精确的生成控制:它接受额外的条件图像输入,引导扩散模型保留其中的特征。

下面的例子使用在修复图像上预训练的 ControlNet(lllyasviel/control_v11p_sd15_inpaint),配合StableDiffusionControlNetInpaintPipeline使用:

import torch import numpy as np from diffusers import ControlNetModel, StableDiffusionControlNetInpaintPipeline from diffusers.utils import load_image, make_image_grid # 加载 ControlNet controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_inpaint", dtype=torch.float16, variant="fp16") # 把 ControlNet 传入管线 pipeline = StableDiffusionControlNetInpaintPipeline.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-inpainting", controlnet=controlnet, dtype=torch.float16, variant="fp16" ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() # 加载原图和掩码 init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint.png") mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/inpaint_mask.png") # 构造 control image:掩码区域置为 -1(黑),其余为原图 def make_inpaint_condition(init_image, mask_image): init_image = np.array(init_image.convert("RGB")).astype(np.float32) / 255.0 mask_image = np.array(mask_image.convert("L")).astype(np.float32) / 255.0 assert init_image.shape[0:1] == mask_image.shape[0:1], "image and image_mask must have the same image size" init_image[mask_image > 0.5] = -1.0 # 掩码像素置为 -1 init_image = np.expand_dims(init_image, 0).transpose(0, 3, 1, 2) init_image = torch.from_numpy(init_image) return init_image control_image = make_inpaint_condition(init_image, mask_image)

现在把原图、掩码和 control image 一起传入生成。你会发现生成图像中原图特征被强烈保留

prompt = "concept art digital painting of an elven castle, inspired by lord of the rings, highly detailed, 8k" image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, control_image=control_image).images[0] make_image_grid([init_image, mask_image, PIL.Image.fromarray(np.uint8(control_image[0][0])).convert('RGB'), image], rows=2, cols=2)

更进一步,可以把 ControlNet 修复的结果再链式接入一个 img2img 管线来套用新风格(例如nitrosocke/elden-ring-diffusion),提示词中加入风格 token 即可:

from diffusers import AutoPipelineForImage2Image pipeline = AutoPipelineForImage2Image.from_pretrained( "nitrosocke/elden-ring-diffusion", dtype=torch.float16, ) pipeline.enable_model_cpu_offload() # 如果未安装 xFormers 且没有 PyTorch 2.0 及以上版本,请移除下一行 pipeline.enable_xformers_memory_efficient_attention() prompt = "elden ring style castle" # 提示词中需包含 "elden ring style" token negative_prompt = "bad architecture, deformed, disfigured, poor details" image_elden_ring = pipeline(prompt, negative_prompt=negative_prompt, image=image).images[0] make_image_grid([init_image, mask_image, image, image_elden_ring], rows=2, cols=2)

性能优化:更省显存、更快推理

在资源受限的环境下运行扩散模型可能又慢又吃内存,以下是几个最有效的优化手段。

内存高效注意力

最立竿见影的优化之一是启用内存高效注意力:

  • 使用PyTorch 2.0时,scaled-dot product attention(SDPA)默认自动启用,无需任何额外操作;
  • 非 PyTorch 2.0 用户可安装并使用xFormers的实现。
pipeline.enable_xformers_memory_efficient_attention()

两种方式都能降低内存占用并加速推理。

模型 CPU 卸载

把模型权重按需从 CPU 卸载到 GPU,可以进一步节省显存:

pipeline.enable_model_cpu_offload()

StableDiffusionInpaintPipeline为此定义了卸载顺序"text_encoder->image_encoder->unet->vae"(见 pipeline_stable_diffusion_inpaint.py)。

torch.compile 加速

想进一步提速推理,可用torch.compile编译管线中最耗时的组件——通常是 UNet:

pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)

更多优化手段可参考 减少内存占用指南 与 加速推理指南(含 SDPA 与 torch.compile 的详细介绍),以及 xFormers 指南。

源码视角:修复管线是如何工作的

为了帮助读者深入理解,这里从源码层面梳理StableDiffusionInpaintPipeline的核心执行流程(对应__call__,见 pipeline_stable_diffusion_inpaint.py):

  1. 参数校验check_inputs检查strength范围、宽高是否能被 8 整除、prompt/prompt_embeds是否只传其一等;
  2. 编码提示词encode_prompt生成文本嵌入;若启用 CFG 则同时生成无条件嵌入,并拼接为一个 batch;
  3. 设定时间步retrieve_timesteps+get_timestepsstrength计算出实际去噪时间步;
  4. 预处理图像与掩码image_processor.preprocess把原图缩放到目标尺寸;mask_processor.preprocess处理掩码(灰度化 + 二值化,见 pipeline_stable_diffusion_inpaint.py);
  5. 准备潜变量prepare_latents生成初始噪声(strength=1时)或"图像潜变量+噪声"(strength<1时);prepare_mask_latents把掩码缩放到潜空间尺寸并编码被掩码图像;
  6. 通道拼接:修复专用 UNet 输入为 9 通道 = 4(潜变量)+ 1(掩码)+ 4(被掩码图像潜变量),在去噪循环中拼接后送入 UNet;
  7. 去噪循环:预测噪声 → CFG 融合 → 调度器step得到上一时间步的潜变量;
  8. 解码:VAE 把潜变量解码回像素空间,经安全检查器(safety checker)过滤后由image_processor.postprocess输出 PIL 图像。

其中掩码处理器的关键配置do_normalize=False, do_binarize=True, do_convert_grayscale=True意味着掩码会被转为灰度、二值化(白色=重绘区域),且不做归一化——这正是"白像素重绘、黑像素保留"约定的实现来源。

仓库的测试文件 test_stable_diffusion_inpaint.py 中对上述行为做了系统性验证:例如测试用 UNet 的in_channels=9构造组件,并针对不同调度器(PNDM、DDIM、DPMSolverMultistep、EulerAncestral、LMS、LCM)验证管线输出(见 L71-L119),感兴趣的读者可进一步阅读。

结语

文本引导修复是 diffusers 生态中极具实用价值的能力。本文从StableDiffusionInpaintPipeline的最小示例出发,覆盖了AutoPipelineForInpainting自动选型、掩码制作与模糊、核心参数(strengthguidance_scalenegative_promptpadding_mask_crop)、修复专用与普通检查点的权衡、管线链式组合、ControlNet 精确控制以及性能优化,并给出了对应的源码路径供深入钻研。掌握这些内容后,你就可以把修复能力灵活嵌入自己的图像编辑与生成工作流中。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询