代码示例 / 生成式深度学习 / 穿越潜在空间与稳定扩散

穿越潜在空间与稳定扩散

作者: Ian Stenbit, fchollet, lukewood
创建日期: 2022/09/28
最后修改: 2022/09/28
描述: 探索稳定扩散的潜在流形。

在Colab中查看 GitHub源代码


概述

生成图像模型学习视觉世界的“潜在流形”: 一个低维向量空间,其中每个点映射到一幅图像。 从流形上的某个点返回到可显示图像 称为“解码”——在稳定扩散模型中,这是通过 “解码器”模型处理的。

稳定扩散架构

这种图像的潜在流形是连续的和可插值的,这意味着:

  1. 在流形上移动一点只会稍微改变对应的图像(连续性)。
  2. 对于流形上的任何两个点A和B(即任何两幅图像),可以 通过一条路径从A移动到B,其中每个中间点也在流形上(即 也是一个有效图像)。中间点将被称为 两个起始图像之间的“插值”。

然而,稳定扩散不仅仅是一个图像模型,它也是一个自然语言模型。 它有两个潜在空间:训练过程中使用的 编码器学习到的图像表示空间,以及使用预训练和 训练时微调结合学习的提示潜在空间。

潜在空间漫步,或_潜在空间探索_,是采样一个潜在空间中的 点并逐步改变潜在表示的过程。它最常见的应用是生成动画, 每个采样点被输入到解码器中,并存储为 最终动画中的一帧。 对于高质量的潜在表示,这会产生连贯的 动画。这些动画可以提供对潜在空间特征图的洞察, 并最终导致训练过程的改善。以下展示了一个这样的GIF:

熊猫到飞机

在本指南中,我们将展示如何利用KerasCV中的稳定扩散API 执行提示插值和循环漫步,通过 稳定扩散的视觉潜在流形,以及通过 文本编码器的潜在流形。

本指南假设读者对稳定扩散有一个 高层次的理解。 如果你还没有,请先阅读 稳定扩散教程

首先,我们导入KerasCV并使用 教程中讨论的优化加载稳定扩散模型 使用稳定扩散生成图像。 请注意,如果您在M1 Mac GPU上运行,则不应启用混合精度。

!pip install keras-cv --upgrade --quiet
import keras_cv
import keras
import matplotlib.pyplot as plt
from keras import ops
import numpy as np
import math
from PIL import Image

# 启用混合精度
# (仅在您拥有最新的NVIDIA GPU时执行此操作)
keras.mixed_precision.set_global_policy("mixed_float16")

# 实例化稳定扩散模型
model = keras_cv.models.StableDiffusion(jit_compile=True)
使用此模型检查点,即表示您承认其使用受限于CreativeML Open RAIL-M许可证的条款,网址为 https://raw.githubusercontent.com/CompVis/stable-diffusion/main/LICENSE

在文本提示之间进行插值

在稳定扩散中,文本提示首先被编码为一个向量, 该编码用于指导扩散过程。 潜在编码向量的形状为 77x768(这很大!),当我们给稳定扩散一个文本提示时,我们 正是从潜在流形的一个这样的点生成图像。

为了探索更多的流形,我们可以在两个文本编码之间插值, 并在那些插值点生成图像:

prompt_1 = "海滩上的一幅金毛犬水彩画"
prompt_2 = "一碗水果的静物 DSLR 照片"
interpolation_steps = 5

encoding_1 = ops.squeeze(model.encode_text(prompt_1))
encoding_2 = ops.squeeze(model.encode_text(prompt_2))

interpolated_encodings = ops.linspace(encoding_1, encoding_2, interpolation_steps)

# 显示潜在流形的大小
print(f"Encoding shape: {encoding_1.shape}")
从 https://github.com/openai/CLIP/blob/main/clip/bpe_simple_vocab_16e6.txt.gz?raw=true 下载数据
 1356917/1356917 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
从 https://huggingface.co/fchollet/stable-diffusion/resolve/main/kcv_encoder.h5 下载数据
 492466864/492466864 ━━━━━━━━━━━━━━━━━━━━ 7s 0us/step
编码形状: (77, 768)

一旦我们对编码进行了插值,我们就可以从每个点生成图像。 请注意,为了在生成的图像之间保持一定的稳定性,我们在图像之间保持扩散噪声不变。

