NSDT工具推荐Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - AI模型在线查看 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

在之前的文章中,我们介绍了使用Diffusers包运行稳定的扩散模型、使用 Real-ESRGAN 放大图像、使用长提示和使用扩散器包进行 CLIP 跳过 — 所有这些步骤必须组合在一起才能获得高分辨率和高质量的输出 稳定扩散。

在本文中,我们将所有内容整合到一个管道中,并演示如何通过Diffusers包从 Civitai 下载和使用模型。

Civitai 是寻找社区训练的各种稳定扩散模型的好地方。 虽然这些模型通常与 UI 一起使用,但经过一些工作,它们也可以与Diffusers包一起使用。

1、依赖安装

在本文中,我们将使用以下软件包的以下版本:

pip install -q transformers==4.31.0
pip install -q accelerate==0.21.0
pip install -q diffusers==0.20.0
pip install -q huggingface_hub==0.16.4
pip install -q omegaconf==2.3.0

2、准备环境

首先,我们加载必要的包,并检查 GPU 是否可用 - 稳定的扩散模型应该在 GPU 上运行! 此外,GPU 上将使用半精度。

import diffusers
import transformers

import sys
import os
import shutil
import time

import torch
import matplotlib.pyplot as plt
import numpy as np

from PIL import Image

if torch.cuda.is_available():
    device_name = torch.device("cuda")
    torch_dtype = torch.float16
else:
    device_name = torch.device("cpu")
    torch_dtype = torch.float32

接下来,我们从 Civita 下载模型 safetensors 文件。 在本文中,我们使用该模型生成 Celsia 发布的中国水彩画风格的美丽风景场景。

wget https://civitai.com/api/download/models/130803 --content-disposition

我们需要将下载的 safetensors 文件转换为可与diffusers包一起使用的另一种格式。 对于此转换,我们下载并使用 HuggingFace 的 GitHub 存储库上提供的 Python 脚本。 请注意,所使用的脚本版本应与diffusers的版本相匹配,在本例中为 0.20.0。

wget https://raw.githubusercontent.com/huggingface/diffusers/v0.20.0/scripts/convert_original_stable_diffusion_to_diffusers.py
python convert_original_stable_diffusion_to_diffusers.py 
--checkpoint_path ChineseLandscapeArt_v10.safetensors 
--dump_path ChineseLandscapeArt_v10/ 
--from_safetensors

使用下载的转换脚本,转换后的模型文件将保存在ChineseLandscapeArt_v10/目录下。 这些文件现在已准备好通过diffusers的稳定扩散管道加载。

3、CLIP Skip

接下来是使用Diffusers实现 CLIP Skip功能,如 GitHub 上的 Patrick von Platen 详细介绍的,以在 CLIP 文本编码器中跳过图层。 现在我们使用 CLIP Skip = 1,它使用 CLIP 文本编码器中的所有层。

# Follows community convention.
# Clip skip = 1 uses the all text encoder layers.
# Clip skip = 2 skips the last text encoder layer.

clip_skip = 1

if clip_skip > 1:
    text_encoder = transformers.CLIPTextModel.from_pretrained(
        "runwayml/stable-diffusion-v1-5",
        subfolder = "text_encoder",
        num_hidden_layers = 12 - (clip_skip - 1),
        torch_dtype = torch_dtype
    )

使用修改后的文本编码器,将转换后的模型文件加载到diffusers的扩散管道中。

# Load the pipeline.

model_path = "ChineseLandscapeArt_v10"

if clip_skip > 1:
    # TODO clean this up with the condition below.
    pipe = diffusers.DiffusionPipeline.from_pretrained(
        model_path,
        torch_dtype = torch_dtype,
        safety_checker = None,
        text_encoder = text_encoder,
    )
else:
    pipe = diffusers.DiffusionPipeline.from_pretrained(
        model_path,
        torch_dtype = torch_dtype,
        safety_checker = None
    )

pipe = pipe.to(device_name)

# Change the pipe scheduler to EADS.
pipe.scheduler = diffusers.EulerAncestralDiscreteScheduler.from_config(
    pipe.scheduler.config
)

4、长提示的提示嵌入

稳定扩散的 CLIP 文本编码器限制为 77 个标记,并且将截断长度超过此限制的编码提示 - 需要提示嵌入来克服此限制。 我们使用 Andre van Zuydam 在 GitHub 上提出的解决方案的修改版本来通过diffusers管道创建提示嵌入。

# Prompt embeddings to overcome CLIP 77 token limit.
# https://github.com/huggingface/diffusers/issues/2136

