186 lines
6.0 KiB
Python
186 lines
6.0 KiB
Python
from .comfyui_invsr_trimmed import get_configs, InvSamplerSR, BaseSampler, Namespace
|
|
import torch
|
|
from comfy.utils import ProgressBar
|
|
from folder_paths import get_full_path, get_folder_paths, models_dir
|
|
import os
|
|
import torch.nn.functional as F
|
|
|
|
def split_tensor_into_batches(tensor, batch_size):
|
|
"""
|
|
Split a tensor into smaller batches of specified size
|
|
|
|
Args:
|
|
tensor (torch.Tensor): Input tensor of shape (N, C, H, W)
|
|
batch_size (int): Desired batch size for splitting
|
|
|
|
Returns:
|
|
list: List of tensors, each with batch_size (except possibly the last one)
|
|
"""
|
|
# Get original batch size
|
|
original_batch_size = tensor.size(0)
|
|
|
|
# Calculate number of full batches and remaining samples
|
|
num_full_batches = original_batch_size // batch_size
|
|
remaining_samples = original_batch_size % batch_size
|
|
|
|
# Split tensor into chunks
|
|
batches = []
|
|
|
|
# Handle full batches
|
|
for i in range(num_full_batches):
|
|
start_idx = i * batch_size
|
|
end_idx = start_idx + batch_size
|
|
batch = tensor[start_idx:end_idx]
|
|
batches.append(batch)
|
|
|
|
# Handle remaining samples if any
|
|
if remaining_samples > 0:
|
|
last_batch = tensor[-remaining_samples:]
|
|
batches.append(last_batch)
|
|
|
|
return batches
|
|
|
|
|
|
class LoadInvSRModels:
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"sd_model": (['stabilityai/sd-turbo'],),
|
|
"invsr_model": (['noise_predictor_sd_turbo_v5.pth'],),
|
|
"dtype": (['fp16', 'fp32', 'bf16'], {"default": "fp16"}),
|
|
"tiled_vae": ("BOOLEAN", {"default": True}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("INVSR_PIPE",)
|
|
RETURN_NAMES = ("invsr_pipe",)
|
|
FUNCTION = "loadmodel"
|
|
CATEGORY = "INVSR"
|
|
|
|
def loadmodel(self, sd_model, invsr_model, dtype, tiled_vae):
|
|
match dtype:
|
|
case "fp16":
|
|
dtype = "torch.float16"
|
|
case "fp32":
|
|
dtype = "torch.float32"
|
|
case "bf16":
|
|
dtype = "torch.bfloat16"
|
|
|
|
cfg_path = os.path.join(
|
|
os.path.dirname(__file__), "configs", "sample-sd-turbo.yaml"
|
|
)
|
|
sd_path = get_folder_paths("diffusers")[0]
|
|
|
|
try:
|
|
ckpt_dir = get_folder_paths("invsr")[0]
|
|
except:
|
|
ckpt_dir = os.path.join(models_dir, "invsr")
|
|
|
|
args = Namespace(
|
|
bs=1,
|
|
chopping_bs=8,
|
|
timesteps=None,
|
|
num_steps=1,
|
|
cfg_path=cfg_path,
|
|
sd_path=sd_path,
|
|
started_ckpt_dir=ckpt_dir,
|
|
tiled_vae=tiled_vae,
|
|
color_fix="",
|
|
chopping_size=128,
|
|
)
|
|
configs = get_configs(args)
|
|
configs["sd_pipe"]["params"]["torch_dtype"] = dtype
|
|
base_sampler = BaseSampler(configs)
|
|
|
|
return (base_sampler,)
|
|
|
|
class InvSRSampler:
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"invsr_pipe": ("INVSR_PIPE",),
|
|
"images": ("IMAGE",),
|
|
"num_steps": ("INT",{"default": 1, "min": 1, "max": 5}),
|
|
"cfg": ("FLOAT",{"default": 1.0, "step":0.1}),
|
|
# "scale_factor": ("INT",{"default": 4}),
|
|
"batch_size": ("INT",{"default": 1}),
|
|
"chopping_batch_size": ("INT",{"default": 8}),
|
|
"chopping_size": ([128, 256, 512],{"default": 128}),
|
|
"color_fix": (['none', 'wavelet', 'ycbcr'], {"default": "none"}),
|
|
"seed": ("INT", {"default": 123, "min": 0, "max": 2**32 - 1, "step": 1}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("image",)
|
|
FUNCTION = "process"
|
|
CATEGORY = "INVSR"
|
|
|
|
def process(self, invsr_pipe, images, num_steps, cfg, batch_size, chopping_batch_size, chopping_size, color_fix, seed):
|
|
base_sampler = invsr_pipe
|
|
if color_fix == "none":
|
|
color_fix = ""
|
|
|
|
cfg_path = os.path.join(
|
|
os.path.dirname(__file__), "configs", "sample-sd-turbo.yaml"
|
|
)
|
|
sd_path = get_folder_paths("diffusers")[0]
|
|
|
|
try:
|
|
ckpt_dir = get_folder_paths("invsr")[0]
|
|
except:
|
|
ckpt_dir = os.path.join(models_dir, "invsr")
|
|
|
|
args = Namespace(
|
|
bs=batch_size,
|
|
chopping_bs=chopping_batch_size,
|
|
timesteps=None,
|
|
num_steps=num_steps,
|
|
cfg_path=cfg_path,
|
|
sd_path=sd_path,
|
|
started_ckpt_dir=ckpt_dir,
|
|
tiled_vae=base_sampler.configs.tiled_vae,
|
|
color_fix=color_fix,
|
|
chopping_size=chopping_size,
|
|
)
|
|
configs = get_configs(args, log=True)
|
|
configs["cfg_scale"] = cfg
|
|
# configs["basesr"]["sf"] = scale_factor
|
|
|
|
base_sampler.configs = configs
|
|
base_sampler.setup_seed(seed)
|
|
sampler = InvSamplerSR(base_sampler)
|
|
|
|
images_bchw = images.permute(0,3,1,2)
|
|
og_h, og_w = images_bchw.shape[2:]
|
|
|
|
# Calculate new dimensions divisible by 16
|
|
new_height = ((og_h + 15) // 16) * 16 # Round up to nearest multiple of 16
|
|
new_width = ((og_w + 15) // 16) * 16
|
|
resized = False
|
|
|
|
if og_h != new_height or og_w != new_width:
|
|
resized = True
|
|
print(f"[InvSR] - Image not divisible by 16. Resizing to {new_height} (h) x {new_width} (w)")
|
|
images_bchw = F.interpolate(images_bchw, size=(new_height, new_width), mode='bicubic', align_corners=False)
|
|
|
|
batches = split_tensor_into_batches(images_bchw, batch_size)
|
|
|
|
results = []
|
|
pbar = ProgressBar(len(batches))
|
|
|
|
for batch in batches:
|
|
result = sampler.inference(image_bchw=batch)
|
|
results.append(torch.from_numpy(result))
|
|
pbar.update(1)
|
|
|
|
result_t = torch.cat(results, dim=0)
|
|
|
|
# Resize to original dimensions * 4
|
|
if resized:
|
|
result_t = F.interpolate(result_t, size=(og_h * 4, og_w * 4), mode='bicubic', align_corners=False)
|
|
|
|
return (result_t.permute(0,2,3,1),)
|