当前位置:AIGC资讯 > AIGC > 正文

【Datawhale组队学习:Sora原理与技术实战】AIGC技术基础知识

AIGC是什么

AIGC全称叫做AI generated content,AlGC (Al-Generated Content,人工智能生产内容),是利用AlI自动生产内容的生产方式。

在传统的内容创作领域中,PGC(Professionally-generated Content,专业生成内容)和UGC(User-generated Content,用户内容生产)作为两大主流模式,共同构成了内容生产的核心来源。然而,随着技术进步,AIGC(人工智能生成内容)的兴起正在引领一场革命,它不仅让人工智能具备了对世界的感知与理解能力,更进一步地将其延伸至创造性生成层面。这一转变预示着AIGC将在未来深刻影响并重塑各行业内容生产的范式和格局。
AIGC的发展依赖如下三个要素:

更强,同时也是更便宜的算力

更多的高质量数据集,包括文本、语音、视觉和多模态

模型技术的发展,更具有扩展性和更好的模型,比如Transformers和diffusion model

所以AIGC能做的,且做得比较好的领域越来越多,包括:

自然语言领域(比如代码生成、论文写作、诗歌对联、剧本创作,agent智能体)

语音领域(比如语音合成,音乐生成,个性化声音生成),

视觉领域的图像生成(stable diffusion, mid-journey)、以及最近也发展很迅速的视频生成(sora)。

这些都是属于AIGC的范畴,而且正快速的改变着我们的生产力工具、改变着我们的生活。本节课主要关注在视觉领域的AIGC,即图像生成和视频生成。

AIGC技术的发展

文生图


根据文生图的发展路线,我们把文生图的发展历程发展成如下4个阶段:

基于生成对抗网络的(GAN)模型

基于自回归(Autoregressive)模型

基于扩散(diffusion)模型

基于Transformers的扩散(diffusion)模型

基于生成对抗网络的(GAN)模型


2014 年,Ian J.Goodfellow 提出了 GAN,它是由一个生成器G和一个判别器D组成。生成网络产生「假」数据,并试图欺骗判别网络;训练的时候,判别网络对生成数据进行真伪鉴别,试图正确识别所有「假」数据。在训练迭代的过程中,两个网络持续地进化和对抗,直到达到平衡状态,判别网络无法再识别「假」数据。

推理的时候,只要保留生成器G就行了,输入一个随机噪声vector,生成一张图像。

右侧是一个经典的AttnGAN的框架,是一个引入了attention结构(使得图片生成局部能够和文本描述更加匹配)、并且从粗粒度到细粒度coarse to fine进行生成的框架,在当时还是取得了不错的生成效果。

GAN的优势是在一些窄分布(比如人脸)数据集上效果很好,采样速度快,方便嵌入到一些实时应用里面去。

缺点是比较难训练、不稳定,而且有Mode Collapse(模式崩塌)等问题。

基于自回归方式的模型


VQGAN是将类似的思路拓展到了视觉生成领域。他主要包括两个步骤:

第一步:将原始的RGB图像通过vqvae或者vqgan 离散压缩成一系列的 视觉code,这些视觉code 可以利用一个训练得到的decoder恢复出原始的图像信息,当然会损失一些细节,但整体恢复质量还是OK的,特别是加了GAN loss的。

第二步:利用transformer或者GPT,来按照一定的顺序,逐个的去预测每个视觉code,当所有code都预测完了之后,就可以用第一步训练好的Decoder来生成对应的图像。因为每个code预测过程是有随机采样的,因此可以生成多样性比较高的不同图像。

这个方法比较出名的就是VQGAN,还有就是openai的dalle。

基于扩散(diffusion)方式的模型

扩散模型也就是我们目前大多数文生图模型所采用的技术。

扩散模型也分为两个过程,一个是前向过程,通过向原始数据不断加入高斯噪声来破坏训练数据,最终加噪声到一定步数之后,原始数据信息就完全被破坏,无限接近与一个纯噪声。另外一个过程是反向过程,通过深度网络来去噪,来学习恢复数据。

训练完成之后,我们可以通过输入随机噪声,传递给去噪过程来生成数据。这就是DDPM的基本原理。

