本篇文章聊聊,如何快速上手 Stable Video Diffusion (SVD) 图生视频大模型。
写在前面
月底计划在机器之心的“AI技术论坛”做关于使用开源模型 “Stable Diffusion 模型” 做有趣视频的实战分享。
因为会议分享时间有限,和之前一样,比较简单的部分,就用博客文章的形式来做补充分享吧。
本篇是一篇相关的补充内容,主要聊聊使用开源行业标杆 stability.ai 出品的 Stable Video Diffusion 的快速上手。
本篇文章相关的代码保存在 soulteary/docker-stable-video-diffusion,有需要可以自取,欢迎“一键三连”。
Stable Video Diffusion
2023 年 11 月末,stability.ai 发布了 Stable Video Diffusion,依旧是扩散模型,但是将图片技术衍生到了视频领域。能够将静态图像作为条件帧,并基于它来生成视频。如果你对 Stable Diffusion 实践和开源软件核心组件解析感兴趣,可以移步之前有关的分享内容。
模型的详细介绍,我们在官方新闻发布页面能够找到,我就不多赘述了。模型的使用方式类似之前文生图的 Stable Diffusion,还是简单的三段式使用方法:“输入内容”、“等待模型处理生成”、“获取AI 生成结果”。
所以,我们现在可以在开源模型上,用一张图片相对快速的生成一小段内容强相关的视频啦。
相关的模型,官方一共开源了两个,一个是基础版本,能够生成 14 帧 1024x576 分辨率内容的基础模型 stabilityai/stable-video-diffusion-img2vid,另外一个是基于基础模型进行 finetune 得到的 “XT” 模型:stabilityai/stable-video-diffusion-img2vid-xt,它能够生成相同分辨率 25 帧的内容。借助 AutoencoderKL(官方文档中称作 F8 解码器)和对 VAE 模型的 finetune,进一步提升了视频内容质量和一致性,降低了画面闪烁的问题。
在官方的介绍中,当时发布模型时的生成效果比 GEN-2 和 PikaLabs 更受到用户的欢迎。
当然,这个模型还比较早期,有一些明显的缺陷:
- 目前直接使用 SVD 生成的视频都很短,通常在 5 秒之内,并且暂时无法实现照片级别的画面真实感。
- 生成结果和早期 Stable Diffusion 类似,比较不可控,可能会生成距离预期偏差比较大的没有运动或者运动频率特别慢的视频镜头画面。
- 暂时无法通过文本控制干预视频的生成。
- 暂时无法呈现清晰的文本内容。
- 通常无法正确的处理人物内容,特别是人脸。
- 模型的
clip_vision_model
编码器在解析图片内容时,会损失一些信息。
当然,上述问题的解决都只是时间问题,开源模型的演进速度是非常快的,所以不妨先捡起这张船票,一起扬帆起航。
基础环境准备
我个人比较倾向使用 Docker 作为运行环境,在投入很少额外资源的情况下,能够快速获得纯净、可复现的一致性非常棒的环境。
如果你选择 Docker 路线,不论你的设备是否有显卡,都可以根据自己的操作系统喜好,参考这两篇来完成基础环境的配置《基于 Docker 的深度学习环境:Windows 篇》、《基于 Docker 的深度学习环境:入门篇》。当然,使用 Docker 之后,你还可以做很多事情,比如:之前几十篇有关 Docker 的实践,在此就不赘述啦。
除此之外,为了高效运行模型,我推荐使用 Nvidia 官方的容器镜像(nvcr.io/nvidia/pytorch:23.12-py3),以及 HuggingFace 出品的 Diffusers 工具包。
我们可以基于上面的内容,快速折腾一个干净、高效的基础运行环境:
FROM nvcr.io/nvidia/pytorch:23.12-py3
RUN pip install transformers==4.35.2 gradio==4.13.0 diffusers==0.25.0 accelerate==0.25.0
RUN pip install opencv-fixer==0.2.5
RUN python -c "from opencv_fixer import AutoFix; AutoFix()"
WORKDIR /app
在本地创建一个名为 docker
的目录,将上面的代码保存到文件夹内,文件名称为 Dockerfile
,然后使用下面的命令完成镜像的构建,基础工作就准备好了一半:
docker build -t soulteary/svd-runtime -f docker/Dockerfile .
当然,如果你和我一样,喜欢“偷懒”,可以用文章开头提到的示例项目中的文件直接开搞:
# 下载项目代码
git clone https://github.com/soulteary/docker-stable-video-diffusion.git
# 切换工作目录
cd docker-stable-video-diffusion
# 构建基础环境镜像
docker build -t soulteary/svd-runtime -f docker/Dockerfile .
# 如果你希望速度快一些,可以用这条命令替代上面的命令
docker build -t soulteary/svd-runtime -f docker/Dockerfile.cn .
等到镜像构建完毕后,我们开始准备模型文件。
修正 Nvidia 镜像中的 OpenCV 依赖问题
如果你仔细看上面的 Docker 镜像准备文件的内容,你会发现有这么两行内容:
RUN pip install opencv-fixer==0.2.5
RUN python -c "from opencv_fixer import AutoFix; AutoFix()"
这个两条命令可以解决从 2023 年 6 月开始的 Nvidia 官方镜像适配 Stable Diffusion Video 相关模型,在使用 Diffusers 等 HuggingFace 工具保存视频文件时,本质上和 module 'cv2.dnn' has no attribute 'DictValue'
相关的报错问题。
这个问题在社区早些时候有被反馈(opencv/opencv-python #884),主要原因是在安装 numpy 时被带入一起安装的版本过旧 opencv 导致的兼容性问题。比较 Trick 的是我们并不能通过简单执行 pip install 来更新软件包,需要遵从帖子进行一些手动清理安装,才能将问题解决。
所以,我写了一个简单的开源小工具,来自动修正这个问题,项目开源地址在:soulteary/opencv-fixer,如果你在其他模型相关的使用遇到了类似问题,都可以试试它。
下载模型
我们来完成镜像准备之外的 50% 的准备工作,下载模型。不论你从哪里获取模型,建议你在得到模型后进行文件 Hash 验证:
shasum svd_xt.safetensors
a74f28bca18f1814b1447c391450b7f720b3b97e
shasum svd_xt_image_decoder.safetensors 1d6f36c441df4a17005167986b12720db1b118f2
你可以根据你的实际网络情况,来选择到底是从 HuggingFace 下载模型还是从 ModelScope 来下载模型,如果你选择的是 Model Scope,别忘记在你下载完模型之后,再从 HuggingFace 进行下仓库内容除两个大尺寸模型文件之外的内容更新。
关于模型的快速下载,我在之前的文章里多次提到过,如果你选择使用 HuggingFace 来下载模型和包含最新的仓库程序文件:
# 安装下载工具
pip install huggingface-cli
# 下载我们所需要的模型
huggingface-cli download --resume-download --local-dir-use-symlinks False stabilityai/stable-video-diffusion-img2vid-xt --local-dir ./models/
如果你在访问网络时,遇到了一些问题,可以搭配使用社区网友提供的加速镜像:
HF_ENDPOINT=https://hf-mirror.com huggingface-cli download --resume-download --local-dir-use-symlinks False stabilityai/stable-video-diffusion-img2vid-xt --local-dir ./models/
或者,使用官方提供的新版本工具进行更快速度的下载:
HF_ENDPOINT=https://hf-mirror.com HF_HUB_ENABLE_HF_TRANSFER=1 huggingface-cli download --resume-download --local-dir-use-symlinks False stabilityai/stable-video-diffusion-img2vid-xt --local-dir ./models/
如果你选择使用 ModelScope,同样比较简单,但是需要注意的是,ModelScope 中的内容很多时候会比 HuggingFace 上的内容旧,所以推荐在下载完毕之后,再检查是否需要使用 HuggingFace 上的内容做更新替换:
# 下载安装工具
pip install modelscope
# 下载模型
from modelscope import snapshot_download
snapshot_download('AI-ModelScope/stable-video-diffusion-img2vid-xt', cache_dir="./models/")
模型下载好之后,我们可以整理下目录结构,保持 Models 目中有我们下载好的模型就好:
├── docker
│ ├── Dockerfile
│ └── Dockerfile.cn
├── models
│ └── stabilityai
│ └── stable-video-diffusion-img2vid-xt
└── web
编写模型推理程序
完整的程序文件在这里,算上空格和美观的换行,大概不到 150 行,我这里再做一些简化,主要讲解下程序的运行流程:
# 若干依赖的引入
import gradio as gr
from diffusers import StableVideoDiffusionPipeline
from diffusers.utils import export_to_video
from PIL import Image
# ... 省略其他引用
# 保证乐子,让随机数范围大一些
max_64_bit_int = 2 ** 63 - 1
# ... 省略其他准备工作
# 使用 diffusers 来创建一个 AI Pipeline
pipe = StableVideoDiffusionPipeline.from_pretrained(
"/app/models/stabilityai/stable-video-diffusion-img2vid-xt",
torch_dtype=torch.float16,
variant="fp16",
)
pipe.to("cuda")
# 加载 UNET 和 VAE 模型,让生成结果效果更好(关于这俩模型干啥的,之前的 Stable Diffusion 文章有展开,不赘述
pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead", fullgraph=True)
pipe.vae = torch.compile(pipe.vae, mode="reduce-overhead", fullgraph=True)
# 核心的视频生成逻辑
def sample(
image: Image,
seed: Optional[int] = 42,
randomize_seed: bool = True,
motion_bucket_id: int = 127,
fps_id: int = 6,
version: str = "svd_xt",
cond_aug: float = 0.02,
decoding_t: int = 3, # 根据你的显卡容量来调整,显存不多可以调整到 1
device: str = "cuda",
output_folder: str = output_folder,
):
# ... 省略一些准备工作
# 调用 AI Pipeline 生成视频帧内容
frames = pipe(
image,
decode_chunk_size=decoding_t,
generator=torch.manual_seed(seed),
motion_bucket_id=motion_bucket_id,
noise_aug_strength=0.1,
num_frames=25,
).frames[0]
# 保存视频
export_to_video(frames, video_path, fps=fps_id)
return video_path, seed
# 调整上传图片内容的尺寸,模型对处理的图片尺寸有要求
def resize_image(image: Image, output_size: Tuple[int, int] =(1024, 576)):
# ...省略若干图片调整逻辑,图片模式、尺寸裁剪等等
return cropped_image
# 用于连接视频生成和 Gradio 界面的“工具人”
def generate(image, seed, randomize_seed, motion_bucket_id, fps_id):
img = resize_image(image, output_size=(1024, 576))
video, seed = sample(img, seed, randomize_seed, motion_bucket_id, fps_id)
return video, seed
# 配置一个 Gradio 网页界面
app = gr.Interface(
fn=generate,
inputs=[
gr.Image(label="Upload your image", type="pil"),
gr.Slider(label="Seed", ...),
gr.Checkbox(label="Randomize seed", value=True),
gr.Slider(label="Motion bucket id", ...),
gr.Slider(label="Frames per second", ...),
],
outputs=[
gr.PlayableVideo(label="Generated video"),
gr.Textbox(label="Seed", type="text"),
],
)
# 启动服务,允许我们来玩
if __name__ == "__main__":
app.queue(max_size=2)
app.launch(share=False, server_name="0.0.0.0", ssl_verify=False)
准备好程序后,我们将程序放置在目录的根部,然后就可以准备运行开玩了。
├── app.py
├── docker
│ ├── Dockerfile
│ └── Dockerfile.cn
└── models
└── stabilityai
└── stable-video-diffusion-img2vid-xt
运行模型
因为使用 Docker ,所以运行模型非常简单,只需要执行下面的命令即可:
docker run --rm -it -p 7860:7860 -p 7680:7680 -p 8080:8080 --gpus all --ipc=host --ulimit memlock=-1 -v `pwd`:/app soulteary/svd-runtime python app.py
当命令执行完毕,我们会看到类似下面的日志:
=============
== PyTorch ==
=============
NVIDIA Release 23.12 (build 76438008)
PyTorch Version 2.2.0a0+81ea7a4
Container image Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Copyright (c) 2014-2023 Facebook Inc.
Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu)
Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
Copyright (c) 2011-2013 NYU (Clement Farabet)
Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston)
Copyright (c) 2006 Idiap Research Institute (Samy Bengio)
Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz)
Copyright (c) 2015 Google Inc.
Copyright (c) 2015 Yangqing Jia
Copyright (c) 2013-2016 The Caffe contributors
All rights reserved.
Various files include modifications (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved.
This container image and its contents are governed by the NVIDIA Deep Learning Container License.
By pulling and using the container, you accept the terms and conditions of this license:
https://developer.nvidia.com/ngc/nvidia-deep-learning-container-license
WARNING: CUDA Minor Version Compatibility mode ENABLED.
Using driver version 525.147.05 which has support for CUDA 12.0. This container
was built with CUDA 12.3 and will be run in Minor Version Compatibility mode.
CUDA Forward Compatibility is preferred over Minor Version Compatibility for use
with this container but was unavailable:
[[Forward compatibility was attempted on non supported HW (CUDA_ERROR_COMPAT_NOT_SUPPORTED_ON_DEVICE) cuInit()=804]]
See https://docs.nvidia.com/deploy/cuda-compatibility/ for details.
The cache for model files in Transformers v4.22.0 has been updated. Migrating your old cache. This is a one-time only operation. You can interrupt this and resume the migration later on by calling `transformers.utils.move_cache()`.
0it [00:00, ?it/s]
Loading pipeline components...: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 12.41it/s]
Running on local URL: http://0.0.0.0:7860
To create a public link, set `share=True` in `launch()`.
然后,我们在浏览器访问容器运行主机的 IP:7860 就可以开始体验和验证 SVD 啦。
在我写这篇文章的时候,Chrome 新版本和 Gradio 有一些兼容问题,只能下载视频,而不能在网页中自动播放视频,所以如果你手头有其他的浏览器,可以试试用其他的浏览器来进行 AI 视频的生成。这里我使用的是 Safari。
打开页面之后,我们可以选择一个自己觉得有趣的图片来进行生成,我选择的是一只正在发射中的火箭。这里我推荐将选项中的帧率拉到 25 帧,来获得丝滑到视频结果,以及尽量多的拉高视频的 “motion” 来让视频结果更好。
当我们将图片上传到 WebUI 后,点击 “Submit”,让“火箭发射”。第一次执行的时候,时间会比较久,可能需要花费 1~3 分钟时间,程序会自动加载相关的 SVD、UNET、VAE 模型,然后将我们指定的图片转换为视频。
等待模型处理完毕后,我们就获得了火箭继续往上飞的视频啦。
默认情况模型消耗资源
在不经过优化的情况下,我们默认会使用 23G+ 的显存。
如果你希望在小显存的环境下完成视频的推理生成,可以将我提供的项目源代码中的注释根据自己的需求去掉:
# According to your actual needs
#
# pipe.enable_model_cpu_offload()
# pipe.unet.enable_forward_chunking()
当开启 pipe.enable_model_cpu_offload()
后,显存需求能够控制在 8GB 之内,当然,视频的生成时间也会变的非常慢。
实际运行过程中,显卡的基本状态如下:
Every 1.0s: nvidia-smi LEGION-REN9000K-34IRZ: Sun Jan 8 14:48:34 2024
Sun Jan 8 14:48:34 2024
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.147.05 Driver Version: 525.147.05 CUDA Version: 12.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA GeForce ... Off | 00000000:01:00.0 Off | Off |
| 41% 51C P2 71W / 450W | 23200MiB / 24564MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 1497 G /usr/lib/xorg/Xorg 75MiB |
| 0 N/A N/A 1606 G /usr/bin/gnome-shell 16MiB |
| 0 N/A N/A 5880 C python 23104MiB |
+-----------------------------------------------------------------------------+
最后
这篇文章就先写到这里,在准备分享内容的过程中,我会陆续的再分享一些和 SD 相关的有趣内容,下篇文章再见。
–EOF