Added FreeNoise noise_type, cleaned up forward_timestep_embed_factory

This commit is contained in:
Jedrzej Kosinski
2024-01-09 09:00:07 -06:00
parent 25e9a9dcda
commit 82fc5fc441
3 changed files with 76 additions and 50 deletions
+1
View File
@@ -510,6 +510,7 @@ class InjectionParams:
def set_noise_extra_args(self, noise_extra_args: dict):
noise_extra_args["context_length"] = self.context_length
noise_extra_args["context_overlap"] = self.context_overlap
def set_context(self, context_length: int, context_stride: int, context_overlap: int, context_schedule: str, closed_loop: bool, sync_context_to_pe: bool=False):
self.context_length = context_length
+50 -7
View File
@@ -25,8 +25,9 @@ class NoiseLayerType:
CONSTANT = "constant"
EMPTY = "empty"
REPEATED_CONTEXT = "repeated_context"
FREENOISE = "FreeNoise"
LIST = [DEFAULT, CONSTANT, EMPTY, REPEATED_CONTEXT]
LIST = [DEFAULT, CONSTANT, EMPTY, REPEATED_CONTEXT, FREENOISE]
class NoiseApplication:
@@ -209,7 +210,7 @@ class SeedNoiseGeneration:
final_noise = torch.randn(offset_shape, dtype=latents.dtype, layout=latents.layout, generator=generator, device="cpu")
final_noise = final_noise[batch_offset:]
# convert to derivative noise type, if needed
derivative_noise = SeedNoiseGeneration._create_derivative_noise(final_noise, noise_type=noise_type, extra_args=extra_args)
derivative_noise = SeedNoiseGeneration._create_derivative_noise(final_noise, noise_type=noise_type, seed=seed, extra_args=extra_args)
if derivative_noise is not None:
return derivative_noise
return final_noise
@@ -235,7 +236,7 @@ class SeedNoiseGeneration:
all_noises.append(torch.randn(single_shape, dtype=latents.dtype, layout=latents.layout, generator=generator, device="cpu"))
final_noise = torch.cat(all_noises, dim=0)
# convert to derivative noise type, if needed
derivative_noise = SeedNoiseGeneration._create_derivative_noise(final_noise, noise_type=noise_type, extra_args=extra_args)
derivative_noise = SeedNoiseGeneration._create_derivative_noise(final_noise, noise_type=noise_type, seed=seed, extra_args=extra_args)
if derivative_noise is not None:
return derivative_noise
return final_noise
@@ -260,14 +261,14 @@ class SeedNoiseGeneration:
return None
@staticmethod
def _create_derivative_noise(noise: Tensor, noise_type: str, extra_args: dict):
def _create_derivative_noise(noise: Tensor, noise_type: str, seed: int, extra_args: dict):
derivative_func = DERIVATIVE_NOISE_FUNC_MAP.get(noise_type, None)
if derivative_func is None:
return None
return derivative_func(noise=noise, extra_args=extra_args)
return derivative_func(noise=noise, seed=seed, extra_args=extra_args)
@staticmethod
def _convert_to_repeated_context(noise: Tensor, extra_args: dict):
def _convert_to_repeated_context(noise: Tensor, extra_args: dict, **kwargs):
# if no context_length, return unmodified noise
context_length: int = extra_args["context_length"]
if context_length is None:
@@ -277,8 +278,50 @@ class SeedNoiseGeneration:
cat_count = (length // context_length) + 1
return torch.cat([noise] * cat_count, dim=0)[:length]
@staticmethod
def _convert_to_freenoise(noise: Tensor, extra_args: dict, seed: int, **kwargs):
# if no context_length, return unmodified noise
context_length: int = extra_args["context_length"]
context_overlap: int = extra_args["context_overlap"]
video_length: int = noise.shape[0]
if context_length is None:
return noise
delta = context_length - context_overlap
generator = torch.manual_seed(seed)
DERIVATIVE_NOISE_FUNC_MAP = {NoiseLayerType.REPEATED_CONTEXT: SeedNoiseGeneration._convert_to_repeated_context,}
for start_idx in range(0, video_length-context_length, delta):
# start_idx corresponds to the beginning of a context window
# goal: place shuffled in the delta region right after the end of the context window
# if space after context window is not enough to place the noise, adjust and finish
place_idx = start_idx + context_length
# if place_idx is outside the valid indexes, we are already finished
if place_idx >= video_length:
break
end_idx = place_idx - 1
# if there is not enough room to copy delta amount of indexes, copy limited amount and finish
if end_idx + delta >= video_length:
final_delta = video_length - place_idx
# generate list of indexes in final delta region
list_idx = torch.Tensor(list(range(start_idx,start_idx+final_delta))).to(torch.long)
# shuffle list
list_idx = list_idx[torch.randperm(final_delta, generator=generator)]
# apply shuffled indexes
noise[place_idx:place_idx+final_delta] = noise[list_idx]
break
# otherwise, do normal behavior
# generate list of indexes in delta region
list_idx = torch.Tensor(list(range(start_idx,start_idx+delta))).to(torch.long)
# shuffle list
list_idx = list_idx[torch.randperm(delta, generator=generator)]
# apply shuffled indexes
noise[place_idx:place_idx+delta] = noise[list_idx]
return noise
DERIVATIVE_NOISE_FUNC_MAP = {
NoiseLayerType.REPEATED_CONTEXT: SeedNoiseGeneration._convert_to_repeated_context,
NoiseLayerType.FREENOISE: SeedNoiseGeneration._convert_to_freenoise,
}
class IterationOptions:
+25 -43
View File
@@ -78,49 +78,31 @@ ADGS = AnimateDiffHelper_GlobalState()
# refer to forward_timestep_embed in comfy/ldm/modules/diffusionmodules/openaimodel.py
def forward_timestep_embed_factory() -> Callable:
if hasattr(attention, "SpatialVideoTransformer"):
def forward_timestep_embed(ts, x, emb, context=None, transformer_options={}, output_shape=None, time_context=None, num_video_frames=None, image_only_indicator=None):
for layer in ts:
if isinstance(layer, openaimodel.VideoResBlock):
x = layer(x, emb, num_video_frames, image_only_indicator)
elif isinstance(layer, openaimodel.TimestepBlock):
x = layer(x, emb)
elif isinstance(layer, VanillaTemporalModule):
x = layer(x, context)
elif isinstance(layer, attention.SpatialVideoTransformer):
x = layer(x, context, time_context, num_video_frames, image_only_indicator, transformer_options)
if "transformer_index" in transformer_options:
transformer_options["transformer_index"] += 1
if "current_index" in transformer_options: # keep this for backward compat, for now
transformer_options["current_index"] += 1
elif isinstance(layer, attention.SpatialTransformer):
x = layer(x, context, transformer_options)
if "transformer_index" in transformer_options:
transformer_options["transformer_index"] += 1
if "current_index" in transformer_options: # keep this for backward compat, for now
transformer_options["current_index"] += 1
elif isinstance(layer, openaimodel.Upsample):
x = layer(x, output_shape=output_shape)
else:
x = layer(x)
return x
# keep old version for backwards compatibility (TODO: remove at end of 2023)
else:
def forward_timestep_embed(ts, x, emb, context=None, transformer_options={}, output_shape=None):
for layer in ts:
if isinstance(layer, openaimodel.TimestepBlock):
x = layer(x, emb)
elif isinstance(layer, VanillaTemporalModule):
x = layer(x, context)
elif isinstance(layer, attention.SpatialTransformer):
x = layer(x, context, transformer_options)
if "current_index" in transformer_options:
transformer_options["current_index"] += 1
elif isinstance(layer, openaimodel.Upsample):
x = layer(x, output_shape=output_shape)
else:
x = layer(x)
return x
def forward_timestep_embed(ts, x, emb, context=None, transformer_options={}, output_shape=None, time_context=None, num_video_frames=None, image_only_indicator=None):
for layer in ts:
if isinstance(layer, openaimodel.VideoResBlock):
x = layer(x, emb, num_video_frames, image_only_indicator)
elif isinstance(layer, openaimodel.TimestepBlock):
x = layer(x, emb)
elif isinstance(layer, VanillaTemporalModule):
x = layer(x, context)
elif isinstance(layer, attention.SpatialVideoTransformer):
x = layer(x, context, time_context, num_video_frames, image_only_indicator, transformer_options)
if "transformer_index" in transformer_options:
transformer_options["transformer_index"] += 1
if "current_index" in transformer_options: # keep this for backward compat, for now
transformer_options["current_index"] += 1
elif isinstance(layer, attention.SpatialTransformer):
x = layer(x, context, transformer_options)
if "transformer_index" in transformer_options:
transformer_options["transformer_index"] += 1
if "current_index" in transformer_options: # keep this for backward compat, for now
transformer_options["current_index"] += 1
elif isinstance(layer, openaimodel.Upsample):
x = layer(x, output_shape=output_shape)
else:
x = layer(x)
return x
return forward_timestep_embed