diff --git a/inference_cli.py b/inference_cli.py index 2b82ef4..76e15ef 100644 --- a/inference_cli.py +++ b/inference_cli.py @@ -703,11 +703,11 @@ def _process_frames_core( 'offload_device': dit_offload, }, encode_tiled=args.vae_encode_tiling_enabled, - encode_tile_size=args.vae_encode_tile_size, - encode_tile_overlap=args.vae_encode_tile_overlap, + encode_tile_size=(args.vae_encode_tile_size, args.vae_encode_tile_size), + encode_tile_overlap=(args.vae_encode_tile_overlap, args.vae_encode_tile_overlap), decode_tiled=args.vae_decode_tiling_enabled, - decode_tile_size=args.vae_decode_tile_size, - decode_tile_overlap=args.vae_decode_tile_overlap, + decode_tile_size=(args.vae_decode_tile_size, args.vae_decode_tile_size), + decode_tile_overlap=(args.vae_decode_tile_overlap, args.vae_decode_tile_overlap), tile_debug=args.tile_debug.lower() if args.tile_debug else "false", attention_mode=args.attention_mode, torch_compile_args_dit=torch_compile_args_dit, @@ -980,53 +980,12 @@ def _gpu_processing( # Argument Parsing # ============================================================================= -class OneOrTwoValues(argparse.Action): - """ - Custom argparse action for tile size arguments accepting 1 or 2 integers. - - Allows flexible input formats: - - Single integer: --tile_size 1024 → (1024, 1024) - - Two integers: --tile_size 1024 768 → (1024, 768) - - Comma-separated: --tile_size 1024,768 → (1024, 768) - - Used for VAE tiling parameters where height and width can be specified - separately or as a single value applied to both dimensions. - """ - - def __call__( - self, - parser: argparse.ArgumentParser, - namespace: argparse.Namespace, - values: List[str], - option_string: Optional[str] = None - ) -> None: - """Parse and validate tile size arguments.""" - if len(values) not in [1, 2]: - parser.error(f"{option_string} requires 1 or 2 arguments") - - if len(values) == 1: - values = values[0] - if ',' in values: - values = [v.strip() for v in values.split(',') if v.strip()] - else: - values = values.split() - - try: - result = tuple(int(v) for v in values) - if len(result) == 1: - result = (result[0], result[0]) # Convert single value to (h, w) - setattr(namespace, self.dest, result) - except ValueError: - parser.error(f"{option_string} arguments must be integers") - - def parse_arguments() -> argparse.Namespace: """ Parse and validate command-line arguments for SeedVR2 CLI. Configures all available options including model selection, processing parameters, - memory optimization settings, and output configuration. Uses custom action classes - for complex argument types (e.g., OneOrTwoValues for tile sizes). + memory optimization settings, and output configuration. Returns: Parsed arguments namespace with all CLI parameters @@ -1034,7 +993,6 @@ def parse_arguments() -> argparse.Namespace: Note: - cuda_device argument only available on non-macOS systems - Default model directory resolves to "models/SEEDVR2" if not specified - - Tile size/overlap arguments use OneOrTwoValues for flexible input """ # Multi-line usage examples for --help @@ -1107,13 +1065,13 @@ Examples: quality_group = parser.add_argument_group('Quality control') quality_group.add_argument("--color_correction", type=str, default="lab", choices=["lab", "wavelet", "wavelet_adaptive", "hsv", "adain", "none"], - help="Color correction: 'lab' (best, perceptual matching), 'wavelet' (natural, preserves detail), " - "'wavelet_adaptive' (adaptive saturation), 'hsv' (hue-conditional), 'adain' (style transfer), " - "'none' (no correction). Default: lab") + help="Color correction method: 'lab' (perceptual color matching, recommended), 'wavelet' (frequency-based), " + "'wavelet_adaptive' (wavelet + saturation correction), 'hsv' (hue-conditional), 'adain' (statistical transfer), " + "'none' (disabled) (default: lab)") quality_group.add_argument("--input_noise_scale", type=float, default=0.0, - help="Input noise (0.0-1.0) to add variation to input (default: 0.0)") + help="Input noise injection scale (0.0-1.0). Adds variation to input images (default: 0.0)") quality_group.add_argument("--latent_noise_scale", type=float, default=0.0, - help="Latent noise (0.0-1.0) during diffusion. Can soften details (default: 0.0)") + help="Latent noise injection scale (0.0-1.0). Adds variation to latent space (default: 0.0)") # Device Management device_group = parser.add_argument_group('Device management') @@ -1140,16 +1098,16 @@ Examples: vae_group = parser.add_argument_group('VAE tiling (for high resolution upscale)') vae_group.add_argument("--vae_encode_tiling_enabled", action="store_true", help="Enable VAE encode tiling to reduce VRAM during encoding") - vae_group.add_argument("--vae_encode_tile_size", action=OneOrTwoValues, nargs='+', default=(1024, 1024), - help="Encode tile size in pixels (height width or single value). Default: 1024") - vae_group.add_argument("--vae_encode_tile_overlap", action=OneOrTwoValues, nargs='+', default=(128, 128), - help="Encode tile overlap in pixels. Higher = better blending. Default: 128") + vae_group.add_argument("--vae_encode_tile_size", type=int, default=1024, + help="VAE encode tile size in pixels (default: 1024). Applied to both height and width. Only used if --vae_encode_tiling_enabled is set") + vae_group.add_argument("--vae_encode_tile_overlap", type=int, default=128, + help="VAE encode tile overlap in pixels (default: 128). Reduces visible seams between tiles. Only used if --vae_encode_tiling_enabled is set") vae_group.add_argument("--vae_decode_tiling_enabled", action="store_true", - help="Enable VAE decode tiling to reduce VRAM during decoding (recommended for 4K+)") - vae_group.add_argument("--vae_decode_tile_size", action=OneOrTwoValues, nargs='+', default=(1024, 1024), - help="Decode tile size in pixels (height width or single value). Default: 1024") - vae_group.add_argument("--vae_decode_tile_overlap", action=OneOrTwoValues, nargs='+', default=(128, 128), - help="Decode tile overlap in pixels. Higher = better blending. Default: 128") + help="Enable VAE decode tiling to reduce VRAM during decoding") + vae_group.add_argument("--vae_decode_tile_size", type=int, default=1024, + help="VAE decode tile size in pixels (default: 1024). Applied to both height and width. Only used if --vae_decode_tiling_enabled is set") + vae_group.add_argument("--vae_decode_tile_overlap", type=int, default=128, + help="VAE decode tile overlap in pixels (default: 128). Reduces visible seams between tiles. Only used if --vae_decode_tiling_enabled is set") vae_group.add_argument("--tile_debug", type=str, default="false", choices=["false", "encode", "decode"], help="Visualize tiles: 'false' (default), 'encode', or 'decode'") @@ -1158,23 +1116,23 @@ Examples: perf_group.add_argument("--attention_mode", type=str, default="sdpa", choices=["sdpa", "flash_attn"], help="Attention backend: 'sdpa' (default, always available) or 'flash_attn' (faster, requires package)") - perf_group.add_argument("--compile_dit", action="store_true", - help="Enable torch.compile for DiT (20-40%% speedup, slower first run)") + perf_group.add_argument("--compile_dit", action="store_true", + help="Enable torch.compile for DiT model (20-40%% speedup, requires PyTorch 2.0+ and Triton)") perf_group.add_argument("--compile_vae", action="store_true", - help="Enable torch.compile for VAE (15-25%% speedup, slower first run)") + help="Enable torch.compile for VAE model (15-25%% speedup, requires PyTorch 2.0+ and Triton)") perf_group.add_argument("--compile_backend", type=str, default="inductor", choices=["inductor", "cudagraphs"], - help="Compile backend (default: inductor)") - perf_group.add_argument("--compile_mode", type=str, default="default", - choices=["default", "reduce-overhead", "max-autotune", "max-autotune-no-cudagraphs"], - help="Compile mode (default: default)") + help="Compilation backend: 'inductor' (full optimization with Triton) or 'cudagraphs' (lightweight, no kernel optimization) (default: inductor)") + perf_group.add_argument("--compile_mode", type=str, default="default", choices=["default", "reduce-overhead", "max-autotune", "max-autotune-no-cudagraphs"], + help="Optimization level: 'default' (fast compilation), 'reduce-overhead' (lower overhead), 'max-autotune' (best runtime, slow compilation), " + "'max-autotune-no-cudagraphs' (like max-autotune without cudagraphs) (default: default)") perf_group.add_argument("--compile_fullgraph", action="store_true", - help="Force single graph compilation (max optimization, may fail)") + help="Compile entire model as single graph (faster but less flexible). May fail with dynamic shapes (default: False)") perf_group.add_argument("--compile_dynamic", action="store_true", - help="Handle dynamic input shapes (slower but more flexible)") + help="Handle varying input shapes without recompilation. Useful for different resolutions/batch sizes (default: False)") perf_group.add_argument("--compile_dynamo_cache_size_limit", type=int, default=64, - help="Max compiled versions cached per function (default: 64)") + help="Max cached compiled versions per function. Increase when using many different input shapes. Higher uses more memory (default: 64)") perf_group.add_argument("--compile_dynamo_recompile_limit", type=int, default=128, - help="Max recompile attempts before fallback (default: 128)") + help="Max recompilation attempts before fallback to eager mode. Safety limit to prevent compilation loops (default: 128)") # Model Caching (for batch processing) cache_group = parser.add_argument_group('Model caching (batch processing)') @@ -1232,12 +1190,12 @@ def main() -> None: for key, value in vars(args).items(): debug.log(f"{key}: {value}", category="none", indent_level=1) - if args.vae_encode_tiling_enabled and (args.vae_encode_tile_overlap[0] >= args.vae_encode_tile_size[0] or args.vae_encode_tile_overlap[1] >= args.vae_encode_tile_size[1]): - debug.log(f"VAE encode tile overlap {args.vae_encode_tile_overlap} must be smaller than tile size {args.vae_encode_tile_size}", level="ERROR", category="vae", force=True) + if args.vae_encode_tiling_enabled and args.vae_encode_tile_overlap >= args.vae_encode_tile_size: + debug.log(f"VAE encode tile overlap ({args.vae_encode_tile_overlap}) must be smaller than tile size ({args.vae_encode_tile_size})", level="ERROR", category="vae", force=True) sys.exit(1) - if args.vae_decode_tiling_enabled and (args.vae_decode_tile_overlap[0] >= args.vae_decode_tile_size[0] or args.vae_decode_tile_overlap[1] >= args.vae_decode_tile_size[1]): - debug.log(f"VAE decode tile overlap {args.vae_decode_tile_overlap} must be smaller than tile size {args.vae_decode_tile_size}", level="ERROR", category="vae", force=True) + if args.vae_decode_tiling_enabled and args.vae_decode_tile_overlap >= args.vae_decode_tile_size: + debug.log(f"VAE decode tile overlap ({args.vae_decode_tile_overlap}) must be smaller than tile size ({args.vae_decode_tile_size})", level="ERROR", category="vae", force=True) sys.exit(1) # Validate BlockSwap configuration - either blocks_to_swap or swap_io_components requires dit_offload_device diff --git a/pyproject.toml b/pyproject.toml index 9058012..ae3ba9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "seedvr2_videoupscaler" description = "SeedVR2 official ComfyUI integration: ByteDance-Seed's one-step diffusion-based video/image upscaling with memory-efficient inference" -version = "3.0.0" +version = "2.5.0" authors = [ {name = "numz"}, {name = "adrientoupet"} diff --git a/src/interfaces/dit_model_loader.py b/src/interfaces/dit_model_loader.py index df35c98..bde510d 100644 --- a/src/interfaces/dit_model_loader.py +++ b/src/interfaces/dit_model_loader.py @@ -34,19 +34,25 @@ class SeedVR2LoadDiTModel(io.ComfyNode): display_name="SeedVR2 (Down)Load DiT Model", category="SEEDVR2", description=( - "Configure DiT model for SeedVR2 upscaling. Supports BlockSwap for limited VRAM, " - "model caching, and torch.compile optimization. Connect output to SeedVR2 Video Upscaler." + "Load and configure SeedVR2 DiT (Diffusion Transformer) model for video upscaling. " + "Supports BlockSwap memory optimization for low VRAM systems, model caching for batch processing, " + "multi-GPU offloading, and torch.compile acceleration. \n\n" + "Connect to Video Upscaler node." ), inputs=[ io.Combo.Input("model", options=dit_models, default=DEFAULT_DIT, - tooltip="DiT model for upscaling. Models will automatically download on first use. Additional models can be added to the ComfyUI models folder." + tooltip=( + "DiT (Diffusion Transformer) model for video upscaling.\n" + "Models automatically download on first use.\n" + "Additional models can be added to the ComfyUI models folder." + ) ), io.Combo.Input("device", options=devices, default=devices[0], - tooltip="Device for DiT inference (upscaling)" + tooltip="GPU/CPU device for DiT model inference (upscaling phase)" ), io.Int.Input("blocks_to_swap", default=0, @@ -54,23 +60,44 @@ class SeedVR2LoadDiTModel(io.ComfyNode): max=36, step=1, optional=True, - tooltip="Number of transformer blocks to swap. Requires offload_device to be set and different from device. 0=disabled. 3B model: 0-32 blocks, 7B model: 0-36 blocks." + tooltip=( + "Number of transformer blocks to swap between devices for VRAM optimization.\n" + "• 0: Disabled (default)\n" + "• 3B model: 0-32 blocks\n" + "• 7B model: 0-36 blocks\n" + "\n" + "Requires offload_device to be set and different from device." + ) ), io.Boolean.Input("swap_io_components", default=False, optional=True, - tooltip="Offload input/output embeddings and norm layers. Requires offload_device to be set and different from device." + tooltip=( + "Offload input/output embeddings and normalization layers to reduce VRAM.\n" + "Requires offload_device to be set and different from device." + ) ), io.Combo.Input("offload_device", options=get_device_list(include_none=True, include_cpu=True), default="none", optional=True, - tooltip="Device to offload DiT model to when not in use. Select 'none' to keep on inference device, or 'cpu' for CPU offload (slower but reduces VRAM usage). Required for BlockSwap." + tooltip=( + "Device to offload DiT model when not actively processing.\n" + "• 'none': Keep model on inference device (default, fastest)\n" + "• 'cpu': Offload to system RAM (reduces VRAM usage)\n" + "• 'cuda:X': Offload to another GPU (good balance if available)\n" + "\n" + "Required for BlockSwap (blocks_to_swap or swap_io_components)." + ) ), io.Boolean.Input("cache_model", default=False, optional=True, - tooltip="Keep DiT model loaded on offload_device between workflow runs. Useful for batch processing." + tooltip=( + "Keep DiT model loaded on offload_device between workflow runs.\n" + "Useful for batch processing to avoid repeated loading.\n" + "Requires offload_device to be set." + ) ), io.Combo.Input("attention_mode", options=["sdpa", "flash_attn"], @@ -78,20 +105,25 @@ class SeedVR2LoadDiTModel(io.ComfyNode): optional=True, tooltip=( "Attention computation backend:\n" - "• sdpa: PyTorch scaled_dot_product_attention (default, always available)\n" - "• flash_attn: Flash Attention 2 (faster, requires flash-attn package)\n" + "• sdpa: PyTorch scaled_dot_product_attention (default, stable, always available)\n" + "• flash_attn: Flash Attention 2 (faster on supported hardware, requires flash-attn package)\n" "\n" - "SDPA is recommended as the default - it's stable and works everywhere.\n" - "Flash Attention provides speedup on some hardware through optimized CUDA kernels." + "SDPA is recommended - stable and works everywhere.\n" + "Flash Attention provides speedup through optimized CUDA kernels on compatible GPUs." ) ), io.Custom("TORCH_COMPILE_ARGS").Input("torch_compile_args", optional=True, - tooltip="Optional torch.compile settings from SeedVR2 Torch Compile Settings node for speedup" + tooltip=( + "Optional torch.compile optimization settings from SeedVR2 Torch Compile Settings node.\n" + "Provides 20-40% speedup with compatible PyTorch 2.0+ and Triton installation." + ) ), ], outputs=[ - io.Custom("SEEDVR2_DIT").Output() + io.Custom("SEEDVR2_DIT").Output( + tooltip="DiT model configuration containing model path, device settings, BlockSwap parameters, and compilation options. Connect to Video Upscaler node." + ) ] ) diff --git a/src/interfaces/torch_compile_settings.py b/src/interfaces/torch_compile_settings.py index a1bb4d4..9958614 100644 --- a/src/interfaces/torch_compile_settings.py +++ b/src/interfaces/torch_compile_settings.py @@ -17,8 +17,9 @@ class SeedVR2TorchCompileSettings(io.ComfyNode): display_name="SeedVR2 Torch Compile Settings", category="SEEDVR2", description=( - "Configure torch.compile optimization for DiT and VAE speedup. " - "Connect to DiT and/or VAE model loader. Requires PyTorch 2.0+ and Triton." + "Configure SeedVR2 torch.compile optimization for 20-40% DiT speedup and 15-25% VAE speedup. " + "Trades longer first-run compilation time for faster inference.\n\n" + "Connect to DiT and/or VAE model loaders. Requires PyTorch 2.0+ and Triton for inductor backend." ), inputs=[ io.Combo.Input("backend", @@ -26,46 +27,69 @@ class SeedVR2TorchCompileSettings(io.ComfyNode): default="inductor", tooltip=( "Compilation backend:\n" - "• inductor: Full optimization with Triton kernel generation and fusion\n" - "• cudagraphs: Lightweight, only wraps model with CUDA graphs, no kernel optimization" + "• inductor: Full optimization with Triton kernel generation and fusion (recommended)\n" + "• cudagraphs: Lightweight wrapper using CUDA graphs, no kernel optimization" ) ), io.Combo.Input("mode", options=["default", "reduce-overhead", "max-autotune", "max-autotune-no-cudagraphs"], default="default", tooltip=( - "Optimization level (compilation time vs runtime speed):\n" - "• default: Fast compilation, good speedup\n" - "• reduce-overhead: Lower overhead, better for smaller models\n" - "• max-autotune: Slowest compilation, best runtime (recommended for production)\n" - "• max-autotune-no-cudagraphs: Like max-autotune but without cudagraphs" + "Optimization level (compilation time vs runtime performance):\n" + "• default: Fast compilation with good speedup (recommended for development)\n" + "• reduce-overhead: Lower overhead, optimized for smaller models\n" + "• max-autotune: Slowest compilation, best runtime performance (recommended for production)\n" + "• max-autotune-no-cudagraphs: Like max-autotune but without CUDA graphs" ) ), io.Boolean.Input("fullgraph", default=False, - tooltip="Compile entire model as single graph (faster but less flexible). May fail with dynamic shapes." + tooltip=( + "Compile entire model as single graph without breaks.\n" + "• False: Allow graph breaks for better compatibility (default)\n" + "• True: Enforce no breaks for maximum optimization (may fail with dynamic shapes)" + ) ), io.Boolean.Input("dynamic", default=False, - tooltip="Handle varying input shapes without recompilation. Useful for different resolutions/batch sizes." + tooltip=( + "Handle varying input shapes without recompilation.\n" + "• False: Specialize for exact input shapes (default)\n" + "• True: Create dynamic kernels that adapt to shape variations\n" + "\n" + "Enable when processing different resolutions or batch sizes." + ) ), io.Int.Input("dynamo_cache_size_limit", default=64, min=0, max=1024, step=1, - tooltip="Maximum cached compiled versions per function. Increase if using many different input shapes." + tooltip=( + "Maximum cached compiled versions per function (default: 64).\n" + "Controls how many shape variations to compile before stopping.\n" + "\n" + "• Increase: When processing many different input shapes (more memory usage)\n" + "• Decrease: When recompilation cost outweighs benefits (faster fallback to eager)" + ) ), io.Int.Input("dynamo_recompile_limit", default=128, min=0, max=1024, step=1, - tooltip="Maximum recompilation attempts before fallback to eager mode. Only increase if you see recompile_limit warnings" + tooltip=( + "Maximum recompilation attempts before fallback to eager mode (default: 128).\n" + "Safety limit to prevent infinite compilation loops.\n" + "\n" + "Only increase if you see 'hit config.recompile_limit' warnings and have bounded shape variations." + ) ), ], outputs=[ - io.Custom("TORCH_COMPILE_ARGS").Output() + io.Custom("TORCH_COMPILE_ARGS").Output( + tooltip="torch.compile optimization settings including backend, mode, and Dynamo configuration. Connect to DiT and/or VAE model loader nodes." + ) ] ) diff --git a/src/interfaces/vae_model_loader.py b/src/interfaces/vae_model_loader.py index ee73612..3becb94 100644 --- a/src/interfaces/vae_model_loader.py +++ b/src/interfaces/vae_model_loader.py @@ -35,82 +35,129 @@ class SeedVR2LoadVAEModel(io.ComfyNode): display_name="SeedVR2 (Down)Load VAE Model", category="SEEDVR2", description=( - "Configure VAE model for SeedVR2 encoding/decoding. Supports tiled processing for VRAM reduction, " - "model caching, and torch.compile optimization. Connect output to SeedVR2 Video Upscaler." + "Load and configure SeedVR2 VAE (Variational Autoencoder) for encoding/decoding video frames to/from latent space. " + "Supports tiled processing to handle high resolutions on limited VRAM, model caching, " + "multi-GPU offloading, and torch.compile acceleration. \n\n" + "Connect to Video Upscaler node." ), inputs=[ io.Combo.Input("model", options=vae_models, default=DEFAULT_VAE, - tooltip="VAE model for encoding/decoding. Models will automatically download on first use. Additional models can be added to the ComfyUI models folder." + tooltip=( + "VAE (Variational Autoencoder) model for encoding/decoding.\n" + "Models automatically download on first use.\n" + "Additional models can be added to the ComfyUI models folder." + ) ), io.Combo.Input("device", options=devices, default=devices[0], - tooltip="Device for VAE inference (encoding/decoding)" + tooltip="GPU/CPU device for VAE model inference (encoding/decoding phases)" ), io.Boolean.Input("encode_tiled", default=False, optional=True, - tooltip="Enable tiled decoding to reduce VRAM during decoding" + tooltip="Enable tiled encoding to reduce VRAM usage during the encoding phase" ), io.Int.Input("encode_tile_size", default=1024, min=64, step=32, optional=True, - tooltip="Encoding tile size in pixels (default: 1024). Adjust based on available VRAM." + tooltip=( + "Encoding tile size in pixels (default: 1024).\n" + "Applied to both height and width.\n" + "Lower values reduce VRAM usage but may increase processing time.\n" + "Only used when encode_tiled is enabled." + ) ), io.Int.Input("encode_tile_overlap", default=128, min=0, step=32, optional=True, - tooltip="Pixel overlap between encoding tiles to reduce visible seams (default: 128). Higher values improve blending at the cost of slower processing." + tooltip=( + "Pixel overlap between encoding tiles (default: 128).\n" + "Reduces visible seams between tiles through blending.\n" + "Higher values improve quality but slow processing.\n" + "Only used when encode_tiled is enabled." + ) ), io.Boolean.Input("decode_tiled", default=False, optional=True, - tooltip="Enable tiled decoding to reduce VRAM during decoding" + tooltip="Enable tiled decoding to reduce VRAM usage during the decoding phase" ), io.Int.Input("decode_tile_size", default=1024, min=64, step=32, optional=True, - tooltip="Decoding tile size in pixels (default: 1024). Adjust based on available VRAM." + tooltip=( + "Decoding tile size in pixels (default: 1024).\n" + "Applied to both height and width.\n" + "Lower values reduce VRAM usage but may increase processing time.\n" + "Only used when decode_tiled is enabled." + ) ), io.Int.Input("decode_tile_overlap", default=128, min=0, step=32, optional=True, - tooltip="Pixel overlap between decoding tiles to reduce visible seams (default: 128). Higher values improve blending at the cost of slower processing." + tooltip=( + "Pixel overlap between decoding tiles (default: 128).\n" + "Reduces visible seams between tiles through blending.\n" + "Higher values improve quality but slow processing.\n" + "Only used when decode_tiled is enabled." + ) ), io.Combo.Input("tile_debug", options=["false", "encode", "decode"], default="false", optional=True, - tooltip="Enable tile debug visualization: 'false' (no overlay), 'encode' (show encode tiles), 'decode' (show decode tiles). Only works when respective tiling is enabled." + tooltip=( + "Tile debug visualization mode:\n" + "• 'false': No visualization overlay (default)\n" + "• 'encode': Show encoding tile boundaries\n" + "• 'decode': Show decoding tile boundaries\n" + "\n" + "Only works when respective tiling is enabled." + ) ), io.Combo.Input("offload_device", options=get_device_list(include_none=True, include_cpu=True), default="none", optional=True, - tooltip="Device to offload VAE model to when not in use. Select 'none' to keep on inference device, or 'cpu' for CPU offload (slower but reduces VRAM usage). Required for BlockSwap." + tooltip=( + "Device to offload VAE model when not actively processing.\n" + "• 'none': Keep model on inference device (default, fastest)\n" + "• 'cpu': Offload to system RAM (reduces VRAM usage)\n" + "• 'cuda:X': Offload to another GPU (good balance if available)" + ) ), io.Boolean.Input("cache_model", default=False, optional=True, - tooltip="Keep VAE model loaded on offload_device between workflow runs. Useful for batch processing." + tooltip=( + "Keep VAE model loaded on offload_device between workflow runs.\n" + "Useful for batch processing to avoid repeated loading.\n" + "Requires offload_device to be set." + ) ), io.Custom("TORCH_COMPILE_ARGS").Input("torch_compile_args", optional=True, - tooltip="Optional torch.compile settings from SeedVR2 Torch Compile Settings node for speedup" + tooltip=( + "Optional torch.compile optimization settings from SeedVR2 Torch Compile Settings node.\n" + "Provides 15-25% speedup with compatible PyTorch 2.0+ and Triton installation." + ) ), ], outputs=[ - io.Custom("SEEDVR2_VAE").Output() + io.Custom("SEEDVR2_VAE").Output( + tooltip="VAE model configuration containing model path, device settings, tiling parameters, and compilation options. Connect to Video Upscaler node." + ) ] ) diff --git a/src/interfaces/video_upscaler.py b/src/interfaces/video_upscaler.py index c887560..59527f0 100644 --- a/src/interfaces/video_upscaler.py +++ b/src/interfaces/video_upscaler.py @@ -53,46 +53,72 @@ class SeedVR2VideoUpscaler(io.ComfyNode): display_name="SeedVR2 Video Upscaler", category="SEEDVR2", description=( - "High-quality video upscaling using diffusion models. " - "Supports RGB and RGBA formats, temporal consistency, and adaptive VRAM management." + "SeedVR2 main upscaling node: processes video frames using DiT and VAE models with diffusion-based enhancement. " + "Handles RGB/RGBA formats, maintains temporal consistency across frames, applies color correction, " + "and manages VRAM through intelligent tensor offloading. \n\n" + "Requires DiT and VAE model configurations." ), inputs=[ io.Image.Input("image", - tooltip="Input video frames. Accepts both RGB (3-channel) and RGBA (4-channel) images. Output will match input format." + tooltip=( + "Input video frames as image batch.\n" + "Accepts both RGB (3-channel) and RGBA (4-channel) formats.\n" + "Output format will match input format." + ) ), io.Custom("SEEDVR2_DIT").Input("dit", - tooltip="DiT model configuration from SeedVR2 Load DiT Model node" + tooltip="DiT model configuration from SeedVR2 (Down)Load DiT Model node" ), io.Custom("SEEDVR2_VAE").Input("vae", - tooltip="VAE model configuration from SeedVR2 Load VAE Model node" + tooltip="VAE model configuration from SeedVR2 (Down)Load VAE Model node" ), io.Int.Input("seed", default=42, min=0, max=2**32 - 1, step=1, - tooltip="Random seed for generation. Same seed = same output." + tooltip=( + "Random seed for reproducible generation (default: 42).\n" + "Same seed with same inputs produces identical output." + ) ), io.Int.Input("new_resolution", default=1080, min=16, max=16384, step=2, - tooltip="Target resolution for the shortest edge. Maintains aspect ratio." + tooltip=( + "Target resolution for the shortest edge in pixels (default: 1080).\n" + "Automatically maintains aspect ratio of input.\n" + "Even values required for optimal processing." + ) ), io.Int.Input("max_resolution", default=0, min=0, max=16384, step=2, - tooltip="Maximum resolution for any edge. If any dimension exceeds this after new_resolution is applied, both dimensions are scaled down proportionally. 0 = no limit (default)." + tooltip=( + "Maximum resolution limit for any dimension (default: 0, no limit).\n" + "If any edge exceeds this after applying new_resolution,\n" + "both dimensions are scaled down proportionally.\n" + "Useful to prevent excessive VRAM usage on extreme aspect ratios." + ) ), io.Int.Input("batch_size", default=5, min=1, max=16384, step=4, - tooltip="Frames per batch (4n+1: 1,5,9,13,17,21,...). Ideally match shot length. Higher = better temporal consistency + speed but more VRAM." + tooltip=( + "Number of frames processed together per batch (default: 5).\n" + "Must follow pattern 4n+1: 1, 5, 9, 13, 17, 21, ...\n" + "\n" + "• Higher values: Better temporal consistency and faster processing\n" + "• Lower values: Reduced VRAM usage\n" + "\n" + "Ideally match to shot length for best quality." + ) ), io.Int.Input("temporal_overlap", default=0, @@ -100,7 +126,11 @@ class SeedVR2VideoUpscaler(io.ComfyNode): max=16, step=1, optional=True, - tooltip="Overlapping frames between batches for smoother transitions. 0 = disabled. Values 1-4 work well for temporal consistency." + tooltip=( + "Overlapping frames between consecutive batches (default: 0, disabled).\n" + "Improves temporal consistency across batch boundaries through blending.\n" + "Values 1-4 work well for most content." + ) ), io.Int.Input("prepend_frames", default=0, @@ -108,12 +138,26 @@ class SeedVR2VideoUpscaler(io.ComfyNode): max=32, step=1, optional=True, - tooltip="Number of frames to prepend to the video (reversed from start). This can help with artifacts at the start of the video and are automatically removed after processing." + tooltip=( + "Number of frames to prepend (reversed from start) before processing (default: 0).\n" + "Helps reduce artifacts at video beginning.\n" + "Prepended frames are automatically removed from final output." + ) ), io.Combo.Input("color_correction", options=["lab", "wavelet", "wavelet_adaptive", "hsv", "adain", "none"], default="lab", - tooltip="Color correction method: 'lab' (full perceptual color matching with detail preservation, recommended), 'wavelet' (frequency-based natural colors, preserves details), 'wavelet_adaptive' (wavelet base + targeted saturation correction), 'hsv' (hue-conditional saturation matching), 'adain' (statistical style transfer), 'none' (no correction)" + tooltip=( + "Corrects color shifts in upscaled output to match original input (default: lab).\n" + "The upscaling process may alter colors; this applies color grading to restore them.\n" + "\n" + "• lab: Perceptual color matching with detail preservation (recommended)\n" + "• wavelet: Frequency-based natural colors, preserves fine details\n" + "• wavelet_adaptive: Wavelet base with targeted saturation correction\n" + "• hsv: Hue-conditional saturation matching\n" + "• adain: Statistical style transfer approach\n" + "• none: No color correction applied" + ) ), io.Float.Input("input_noise_scale", default=0.0, @@ -121,7 +165,12 @@ class SeedVR2VideoUpscaler(io.ComfyNode): max=1.0, step=0.001, optional=True, - tooltip="Input noise injection scale [0.0-1.0]. Adds variation to input. 0.0 = disabled." + tooltip=( + "Input noise injection scale (default: 0.0, disabled).\n" + "Adds controlled variation to input images before encoding.\n" + "Range: 0.0 (no noise) to 1.0 (maximum noise).\n" + "Can help with certain types of artifacts." + ) ), io.Float.Input("latent_noise_scale", default=0.0, @@ -129,22 +178,38 @@ class SeedVR2VideoUpscaler(io.ComfyNode): max=1.0, step=0.001, optional=True, - tooltip="Latent noise injection scale [0.0-1.0]. Adds variation to latent space. 0.0 = disabled." + tooltip=( + "Latent space noise injection scale (default: 0.0, disabled).\n" + "Adds controlled variation during the diffusion process.\n" + "Range: 0.0 (no noise) to 1.0 (maximum noise).\n" + "Can soften details if input_noise_scale doesn't help." + ) ), io.Combo.Input("offload_device", options=get_device_list(include_none=True, include_cpu=True), default="cpu", optional=True, - tooltip="Device to offload intermediate tensors. 'cpu' prevents VRAM accumulation for long videos. 'none' keeps all tensors on inference device (faster but increases VRAM usage)." + tooltip=( + "Device for storing intermediate tensors between processing phases (default: cpu).\n" + "• 'none': Keep all tensors on inference device (fastest but highest VRAM usage)\n" + "• 'cpu': Offload to system RAM (recommended for long videos, slower transfers)\n" + "• 'cuda:X': Offload to another GPU (good balance if available, faster than CPU)" + ) ), io.Boolean.Input("enable_debug", default=False, optional=True, - tooltip="Show detailed memory usage and timing information during generation, useful for troubleshooting." + tooltip=( + "Enable detailed debug logging (default: False).\n" + "Shows memory usage, timing information, and processing details.\n" + "Useful for troubleshooting errors and performance issues." + ) ), ], outputs=[ - io.Image.Output() + io.Image.Output( + tooltip="Upscaled video frames with color correction applied. Format (RGB/RGBA) matches input. Range [0, 1] normalized for ComfyUI compatibility." + ) ] )