seed = 12345
noise = keras.random.normal((512 // 8, 512 // 8, 4), seed=seed)

images = model.generate_image(
    interpolated_encodings,
    batch_size=interpolation_steps,
    diffusion_noise=noise,
)
从 https://huggingface.co/fchollet/stable-diffusion/resolve/main/kcv_diffusion_model.h5 下载数据
 3439090152/3439090152 ━━━━━━━━━━━━━━━━━━━━ 26s 0us/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 173s 311ms/step
从 https://huggingface.co/fchollet/stable-diffusion/resolve/main/kcv_decoder.h5 下载数据
 198180272/198180272 ━━━━━━━━━━━━━━━━━━━━ 1s 0us/step

现在我们已经生成了一些插值图像,让我们来看看它们!

在本教程中,我们将导出一系列图像作为GIF,这样它们可以在某些时间上下文中轻松查看。对于第一张和最后一张图像在概念上不匹配的图像序列,我们会将GIF拉伸。

如果您在Colab中运行,可以通过运行以下代码查看自己的GIF:

from IPython.display import Image as IImage
IImage("doggo-and-fruit-5.gif")
def export_as_gif(filename, images, frames_per_second=10, rubber_band=False):
    if rubber_band:
        images += images[2:-1][::-1]
    images[0].save(
        filename,
        save_all=True,
        append_images=images[1:],
        duration=1000 // frames_per_second,
        loop=0,
    )


export_as_gif(
    "doggo-and-fruit-5.gif",
    [Image.fromarray(img) for img in images],
    frames_per_second=2,
    rubber_band=True,
)

Dog to Fruit 5

结果可能让人感到惊讶。通常情况下,在提示之间进行插值会产生连贯的图像,并且通常会展示两个提示内容之间的渐进概念转变。这表明了一个高质量的表示空间,紧密反映了视觉世界的自然结构。

为了更好地可视化这一点,我们应该进行更加细粒度的插值,使用数百个步骤。为了保持批大小较小(这样我们不会使GPU内存溢出),这需要手动分批我们的插值编码。

interpolation_steps = 150
batch_size = 3
batches = interpolation_steps // batch_size

interpolated_encodings = ops.linspace(encoding_1, encoding_2, interpolation_steps)
batched_encodings = ops.split(interpolated_encodings, batches)

images = []
for batch in range(batches):
    images += [
        Image.fromarray(img)
        for img in model.generate_image(
            batched_encodings[batch],
            batch_size=batch_size,
            num_steps=25,
            diffusion_noise=noise,
        )
    ]

export_as_gif("doggo-and-fruit-150.gif", images, rubber_band=True)

25/25 ━━━━━━━━━━━━━━━━━━━━ 77s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 211ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 215ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 203ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 211ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 215ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 203ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 211ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 203ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/步 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/步

狗到水果 150

生成的gif展示了两个提示之间更清晰、更连贯的转换。尝试一些自己的提示并进行实验!

我们甚至可以将这个概念扩展到多个图像。例如,我们可以在四个提示之间进行插值:

# 四个提示
prompt_1 = "海滩上的一只金色猎犬的水彩画"
prompt_2 = "一碗水果的静物DSLR照片"
prompt_3 = "星夜风格的埃菲尔铁塔"
prompt_4 = "摩天大楼的建筑草图"

# 插值步骤、批大小和批次数
interpolation_steps = 6
batch_size = 3
batches = (interpolation_steps**2) // batch_size

# 编码提示
encoding_1 = ops.squeeze(model.encode_text(prompt_1))
encoding_2 = ops.squeeze(model.encode_text(prompt_2))
encoding_3 = ops.squeeze(model.encode_text(prompt_3))
encoding_4 = ops.squeeze(model.encode_text(prompt_4))

# 插值编码
interpolated_encodings = ops.linspace(
    ops.linspace(encoding_1, encoding_2, interpolation_steps),
    ops.linspace(encoding_3, encoding_4, interpolation_steps),
    interpolation_steps,
)
interpolated_encodings = ops.reshape(
    interpolated_encodings, (interpolation_steps**2, 77, 768)
)
batched_encodings = ops.split(interpolated_encodings, batches)

# 生成图像
images = []
for batch in range(batches):
    images.append(
        model.generate_image(
            batched_encodings[batch],
            batch_size=batch_size,
            diffusion_noise=noise,
        )
    )


# 绘制网格
def plot_grid(images, path, grid_size, scale=2):
    fig, axs = plt.subplots(
        grid_size, grid_size, figsize=(grid_size * scale, grid_size * scale)
    )
    fig.tight_layout()
    plt.subplots_adjust(wspace=0, hspace=0)
    plt.axis("off")
    for ax in axs.flat:
        ax.axis("off")

    images = images.astype(int)
    for i in range(min(grid_size * grid_size, len(images))):
        ax = axs.flat[i]
        ax.imshow(images[i].astype("uint8"))
        ax.axis("off")

    for i in range(len(images), grid_size * grid_size):
        axs.flat[i].axis("off")
        axs.flat[i].remove()

    plt.savefig(
        fname=path,
        pad_inches=0,
        bbox_inches="tight",
        transparent=False,
        dpi=60,
    )


images = np.concatenate(images)
plot_grid(images, "4-way-interpolation.jpg", interpolation_steps)
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 209ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 204ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 209ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 205ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 208ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 205ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 210ms/step

png

我们还可以在允许扩散噪声变化的情况下进行插值,方法是去掉diffusion_noise参数:

images = []
for batch in range(batches):
    images.append(model.generate_image(batched_encodings[batch], batch_size=batch_size))

images = np.concatenate(images)
plot_grid(images, "4-way-interpolation-varying-noise.jpg", interpolation_steps)
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 215ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 13s 254ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 12s 235ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 12s 230ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 214ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 208ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 210ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 209ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 208ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 10s 205ms/step
 50/50 ━━━━━━━━━━━━━━━━━━━━ 11s 213ms/step

png

接下来,来进行一些漫步吧!


围绕文本提示漫步

我们的下一个实验是围绕潜在流形漫步,从某个特定提示生成的点开始。

walk_steps = 150
batch_size = 3
batches = walk_steps // batch_size
step_size = 0.005

encoding = ops.squeeze(
    model.encode_text("The Eiffel Tower in the style of starry night")
)
# 注意 (77, 768) 是文本编码的形状。
delta = ops.ones_like(encoding) * step_size

walked_encodings = []
for step_index in range(walk_steps):
    walked_encodings.append(encoding)
    encoding += delta
walked_encodings = ops.stack(walked_encodings)
batched_encodings = ops.split(walked_encodings, batches)

images = []
for batch in range(batches):
    images += [
        Image.fromarray(img)
        for img in model.generate_image(
            batched_encodings[batch],
            batch_size=batch_size,
            num_steps=25,
            diffusion_noise=noise,
        )
    ]

export_as_gif("eiffel-tower-starry-night.gif", images, rubber_band=True)
 25/25 ━━━━━━━━━━━━━━━━━━━━ 6s 228ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 218ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 215ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 218ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 218ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 217ms/step

埃菲尔铁塔散步动图

或许不出所料,远离编码器的潜在流形太远会产生看起来不连贯的图像。尝试自己设置提示,并调整 step_size 来增加或减少步行的幅度。请注意,当步行的幅度变大时,步行往往会导致进入那些生成极其嘈杂的图像的区域。


单个提示的扩散噪声空间中的圆形步行

我们最后的实验是坚持一个提示,并探索扩散模型可以从该提示中生成的多样图像。我们通过控制用于启动扩散过程的噪声来实现这一点。

我们创建两个噪声分量 xy,并从 0 到 2π 进行步行,将 x 分量的余弦与 y 分量的正弦相加以产生噪声。使用这种方法,我们的步行结束时到达的噪声输入与我们开始时相同,因此我们得到了一个“可循环”的结果!

prompt = "荷兰风车旁一片田野上的牛的油画"
encoding = ops.squeeze(model.encode_text(prompt))
walk_steps = 150
batch_size = 3
batches = walk_steps // batch_size

walk_noise_x = keras.random.normal(noise.shape, dtype="float64")
walk_noise_y = keras.random.normal(noise.shape, dtype="float64")

walk_scale_x = ops.cos(ops.linspace(0, 2, walk_steps) * math.pi)
walk_scale_y = ops.sin(ops.linspace(0, 2, walk_steps) * math.pi)
noise_x = ops.tensordot(walk_scale_x, walk_noise_x, axes=0)
noise_y = ops.tensordot(walk_scale_y, walk_noise_y, axes=0)
noise = ops.add(noise_x, noise_y)
batched_noise = ops.split(noise, batches)

images = []
for batch in range(batches):
    images += [
        Image.fromarray(img)
        for img in model.generate_image(
            encoding,
            batch_size=batch_size,
            num_steps=25,
            diffusion_noise=batched_noise[batch],
        )
    ]

export_as_gif("cows.gif", images)
 25/25 ━━━━━━━━━━━━━━━━━━━━ 35s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 215ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 213ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 218ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 211ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 210ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 217ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 204ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 208ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 207ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 215ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 212ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 209ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 216ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 205ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 206ms/step
 25/25 ━━━━━━━━━━━━━━━━━━━━ 5s 214ms/step

快乐的牛

试验你自己的提示和不同的 unconditional_guidance_scale 值!


结论

稳定扩散不仅仅提供单一的文本到图像生成。探索文本编码器的潜在流形和扩散模型的噪声空间是体验该模型强大功能的两种有趣方式,而 KerasCV 使这一切变得简单!