【人工智能前沿弄潮】——生成式AI系列:Diffusers应用 (1) 了解Pipeline 、模型和scheduler

Diffusers旨在成为一个用户友好且灵活的工具箱,用于构建针对您的用例量身定制的扩散系统。工具箱的核心是模型和scheduler。虽然DiffusionPipeline为了方便起见将这些组件捆绑在一起,但您也可以拆分管道并单独使用模型和scheduler来创建新的扩散系统。

在本教程中,您将学习如何使用模型和scheduler来组装用于推理的扩散系统,从基本管道开始,然后发展到稳定扩散管道。

1、解构Diffusion Model基本Pipeline

Pipeline是运行模型进行推理的一种快速简便的方法,生成图像需要不超过四行代码:

from diffusers import DDPMPipeline

ddpm = DDPMPipeline.from_pretrained("google/ddpm-cat-256").to("cuda")
image = ddpm(num_inference_steps=25).images[0]
image

这非常容易,但是Pipeline是怎么做到的呢?让我们分解Pipeline,看看发生了什么。

在上面的示例中,管道包含一个UNet2DModel模型和一个DDPMScheduler

Pipeline通过获取所需输出大小的随机噪声并将其多次传递到模型中来对图像进行去噪。在每个时间步,模型预测噪声残余,scheduler使用它来预测噪声较小的图像。Pipeline重复此过程,直到到达指定数量的推理步骤的末尾。

要分别使用模型和scheduler重新创建Pipeline,让我们编写自己的去噪过程。

在这里插入图片描述

  • 加载模型和scheduler:
from diffusers import DDPMScheduler, UNet2DModel

scheduler = DDPMScheduler.from_pretrained("google/ddpm-cat-256")
model = UNet2DModel.from_pretrained("google/ddpm-cat-256").to("cuda")
  • 设置运行去噪过程的时间步数:
scheduler.set_timesteps(50)
  • 设置scheduler时间步长会创建一个张量,其中包含均匀间隔的元素,在本例中为50。每个元素对应于模型对图像进行去噪的时间步长。稍后创建去噪循环时,您将迭代此张量以对图像进行去噪:
scheduler.timesteps
tensor([980, 960, 940, 920, 900, 880, 860, 840, 820, 800, 780, 760, 740, 720,
    700, 680, 660, 640, 620, 600, 580, 560, 540, 520, 500, 480, 460, 440,
    420, 400, 380, 360, 340, 320, 300, 280, 260, 240, 220, 200, 180, 160,
    140, 120, 100,  80,  60,  40,  20,   0])
  • 创建一些与所需输出形状相同的随机噪声:
import torch

sample_size = model.config.sample_size
noise = torch.randn((1, 3, sample_size, sample_size)).to("cuda")
  • 现在编写一个循环来迭代时间步长。在每个时间步长,模型都会进行UNet2DModel.forward() 传递并返回带噪声的残差。scheduler的 step()方法接受带噪声的残差、时间步长和输入,并预测前一个时间步长的图像。该输出成为去噪循环中模型的下一个输入,它会重复,直到到达时间步长数组的末尾。
input = noise

for t in scheduler.timesteps:
    with torch.no_grad():
        noisy_residual = model(input, t).sample
    previous_noisy_sample = scheduler.step(noisy_residual, t, input).prev_sample
    input = previous_noisy_sample

这是整个去噪过程,您可以使用相同的模式来编写任何扩散系统。

  • 最后一步是将去噪输出转换为图像:
from PIL import Image
import numpy as np

image = (input / 2 + 0.5).clamp(0, 1)
image = image.cpu().permute(0, 2, 3, 1).numpy()[0]
image = Image.fromarray((image * 255).round().astype("uint8"))
image

在下一节中,您将测试您的技能,并分解更复杂的稳定扩散Pipeline。步骤或多或少是一样的。您将初始化必要的组件,并设置时间步数来创建时间步数数组。时间步数数组用于去噪循环,对于该数组中的每个元素,模型预测噪声较小的图像。去噪循环在时间步上迭代,在每个时间步上,它输出一个嘈杂的残差,scheduler使用它来预测前一个时间步上噪声较小的图像。重复此过程,直到到达时间步长数组的末尾。 我们来试试看吧!