图中是DALLE2的一个基本框架,他的整个pipeline稍微有些复杂,输入文本,经过一个多模态的CLIP模型的文本编码器,

学习一个prior网络,生成clip 图像编码,然后decoder到6464小图,再经过两个超分网络到256256,再到1024*1024。

基于Transformers的架构的Diffusion模型

基于Transformers的架构的Diffusion模型设计了一个简单而通用的基于Vision Transformers(ViT)的架构(U-ViT),替换了latent diffusion model中的U-Net部分中的卷积神经网络(CNN),用于diffusion模型的图像生成任务。

遵循Transformers的设计方法,这类方式将包括时间、条件和噪声图像patches在内的所有输入都视作为token。


推理链路:

第一步:输入一张256x256x3的图片,经过Encoder后得到对应的latent,压缩比为8,latent space推理时输入32x32x4的噪声,将latentspace的输入token化,图片使用patchify,label和timestep使用embedding。

第二步:结合当前的step t , 输入label y, 经过N个Dit Block通过 MLP进行输出,得到输出的噪声以及对应的协方差矩阵

第三步:经过T个step采样,得到32x32x4的降噪后的latent

在训练时,需要使得去躁后的latent和第一步得到的latent尽可能一致

视频生成技术发展

基于Stable Diffusion视频生成:将视觉空间的数据映射到隐空间中,通过输入文本(或其他条件)在隐空间训练扩散模型,与图像不同的是地方在于Unet需具备时序编码的能力。

通常的视频生成的任务有两种:文生视频和图生视频

代码实践

SD推理最佳实践

安装依赖库

pip install torch torchvision transformers opencv-python torch diffusers modelscope accelerate PEFT

SDXL模型,魔搭社区Pipeline已经集成SDXL模型

from modelscope.utils.constant import Tasks
from modelscope.pipelines import pipeline
import cv2

pipe = pipeline(task=Tasks.text_to_image_synthesis, 
                model='AI-ModelScope/stable-diffusion-xl-base-1.0',
                use_safetensors=True,
                model_revision='v1.0.0')

prompt = "Beautiful and cute girl, 16 years old, rain jacket, gradient background, soft colors, soft lighting, cinematic edge lighting, light and dark contrast, anime, art station Seraflur, blind box, super detail, 8k"
output = pipe({'text': prompt})
cv2.imwrite('SDXL.png', output['output_imgs'][0])

运行结果:

秒级推理方法1:SDXL-turbo模型是SDXL 1.0的蒸馏版本,SDXL-Turbo基于一种称之为对抗扩散蒸馏(ADD)的新颖的训练方法,这种方法在扩散模型采样可以减少到1到4步,而生成高质量图像。ADD的训练方式使用得分蒸馏,利用大规模扩散模型作为教师模型,并将其与对抗性损失相结合,即使在1-2步的采样步骤的低步骤状态下,使用对抗学习的方式,引入discriminator来辅助生成质量的把控,也可以确保高质量图像的保真度。

from diffusers import AutoPipelineForText2Image
import torch
from modelscope import snapshot_download

model_dir = snapshot_download("AI-ModelScope/sdxl-turbo")

