文本或图像到视频
受文本到图像扩散模型成功的推动,生成视频模型能够从文本提示或初始图像生成短视频剪辑。这些模型通过在架构中添加某种类型的时态和/或空间卷积层来扩展预训练的扩散模型以生成视频。图像和视频的混合数据集用于训练模型,该模型学习根据文本或图像条件输出一系列视频帧。
本指南将向您展示如何生成视频,如何配置视频模型参数以及如何控制视频生成。
流行模型
在 Hub 上发现其他酷炫且趋势的视频生成模型 这里!
Stable Video Diffusions (SVD)、I2VGen-XL、AnimateDiff 和 ModelScopeT2V 是用于视频扩散的流行模型。每个模型都是不同的。例如,AnimateDiff 在冻结的文本到图像模型中插入一个运动建模模块以生成个性化的动画图像,而 SVD 完全从头开始训练,采用三阶段训练过程以生成短的高质量视频。
Stable Video Diffusion
SVD 基于 Stable Diffusion 2.1 模型,它在图像上训练,然后在低分辨率视频上训练,最后在较小的数据集上训练高分辨率视频。该模型从初始图像生成一个短的 2-4 秒视频。您可以在 Stable Video Diffusion 指南中了解有关模型的更多详细信息,例如微条件。
首先加载 StableVideoDiffusionPipeline 并传递初始图像以从该图像生成视频。
import torch
from diffusers import StableVideoDiffusionPipeline
from diffusers.utils import load_image, export_to_video
pipeline = StableVideoDiffusionPipeline.from_pretrained(
"stabilityai/stable-video-diffusion-img2vid-xt", torch_dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/svd/rocket.png")
image = image.resize((1024, 576))
generator = torch.manual_seed(42)
frames = pipeline(image, decode_chunk_size=8, generator=generator).frames[0]
export_to_video(frames, "generated.mp4", fps=7)
I2VGen-XL
I2VGen-XL 是一种扩散模型,它可以生成比 SVD 更高分辨率的视频,并且它也能够接受文本提示,除了图像之外。该模型经过两个分层编码器(细节编码器和全局编码器)的训练,以更好地捕获图像中的低级和高级细节。这些学习到的细节用于训练视频扩散模型,该模型在生成的视频中细化视频分辨率和细节。
您可以通过加载 I2VGenXLPipeline 并传递文本和图像提示来生成视频来使用 I2VGen-XL。
import torch
from diffusers import I2VGenXLPipeline
from diffusers.utils import export_to_gif, load_image
pipeline = I2VGenXLPipeline.from_pretrained("ali-vilab/i2vgen-xl", torch_dtype=torch.float16, variant="fp16")
pipeline.enable_model_cpu_offload()
image_url = "https://huggingface.co/datasets/diffusers/docs-images/resolve/main/i2vgen_xl_images/img_0009.png"
image = load_image(image_url).convert("RGB")
prompt = "Papers were floating in the air on a table in the library"
negative_prompt = "Distorted, discontinuous, Ugly, blurry, low resolution, motionless, static, disfigured, disconnected limbs, Ugly faces, incomplete arms"
generator = torch.manual_seed(8888)
frames = pipeline(
prompt=prompt,
image=image,
num_inference_steps=50,
negative_prompt=negative_prompt,
guidance_scale=9.0,
generator=generator
).frames[0]
export_to_gif(frames, "i2v.gif")
AnimateDiff
AnimateDiff 是一种适配器模型,它在预训练的扩散模型中插入运动模块以对图像进行动画处理。适配器在视频剪辑上进行训练以学习运动,该运动用于对生成过程进行条件化以创建视频。它更快更容易,只需要训练适配器,并且可以加载到大多数扩散模型中,有效地将它们转变为“视频模型”。
首先加载一个 MotionAdapter
。
import torch
from diffusers import AnimateDiffPipeline, DDIMScheduler, MotionAdapter
from diffusers.utils import export_to_gif
adapter = MotionAdapter.from_pretrained("guoyww/animatediff-motion-adapter-v1-5-2", torch_dtype=torch.float16)
然后使用 AnimateDiffPipeline 加载一个微调后的 Stable Diffusion 模型。
pipeline = AnimateDiffPipeline.from_pretrained("emilianJR/epiCRealism", motion_adapter=adapter, torch_dtype=torch.float16)
scheduler = DDIMScheduler.from_pretrained(
"emilianJR/epiCRealism",
subfolder="scheduler",
clip_sample=False,
timestep_spacing="linspace",
beta_schedule="linear",
steps_offset=1,
)
pipeline.scheduler = scheduler
pipeline.enable_vae_slicing()
pipeline.enable_model_cpu_offload()
创建一个提示并生成视频。
output = pipeline(
prompt="A space rocket with trails of smoke behind it launching into space from the desert, 4k, high resolution",
negative_prompt="bad quality, worse quality, low resolution",
num_frames=16,
guidance_scale=7.5,
num_inference_steps=50,
generator=torch.Generator("cpu").manual_seed(49),
)
frames = output.frames[0]
export_to_gif(frames, "animation.gif")
ModelscopeT2V
ModelscopeT2V 在 UNet 中添加了空间和时间卷积以及注意力,并且它在图像-文本和视频-文本数据集上进行训练以增强其在训练期间的学习内容。该模型获取提示,对其进行编码并创建文本嵌入,这些文本嵌入由 UNet 去噪,然后由 VQGAN 解码为视频。
ModelScopeT2V 生成带水印的视频,因为它是使用这些数据集进行训练的。要使用无水印模型,请首先尝试使用 TextToVideoSDPipeline 使用 cerspense/zeroscope_v2_76w 模型,然后使用 VideoToVideoSDPipeline 使用 cerspense/zeroscope_v2_XL 检查点对其输出进行放大。
将 ModelScopeT2V 检查点加载到 DiffusionPipeline 中以及提示以生成视频。
import torch
from diffusers import DiffusionPipeline
from diffusers.utils import export_to_video
pipeline = DiffusionPipeline.from_pretrained("damo-vilab/text-to-video-ms-1.7b", torch_dtype=torch.float16, variant="fp16")
pipeline.enable_model_cpu_offload()
pipeline.enable_vae_slicing()
prompt = "Confident teddy bear surfer rides the wave in the tropics"
video_frames = pipeline(prompt).frames[0]
export_to_video(video_frames, "modelscopet2v.mp4", fps=10)
配置模型参数
您可以在管道中配置一些重要的参数,这些参数会影响视频生成过程和质量。让我们仔细看看这些参数的作用以及更改它们如何影响输出。
帧数
num_frames
参数决定每秒生成多少视频帧。帧是按顺序播放的一系列图像,以创建运动或视频。这会影响视频长度,因为管道每秒会生成一定数量的帧(查看管道的 API 参考以获取默认值)。要增加视频时长,您需要增加 num_frames
参数。
import torch
from diffusers import StableVideoDiffusionPipeline
from diffusers.utils import load_image, export_to_video
pipeline = StableVideoDiffusionPipeline.from_pretrained(
"stabilityai/stable-video-diffusion-img2vid", torch_dtype=torch.float16, variant="fp16"
)
pipeline.enable_model_cpu_offload()
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/svd/rocket.png")
image = image.resize((1024, 576))
generator = torch.manual_seed(42)
frames = pipeline(image, decode_chunk_size=8, generator=generator, num_frames=25).frames[0]
export_to_video(frames, "generated.mp4", fps=7)
引导尺度
guidance_scale
参数控制生成的视频和文本提示或初始图像的匹配程度。较高的 guidance_scale
值意味着生成的视频与文本提示或初始图像更加匹配,而较低的 guidance_scale
值意味着生成的视频匹配程度较低,这可以让模型对条件输入进行更“创造性”的解释。
SVD 使用 min_guidance_scale
和 max_guidance_scale
参数分别对第一帧和最后一帧应用引导。
import torch
from diffusers import I2VGenXLPipeline
from diffusers.utils import export_to_gif, load_image
pipeline = I2VGenXLPipeline.from_pretrained("ali-vilab/i2vgen-xl", torch_dtype=torch.float16, variant="fp16")
pipeline.enable_model_cpu_offload()
image_url = "https://huggingface.co/datasets/diffusers/docs-images/resolve/main/i2vgen_xl_images/img_0009.png"
image = load_image(image_url).convert("RGB")
prompt = "Papers were floating in the air on a table in the library"
negative_prompt = "Distorted, discontinuous, Ugly, blurry, low resolution, motionless, static, disfigured, disconnected limbs, Ugly faces, incomplete arms"
generator = torch.manual_seed(0)
frames = pipeline(
prompt=prompt,
image=image,
num_inference_steps=50,
negative_prompt=negative_prompt,
guidance_scale=1.0,
generator=generator
).frames[0]
export_to_gif(frames, "i2v.gif")
负面提示
负面提示可以阻止模型生成您不想要的东西。此参数通常用于通过去除“低分辨率”或“细节不好”等不良特征来提高整体生成质量。
import torch
from diffusers import AnimateDiffPipeline, DDIMScheduler, MotionAdapter
from diffusers.utils import export_to_gif
adapter = MotionAdapter.from_pretrained("guoyww/animatediff-motion-adapter-v1-5-2", torch_dtype=torch.float16)
pipeline = AnimateDiffPipeline.from_pretrained("emilianJR/epiCRealism", motion_adapter=adapter, torch_dtype=torch.float16)
scheduler = DDIMScheduler.from_pretrained(
"emilianJR/epiCRealism",
subfolder="scheduler",
clip_sample=False,
timestep_spacing="linspace",
beta_schedule="linear",
steps_offset=1,
)
pipeline.scheduler = scheduler
pipeline.enable_vae_slicing()
pipeline.enable_model_cpu_offload()
output = pipeline(
prompt="360 camera shot of a sushi roll in a restaurant",
negative_prompt="Distorted, discontinuous, ugly, blurry, low resolution, motionless, static",
num_frames=16,
guidance_scale=7.5,
num_inference_steps=50,
generator=torch.Generator("cpu").manual_seed(0),
)
frames = output.frames[0]
export_to_gif(frames, "animation.gif")
模型特定参数
有些管道参数是每个模型独有的,例如调整视频中的运动或向初始图像添加噪声。
稳定视频扩散使用 fps
参数为帧率提供额外的微调,使用 motion_bucket_id
参数为运动提供额外的微调。这些参数共同允许调整生成的视频中的运动量。
还有一个 noise_aug_strength
参数可以增加添加到初始图像的噪声量。更改此参数会影响生成的视频和初始图像的相似程度。较高的 noise_aug_strength
也会增加运动量。要了解更多信息,请阅读 微调 指南。
控制视频生成
视频生成可以像文本到图像、图像到图像和修复一样进行控制,方法是使用 ControlNetModel。唯一的区别是您需要使用 CrossFrameAttnProcessor,以便每一帧都关注第一帧。
Text2Video-Zero
Text2Video-Zero 视频生成可以根据姿势和边缘图像进行条件化,以便更好地控制生成的视频中主题的运动,或保留视频中主题/对象的标识。您还可以将 Text2Video-Zero 与 InstructPix2Pix 结合使用,以使用文本编辑视频。
首先下载视频并从中提取姿势图像。
from huggingface_hub import hf_hub_download
from PIL import Image
import imageio
filename = "__assets__/poses_skeleton_gifs/dance1_corr.mp4"
repo_id = "PAIR/Text2Video-Zero"
video_path = hf_hub_download(repo_type="space", repo_id=repo_id, filename=filename)
reader = imageio.get_reader(video_path, "ffmpeg")
frame_count = 8
pose_images = [Image.fromarray(reader.get_data(i)) for i in range(frame_count)]
将 ControlNetModel 用于姿势估计,并将检查点加载到 StableDiffusionControlNetPipeline 中。然后,您将对 UNet 和 ControlNet 使用 CrossFrameAttnProcessor。
import torch
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from diffusers.pipelines.text_to_video_synthesis.pipeline_text_to_video_zero import CrossFrameAttnProcessor
model_id = "runwayml/stable-diffusion-v1-5"
controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-openpose", torch_dtype=torch.float16)
pipeline = StableDiffusionControlNetPipeline.from_pretrained(
model_id, controlnet=controlnet, torch_dtype=torch.float16
).to("cuda")
pipeline.unet.set_attn_processor(CrossFrameAttnProcessor(batch_size=2))
pipeline.controlnet.set_attn_processor(CrossFrameAttnProcessor(batch_size=2))
修复所有帧的潜码,然后将您的提示和提取的姿势图像传递给模型以生成视频。
latents = torch.randn((1, 4, 64, 64), device="cuda", dtype=torch.float16).repeat(len(pose_images), 1, 1, 1)
prompt = "Darth Vader dancing in a desert"
result = pipeline(prompt=[prompt] * len(pose_images), image=pose_images, latents=latents).images
imageio.mimsave("video.mp4", result, fps=4)
优化
视频生成需要大量的内存,因为您要一次生成多个视频帧。您可以以牺牲部分推理速度为代价来减少内存需求。尝试
- 将不再需要的管道组件卸载到 CPU
- 前馈分块在循环中运行前馈层,而不是一次运行所有层
- 将 VAE 要解码的帧数分解成块,而不是一次解码所有块
- pipeline.enable_model_cpu_offload()
- frames = pipeline(image, decode_chunk_size=8, generator=generator).frames[0]
+ pipeline.enable_model_cpu_offload()
+ pipeline.unet.enable_forward_chunking()
+ frames = pipeline(image, decode_chunk_size=2, generator=generator, num_frames=25).frames[0]
如果内存不是问题,并且您想优化速度,请尝试使用 torch.compile
包装 UNet。
- pipeline.enable_model_cpu_offload()
+ pipeline.to("cuda")
+ pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)