2、解构Stable Diffusion pipeline

Stable Diffusion是一种文本到图像的潜在扩散模型。它被称为潜在扩散模型因为它使用图像的低维表示而不是实际的像素空间,这使得它的内存效率更高。编码器将图像压缩成更小的表示,解码器将压缩的表示转换回图像。对于文本到图像模型,您需要一个标记器和一个编码器来生成文本嵌入。从前面的例子中,您已经知道您需要一个UNet模型和一个Scheduler。

如您所见,这已经比仅包含UNet模型的DDPM管道更复杂。Stable Diffusion模型有三个独立的预训练模型。

💡 阅读 How does Stable Diffusion work?了解有关VAE、UNet和文本编码器模型的更多详细信息。

现在您知道Stable Diffusion pipeline需要什么了,使用from_pretrained()方法加载所有这些组件。您可以在预训练的runwayml/stable-diffusion-v1-5checkpoint中找到它们,每个组件都存储在单独的子文件夹中:

from PIL import Image
import torch
from transformers import CLIPTextModel, CLIPTokenizer
from diffusers import AutoencoderKL, UNet2DConditionModel, PNDMScheduler

vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae")
tokenizer = CLIPTokenizer.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="tokenizer")
text_encoder = CLIPTextModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="text_encoder")
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet")

代替默认的PNDMScheduler,将其换成UniPCMultistepScheduler,看看插入不同的Scheduler有多容易:

from diffusers import UniPCMultistepScheduler

scheduler = UniPCMultistepScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")

为了加快推理速度,请将模型移动到GPU,因为与调度程序不同,它们具有可训练的权重:

torch_device = "cuda"
vae.to(torch_device)
text_encoder.to(torch_device)
unet.to(torch_device)

2.1 创建文本嵌入

下一步是标记文本以生成embedding。文本用于调节UNet模型并将扩散过程引导到类似于输入提示符的东西。

💡注: guidance_scale参数决定了在生成图像时应该给prompt多少权重。

如果您想生成其他内容,请随意选择您喜欢的任何prompt!

prompt = ["a photograph of an astronaut riding a horse"]
height = 512  # default height of Stable Diffusion
width = 512  # default width of Stable Diffusion
num_inference_steps = 25  # Number of denoising steps
guidance_scale = 7.5  # Scale for classifier-free guidance
generator = torch.manual_seed(0)  # Seed generator to create the inital latent noise
batch_size = len(prompt)

标记文本并从提示生成embeddings :

text_input = tokenizer(
    prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt"
)

with torch.no_grad():
    text_embeddings = text_encoder(text_input.input_ids.to(torch_device))[0]

您还需要生成**无条件文本embeddings **,它们是填充标记的embeddings 。这些需要具有与条件text_embeddings相同的形状(batch_size和seq_length):

max_length = text_input.input_ids.shape[-1]
uncond_input = tokenizer([""] * batch_size, padding="max_length", max_length=max_length, return_tensors="pt")
uncond_embeddings = text_encoder(uncond_input.input_ids.to(torch_device))[0]

让我们将条件和无条件嵌入连接到一个批处理中,以避免进行两次前向传递:

text_embeddings = torch.cat([uncond_embeddings, text_embeddings])

2.2 制造随机噪音

接下来,生成一些初始随机噪声作为扩散过程的起点。这是图像的潜在表示(latent representation),它将逐渐去噪。在这一点上,潜在图像小于最终图像尺寸,但没关系,因为模型稍后会将其转换为最终的512x512图像尺寸。

💡注: 高度和宽度除以8,因为vae模型有3个下采样层。您可以通过运行以下命令来检查:

2 ** (len(vae.config.block_out_channels) - 1) == 8
latents = torch.randn(
    (batch_size, unet.in_channels, height // 8, width // 8),
    generator=generator,
)
latents = latents.to(torch_device)

2.3 去噪图像

首先使用**初始噪声分布sigma(噪声标度值)**缩放输入,这是改进scheduler(如UniPCMultistepScheduler)所必需的:

latents = latents * scheduler.init_noise_sigma

最后一步是创建去噪循环,将潜在的纯噪声逐步转换为提示所描述的图像。记住,去噪循环需要做三件事:

  1. 设置在去噪期间使用的scheduler的时间步长。
  2. 迭代时间步长。
  3. 在每个时间步,调用UNet模型来预测噪声残余并将其传递给scheduler以计算先前的噪声样本。
from tqdm.auto import tqdm

scheduler.set_timesteps(num_inference_steps)

for t in tqdm(scheduler.timesteps):
    # 如果我们正在进行无分类器引导以避免进行两次前向传递,则扩展latents。
    latent_model_input = torch.cat([latents] * 2)

    latent_model_input = scheduler.scale_model_input(latent_model_input, timestep=t)

    # 预测噪声残余
    with torch.no_grad():
        noise_pred = unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample

    # 执行guidance
    noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
    noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)

    # 计算先前的噪声样本x_t->x_t-1
    latents = scheduler.step(noise_pred, t, latents).prev_sample

2.4 解码图像

最后一步是使用vae将潜在表示解码为图像并获得带有样本的解码输出:

# 用vae缩放和解码图像latents
latents = 1 / 0.18215 * latents
with torch.no_grad():
    image = vae.decode(latents).sample

最后,将图像转换为PIL. Image以查看您生成的图像!

image = (image / 2 + 0.5).clamp(0, 1)
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
images = (image * 255).round().astype("uint8")
pil_images = [Image.fromarray(image) for image in images]
pil_images[0]

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/72351.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用AI工具Lama Cleaner一键去除水印、人物、背景等图片里的内容

使用AI工具Lama Cleaner一键去除水印、人物、背景等图片里的内容 前言前提条件相关介绍Lama Cleaner环境要求安装Lama Cleaner启动Lama CleanerCPU方式启动GPU方式启动 使用Lama Cleaner测试结果NO.1 检测框NO.2 水印NO.3 广州塔NO.4 人物背景 参考 前言 由于本人水平有限&…

Faker库详解 - Python中的随机数据生成器

文章目录 Faker介绍Faker安装Faker使用基本使用方法随机生成人物相关的基础信息随机生成地理相关的信息随机生成网络相关的信息随机生成日期相关的信息随机生成数字/字符串/文本随机生成列表/元组/字典/集合/迭代器/json随机生成文件相关的信息随机生成颜色/表情每次请求获取相…

2023“钉耙编程”中国大学生算法设计超级联赛(5)

Typhoon 计算几何,点到线段距离 String Magic (Easy Version) Manacher可持久化线段树 Touhou Red Red Blue DP 模拟 Expectation (Easy Version) 签到,组合数学 Tree 树形DP Cactus Circuit 仙人掌图,tarjan找简单环 Counting Stars 暴力…

Mac安装nvm教程及使用

nvm 是 node 版本管理器,也就是说一个 nvm 可以管理多个 node 版本(包含 npm 与 npx),可以方便快捷的安装、切换 不同版本的 node。 1、直接通过brew安装 执行命令:brew install nvm PS: 如果没有安装br…

机器学习笔记:李宏毅diffusion model

1 概念原理 首先sample 一个都是噪声的vector然后经过denoise network 过滤一些杂质接着继续不断denoise,直到最后出来一张清晰图片 【类似于做雕塑,一开始只是一块石头(噪声很杂的雕塑),慢慢雕刻出想要的花纹】 同一个…

MySQL修改编码

插入中文乱码,我电脑上没有出现,我只是来记录一下 MySQL版本: 8.0.34Windows 查看编码 mysql中输入下面的命令 show variables like ‘character_%’; 乱码的一般是图片中划红线的部分不是utf8 character_set_database是设置数据库的默认编码的 character_set_ser…

ETLCloud+MaxCompute实现云数据仓库的高效实时同步

MaxCompute介绍 MaxCompute是适用于数据分析场景的企业级SaaS(Software as a Service)模式云数据仓库,以Serverless架构提供快速、全托管的在线数据仓库服务,消除了传统数据平台在资源扩展性和弹性方面的限制,最小化用…

