|
""" |
|
This script demonstrates how to generate a video using the CogVideoX model with the Hugging Face `diffusers` pipeline. |
|
The script supports different types of video generation, including text-to-video (t2v), image-to-video (i2v), |
|
and video-to-video (v2v), depending on the input data and different weight. |
|
|
|
- text-to-video: THUDM/CogVideoX-5b, THUDM/CogVideoX-2b or THUDM/CogVideoX1.5-5b |
|
- video-to-video: THUDM/CogVideoX-5b, THUDM/CogVideoX-2b or THUDM/CogVideoX1.5-5b |
|
- image-to-video: THUDM/CogVideoX-5b-I2V or THUDM/CogVideoX1.5-5b-I2V |
|
|
|
Running the Script: |
|
To run the script, use the following command with appropriate arguments: |
|
|
|
```bash |
|
$ python cli_demo.py --prompt "A girl riding a bike." --model_path THUDM/CogVideoX1.5-5b --generate_type "t2v" |
|
``` |
|
|
|
You can change `pipe.enable_sequential_cpu_offload()` to `pipe.enable_model_cpu_offload()` to speed up inference, but this will use more GPU memory |
|
|
|
Additional options are available to specify the model path, guidance scale, number of inference steps, video generation type, and output paths. |
|
|
|
""" |
|
|
|
import argparse |
|
import logging |
|
from typing import Literal, Optional |
|
|
|
import torch |
|
|
|
from diffusers import ( |
|
CogVideoXDPMScheduler, |
|
CogVideoXImageToVideoPipeline, |
|
CogVideoXPipeline, |
|
CogVideoXVideoToVideoPipeline, |
|
) |
|
from diffusers.utils import export_to_video, load_image, load_video |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
|
|
|
|
RESOLUTION_MAP = { |
|
|
|
"cogvideox1.5-5b-i2v": (768, 1360), |
|
"cogvideox1.5-5b": (768, 1360), |
|
|
|
"cogvideox-5b-i2v": (480, 720), |
|
"cogvideox-5b": (480, 720), |
|
"cogvideox-2b": (480, 720), |
|
} |
|
|
|
|
|
def generate_video( |
|
prompt: str, |
|
model_path: str, |
|
lora_path: str = None, |
|
lora_rank: int = 128, |
|
num_frames: int = 81, |
|
width: Optional[int] = None, |
|
height: Optional[int] = None, |
|
output_path: str = "./output.mp4", |
|
image_or_video_path: str = "", |
|
num_inference_steps: int = 50, |
|
guidance_scale: float = 6.0, |
|
num_videos_per_prompt: int = 1, |
|
dtype: torch.dtype = torch.bfloat16, |
|
generate_type: str = Literal["t2v", "i2v", "v2v"], |
|
seed: int = 42, |
|
fps: int = 16, |
|
): |
|
""" |
|
Generates a video based on the given prompt and saves it to the specified path. |
|
|
|
Parameters: |
|
- prompt (str): The description of the video to be generated. |
|
- model_path (str): The path of the pre-trained model to be used. |
|
- lora_path (str): The path of the LoRA weights to be used. |
|
- lora_rank (int): The rank of the LoRA weights. |
|
- output_path (str): The path where the generated video will be saved. |
|
- num_inference_steps (int): Number of steps for the inference process. More steps can result in better quality. |
|
- num_frames (int): Number of frames to generate. CogVideoX1.0 generates 49 frames for 6 seconds at 8 fps, while CogVideoX1.5 produces either 81 or 161 frames, corresponding to 5 seconds or 10 seconds at 16 fps. |
|
- width (int): The width of the generated video, applicable only for CogVideoX1.5-5B-I2V |
|
- height (int): The height of the generated video, applicable only for CogVideoX1.5-5B-I2V |
|
- guidance_scale (float): The scale for classifier-free guidance. Higher values can lead to better alignment with the prompt. |
|
- num_videos_per_prompt (int): Number of videos to generate per prompt. |
|
- dtype (torch.dtype): The data type for computation (default is torch.bfloat16). |
|
- generate_type (str): The type of video generation (e.g., 't2v', 'i2v', 'v2v').· |
|
- seed (int): The seed for reproducibility. |
|
- fps (int): The frames per second for the generated video. |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
image = None |
|
video = None |
|
|
|
model_name = model_path.split("/")[-1].lower() |
|
desired_resolution = RESOLUTION_MAP[model_name] |
|
if width is None or height is None: |
|
height, width = desired_resolution |
|
logging.info(f"\033[1mUsing default resolution {desired_resolution} for {model_name}\033[0m") |
|
elif (height, width) != desired_resolution: |
|
if generate_type == "i2v": |
|
|
|
logging.warning( |
|
f"\033[1;31mThe width({width}) and height({height}) are not recommended for {model_name}. The best resolution is {desired_resolution}.\033[0m" |
|
) |
|
else: |
|
|
|
logging.warning( |
|
f"\033[1;31m{model_name} is not supported for custom resolution. Setting back to default resolution {desired_resolution}.\033[0m" |
|
) |
|
height, width = desired_resolution |
|
|
|
if generate_type == "i2v": |
|
pipe = CogVideoXImageToVideoPipeline.from_pretrained(model_path, torch_dtype=dtype) |
|
image = load_image(image=image_or_video_path) |
|
elif generate_type == "t2v": |
|
pipe = CogVideoXPipeline.from_pretrained(model_path, torch_dtype=dtype) |
|
else: |
|
pipe = CogVideoXVideoToVideoPipeline.from_pretrained(model_path, torch_dtype=dtype) |
|
video = load_video(image_or_video_path) |
|
|
|
|
|
if lora_path: |
|
pipe.load_lora_weights(lora_path, weight_name="pytorch_lora_weights.safetensors", adapter_name="test_1") |
|
pipe.fuse_lora(components=["transformer"], lora_scale=1 / lora_rank) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pipe.scheduler = CogVideoXDPMScheduler.from_config(pipe.scheduler.config, timestep_spacing="trailing") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pipe.enable_sequential_cpu_offload() |
|
pipe.vae.enable_slicing() |
|
pipe.vae.enable_tiling() |
|
|
|
|
|
|
|
if generate_type == "i2v": |
|
video_generate = pipe( |
|
height=height, |
|
width=width, |
|
prompt=prompt, |
|
image=image, |
|
|
|
num_videos_per_prompt=num_videos_per_prompt, |
|
num_inference_steps=num_inference_steps, |
|
num_frames=num_frames, |
|
use_dynamic_cfg=True, |
|
guidance_scale=guidance_scale, |
|
generator=torch.Generator().manual_seed(seed), |
|
).frames[0] |
|
elif generate_type == "t2v": |
|
video_generate = pipe( |
|
height=height, |
|
width=width, |
|
prompt=prompt, |
|
num_videos_per_prompt=num_videos_per_prompt, |
|
num_inference_steps=num_inference_steps, |
|
num_frames=num_frames, |
|
use_dynamic_cfg=True, |
|
guidance_scale=guidance_scale, |
|
generator=torch.Generator().manual_seed(seed), |
|
).frames[0] |
|
else: |
|
video_generate = pipe( |
|
height=height, |
|
width=width, |
|
prompt=prompt, |
|
video=video, |
|
num_videos_per_prompt=num_videos_per_prompt, |
|
num_inference_steps=num_inference_steps, |
|
num_frames=num_frames, |
|
use_dynamic_cfg=True, |
|
guidance_scale=guidance_scale, |
|
generator=torch.Generator().manual_seed(seed), |
|
).frames[0] |
|
export_to_video(video_generate, output_path, fps=fps) |
|
|
|
|
|
if __name__ == "__main__": |
|
parser = argparse.ArgumentParser(description="Generate a video from a text prompt using CogVideoX") |
|
parser.add_argument("--prompt", type=str, required=True, help="The description of the video to be generated") |
|
parser.add_argument( |
|
"--image_or_video_path", |
|
type=str, |
|
default=None, |
|
help="The path of the image to be used as the background of the video", |
|
) |
|
parser.add_argument( |
|
"--model_path", type=str, default="THUDM/CogVideoX1.5-5B", help="Path of the pre-trained model use" |
|
) |
|
parser.add_argument("--lora_path", type=str, default=None, help="The path of the LoRA weights to be used") |
|
parser.add_argument("--lora_rank", type=int, default=128, help="The rank of the LoRA weights") |
|
parser.add_argument("--output_path", type=str, default="./output.mp4", help="The path save generated video") |
|
parser.add_argument("--guidance_scale", type=float, default=6.0, help="The scale for classifier-free guidance") |
|
parser.add_argument("--num_inference_steps", type=int, default=50, help="Inference steps") |
|
parser.add_argument("--num_frames", type=int, default=81, help="Number of steps for the inference process") |
|
parser.add_argument("--width", type=int, default=None, help="The width of the generated video") |
|
parser.add_argument("--height", type=int, default=None, help="The height of the generated video") |
|
parser.add_argument("--fps", type=int, default=16, help="The frames per second for the generated video") |
|
parser.add_argument("--num_videos_per_prompt", type=int, default=1, help="Number of videos to generate per prompt") |
|
parser.add_argument("--generate_type", type=str, default="t2v", help="The type of video generation") |
|
parser.add_argument("--dtype", type=str, default="bfloat16", help="The data type for computation") |
|
parser.add_argument("--seed", type=int, default=42, help="The seed for reproducibility") |
|
|
|
args = parser.parse_args() |
|
dtype = torch.float16 if args.dtype == "float16" else torch.bfloat16 |
|
generate_video( |
|
prompt=args.prompt, |
|
model_path=args.model_path, |
|
lora_path=args.lora_path, |
|
lora_rank=args.lora_rank, |
|
output_path=args.output_path, |
|
num_frames=args.num_frames, |
|
width=args.width, |
|
height=args.height, |
|
image_or_video_path=args.image_or_video_path, |
|
num_inference_steps=args.num_inference_steps, |
|
guidance_scale=args.guidance_scale, |
|
num_videos_per_prompt=args.num_videos_per_prompt, |
|
dtype=dtype, |
|
generate_type=args.generate_type, |
|
seed=args.seed, |
|
fps=args.fps, |
|
) |
|
|