pipe = AutoPipelineForText2Image.from_pretrained(model_dir, torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")

prompt = "Beautiful and cute girl, 16 years old, rain jacket, gradient background, soft colors, soft lighting, cinematic edge lighting, light and dark contrast, anime, art station Seraflur, blind box, super detail, 8k"

image = pipe(prompt=prompt, num_inference_steps=1, guidance_scale=0.0).images[0]
image.save("SDXLturbo.png")

运行结果:

秒级推理方法2:SDXL+LCM,潜在一致性模型(LCM)受一致性模型(CM)启发,在预训练的LDM上以较少的步骤进行快速推理。LCM-SD系列是在Stable Diffusion的基础上新增Consistency 约束蒸馏的结果,仅通过2-8步的推理即可实现高质量的文本到图片的生成性能。

from diffusers import UNet2DConditionModel, DiffusionPipeline, LCMScheduler
import torch
from modelscope import snapshot_download

model_dir_lcm = snapshot_download("AI-ModelScope/lcm-sdxl",revision = "master")
model_dir_sdxl = snapshot_download("AI-ModelScope/stable-diffusion-xl-base-1.0",revision = "v1.0.9")

unet = UNet2DConditionModel.from_pretrained(model_dir_lcm, torch_dtype=torch.float16, variant="fp16")
pipe = DiffusionPipeline.from_pretrained(model_dir_sdxl, unet=unet, torch_dtype=torch.float16, variant="fp16")

pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
pipe.to("cuda")

prompt = "Beautiful and cute girl, 16 years old, rain jacket, gradient background, soft colors, soft lighting, cinematic edge lighting, light and dark contrast, anime, art station Seraflur, blind box, super detail, 8k"
image = pipe(prompt, num_inference_steps=4, guidance_scale=8.0).images[0]
image.save("SDXLLCM.png")

运行结果

秒级推理方法3:stable-cascade模型基于Würstchen架构构建,与稳定扩散等其他模型的主要区别在于它在更小的潜在空间中工作。潜在空间越小,推理速度就越快,训练成本也就越低。潜在空间有多小?稳定扩散使用压缩因子 8,从而将 1024x1024 图像编码为 128x128。Stable Cascade 的压缩系数为 42,这意味着可以将 1024x1024 图像编码为 24x24,同时保持清晰的重建。然后在高度压缩的潜在空间中训练文本条件模型。与稳定扩散 1.5 相比,该架构的先前版本实现了 16 倍的成本降低

import torch
from modelscope import snapshot_download
from diffusers import StableCascadeDecoderPipeline, StableCascadePriorPipeline

device = "cuda"
num_images_per_prompt = 1

stable_cascade_prior = snapshot_download("AI-ModelScope/stable-cascade-prior")
stable_cascade = snapshot_download("AI-ModelScope/stable-cascade")

prior = StableCascadePriorPipeline.from_pretrained(stable_cascade_prior, torch_dtype=torch.bfloat16).to(device)
decoder = StableCascadeDecoderPipeline.from_pretrained(stable_cascade,  torch_dtype=torch.float16).to(device)

prompt = "Beautiful and cute girl, 16 years old, rain jacket, gradient background, soft colors, soft lighting, cinematic edge lighting, light and dark contrast, anime, art station Seraflur, blind box, super detail, 8k"
negative_prompt = ""

prior_output = prior(
    prompt=prompt,
    height=1024,
    width=1024,
    negative_prompt=negative_prompt,
    guidance_scale=4.0,
    num_images_per_prompt=num_images_per_prompt,
    num_inference_steps=20
)
decoder_output = decoder(
    image_embeddings=prior_output.image_embeddings.half(),
    prompt=prompt,
    negative_prompt=negative_prompt,
    guidance_scale=0.0,
    output_type="pil",
    num_inference_steps=10
).images

for i, img in enumerate(decoder_output):
    img.save(f"stablecascade_{i+1}.png")
#Now decoder_output is a list with your PIL images

运行结果:

Tips:
遇到如下报错:

ValueError: Cannot load /root/.cache/modelscope/hub/AI-ModelScope/stable-cascade/decoder because embedding.1.weight expected shape tensor(..., device='meta', size=(320, 64, 1, 1)), but got torch.Size([320, 16, 1, 1]). If you want to instead overwrite randomly initialized weights, please make sure to pass both `low_cpu_mem_usage=False` and `ignore_mismatched_sizes=True`. For more information, see also: https://github.com/huggingface/diffusers/issues/1619#issuecomment-1345604389 as an example.

解决方法:

重新装diffusers.
pip install --force-reinstall --no-deps git+https://github.com/huggingface/diffusers.git@a3dc21385b7386beb3dab3a9845962ede6765887
修改~/.cache/modelscope/hub/AI-ModelScope/stable-cascade/decoder/config.json
将其中的in_channels修改为c_in即可

秒级推理方法4:

import torch
from diffusers import StableDiffusionXLPipeline, UNet2DConditionModel, EulerDiscreteScheduler
from modelscope.hub.file_download import model_file_download
from modelscope import snapshot_download
from safetensors.torch import load_file

base = snapshot_download("AI-ModelScope/stable-diffusion-xl-base-1.0")
repo = "AI-ModelScope/SDXL-Lightning"
ckpt = "sdxl_lightning_4step_unet.safetensors" # Use the correct ckpt for your step setting!

# Load model.
unet = UNet2DConditionModel.from_config(base, subfolder="unet").to("cuda", torch.float16)
unet.load_state_dict(load_file(model_file_download(repo, ckpt), device="cuda"))
pipe = StableDiffusionXLPipeline.from_pretrained(base, unet=unet, torch_dtype=torch.float16, variant="fp16").to("cuda")

# Ensure sampler uses "trailing" timesteps.
pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config, timestep_spacing="trailing")