基于grpc从零开始搭建一个准生产分布式应用(3) - GRPC实现

本章开始会进入GRPC子专题,先实现前面章节中提到的例子。然后就使用的知识点展开全面的描述。本章代码任务:1、实现一个简单的GRPC服务;2、实现GRPC拦截器。 本章的代码承接上一章的代码进行迭代。因模块间存在相互依赖关系,读者一…

【数据结构】二叉树篇| 纲领思路02+刷题

博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: 是瑶瑶子啦每日一言🌼: 所谓自由,不是随心所欲,而是自我主宰。——康德 目录 一、前言二、刷题1、翻转二叉树 2、二叉树的层序遍历✨3、 二…

2023国赛数学建模D题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…

【Java】一只小菜坤的编程题之旅【3】

文章目录 1丶判定是否互为字符重排2、杨辉三角3丶某公司的1个面试题(字符串包含问题) 1丶判定是否互为字符重排 这个题我们用一个非常简单的思想就能实现,我们先将字符串转换为字符数组,然后对字符数组进行排序,然后再…

安卓如何卸载应用

卸载系统应用 首先需要打开手机的开发者选项,启动usb调试。 第二步需要在电脑上安装adb命令,喜欢的话还可以将它加入系统path。如果不知道怎么安装,可以从这里下载免安装版本。 第三步将手机与电脑用数据线连接,注意是数据线&a…

阿里云服务器部署Drupal网站教程基于CentOS系统

阿里云百科分享如何在CentOS 7操作系统的ECS实例上搭建Drupal电子商务网站。Drupal是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成。它用于…

安装Jenkins

一、什么是Jenkins Jenkins是一个开源软件项目,是基于Java开发的。我们可以利用Jenkins来实现持续集成的功能。 因为Jenkins是基于Java开发的,所以在安装Jenkins之前首先需要安装Java的JDK。 二、安装Jenkins 在Windows平台上面安装Jenkins共有两种方式…

gSpan算法执行步骤详解示例

目录 1. 问题描述2. gSpan算法步骤2.1 数据预处理2.2 深度递归挖掘频繁子图2.2.1 获取所有的频繁边2.2.2 深度递归挖掘频繁子图 参考文献 1. 问题描述 gSpan 是一款图规则挖掘算法,目标是从现有的图集中挖掘频繁子图。如下图中包含三个图: 其中圆圈为顶…

13-把矩阵看作是对系统的描述

探索矩阵乘法:更深刻的理解与应用视角 🧩🔍 引言 📖 在我们进一步探讨矩阵乘法之前,让我们从不同的角度来理解什么是矩阵,以及如何将矩阵视为一个系统。我们之前已经介绍了矩阵的基本概念和运算&#xff…

SpringBoot案例-部门管理-新增

根据页面原型,明确需求 页面原型 需求 阅读接口文档 接口文档链接如下: 【腾讯文档】SpringBoot案例所需文档 https://docs.qq.com/doc/DUkRiTWVaUmFVck9N 思路分析 前端在输入要新增的部门名称后,会以JSON格式将数据传入至后端&#xf…

idea如何开启远程调试

一:打包需要部署的jar包上传到服务器 二:服务器(开启远程调试接口) nohup java -jar -Xdebug -Xrunjdwp:transportdt_socket,servery,suspendn,address8453 xxx.jar > xxx.log 2>&1 & 三: idea配置rem…

电脑开机出现Boot Device怎么办?

开机出现Boot Device这个问题很常见,有时还会出现No Boot Device的问题,虽然多了一个单词,但意思是相同的,这些问题说明你的系统盘出现了问题,或者是引导出现了问题。这该如何解决呢? 方法1. 检查主板或硬盘…

如何定位线上CPU飙高的问题

1.问题情景 我们的接口卡死,CPU飙高到打不开的网页 2.问题定位 2.1 top指令 通过top命令找到CPU耗用最厉害的那个进程的PID 直接输入top Linux下的100%代表一个核心,如果是八核,最高可以到800%,这样才算满 然后通过PID找到CP…