Spaces:
Running
Running
File size: 6,941 Bytes
e0336bc |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 26 15:11:58 2025
@author: blyss
"""
import sys
import os
import argparse
import torch
from rich.traceback import install as install_rich_tracebacks
from blissful_tuner.utils import BlissfulLogger, string_to_seed, parse_scheduled_cfg, error_out
logger = BlissfulLogger(__name__, "#8e00ed")
BLISSFUL_VERSION = "0.4.0"
CFG_SCHEDULE_HELP = """
Comma-separated list of steps/ranges where CFG should be applied.
You can specify:
- Single steps (e.g., '5')
- Ranges (e.g., '1-10')
- Modulus patterns (e.g., 'e~2' for every 2 steps)
- Guidance scale overrides (e.g., '1-10:5.0')
Example schedule:
'e~2:6.4, 1-10, 46-50'
This would apply:
- Default CFG scale for steps 1-10 and 46-50
- 6.4 CFG scale every 2 steps outside that range
- No CFG otherwise
You can exclude steps using '!', e.g., '!32' skips step 32.
Note: The list is processed left to right, so modulus ranges should come first and exclusions at the end!
"""
ROOT_SCRIPT = os.path.basename(sys.argv[0]).lower()
if "hv_" in ROOT_SCRIPT:
DIFFUSION_MODEL = "hunyuan"
elif "wan_" in ROOT_SCRIPT:
DIFFUSION_MODEL = "wan"
elif "fpack_" in ROOT_SCRIPT:
DIFFUSION_MODEL = "framepack"
else:
raise ValueError("Unsupported root_script for Blissful Extension")
if "generate" in ROOT_SCRIPT:
MODE = "generate"
elif "train" in ROOT_SCRIPT:
MODE = "train"
else:
raise ValueError("Unsupported root script for Blissful Extension!")
def blissful_prefunc(args: argparse.Namespace):
"""Simple function to print about version, environment, and things"""
cuda_list = [f"PyTorch: {torch.__version__}"]
if torch.cuda.is_available():
allocator = torch.cuda.get_allocator_backend()
cuda = torch.cuda.get_device_properties(0)
cuda_list[0] += f", CUDA: {torch.version.cuda} CC: {cuda.major}.{cuda.minor}"
cuda_list.append(f"Device: '{cuda.name}', VRAM: '{cuda.total_memory // 1024 ** 2}MB'")
for string in cuda_list:
logger.info(string)
if args.fp16_accumulation and MODE == "generate":
logger.info("Enabling FP16 accumulation")
if hasattr(torch.backends.cuda.matmul, "allow_fp16_accumulation"):
torch.backends.cuda.matmul.allow_fp16_accumulation = True
else:
raise ValueError("torch.backends.cuda.matmul.allow_fp16_accumulation is not available in this version of torch, requires torch 2.7.0.dev2025 02 26 nightly minimum")
def add_blissful_args(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
install_rich_tracebacks()
if DIFFUSION_MODEL == "wan":
parser.add_argument("--noise_aug_strength", type=float, default=0.0, help="Additional multiplier for i2v noise, higher might help motion/quality")
parser.add_argument("--prompt_weighting", action="store_true", help="Enable (prompt weighting:1.2)")
parser.add_argument(
"--rope_func", type=str, default="default",
help="Function to use for ROPE. Choose from 'default' or 'comfy' the latter of which uses ComfyUI implementation and is compilable with torch.compile to enable BIG VRAM savings"
)
elif DIFFUSION_MODEL == "hunyuan":
parser.add_argument("--hidden_state_skip_layer", type=int, default=2, help="Hidden state skip layer for LLM. Default is 2. Think 'clip skip' for the LLM")
parser.add_argument("--apply_final_norm", type=bool, default=False, help="Apply final norm for LLM. Default is False. Usually makes things worse.")
parser.add_argument("--reproduce", action="store_true", help="Enable reproducible output(Same seed = same result. Default is False.")
parser.add_argument("--fp8_scaled", action="store_true", help="Scaled FP8 quantization. Better quality/accuracy with slightly more VRAM usage.")
parser.add_argument("--prompt_2", type=str, required=False, help="Optional different prompt for CLIP")
parser.add_argument("--te_multiplier", nargs=2, metavar=("llm_multiplier", "clip_multiplier"), help="Scale clip and llm influence")
elif DIFFUSION_MODEL == "framepack":
parser.add_argument("--preview_latent_every", type=int, default=None, help="Enable latent preview every N sections. If --preview_vae is not specified it will use latent2rgb")
if DIFFUSION_MODEL in ["wan", "hunyuan"]:
parser.add_argument("--riflex_index", type=int, default=0, help="Frequency for RifleX extension. 4 is good for Hunyuan, 6 is good for Wan. Only 'comfy' rope_func supports this with Wan!")
parser.add_argument("--cfgzerostar_scaling", action="store_true", help="Enables CFG-Zero* scaling - https://github.com/WeichenFan/CFG-Zero-star")
parser.add_argument("--cfgzerostar_init_steps", type=int, default=-1, help="Enables CFGZero* zeroing out the first N steps. 2 is good for Wan T2V, 1 for I2V")
parser.add_argument("--preview_latent_every", type=int, default=None, help="Enable latent preview every N steps. If --preview_vae is not specified it will use latent2rgb")
# Common
parser.add_argument("--preview_vae", type=str, help="Path to TAE vae for taehv previews")
parser.add_argument("--cfg_schedule", type=str, help=CFG_SCHEDULE_HELP)
parser.add_argument("--keep_pngs", action="store_true", help="Save frames as PNGs in addition to output video")
parser.add_argument("--codec", choices=["prores", "h264", "h265"], default=None, help="Codec to use, choose from 'prores', 'h264', or 'h265'")
parser.add_argument("--container", choices=["mkv", "mp4"], default="mkv", help="Container format to use, choose from 'mkv' or 'mp4'. Note prores can only go in MKV!")
parser.add_argument("--fp16_accumulation", action="store_true", help="Enable full FP16 Accmumulation in FP16 GEMMs, requires Pytorch 2.7.0 or higher")
return parser
def parse_blissful_args(args: argparse.Namespace) -> argparse.Namespace:
if args.seed is not None:
try:
args.seed = int(args.seed)
except ValueError:
string_seed = args.seed
args.seed = string_to_seed(args.seed)
logger.info(f"Seed {args.seed} was generated from string '{string_seed}'!")
if DIFFUSION_MODEL == "wan":
if args.riflex_index != 0 and args.rope_func.lower() != "comfy":
logger.error("RIFLEx can only be used with rope_func == 'comfy'!")
raise ValueError("RIFLEx can only be used with rope_func =='comfy'!")
if DIFFUSION_MODEL in ["wan", "hunyuan"]:
if args.cfg_schedule:
args.cfg_schedule = parse_scheduled_cfg(args.cfg_schedule, args.infer_steps, args.guidance_scale)
if args.cfgzerostar_scaling or args.cfgzerostar_init_steps != -1:
if args.guidance_scale == 1 and not args.cfg_schedule:
error_out(AttributeError, "Requested CFGZero* but CFG is not enabled so it will have no effect!")
blissful_prefunc(args)
return args
|