def get_prompt_embeddings(
    pipe,
    prompt,
    negative_prompt,
    split_character = ",",
    device = torch.device("cpu")
):
    max_length = pipe.tokenizer.model_max_length
    # Simple method of checking if the prompt is longer than the negative
    # prompt - split the input strings using `split_character`.
    count_prompt = len(prompt.split(split_character))
    count_negative_prompt = len(negative_prompt.split(split_character))

    # If prompt is longer than negative prompt.
    if count_prompt >= count_negative_prompt:
        input_ids = pipe.tokenizer(
            prompt, return_tensors = "pt", truncation = False
        ).input_ids.to(device)
        shape_max_length = input_ids.shape[-1]
        negative_ids = pipe.tokenizer(
            negative_prompt,
            truncation = False,
            padding = "max_length",
            max_length = shape_max_length,
            return_tensors = "pt"
        ).input_ids.to(device)

    # If negative prompt is longer than prompt.
    else:
        negative_ids = pipe.tokenizer(
            negative_prompt, return_tensors = "pt", truncation = False
        ).input_ids.to(device)
        shape_max_length = negative_ids.shape[-1]
        input_ids = pipe.tokenizer(
            prompt,
            return_tensors = "pt",
            truncation = False,
            padding = "max_length",
            max_length = shape_max_length
        ).input_ids.to(device)

    # Concatenate the individual prompt embeddings.
    concat_embeds = []
    neg_embeds = []
    for i in range(0, shape_max_length, max_length):
        concat_embeds.append(
            pipe.text_encoder(input_ids[:, i: i + max_length])[0]
        )
        neg_embeds.append(
            pipe.text_encoder(negative_ids[:, i: i + max_length])[0]
        )

    return torch.cat(concat_embeds, dim = 1), torch.cat(neg_embeds, dim = 1)

最后,所有基本构建块都已就位,我们可以使用从 Civita 下载的模型来运行diffusers管线。

5、提示和提示嵌入

与往常一样,管线中的第一步是创建提示和否定提示,以及相应的提示嵌入。

prompt = """beautiful Chinese Landscape Art, best quality, intricate,
water colors, snowy mountains, glacier, snow, starry night sky, stars,
milkyway"""


negative_prompt = """deformed, weird, bad resolution, bad depiction,
not Chinese style, weird, has people, worst quality, worst resolution,
too blurry, not relevant"""


prompt_embeds, negative_prompt_embeds = get_prompt_embeddings(
    pipe,
    prompt,
    negative_prompt,
    split_character = ",",
    device = device_name
)

6、生成合成图像

接下来是用于生成将所有不同部分放在一起的合成图像的实际循环。

目前,我们在 20 个步骤中生成了 10 张图像,引导比例为 7。此外,输出图像的分辨率为 768×512——稍后我们将使用 Real-ESRGAN 将它们升级到更高分辨率。

# Set to True to use prompt embeddings, and False to
# use the prompt strings.
use_prompt_embeddings = True

# Seed and batch size.
start_idx = 0
batch_size = 10
seeds = [i for i in range(start_idx , start_idx + batch_size, 1)]

# Number of inference steps.
num_inference_steps = 20

# Guidance scale.
guidance_scale = 7

# Image dimensions - limited to GPU memory.
width  = 768
height = 512

images = []

for count, seed in enumerate(seeds):
    start_time = time.time()

    if use_prompt_embeddings is False:
        new_img = pipe(
            prompt = prompt,
            negative_prompt = negative_prompt,
            width = width,
            height = height,
            guidance_scale = guidance_scale,
            num_inference_steps = num_inference_steps,
            num_images_per_prompt = 1,
            generator = torch.manual_seed(seed),
        ).images
    else:
        new_img = pipe(
            prompt_embeds = prompt_embeds,
            negative_prompt_embeds = negative_prompt_embeds,
            width = width,
            height = height,
            guidance_scale = guidance_scale,
            num_inference_steps = num_inference_steps,
            num_images_per_prompt = 1,
            generator = torch.manual_seed(seed),
        ).images


    images = images + new_img

7、可视化生成的图像

使用下面的函数可以轻松可视化生成的图像。

# Plot pipeline outputs.
def plot_images(images, labels = None):
    N = len(images)
    n_cols = 5
    n_rows = int(np.ceil(N / n_cols))

    plt.figure(figsize = (20, 5 * n_rows))
    for i in range(len(images)):
        plt.subplot(n_rows, n_cols, i + 1)
        if labels is not None:
            plt.title(labels[i])
        plt.imshow(np.array(images[i]))
        plt.axis(False)
    plt.show()
plot_images(images, seeds[:len(images)])
银河下的雪山

特别是,图像 5 看起来相当不错,但它的尺寸为 768×512,相当小。 让我们使用 Real-ESRGAN 对其进行升级!

8、使用 Real-ESRGAN 放大图像

我们使用 HuggingFace 上的 doevent 创建的 Real-ESRGAN 空间来放大Diffusers管道输出的图像。 该空间在 T4 GPU 上运行,速度相当快。

通过 Real-ESRGAN 运行图像两次,放大系数为 2 倍,得到的图像是原始尺寸的 4 倍!

9、结束语

在本文中,我们演示了使用 Civitai 模型与diffusers包的管道,从下载到转换模型,再到实现 CLIP 跳过和提示嵌入。 最后使用 Real-ESRGAN 来升级扩散管道的输出。 完整的管道已作为 Jupyter 笔记本发布在我的 GitHub 存储库


原文链接:Using Civitai Models with Diffusers

BimAnt翻译整理,转载请标明出处