# Ensure using the same inference steps as the loaded model and CFG set to 0.
pipe("A girl smiling", num_inference_steps=4, guidance_scale=0).images[0].save("sdxllightning.png")

运行结果

微调lora叠加推理

from diffusers import AutoPipelineForText2Image
from modelscope import snapshot_download
import torch

model_dir=snapshot_download("YorickHe/majicmixRealistic_v6")
lora_dir = snapshot_download("PaperCloud/zju19_dunhuang_style_lora")

pipeline = AutoPipelineForText2Image.from_pretrained(f"{model_dir}/v7", torch_dtype=torch.float16).to("cuda")
pipeline.load_lora_weights(lora_dir, weight_name="dunhuang.safetensors")
prompt = "1 girl, close-up, waist shot, black long hair, clean face, dunhuang, Chinese ancient style, clean skin, organza_lace, Dunhuang wind, Art deco, Necklace, jewelry, Bracelet, Earrings, dunhuang_style, see-through_dress, Expressionism, looking towards the camera, upper_body, raw photo, masterpiece, solo, medium shot, high detail face, photorealistic, best quality"
#Negative Prompt = """(nsfw:2), paintings, sketches, (worst quality:2), (low quality:2), lowers, normal quality, ((monochrome)), ((grayscale)), logo, word, character, bad hand, tattoo, (username, watermark, signature, time signature, timestamp, artist name, copyright name, copyright),low res, ((monochrome)), ((grayscale)), skin spots, acnes, skin blemishes, age spot, glans, extra fingers, fewer fingers, strange fingers, bad hand, mole, ((extra legs)), ((extra hands))"""
image = pipeline(prompt).images[0]
image.save("sdlora.png")

运行结果

SD+controlnet

from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL
from diffusers.utils import load_image, make_image_grid
from PIL import Image
from modelscope import snapshot_download
import cv2
import numpy as np
import torch


model_dir = snapshot_download("AI-ModelScope/stable-diffusion-xl-base-1.0")
controlnet_dir = snapshot_download("AI-ModelScope/controlnet-canny-sdxl-1.0")
VAE_dir = snapshot_download("AI-ModelScope/sdxl-vae-fp16-fix")
original_image = load_image(
    "/mnt/workspace/canny.jpg"
)

prompt = "sea turtle, hard lighting"
negative_prompt = 'low quality, bad quality, sketches'

image = load_image("/mnt/workspace/canny.jpg")

controlnet_conditioning_scale = 0.5  # recommended for good generalization

controlnet = ControlNetModel.from_pretrained(
    controlnet_dir,
    torch_dtype=torch.float16
)
vae = AutoencoderKL.from_pretrained(VAE_dir, torch_dtype=torch.float16)
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    model_dir,
    controlnet=controlnet,
    vae=vae,
    torch_dtype=torch.float16,
)
pipe.enable_model_cpu_offload()

image = np.array(image)
image = cv2.Canny(image, 100, 200)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
image = Image.fromarray(image)

images = pipe(
    prompt, negative_prompt=negative_prompt, image=image, controlnet_conditioning_scale=controlnet_conditioning_scale,
    ).images

images[0].save(f"controlnet.png")

运行结果

参考资料

教程:
https://github.com/datawhalechina/sora-tutorial/blob/main/docs/chapter2/chapter2_1.md
视频录像:
https://www.bilibili.com/video/BV1ZS421A7sR/?vd_source=79686b80ce91d6c3977b2e269db5e8b8

更新时间 2024-03-18