Asymmetric Tiled KSampler¶
Documentation¶
- Class name:
Asymmetric Tiled KSampler
- Category:
Sampling/Tiled
- Output node:
False
This node specializes in generating samples through a tiling approach that allows for asymmetric adjustments to the tiling pattern. It modifies the convolutional layers of a model to use circular or constant padding based on the tiling configuration, enabling more flexible and potentially more aesthetically pleasing image generation.
Input types¶
Required¶
model
- The model parameter represents the generative model to be used for sampling. It is crucial as it defines the architecture and parameters that will be adjusted for asymmetric tiling during the sampling process.
- Comfy dtype:
MODEL
- Python dtype:
torch.nn.Module
seed
- The seed parameter ensures reproducibility of the sampling process by initializing the random number generator to a specific state.
- Comfy dtype:
INT
- Python dtype:
int
tileX
- The tileX parameter controls the horizontal tiling behavior, allowing for circular or constant padding to be applied asymmetrically.
- Comfy dtype:
INT
- Python dtype:
int
tileY
- The tileY parameter controls the vertical tiling behavior, complementing tileX by enabling asymmetric padding adjustments in the vertical direction.
- Comfy dtype:
INT
- Python dtype:
int
steps
- The steps parameter determines the number of iterations the sampling process will undergo, affecting the detail and quality of the generated sample.
- Comfy dtype:
INT
- Python dtype:
int
cfg
- The cfg parameter adjusts the conditioning factor, influencing the strength of the conditioning signal during the sampling process.
- Comfy dtype:
FLOAT
- Python dtype:
float
sampler_name
- The sampler_name parameter specifies the sampling algorithm to be used, impacting the characteristics of the generated sample.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
scheduler
- The scheduler parameter selects the scheduling algorithm for controlling the sampling process, affecting the progression of sampling steps.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
positive
- The positive parameter provides positive conditioning information, guiding the sampling process towards desired attributes.
- Comfy dtype:
CONDITIONING
- Python dtype:
str
negative
- The negative parameter provides negative conditioning information, steering the sampling process away from undesired attributes.
- Comfy dtype:
CONDITIONING
- Python dtype:
str
latent_image
- The latent_image parameter represents the initial state in the latent space from which the sampling process begins.
- Comfy dtype:
LATENT
- Python dtype:
torch.Tensor
denoise
- The denoise parameter controls the level of denoising applied during the sampling process, affecting the clarity and smoothness of the generated sample.
- Comfy dtype:
FLOAT
- Python dtype:
float
Output types¶
latent
- Comfy dtype:
LATENT
- The output is a modified latent representation, reflecting the asymmetric tiling adjustments and sampling process.
- Python dtype:
torch.Tensor
- Comfy dtype:
Usage tips¶
- Infra type:
GPU
- Common nodes: unknown
Source code¶
class Asymmetric_Tiled_KSampler:
@classmethod
def INPUT_TYPES(cls):
return {"required":
{"model": ("MODEL", ),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"tileX": ("INT", {"default": 1, "min": 0, "max": 1}),
"tileY": ("INT", {"default": 1, "min": 0, "max": 1}),
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, ),
"positive": ("CONDITIONING", ),
"negative": ("CONDITIONING", ),
"latent_image": ("LATENT", ),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
}}
RETURN_TYPES = ("LATENT",)
FUNCTION = "sample"
CATEGORY = "Sampling/Tiled"
def apply_asymmetric_tiling(self, model, tileX, tileY):
for layer in [layer for layer in model.modules() if isinstance(layer, torch.nn.Conv2d)]:
layer.padding_modeX = 'circular' if tileX else 'constant'
layer.padding_modeY = 'circular' if tileY else 'constant'
layer.paddingX = (layer._reversed_padding_repeated_twice[0], layer._reversed_padding_repeated_twice[1], 0, 0)
layer.paddingY = (0, 0, layer._reversed_padding_repeated_twice[2], layer._reversed_padding_repeated_twice[3])
print(layer.paddingX, layer.paddingY)
def __hijackConv2DMethods(self, model, tileX: bool, tileY: bool):
for layer in [l for l in model.modules() if isinstance(l, torch.nn.Conv2d)]:
layer.padding_modeX = 'circular' if tileX else 'constant'
layer.padding_modeY = 'circular' if tileY else 'constant'
layer.paddingX = (layer._reversed_padding_repeated_twice[0], layer._reversed_padding_repeated_twice[1], 0, 0)
layer.paddingY = (0, 0, layer._reversed_padding_repeated_twice[2], layer._reversed_padding_repeated_twice[3])
def make_bound_method(method, current_layer):
def bound_method(self, *args, **kwargs): # Add 'self' here
return method(current_layer, *args, **kwargs)
return bound_method
bound_method = make_bound_method(self.__replacementConv2DConvForward, layer)
layer._conv_forward = bound_method.__get__(layer, type(layer))
def __replacementConv2DConvForward(self, layer, input: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor]):
working = torch.nn.functional.pad(input, layer.paddingX, mode=layer.padding_modeX)
working = torch.nn.functional.pad(working, layer.paddingY, mode=layer.padding_modeY)
return torch.nn.functional.conv2d(working, weight, bias, layer.stride, (0, 0), layer.dilation, layer.groups)
def __restoreConv2DMethods(self, model):
for layer in [l for l in model.modules() if isinstance(l, torch.nn.Conv2d)]:
layer._conv_forward = torch.nn.Conv2d._conv_forward.__get__(layer, torch.nn.Conv2d)
def sample(self, model, seed, tileX, tileY, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0):
self.__hijackConv2DMethods(model.model, tileX == 1, tileY == 1)
result = nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise)
self.__restoreConv2DMethods(model.model)
return result