From adc31ec77d92dd2191441172fe73a9a728da834b Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 3 Jun 2025 20:08:35 -0600 Subject: [PATCH 01/10] Small updates and bug fixes for various things --- extensions_built_in/sd_trainer/SDTrainer.py | 2 ++ jobs/process/TrainVAEProcess.py | 31 ++++++++++++++++++--- toolkit/lora_special.py | 13 +++++++-- toolkit/losses.py | 16 +++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/extensions_built_in/sd_trainer/SDTrainer.py b/extensions_built_in/sd_trainer/SDTrainer.py index 7468e0fc..ba44ff8d 100644 --- a/extensions_built_in/sd_trainer/SDTrainer.py +++ b/extensions_built_in/sd_trainer/SDTrainer.py @@ -764,6 +764,7 @@ class SDTrainer(BaseSDTrainProcess): conditional_embeds: Union[PromptEmbeds, None] = None, unconditional_embeds: Union[PromptEmbeds, None] = None, batch: Optional['DataLoaderBatchDTO'] = None, + is_primary_pred: bool = False, **kwargs, ): dtype = get_torch_dtype(self.train_config.dtype) @@ -1553,6 +1554,7 @@ class SDTrainer(BaseSDTrainProcess): conditional_embeds=conditional_embeds.to(self.device_torch, dtype=dtype), unconditional_embeds=unconditional_embeds, batch=batch, + is_primary_pred=True, **pred_kwargs ) self.after_unet_predict() diff --git a/jobs/process/TrainVAEProcess.py b/jobs/process/TrainVAEProcess.py index 0b6d5fab..4530b7cd 100644 --- a/jobs/process/TrainVAEProcess.py +++ b/jobs/process/TrainVAEProcess.py @@ -18,7 +18,7 @@ from jobs.process import BaseTrainProcess from toolkit.image_utils import show_tensors from toolkit.kohya_model_util import load_vae, convert_diffusers_back_to_ldm from toolkit.data_loader import ImageDataset -from toolkit.losses import ComparativeTotalVariation, get_gradient_penalty, PatternLoss, total_variation +from toolkit.losses import ComparativeTotalVariation, get_gradient_penalty, PatternLoss, total_variation, total_variation_deltas from toolkit.metadata import get_meta_for_safetensors from toolkit.optimizer import get_optimizer from toolkit.style import get_style_model_and_losses @@ -283,10 +283,33 @@ class TrainVAEProcess(BaseTrainProcess): else: return torch.tensor(0.0, device=self.device) - def get_ltv_loss(self, latent): + def get_ltv_loss(self, latent, images): # loss to reduce the latent space variance if self.ltv_weight > 0: - return total_variation(latent).mean() + with torch.no_grad(): + images = images.to(latent.device, dtype=latent.dtype) + # resize down to latent size + images = torch.nn.functional.interpolate(images, size=(latent.shape[2], latent.shape[3]), mode='bilinear', align_corners=False) + + # mean the color channel and then expand to latent size + images = images.mean(dim=1, keepdim=True) + images = images.repeat(1, latent.shape[1], 1, 1) + + # normalize to a mean of 0 and std of 1 + images_mean = images.mean(dim=(2, 3), keepdim=True) + images_std = images.std(dim=(2, 3), keepdim=True) + images = (images - images_mean) / (images_std + 1e-6) + + # now we target the same std of the image for the latent space as to not reduce to 0 + + latent_tv = torch.abs(total_variation_deltas(latent)) + images_tv = torch.abs(total_variation_deltas(images)) + loss = torch.abs(latent_tv - images_tv) # keep it spatially aware + loss = loss.mean(dim=2, keepdim=True) + loss = loss.mean(dim=3, keepdim=True) # mean over height and width + loss = loss.mean(dim=1, keepdim=True) # mean over channels + loss = loss.mean() + return loss else: return torch.tensor(0.0, device=self.device) @@ -733,7 +756,7 @@ class TrainVAEProcess(BaseTrainProcess): mv_loss = torch.tensor(0.0, device=self.device, dtype=self.torch_dtype) if self.ltv_weight > 0: - ltv_loss = self.get_ltv_loss(latents) * self.ltv_weight + ltv_loss = self.get_ltv_loss(latents, batch) * self.ltv_weight else: ltv_loss = torch.tensor(0.0, device=self.device, dtype=self.torch_dtype) diff --git a/toolkit/lora_special.py b/toolkit/lora_special.py index b0c2d7f4..cd443735 100644 --- a/toolkit/lora_special.py +++ b/toolkit/lora_special.py @@ -7,7 +7,7 @@ import re import sys from typing import List, Optional, Dict, Type, Union import torch -from diffusers import UNet2DConditionModel, PixArtTransformer2DModel, AuraFlowTransformer2DModel +from diffusers import UNet2DConditionModel, PixArtTransformer2DModel, AuraFlowTransformer2DModel, WanTransformer3DModel from transformers import CLIPTextModel from toolkit.models.lokr import LokrModule @@ -522,6 +522,14 @@ class LoRASpecialNetwork(ToolkitNetworkMixin, LoRANetwork): transformer.pos_embed = self.transformer_pos_embed transformer.proj_out = self.transformer_proj_out + + elif base_model is not None and base_model.arch == "wan21": + transformer: WanTransformer3DModel = unet + self.transformer_pos_embed = copy.deepcopy(transformer.patch_embedding) + self.transformer_proj_out = copy.deepcopy(transformer.proj_out) + + transformer.patch_embedding = self.transformer_pos_embed + transformer.proj_out = self.transformer_proj_out else: unet: UNet2DConditionModel = unet @@ -539,7 +547,8 @@ class LoRASpecialNetwork(ToolkitNetworkMixin, LoRANetwork): all_params = super().prepare_optimizer_params(text_encoder_lr, unet_lr, default_lr) if self.full_train_in_out: - if self.is_pixart or self.is_auraflow or self.is_flux: + base_model = self.base_model_ref() if self.base_model_ref is not None else None + if self.is_pixart or self.is_auraflow or self.is_flux or (base_model is not None and base_model.arch == "wan21"): all_params.append({"lr": unet_lr, "params": list(self.transformer_pos_embed.parameters())}) all_params.append({"lr": unet_lr, "params": list(self.transformer_proj_out.parameters())}) else: diff --git a/toolkit/losses.py b/toolkit/losses.py index eeea3571..fef9310d 100644 --- a/toolkit/losses.py +++ b/toolkit/losses.py @@ -13,6 +13,22 @@ def total_variation(image): n_elements = image.shape[1] * image.shape[2] * image.shape[3] return ((torch.sum(torch.abs(image[:, :, :, :-1] - image[:, :, :, 1:])) + torch.sum(torch.abs(image[:, :, :-1, :] - image[:, :, 1:, :]))) / n_elements) + +def total_variation_deltas(image): + """ + Compute per-pixel total variation deltas. + Input: + - image: Tensor of shape (N, C, H, W) + Returns: + - Tensor with shape (N, C, H, W), padded to match input shape + """ + dh = torch.zeros_like(image) + dv = torch.zeros_like(image) + + dh[:, :, :, :-1] = torch.abs(image[:, :, :, 1:] - image[:, :, :, :-1]) + dv[:, :, :-1, :] = torch.abs(image[:, :, 1:, :] - image[:, :, :-1, :]) + + return dh + dv class ComparativeTotalVariation(torch.nn.Module): From 22cdfadab6e59bf27bd22bf28a650a7da23ca966 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Wed, 4 Jun 2025 01:16:02 -0600 Subject: [PATCH 02/10] Added new timestep weighing strategy --- extensions_built_in/sd_trainer/SDTrainer.py | 13 +- scripts/calculate_timestep_weighing_flex.py | 228 ++++ toolkit/config_modules.py | 2 +- toolkit/dataloader_mixins.py | 91 ++ toolkit/samplers/custom_flowmatch_sampler.py | 19 +- toolkit/timestep_weighing/__init__.py | 0 .../default_weighing_scheme.py | 1004 +++++++++++++++++ .../flex_timestep_weights_plot.png | Bin 0 -> 194021 bytes 8 files changed, 1348 insertions(+), 9 deletions(-) create mode 100644 scripts/calculate_timestep_weighing_flex.py create mode 100644 toolkit/timestep_weighing/__init__.py create mode 100644 toolkit/timestep_weighing/default_weighing_scheme.py create mode 100644 toolkit/timestep_weighing/flex_timestep_weights_plot.png diff --git a/extensions_built_in/sd_trainer/SDTrainer.py b/extensions_built_in/sd_trainer/SDTrainer.py index ba44ff8d..27e57025 100644 --- a/extensions_built_in/sd_trainer/SDTrainer.py +++ b/extensions_built_in/sd_trainer/SDTrainer.py @@ -501,13 +501,22 @@ class SDTrainer(BaseSDTrainProcess): loss = wavelet_loss(pred, batch.latents, noise) else: loss = torch.nn.functional.mse_loss(pred.float(), target.float(), reduction="none") + + do_weighted_timesteps = False + if self.sd.is_flow_matching: + if self.train_config.linear_timesteps or self.train_config.linear_timesteps2: + do_weighted_timesteps = True + if self.train_config.timestep_type == "weighted": + # use the noise scheduler to get the weights for the timesteps + do_weighted_timesteps = True # handle linear timesteps and only adjust the weight of the timesteps - if self.sd.is_flow_matching and (self.train_config.linear_timesteps or self.train_config.linear_timesteps2): + if do_weighted_timesteps: # calculate the weights for the timesteps timestep_weight = self.sd.noise_scheduler.get_weights_for_timesteps( timesteps, - v2=self.train_config.linear_timesteps2 + v2=self.train_config.linear_timesteps2, + timestep_type=self.train_config.timestep_type ).to(loss.device, dtype=loss.dtype) timestep_weight = timestep_weight.view(-1, 1, 1, 1).detach() loss = loss * timestep_weight diff --git a/scripts/calculate_timestep_weighing_flex.py b/scripts/calculate_timestep_weighing_flex.py new file mode 100644 index 00000000..05a21766 --- /dev/null +++ b/scripts/calculate_timestep_weighing_flex.py @@ -0,0 +1,228 @@ +import gc +import os, sys +from tqdm import tqdm +import numpy as np +import json +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +# set visible devices to 0 +# os.environ["CUDA_VISIBLE_DEVICES"] = "0" + +# protect from formatting +if True: + import torch + from optimum.quanto import freeze, qfloat8, QTensor, qint4 + from diffusers import FluxTransformer2DModel, FluxPipeline, AutoencoderKL, FlowMatchEulerDiscreteScheduler + from toolkit.util.quantize import quantize, get_qtype + from transformers import T5EncoderModel, T5TokenizerFast, CLIPTextModel, CLIPTokenizer + from torchvision import transforms + +qtype = "qfloat8" +dtype = torch.bfloat16 +# base_model_path = "black-forest-labs/FLUX.1-dev" +base_model_path = "ostris/Flex.1-alpha" +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") +print("Loading Transformer...") +prompt = "Photo of a man and a woman in a park, sunny day" + +output_root = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "output") +output_path = os.path.join(output_root, "flex_timestep_weights.json") +img_output_path = os.path.join(output_root, "flex_timestep_weights.png") + +quantization_type = get_qtype(qtype) + +def flush(): + torch.cuda.empty_cache() + gc.collect() + +pil_to_tensor = transforms.ToTensor() + +with torch.no_grad(): + transformer = FluxTransformer2DModel.from_pretrained( + base_model_path, + subfolder='transformer', + torch_dtype=dtype + ) + + transformer.to(device, dtype=dtype) + + print("Quantizing Transformer...") + quantize(transformer, weights=quantization_type) + freeze(transformer) + flush() + + print("Loading Scheduler...") + scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(base_model_path, subfolder="scheduler") + + print("Loading Autoencoder...") + vae = AutoencoderKL.from_pretrained(base_model_path, subfolder="vae", torch_dtype=dtype) + + vae.to(device, dtype=dtype) + + flush() + print("Loading Text Encoder...") + tokenizer_2 = T5TokenizerFast.from_pretrained(base_model_path, subfolder="tokenizer_2", torch_dtype=dtype) + text_encoder_2 = T5EncoderModel.from_pretrained(base_model_path, subfolder="text_encoder_2", torch_dtype=dtype) + text_encoder_2.to(device, dtype=dtype) + + print("Quantizing Text Encoder...") + quantize(text_encoder_2, weights=get_qtype(qtype)) + freeze(text_encoder_2) + flush() + + print("Loading CLIP") + text_encoder = CLIPTextModel.from_pretrained(base_model_path, subfolder="text_encoder", torch_dtype=dtype) + tokenizer = CLIPTokenizer.from_pretrained(base_model_path, subfolder="tokenizer", torch_dtype=dtype) + text_encoder.to(device, dtype=dtype) + + print("Making pipe") + + pipe: FluxPipeline = FluxPipeline( + scheduler=scheduler, + text_encoder=text_encoder, + tokenizer=tokenizer, + text_encoder_2=None, + tokenizer_2=tokenizer_2, + vae=vae, + transformer=None, + ) + pipe.text_encoder_2 = text_encoder_2 + pipe.transformer = transformer + + pipe.to(device, dtype=dtype) + + print("Encoding prompt...") + + prompt_embeds, pooled_prompt_embeds, text_ids = pipe.encode_prompt( + prompt, + prompt_2=prompt, + device=device + ) + + + generator = torch.manual_seed(42) + + height = 1024 + width = 1024 + + print("Generating image...") + + # Fix a bug in diffusers/torch + def callback_on_step_end(pipe, i, t, callback_kwargs): + latents = callback_kwargs["latents"] + if latents.dtype != dtype: + latents = latents.to(dtype) + return {"latents": latents} + img = pipe( + prompt_embeds=prompt_embeds, + pooled_prompt_embeds=pooled_prompt_embeds, + height=height, + width=height, + num_inference_steps=30, + guidance_scale=3.5, + generator=generator, + callback_on_step_end=callback_on_step_end, + ).images[0] + + img.save(img_output_path) + print(f"Image saved to {img_output_path}") + + print("Encoding image...") + # img is a PIL image. convert it to a -1 to 1 tensor + img = pil_to_tensor(img) + img = img.unsqueeze(0) # add batch dimension + img = img * 2 - 1 # convert to -1 to 1 range + img = img.to(device, dtype=dtype) + latents = vae.encode(img).latent_dist.sample() + + shift = vae.config['shift_factor'] if vae.config['shift_factor'] is not None else 0 + latents = vae.config['scaling_factor'] * (latents - shift) + + num_channels_latents = pipe.transformer.config.in_channels // 4 + + l_height = 2 * (int(height) // (pipe.vae_scale_factor * 2)) + l_width = 2 * (int(width) // (pipe.vae_scale_factor * 2)) + packed_latents = pipe._pack_latents(latents, 1, num_channels_latents, l_height, l_width) + + packed_latents, latent_image_ids = pipe.prepare_latents( + 1, + num_channels_latents, + height, + width, + prompt_embeds.dtype, + device, + generator, + packed_latents, + ) + + print("Calculating timestep weights...") + + torch.manual_seed(8675309) + noise = torch.randn_like(packed_latents, device=device, dtype=dtype) + + # Create linear timesteps from 1000 to 0 + num_train_timesteps = 1000 + timesteps_torch = torch.linspace(1000, 1, num_train_timesteps, device='cpu') + timesteps = np.linspace(1, num_train_timesteps, num_train_timesteps, dtype=np.float32)[::-1].copy() + timesteps = torch.from_numpy(timesteps).to(dtype=torch.float32) + + timestep_weights = torch.zeros(num_train_timesteps, dtype=torch.float32, device=device) + + guidance = torch.full([1], 1.0, device=device, dtype=torch.float32) + guidance = guidance.expand(latents.shape[0]) + + pbar = tqdm(range(num_train_timesteps), desc="loss: 0.000000 scaler: 0.0000") + for i in pbar: + timestep = timesteps[i:i+1].to(device) + t_01 = (timestep / 1000).to(device) + t_01 = t_01.reshape(-1, 1, 1) + noisy_latents = (1.0 - t_01) * packed_latents + t_01 * noise + + noise_pred = pipe.transformer( + hidden_states=noisy_latents, # torch.Size([1, 4096, 64]) + timestep=timestep / 1000, + guidance=guidance, + pooled_projections=pooled_prompt_embeds, + encoder_hidden_states=prompt_embeds, + txt_ids=text_ids, + img_ids=latent_image_ids, + return_dict=False, + )[0] + + target = noise - packed_latents + + loss = torch.nn.functional.mse_loss(noise_pred.float(), target.float()) + loss = loss + + # determine scaler to multiply loss by to make it 1 + scaler = 1.0 / (loss + 1e-6) + + timestep_weights[i] = scaler + pbar.set_description(f"loss: {loss.item():.6f} scaler: {scaler.item():.4f}") + + print("normalizing timestep weights...") + # normalize the timestep weights so they are a mean of 1.0 + timestep_weights = timestep_weights / timestep_weights.mean() + timestep_weights = timestep_weights.cpu().numpy().tolist() + + print("Saving timestep weights...") + + with open(output_path, 'w') as f: + json.dump(timestep_weights, f) + + +print(f"Timestep weights saved to {output_path}") +print("Done!") +flush() + + + + + + + + + + + + \ No newline at end of file diff --git a/toolkit/config_modules.py b/toolkit/config_modules.py index aa3d84a6..0202eb8e 100644 --- a/toolkit/config_modules.py +++ b/toolkit/config_modules.py @@ -437,7 +437,7 @@ class TrainConfig: # adds an additional loss to the network to encourage it output a normalized standard deviation self.target_norm_std = kwargs.get('target_norm_std', None) self.target_norm_std_value = kwargs.get('target_norm_std_value', 1.0) - self.timestep_type = kwargs.get('timestep_type', 'sigmoid') # sigmoid, linear, lognorm_blend, next_sample + self.timestep_type = kwargs.get('timestep_type', 'sigmoid') # sigmoid, linear, lognorm_blend, next_sample, weighted self.next_sample_timesteps = kwargs.get('next_sample_timesteps', 8) self.linear_timesteps = kwargs.get('linear_timesteps', False) self.linear_timesteps2 = kwargs.get('linear_timesteps2', False) diff --git a/toolkit/dataloader_mixins.py b/toolkit/dataloader_mixins.py index 7985bfe7..5f419ff0 100644 --- a/toolkit/dataloader_mixins.py +++ b/toolkit/dataloader_mixins.py @@ -1773,6 +1773,97 @@ class LatentCachingMixin: self.sd.restore_device_state() + +class TextEmbeddingCachingMixin: + def __init__(self: 'AiToolkitDataset', **kwargs): + # if we have super, call it + if hasattr(super(), '__init__'): + super().__init__(**kwargs) + self.is_caching_text_embeddings = self.dataset_config.cache_text_embeddings + + def cache_text_embeddings(self: 'AiToolkitDataset'): + + with accelerator.main_process_first(): + print_acc(f"Caching text_embeddings for {self.dataset_path}") + # cache all latents to disk + to_disk = self.is_caching_latents_to_disk + to_memory = self.is_caching_latents_to_memory + print_acc(" - Saving text embeddings to disk") + # move sd items to cpu except for vae + self.sd.set_device_state_preset('cache_latents') + + # use tqdm to show progress + i = 0 + for file_item in tqdm(self.file_list, desc=f'Caching latents{" to disk" if to_disk else ""}'): + # set latent space version + if self.sd.model_config.latent_space_version is not None: + file_item.latent_space_version = self.sd.model_config.latent_space_version + elif self.sd.is_xl: + file_item.latent_space_version = 'sdxl' + elif self.sd.is_v3: + file_item.latent_space_version = 'sd3' + elif self.sd.is_auraflow: + file_item.latent_space_version = 'sdxl' + elif self.sd.is_flux: + file_item.latent_space_version = 'flux1' + elif self.sd.model_config.is_pixart_sigma: + file_item.latent_space_version = 'sdxl' + else: + file_item.latent_space_version = self.sd.model_config.arch + file_item.is_caching_to_disk = to_disk + file_item.is_caching_to_memory = to_memory + file_item.latent_load_device = self.sd.device + + latent_path = file_item.get_latent_path(recalculate=True) + # check if it is saved to disk already + if os.path.exists(latent_path): + if to_memory: + # load it into memory + state_dict = load_file(latent_path, device='cpu') + file_item._encoded_latent = state_dict['latent'].to('cpu', dtype=self.sd.torch_dtype) + else: + # not saved to disk, calculate + # load the image first + file_item.load_and_process_image(self.transform, only_load_latents=True) + dtype = self.sd.torch_dtype + device = self.sd.device_torch + # add batch dimension + try: + imgs = file_item.tensor.unsqueeze(0).to(device, dtype=dtype) + latent = self.sd.encode_images(imgs).squeeze(0) + except Exception as e: + print_acc(f"Error processing image: {file_item.path}") + print_acc(f"Error: {str(e)}") + raise e + # save_latent + if to_disk: + state_dict = OrderedDict([ + ('latent', latent.clone().detach().cpu()), + ]) + # metadata + meta = get_meta_for_safetensors(file_item.get_latent_info_dict()) + os.makedirs(os.path.dirname(latent_path), exist_ok=True) + save_file(state_dict, latent_path, metadata=meta) + + if to_memory: + # keep it in memory + file_item._encoded_latent = latent.to('cpu', dtype=self.sd.torch_dtype) + + del imgs + del latent + del file_item.tensor + + # flush(garbage_collect=False) + file_item.is_latent_cached = True + i += 1 + # flush every 100 + # if i % 100 == 0: + # flush() + + # restore device state + self.sd.restore_device_state() + + class CLIPCachingMixin: def __init__(self: 'AiToolkitDataset', **kwargs): # if we have super, call it diff --git a/toolkit/samplers/custom_flowmatch_sampler.py b/toolkit/samplers/custom_flowmatch_sampler.py index 1e0ae2ab..bac7f3fd 100644 --- a/toolkit/samplers/custom_flowmatch_sampler.py +++ b/toolkit/samplers/custom_flowmatch_sampler.py @@ -4,6 +4,7 @@ from torch.distributions import LogNormal from diffusers import FlowMatchEulerDiscreteScheduler import torch import numpy as np +from toolkit.timestep_weighing.default_weighing_scheme import default_weighing_scheme def calculate_shift( @@ -47,20 +48,26 @@ class CustomFlowMatchEulerDiscreteScheduler(FlowMatchEulerDiscreteScheduler): hbsmntw_weighing[num_timesteps // 2:] = hbsmntw_weighing[num_timesteps // 2:].max() - # Create linear timesteps from 1000 to 0 - timesteps = torch.linspace(1000, 0, num_timesteps, device='cpu') + # Create linear timesteps from 1000 to 1 + timesteps = torch.linspace(1000, 1, num_timesteps, device='cpu') self.linear_timesteps = timesteps self.linear_timesteps_weights = bsmntw_weighing self.linear_timesteps_weights2 = hbsmntw_weighing pass - def get_weights_for_timesteps(self, timesteps: torch.Tensor, v2=False) -> torch.Tensor: + def get_weights_for_timesteps(self, timesteps: torch.Tensor, v2=False, timestep_type="linear") -> torch.Tensor: # Get the indices of the timesteps step_indices = [(self.timesteps == t).nonzero().item() for t in timesteps] # Get the weights for the timesteps + if timestep_type == "weighted": + weights = torch.tensor( + [default_weighing_scheme[i] for i in step_indices], + device=timesteps.device, + dtype=timesteps.dtype + ) if v2: weights = self.linear_timesteps_weights2[step_indices].flatten() else: @@ -106,8 +113,8 @@ class CustomFlowMatchEulerDiscreteScheduler(FlowMatchEulerDiscreteScheduler): patch_size=1 ): self.timestep_type = timestep_type - if timestep_type == 'linear': - timesteps = torch.linspace(1000, 0, num_timesteps, device=device) + if timestep_type == 'linear' or timestep_type == 'weighted': + timesteps = torch.linspace(1000, 1, num_timesteps, device=device) self.timesteps = timesteps return timesteps elif timestep_type == 'sigmoid': @@ -198,7 +205,7 @@ class CustomFlowMatchEulerDiscreteScheduler(FlowMatchEulerDiscreteScheduler): t1 = ((1 - t1/t1.max()) * 1000) # add half of linear - t2 = torch.linspace(1000, 0, int( + t2 = torch.linspace(1000, 1, int( num_timesteps * (1 - alpha)), device=device) timesteps = torch.cat((t1, t2)) diff --git a/toolkit/timestep_weighing/__init__.py b/toolkit/timestep_weighing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/toolkit/timestep_weighing/default_weighing_scheme.py b/toolkit/timestep_weighing/default_weighing_scheme.py new file mode 100644 index 00000000..72699744 --- /dev/null +++ b/toolkit/timestep_weighing/default_weighing_scheme.py @@ -0,0 +1,1004 @@ +# these weights were calculated using flex.1-alpha. A similar weighing scheme has been seen with other flowmatch models as well. + +default_weighing_scheme = [ + 0.905706524848938, + 0.9097874164581299, + 0.9251009821891785, + 0.9399133920669556, + 0.9497355818748474, + 0.962195873260498, + 0.9691638946533203, + 0.9927358627319336, + 1.01659095287323, + 1.0392684936523438, + 1.0429067611694336, + 1.0677919387817383, + 1.092896580696106, + 1.1149251461029053, + 1.1015851497650146, + 1.1209120750427246, + 1.1399472951889038, + 1.1559219360351562, + 1.143755555152893, + 1.160578727722168, + 1.1761468648910522, + 1.1895899772644043, + 1.1867371797561646, + 1.1993824243545532, + 1.2113513946533203, + 1.2201216220855713, + 1.221794605255127, + 1.2329251766204834, + 1.2426395416259766, + 1.251118540763855, + 1.2562459707260132, + 1.2668883800506592, + 1.2760146856307983, + 1.2822540998458862, + 1.2892439365386963, + 1.2972776889801025, + 1.3042182922363281, + 1.3104143142700195, + 1.3190876245498657, + 1.3253265619277954, + 1.3295484781265259, + 1.3324649333953857, + 1.3436106443405151, + 1.3482736349105835, + 1.351183533668518, + 1.3556060791015625, + 1.359933614730835, + 1.3625402450561523, + 1.3641390800476074, + 1.3723753690719604, + 1.3748365640640259, + 1.3776681423187256, + 1.3802807331085205, + 1.3848408460617065, + 1.3877429962158203, + 1.390969157218933, + 1.3927756547927856, + 1.4031920433044434, + 1.4064390659332275, + 1.4097232818603516, + 1.4132285118103027, + 1.4208053350448608, + 1.4254504442214966, + 1.4294012784957886, + 1.4323071241378784, + 1.44380521774292, + 1.4465110301971436, + 1.4490883350372314, + 1.451446533203125, + 1.458960771560669, + 1.460111379623413, + 1.4603426456451416, + 1.4595434665679932, + 1.4694839715957642, + 1.470526099205017, + 1.4705318212509155, + 1.4697961807250977, + 1.477265477180481, + 1.4771337509155273, + 1.4768965244293213, + 1.4760032892227173, + 1.4871419668197632, + 1.4877341985702515, + 1.488408088684082, + 1.489357829093933, + 1.4884581565856934, + 1.4882304668426514, + 1.4878745079040527, + 1.4949846267700195, + 1.4957915544509888, + 1.4951081275939941, + 1.4950779676437378, + 1.4995663166046143, + 1.4994632005691528, + 1.4986882209777832, + 1.4976568222045898, + 1.5038518905639648, + 1.503743052482605, + 1.502982258796692, + 1.502566933631897, + 1.5068002939224243, + 1.506575584411621, + 1.5067178010940552, + 1.5050104856491089, + 1.508437991142273, + 1.5073161125183105, + 1.506223440170288, + 1.504751205444336, + 1.512485384941101, + 1.5121595859527588, + 1.5116060972213745, + 1.5102864503860474, + 1.5156408548355103, + 1.5157924890518188, + 1.5142825841903687, + 1.5141233205795288, + 1.5191627740859985, + 1.518998622894287, + 1.5177574157714844, + 1.516713261604309, + 1.5186537504196167, + 1.5179635286331177, + 1.5159885883331299, + 1.5150446891784668, + 1.5226575136184692, + 1.5215232372283936, + 1.5201103687286377, + 1.5225480794906616, + 1.5215368270874023, + 1.520209789276123, + 1.5184354782104492, + 1.5220975875854492, + 1.5209708213806152, + 1.519667625427246, + 1.5177332162857056, + 1.5203157663345337, + 1.519271731376648, + 1.5175830125808716, + 1.5161852836608887, + 1.517741322517395, + 1.5163099765777588, + 1.5150357484817505, + 1.513055682182312, + 1.5154107809066772, + 1.513993501663208, + 1.5126358270645142, + 1.510875940322876, + 1.5125701427459717, + 1.510590672492981, + 1.5086392164230347, + 1.5068501234054565, + 1.5094420909881592, + 1.5080277919769287, + 1.5060293674468994, + 1.5040230751037598, + 1.504892110824585, + 1.5031654834747314, + 1.5013214349746704, + 1.499170184135437, + 1.500420331954956, + 1.4979915618896484, + 1.4959659576416016, + 1.494127631187439, + 1.4961415529251099, + 1.494597315788269, + 1.4926577806472778, + 1.4904958009719849, + 1.4913445711135864, + 1.489889144897461, + 1.4880430698394775, + 1.4873780012130737, + 1.485144019126892, + 1.4830609560012817, + 1.48123037815094, + 1.483134150505066, + 1.4808504581451416, + 1.4793643951416016, + 1.4773707389831543, + 1.4774049520492554, + 1.4752962589263916, + 1.4733281135559082, + 1.4712235927581787, + 1.470260500907898, + 1.4684780836105347, + 1.4657323360443115, + 1.4639259576797485, + 1.4644291400909424, + 1.4621423482894897, + 1.4604870080947876, + 1.4585931301116943, + 1.458650827407837, + 1.456871747970581, + 1.4548134803771973, + 1.4528228044509888, + 1.4519706964492798, + 1.4501826763153076, + 1.448083519935608, + 1.446316123008728, + 1.4454604387283325, + 1.4432463645935059, + 1.4412567615509033, + 1.4390138387680054, + 1.4388699531555176, + 1.437005877494812, + 1.4348008632659912, + 1.4327361583709717, + 1.4320861101150513, + 1.4304683208465576, + 1.4287059307098389, + 1.4264065027236938, + 1.424929141998291, + 1.4226492643356323, + 1.4205398559570312, + 1.4207192659378052, + 1.4187930822372437, + 1.4170515537261963, + 1.415097713470459, + 1.4142191410064697, + 1.412431001663208, + 1.4104442596435547, + 1.4082318544387817, + 1.4076896905899048, + 1.4057838916778564, + 1.4034852981567383, + 1.4016139507293701, + 1.4003900289535522, + 1.3983466625213623, + 1.3962912559509277, + 1.3940908908843994, + 1.3933204412460327, + 1.3910188674926758, + 1.3888089656829834, + 1.3865182399749756, + 1.3853325843811035, + 1.3832392692565918, + 1.3812776803970337, + 1.3789170980453491, + 1.3797601461410522, + 1.3777130842208862, + 1.3756908178329468, + 1.3735847473144531, + 1.3711339235305786, + 1.3690725564956665, + 1.366849660873413, + 1.364676833152771, + 1.364690899848938, + 1.362541675567627, + 1.3608990907669067, + 1.358725666999817, + 1.3566731214523315, + 1.3549315929412842, + 1.3522361516952515, + 1.3527694940567017, + 1.3506978750228882, + 1.3486748933792114, + 1.3464853763580322, + 1.344880223274231, + 1.3429863452911377, + 1.3410741090774536, + 1.3392194509506226, + 1.3374866247177124, + 1.3356633186340332, + 1.333699345588684, + 1.3316830396652222, + 1.3293700218200684, + 1.327602744102478, + 1.325606107711792, + 1.323636770248413, + 1.322487473487854, + 1.3201935291290283, + 1.3185865879058838, + 1.3163570165634155, + 1.315348505973816, + 1.3135069608688354, + 1.3115581274032593, + 1.309351921081543, + 1.3080940246582031, + 1.306084394454956, + 1.3041918277740479, + 1.3022172451019287, + 1.30052649974823, + 1.2984906435012817, + 1.296433925628662, + 1.294618844985962, + 1.2924813032150269, + 1.290629267692566, + 1.288609504699707, + 1.286437749862671, + 1.2852808237075806, + 1.2831010818481445, + 1.281022071838379, + 1.2789161205291748, + 1.2785669565200806, + 1.2766060829162598, + 1.274585485458374, + 1.2728400230407715, + 1.2709832191467285, + 1.2691309452056885, + 1.2671318054199219, + 1.265442132949829, + 1.2635501623153687, + 1.2614946365356445, + 1.2593908309936523, + 1.257880449295044, + 1.2560313940048218, + 1.254082441329956, + 1.2522804737091064, + 1.2505096197128296, + 1.2482692003250122, + 1.2462091445922852, + 1.2445822954177856, + 1.2432236671447754, + 1.2414650917053223, + 1.2396503686904907, + 1.2376699447631836, + 1.2357380390167236, + 1.2339240312576294, + 1.2320566177368164, + 1.2299892902374268, + 1.2286840677261353, + 1.226925015449524, + 1.2250070571899414, + 1.223126769065857, + 1.2215166091918945, + 1.2196996212005615, + 1.2178195714950562, + 1.2158279418945312, + 1.2140803337097168, + 1.2121261358261108, + 1.210100769996643, + 1.2083507776260376, + 1.2063525915145874, + 1.2046012878417969, + 1.2027149200439453, + 1.201154112815857, + 1.1992254257202148, + 1.1971834897994995, + 1.1951549053192139, + 1.1935709714889526, + 1.191764235496521, + 1.1898930072784424, + 1.187896728515625, + 1.186535120010376, + 1.184600591659546, + 1.1826894283294678, + 1.1809728145599365, + 1.1789331436157227, + 1.1774684190750122, + 1.1756458282470703, + 1.1736308336257935, + 1.1719911098480225, + 1.1701127290725708, + 1.1681468486785889, + 1.165921926498413, + 1.16463041305542, + 1.1627451181411743, + 1.1608567237854004, + 1.1590938568115234, + 1.1575335264205933, + 1.1555901765823364, + 1.1538552045822144, + 1.1518657207489014, + 1.14994215965271, + 1.1481153964996338, + 1.14644455909729, + 1.1444120407104492, + 1.1428122520446777, + 1.1410313844680786, + 1.1391836404800415, + 1.137330412864685, + 1.135434627532959, + 1.1336791515350342, + 1.131978154182434, + 1.1300874948501587, + 1.128359317779541, + 1.1264809370040894, + 1.1248611211776733, + 1.122762680053711, + 1.1209162473678589, + 1.1190710067749023, + 1.1172044277191162, + 1.1158984899520874, + 1.1140459775924683, + 1.1124012470245361, + 1.110682487487793, + 1.1087219715118408, + 1.106826901435852, + 1.1050584316253662, + 1.1034021377563477, + 1.1011031866073608, + 1.0996853113174438, + 1.0978131294250488, + 1.0963127613067627, + 1.0944904088974, + 1.0927494764328003, + 1.0910944938659668, + 1.0892736911773682, + 1.0878331661224365, + 1.0860958099365234, + 1.0842169523239136, + 1.0826303958892822, + 1.0806686878204346, + 1.078961730003357, + 1.0773676633834839, + 1.0755786895751953, + 1.073934555053711, + 1.0721861124038696, + 1.0704376697540283, + 1.0689181089401245, + 1.067183256149292, + 1.0654473304748535, + 1.0637754201889038, + 1.0620981454849243, + 1.0604465007781982, + 1.0587077140808105, + 1.0570865869522095, + 1.0553107261657715, + 1.053688883781433, + 1.0520380735397339, + 1.0502020120620728, + 1.048741340637207, + 1.046962022781372, + 1.0453627109527588, + 1.0439050197601318, + 1.041886806488037, + 1.0405514240264893, + 1.0387938022613525, + 1.0370451211929321, + 1.035706877708435, + 1.03403902053833, + 1.0325669050216675, + 1.0308712720870972, + 1.0291008949279785, + 1.0275760889053345, + 1.0258709192276, + 1.024153470993042, + 1.022807240486145, + 1.0211118459701538, + 1.019489049911499, + 1.0178107023239136, + 1.0159832239151, + 1.0143824815750122, + 1.0128840208053589, + 1.0111985206604004, + 1.0098742246627808, + 1.0081874132156372, + 1.0064918994903564, + 1.0050266981124878, + 1.0036821365356445, + 1.0018991231918335, + 1.0004172325134277, + 0.9988566637039185, + 0.9969817399978638, + 0.9954714179039001, + 0.9939242005348206, + 0.9923979640007019, + 0.9910774230957031, + 0.9894015789031982, + 0.9880895614624023, + 0.9861252903938293, + 0.9846389889717102, + 0.9831112027168274, + 0.9815076589584351, + 0.9799305200576782, + 0.9784950017929077, + 0.976923942565918, + 0.975475549697876, + 0.9737277626991272, + 0.9722781181335449, + 0.9707712531089783, + 0.9693742394447327, + 0.9677569270133972, + 0.9663806557655334, + 0.9648120999336243, + 0.963326096534729, + 0.9619874358177185, + 0.9605197906494141, + 0.9590029120445251, + 0.9575618505477905, + 0.9558634757995605, + 0.9542866945266724, + 0.9530059099197388, + 0.9513764977455139, + 0.9499674439430237, + 0.948621392250061, + 0.947046160697937, + 0.945502519607544, + 0.9441988468170166, + 0.9427464604377747, + 0.9413387179374695, + 0.9397821426391602, + 0.9385508894920349, + 0.9372508525848389, + 0.9356773495674133, + 0.9340954422950745, + 0.9325379133224487, + 0.9311357140541077, + 0.9296550154685974, + 0.9283716082572937, + 0.9268398880958557, + 0.9254037141799927, + 0.9239259362220764, + 0.9225856065750122, + 0.921108603477478, + 0.9197893142700195, + 0.9185012578964233, + 0.9169778823852539, + 0.9154301881790161, + 0.9140625, + 0.9127756357192993, + 0.9113842844963074, + 0.9101965427398682, + 0.9088224172592163, + 0.9074375629425049, + 0.9061430096626282, + 0.9046499133110046, + 0.9033547043800354, + 0.9018712639808655, + 0.9006990790367126, + 0.8993589878082275, + 0.8980291485786438, + 0.8965833187103271, + 0.8953617811203003, + 0.8940249681472778, + 0.8928234577178955, + 0.8914735913276672, + 0.8900470733642578, + 0.8885773420333862, + 0.887448251247406, + 0.8860753178596497, + 0.8848751783370972, + 0.8835704326629639, + 0.8822427988052368, + 0.8808343410491943, + 0.8794860243797302, + 0.8782272338867188, + 0.876940131187439, + 0.8755697011947632, + 0.8743593096733093, + 0.8731096982955933, + 0.8717764019966125, + 0.870373547077179, + 0.869137704372406, + 0.8679963946342468, + 0.8665465116500854, + 0.8653771281242371, + 0.8643192052841187, + 0.8630129098892212, + 0.8618021011352539, + 0.8606610894203186, + 0.8596193194389343, + 0.8584977984428406, + 0.8571111559867859, + 0.8558118343353271, + 0.854767382144928, + 0.8535858392715454, + 0.8525562882423401, + 0.851208508014679, + 0.8500548601150513, + 0.8489854335784912, + 0.8476380109786987, + 0.8465084433555603, + 0.8454263806343079, + 0.8440982699394226, + 0.8429536819458008, + 0.8419493436813354, + 0.8406177759170532, + 0.8395005464553833, + 0.83843994140625, + 0.8372390866279602, + 0.836262583732605, + 0.8351759910583496, + 0.8340833187103271, + 0.8330100178718567, + 0.8318305611610413, + 0.8307360410690308, + 0.8296796083450317, + 0.8287205696105957, + 0.8275678753852844, + 0.8264811038970947, + 0.8253570795059204, + 0.8243551254272461, + 0.8232539296150208, + 0.822137176990509, + 0.8212800025939941, + 0.8199703097343445, + 0.8190608024597168, + 0.8179953098297119, + 0.8167867064476013, + 0.8158150315284729, + 0.8149182200431824, + 0.8140754699707031, + 0.8131433129310608, + 0.8118599057197571, + 0.8109708428382874, + 0.8099024891853333, + 0.8090004324913025, + 0.8079776763916016, + 0.807029664516449, + 0.8058684468269348, + 0.8049055337905884, + 0.8039948344230652, + 0.803061306476593, + 0.8021382689476013, + 0.8012913465499878, + 0.8002091646194458, + 0.7992268204689026, + 0.7981467247009277, + 0.7973214983940125, + 0.7964017987251282, + 0.7954541444778442, + 0.7945792078971863, + 0.7938122153282166, + 0.7926003932952881, + 0.7917800545692444, + 0.7908596396446228, + 0.7899304628372192, + 0.7890149354934692, + 0.7882192730903625, + 0.7870058417320251, + 0.7863731980323792, + 0.7852027416229248, + 0.7844488024711609, + 0.783501386642456, + 0.7827003598213196, + 0.7819803357124329, + 0.7808201909065247, + 0.7800688147544861, + 0.7791293263435364, + 0.7784658670425415, + 0.7775732278823853, + 0.7768633961677551, + 0.7760342359542847, + 0.775243878364563, + 0.7743030786514282, + 0.7735926508903503, + 0.7724748849868774, + 0.7718163728713989, + 0.77097487449646, + 0.7702510356903076, + 0.7693900465965271, + 0.7687169313430786, + 0.7678922414779663, + 0.7672128081321716, + 0.7663589715957642, + 0.7657037377357483, + 0.7647771239280701, + 0.7640203237533569, + 0.7633466720581055, + 0.7625623941421509, + 0.7617509961128235, + 0.7610896229743958, + 0.760379433631897, + 0.7596492767333984, + 0.7588953971862793, + 0.7581916451454163, + 0.7573999166488647, + 0.7568274736404419, + 0.756077229976654, + 0.7554765939712524, + 0.7546539306640625, + 0.7539674043655396, + 0.753139853477478, + 0.7525543570518494, + 0.7519160509109497, + 0.7513154149055481, + 0.7505142688751221, + 0.7497125864028931, + 0.74923175573349, + 0.7484207153320312, + 0.7479155659675598, + 0.7473617792129517, + 0.7468436360359192, + 0.7462318539619446, + 0.7456430792808533, + 0.7447810769081116, + 0.7442206144332886, + 0.7435954809188843, + 0.7431489825248718, + 0.7422271370887756, + 0.7418114542961121, + 0.7412892580032349, + 0.740713357925415, + 0.7401546239852905, + 0.7396021485328674, + 0.7390599846839905, + 0.73844313621521, + 0.7377904653549194, + 0.737305223941803, + 0.7368288636207581, + 0.7363747358322144, + 0.7358483076095581, + 0.7354381680488586, + 0.7348212003707886, + 0.7343763709068298, + 0.7336553335189819, + 0.7332231402397156, + 0.73262619972229, + 0.7321929931640625, + 0.7315752506256104, + 0.7312256693840027, + 0.7306149005889893, + 0.7302426695823669, + 0.7299467325210571, + 0.7294563055038452, + 0.728706419467926, + 0.7283353209495544, + 0.7279900312423706, + 0.7276231646537781, + 0.7273217439651489, + 0.7269001007080078, + 0.7265130877494812, + 0.7261000871658325, + 0.7257733345031738, + 0.725188672542572, + 0.724976658821106, + 0.7242119908332825, + 0.7238465547561646, + 0.7236427664756775, + 0.7232236266136169, + 0.7227877974510193, + 0.7226144075393677, + 0.7221262454986572, + 0.7218216061592102, + 0.7215451002120972, + 0.7213869094848633, + 0.7209206819534302, + 0.7207257747650146, + 0.7203994989395142, + 0.7200448513031006, + 0.7197679281234741, + 0.7195186018943787, + 0.7190226912498474, + 0.7188836932182312, + 0.7186117768287659, + 0.7185105681419373, + 0.718199610710144, + 0.7180152535438538, + 0.7175536155700684, + 0.7173341512680054, + 0.7171205878257751, + 0.7168837189674377, + 0.7163654565811157, + 0.7162774801254272, + 0.7161651253700256, + 0.7160663604736328, + 0.7159175872802734, + 0.7157440185546875, + 0.7154026031494141, + 0.7153436541557312, + 0.715220034122467, + 0.7150475978851318, + 0.7150062322616577, + 0.7149052619934082, + 0.7147804498672485, + 0.7147180438041687, + 0.7146442532539368, + 0.7143230438232422, + 0.7142894268035889, + 0.7143252491950989, + 0.7141361236572266, + 0.7140751481056213, + 0.7138771414756775, + 0.7138750553131104, + 0.7138450145721436, + 0.7138748168945312, + 0.7137607336044312, + 0.7137340903282166, + 0.7137055993080139, + 0.7136792540550232, + 0.7135677337646484, + 0.7134214639663696, + 0.7135778069496155, + 0.7136402130126953, + 0.713737964630127, + 0.7136131525039673, + 0.7135958075523376, + 0.713367760181427, + 0.7136869430541992, + 0.7137601971626282, + 0.7137682437896729, + 0.7137079834938049, + 0.7138195633888245, + 0.713512122631073, + 0.7136629819869995, + 0.7137271761894226, + 0.7138593792915344, + 0.714098334312439, + 0.714293360710144, + 0.7142848372459412, + 0.7144456505775452, + 0.714730978012085, + 0.7147268652915955, + 0.7149925231933594, + 0.7151434421539307, + 0.7151704430580139, + 0.7152837514877319, + 0.7152866125106812, + 0.7155521512031555, + 0.7158286571502686, + 0.7161067724227905, + 0.7161760926246643, + 0.716302752494812, + 0.7165276408195496, + 0.716739296913147, + 0.7168811559677124, + 0.7171459794044495, + 0.7174181342124939, + 0.7176154255867004, + 0.7177509069442749, + 0.7180988192558289, + 0.718157172203064, + 0.7184935212135315, + 0.7185874581336975, + 0.7188709378242493, + 0.7191057801246643, + 0.7192631959915161, + 0.7195265293121338, + 0.7197085618972778, + 0.720137357711792, + 0.7203015089035034, + 0.7204228639602661, + 0.720592737197876, + 0.7209603786468506, + 0.7212156057357788, + 0.7214911580085754, + 0.72171950340271, + 0.7221818566322327, + 0.7225285768508911, + 0.7227242588996887, + 0.7229769825935364, + 0.7232232689857483, + 0.7235181927680969, + 0.7238690853118896, + 0.7240993976593018, + 0.7244613170623779, + 0.7245984673500061, + 0.7250016331672668, + 0.7251067161560059, + 0.7255734205245972, + 0.7258168458938599, + 0.7260231375694275, + 0.7262008786201477, + 0.7266826629638672, + 0.7266356945037842, + 0.7272213697433472, + 0.7274652719497681, + 0.7279736399650574, + 0.7281084656715393, + 0.7283049821853638, + 0.7285397052764893, + 0.7289696931838989, + 0.7293713688850403, + 0.72969651222229, + 0.7298030853271484, + 0.7300551533699036, + 0.7303762435913086, + 0.7306288480758667, + 0.7307636141777039, + 0.7312272787094116, + 0.7314295172691345, + 0.7316324710845947, + 0.7314282655715942, + 0.7316331267356873, + 0.7319273352622986, + 0.732114315032959, + 0.732216477394104, + 0.7322894930839539, + 0.7325413227081299, + 0.7325369715690613, + 0.7325401902198792, + 0.7323561906814575, + 0.7322503924369812, + 0.7322250008583069, + 0.7320146560668945, + 0.7321474552154541, + 0.732187032699585, + 0.7320796251296997, + 0.7315171360969543, + 0.7313243746757507, + 0.7310792803764343, + 0.7308080196380615, + 0.7306304574012756, + 0.7296295166015625, + 0.7289745807647705, + 0.7288649082183838, + 0.7281786799430847, + 0.7277448773384094, + 0.7272322177886963, + 0.7265949845314026, + 0.725848376750946, + 0.7252488136291504, + 0.7245422601699829, + 0.723800003528595, + 0.7228619456291199, + 0.7218728065490723, + 0.720892071723938, + 0.7198144793510437, + 0.7186352610588074, + 0.717454731464386, + 0.7162171602249146, + 0.7149246335029602, + 0.7136655449867249, + 0.7121627926826477, + 0.7108365297317505, + 0.7092090249061584, + 0.7076245546340942, + 0.7060236930847168, + 0.704273521900177, + 0.7023670673370361, + 0.7007937431335449, + 0.698858916759491, + 0.696875810623169, + 0.69483882188797, + 0.6926799416542053, + 0.6907360553741455, + 0.6884570121765137, + 0.68642657995224, + 0.6837813258171082, + 0.6816286444664001, + 0.6790634989738464, + 0.6767467260360718, + 0.6742716431617737, + 0.6715688705444336, + 0.6689924001693726, + 0.6662940382957458, + 0.6634176969528198, + 0.6603904962539673, + 0.6574862599372864, + 0.6544369459152222, + 0.651530385017395, + 0.6485568284988403, + 0.6453983187675476, + 0.6423068046569824, + 0.6392328143119812, + 0.6360040307044983, + 0.6325976252555847, + 0.6291093826293945, + 0.6256147623062134, + 0.6223041415214539, + 0.6188730001449585, + 0.615329921245575, + 0.6118036508560181, + 0.6081951260566711, + 0.604539155960083, + 0.6009404063224792, + 0.5972440242767334, + 0.5937116146087646, + 0.5897051692008972, + 0.5859677195549011, + 0.5821571946144104, + 0.578381359577179, + 0.5747998952865601, + 0.5709896683692932, + 0.5671953558921814, + 0.5633583068847656, + 0.5594204068183899, + 0.5555382370948792, + 0.5519280433654785, + 0.5482934713363647, + 0.544551432132721, + 0.5410515666007996, + 0.5374910831451416, + 0.5340041518211365, + 0.5304144024848938, + 0.5269584655761719, + 0.5235306620597839, + 0.520039975643158, + 0.516674280166626, + 0.513296902179718, + 0.5098193883895874, + 0.5064578652381897, + 0.5030517578125, + 0.4997297525405884, + 0.4967145025730133, + 0.49335765838623047, + 0.4902186989784241, + 0.486634224653244, + 0.48311659693717957, + 0.4792158007621765, + 0.4755136966705322, + 0.4720709025859833, + 0.4689248502254486, + 0.4660993814468384, + 0.46355342864990234, + 0.46058982610702515, + 0.45763304829597473, + 0.45535609126091003, + 0.45405313372612, + 0.45241352915763855, + 0.45207348465919495, + 0.45095735788345337, + 0.45052871108055115, + 0.449806272983551, + 0.4484655559062958, + 0.44648951292037964, + 0.44580715894699097, + 0.4447800815105438, + 0.4453802704811096, + 0.4472601115703583 +] \ No newline at end of file diff --git a/toolkit/timestep_weighing/flex_timestep_weights_plot.png b/toolkit/timestep_weighing/flex_timestep_weights_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..b77632e283f8c527fe94a70d838401f3e3452d9b GIT binary patch literal 194021 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 literal 0 HcmV?d00001 From eefa93f16e1e53a0389f05540264c41d9ae128c9 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Mon, 9 Jun 2025 11:19:21 -0600 Subject: [PATCH 03/10] Various code to support experiments. --- .vscode/launch.json | 12 + extensions_built_in/sd_trainer/SDTrainer.py | 7 +- jobs/process/BaseSDTrainProcess.py | 3 + requirements.txt | 2 +- toolkit/config_modules.py | 2 +- .../models/diffusion_feature_extraction.py | 240 +++++ toolkit/models/wan21/autoencoder_kl_wan.py | 865 ++++++++++++++++++ toolkit/models/wan21/wan21.py | 3 +- 8 files changed, 1129 insertions(+), 5 deletions(-) create mode 100644 toolkit/models/wan21/autoencoder_kl_wan.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 02d5cacf..abbc2f3d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -40,5 +40,17 @@ "console": "integratedTerminal", "justMyCode": false }, + { + "name": "Python: Debug Current File (cuda:1)", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "env": { + "CUDA_LAUNCH_BLOCKING": "1", + "CUDA_VISIBLE_DEVICES": "1" + }, + "justMyCode": false + }, ] } \ No newline at end of file diff --git a/extensions_built_in/sd_trainer/SDTrainer.py b/extensions_built_in/sd_trainer/SDTrainer.py index 27e57025..5d0105f2 100644 --- a/extensions_built_in/sd_trainer/SDTrainer.py +++ b/extensions_built_in/sd_trainer/SDTrainer.py @@ -438,7 +438,7 @@ class SDTrainer(BaseSDTrainProcess): dfe_loss += torch.nn.functional.mse_loss(pred_feature_list[i], target_feature_list[i], reduction="mean") additional_loss += dfe_loss * self.train_config.diffusion_feature_extractor_weight * 100.0 - elif self.dfe.version == 3: + elif self.dfe.version == 3 or self.dfe.version == 4: dfe_loss = self.dfe( noise=noise, noise_pred=noise_pred, @@ -518,7 +518,10 @@ class SDTrainer(BaseSDTrainProcess): v2=self.train_config.linear_timesteps2, timestep_type=self.train_config.timestep_type ).to(loss.device, dtype=loss.dtype) - timestep_weight = timestep_weight.view(-1, 1, 1, 1).detach() + if len(loss.shape) == 4: + timestep_weight = timestep_weight.view(-1, 1, 1, 1).detach() + elif len(loss.shape) == 5: + timestep_weight = timestep_weight.view(-1, 1, 1, 1, 1).detach() loss = loss * timestep_weight if self.train_config.do_prior_divergence and prior_pred is not None: diff --git a/jobs/process/BaseSDTrainProcess.py b/jobs/process/BaseSDTrainProcess.py index b4f768d9..064e89fc 100644 --- a/jobs/process/BaseSDTrainProcess.py +++ b/jobs/process/BaseSDTrainProcess.py @@ -1116,6 +1116,7 @@ class BaseSDTrainProcess(BaseTrainProcess): self.train_config.linear_timesteps, self.train_config.linear_timesteps2, self.train_config.timestep_type == 'linear', + self.train_config.timestep_type == 'one_step', ]) timestep_type = 'linear' if linear_timesteps else None @@ -1159,6 +1160,8 @@ class BaseSDTrainProcess(BaseTrainProcess): device=self.device_torch ) timestep_indices = timestep_indices.long() + elif self.train_config.timestep_type == 'one_step': + timestep_indices = torch.zeros((batch_size,), device=self.device_torch, dtype=torch.long) elif content_or_style in ['style', 'content']: # this is from diffusers training code # Cubic sampling for favoring later or earlier timesteps diff --git a/requirements.txt b/requirements.txt index 5bed325e..c893cdaf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ torchao==0.9.0 safetensors git+https://github.com/jaretburkett/easy_dwpose.git git+https://github.com/huggingface/diffusers@363d1ab7e24c5ed6c190abb00df66d9edb74383b -transformers==4.49.0 +transformers==4.52.4 lycoris-lora==1.8.3 flatten_json pyyaml diff --git a/toolkit/config_modules.py b/toolkit/config_modules.py index 0202eb8e..0e8b8af0 100644 --- a/toolkit/config_modules.py +++ b/toolkit/config_modules.py @@ -437,7 +437,7 @@ class TrainConfig: # adds an additional loss to the network to encourage it output a normalized standard deviation self.target_norm_std = kwargs.get('target_norm_std', None) self.target_norm_std_value = kwargs.get('target_norm_std_value', 1.0) - self.timestep_type = kwargs.get('timestep_type', 'sigmoid') # sigmoid, linear, lognorm_blend, next_sample, weighted + self.timestep_type = kwargs.get('timestep_type', 'sigmoid') # sigmoid, linear, lognorm_blend, next_sample, weighted, one_step self.next_sample_timesteps = kwargs.get('next_sample_timesteps', 8) self.linear_timesteps = kwargs.get('linear_timesteps', False) self.linear_timesteps2 = kwargs.get('linear_timesteps2', False) diff --git a/toolkit/models/diffusion_feature_extraction.py b/toolkit/models/diffusion_feature_extraction.py index 17b259e6..e911484a 100644 --- a/toolkit/models/diffusion_feature_extraction.py +++ b/toolkit/models/diffusion_feature_extraction.py @@ -1,3 +1,4 @@ +import math import torch import os from torch import nn @@ -351,12 +352,251 @@ class DiffusionFeatureExtractor3(nn.Module): return total_loss +class DiffusionFeatureExtractor4(nn.Module): + def __init__(self, device=torch.device("cuda"), dtype=torch.bfloat16, vae=None): + super().__init__() + self.version = 4 + if vae is None: + raise ValueError("vae must be provided for DFE4") + self.vae = vae + # image_encoder_path = "google/siglip-so400m-patch14-384" + image_encoder_path = "google/siglip2-so400m-patch16-naflex" + from transformers import Siglip2ImageProcessor, Siglip2VisionModel + try: + self.image_processor = Siglip2ImageProcessor.from_pretrained( + image_encoder_path) + except EnvironmentError: + self.image_processor = Siglip2ImageProcessor() + + self.image_processor.max_num_patches = 1024 + + self.vision_encoder = Siglip2VisionModel.from_pretrained( + image_encoder_path, + ignore_mismatched_sizes=True + ).to(device, dtype=dtype) + + self.losses = {} + self.log_every = 100 + self.step = 0 + + def _target_hw(self, h, w, patch, max_patches, eps: float = 1e-5): + def _snap(x, s): + x = math.ceil((x * s) / patch) * patch + return max(patch, int(x)) + + lo, hi = eps / 10, 1.0 + while hi - lo >= eps: + mid = (lo + hi) / 2 + th, tw = _snap(h, mid), _snap(w, mid) + if (th // patch) * (tw // patch) <= max_patches: + lo = mid + else: + hi = mid + return _snap(h, lo), _snap(w, lo) + + + def tensors_to_siglip_like_features(self, batch: torch.Tensor): + """ + Args: + batch: (bs, 3, H, W) tensor already in the desired value range + (e.g. [-1, 1] or [0, 1]); no extra rescale / normalize here. + + Returns: + dict( + pixel_values – (bs, L, P) where L = n_h*n_w, P = 3*patch*patch + pixel_attention_mask– (L,) all-ones + spatial_shapes – (n_h, n_w) + ) + """ + if batch.ndim != 4: + raise ValueError("Expected (bs, 3, H, W) tensor") + + bs, c, H, W = batch.shape + proc = self.image_processor + patch = proc.patch_size + max_patches = proc.max_num_patches + + # One shared resize for the whole batch + tgt_h, tgt_w = self._target_hw(H, W, patch, max_patches) + batch = torch.nn.functional.interpolate( + batch, size=(tgt_h, tgt_w), mode="bilinear", align_corners=False + ) + + n_h, n_w = tgt_h // patch, tgt_w // patch + # flat_dim = c * patch * patch + num_p = n_h * n_w + + # unfold → (bs, flat_dim, num_p) → (bs, num_p, flat_dim) + patches = ( + torch.nn.functional.unfold(batch, kernel_size=patch, stride=patch) + .transpose(1, 2) + ) + + attn_mask = torch.ones(num_p, dtype=torch.long, device=batch.device) + spatial = torch.tensor((n_h, n_w), device=batch.device, dtype=torch.int32) + + # repeat attn_mask for each batch element + attn_mask = attn_mask.unsqueeze(0).repeat(bs, 1) + spatial = spatial.unsqueeze(0).repeat(bs, 1) + + return { + "pixel_values": patches, # (bs, num_patches, patch_dim) + "pixel_attention_mask": attn_mask, # (num_patches,) + "spatial_shapes": spatial + } + + def get_siglip_features(self, tensors_0_1): + dtype = torch.bfloat16 + device = self.vae.device + + tensors_0_1 = torch.clamp(tensors_0_1, 0.0, 1.0) + + mean = torch.tensor(self.image_processor.image_mean).to( + device, dtype=dtype + ).detach() + std = torch.tensor(self.image_processor.image_std).to( + device, dtype=dtype + ).detach() + # tensors_0_1 = torch.clip((255. * tensors_0_1), 0, 255).round() / 255.0 + clip_image = (tensors_0_1 - mean.view([1, 3, 1, 1])) / std.view([1, 3, 1, 1]) + + encoder_kwargs = self.tensors_to_siglip_like_features(clip_image) + id_embeds = self.vision_encoder( + pixel_values=encoder_kwargs['pixel_values'], + pixel_attention_mask=encoder_kwargs['pixel_attention_mask'], + spatial_shapes=encoder_kwargs['spatial_shapes'], + output_hidden_states=True, + ) + + # embeds = id_embeds['hidden_states'][-2] # penultimate layer + embeds = id_embeds['pooler_output'] + return embeds + + def forward( + self, + noise, + noise_pred, + noisy_latents, + timesteps, + batch: DataLoaderBatchDTO, + scheduler: CustomFlowMatchEulerDiscreteScheduler, + clip_weight=1.0, + mse_weight=0.0, + model=None + ): + dtype = torch.bfloat16 + device = self.vae.device + tensors = batch.tensor.to(device, dtype=dtype) + is_video = False + # stack time for video models on the batch dimension + if len(noise_pred.shape) == 5: + # B, C, T, H, W = images.shape + # only take first time + noise = noise[:, :, 0, :, :] + noise_pred = noise_pred[:, :, 0, :, :] + noisy_latents = noisy_latents[:, :, 0, :, :] + is_video = True + + if len(tensors.shape) == 5: + # batch is different + # (B, T, C, H, W) + # only take first time + tensors = tensors[:, 0, :, :, :] + + if model is not None and hasattr(model, 'get_stepped_pred'): + stepped_latents = model.get_stepped_pred(noise_pred, noise) + else: + # stepped_latents = noise - noise_pred + # first we step the scheduler from current timestep to the very end for a full denoise + bs = noise_pred.shape[0] + noise_pred_chunks = torch.chunk(noise_pred, bs) + timestep_chunks = torch.chunk(timesteps, bs) + noisy_latent_chunks = torch.chunk(noisy_latents, bs) + stepped_chunks = [] + for idx in range(bs): + model_output = noise_pred_chunks[idx] + timestep = timestep_chunks[idx] + scheduler._step_index = None + scheduler._init_step_index(timestep) + sample = noisy_latent_chunks[idx].to(torch.float32) + + sigma = scheduler.sigmas[scheduler.step_index] + sigma_next = scheduler.sigmas[-1] # use last sigma for final step + prev_sample = sample + (sigma_next - sigma) * model_output + stepped_chunks.append(prev_sample) + + stepped_latents = torch.cat(stepped_chunks, dim=0) + + latents = stepped_latents.to(self.vae.device, dtype=self.vae.dtype) + + scaling_factor = self.vae.config['scaling_factor'] if 'scaling_factor' in self.vae.config else 1.0 + shift_factor = self.vae.config['shift_factor'] if 'shift_factor' in self.vae.config else 0.0 + latents = (latents / scaling_factor) + shift_factor + if is_video: + # if video, we need to unsqueeze the latents to match the vae input shape + latents = latents.unsqueeze(2) + tensors_n1p1 = self.vae.decode(latents).sample # -1 to 1 + + if is_video: + # if video, we need to squeeze the tensors to match the output shape + tensors_n1p1 = tensors_n1p1.squeeze(2) + + pred_images = (tensors_n1p1 + 1) / 2 # 0 to 1 + + total_loss = 0 + + with torch.no_grad(): + target_img = tensors.to(device, dtype=dtype) + # go from -1 to 1 to 0 to 1 + target_img = (target_img + 1) / 2 + if clip_weight > 0: + target_clip_output = self.get_siglip_features(target_img).detach() + if clip_weight > 0: + pred_clip_output = self.get_siglip_features(pred_images) + clip_loss = torch.nn.functional.mse_loss( + pred_clip_output.float(), target_clip_output.float() + ) * clip_weight + + if 'clip_loss' not in self.losses: + self.losses['clip_loss'] = clip_loss.item() + else: + self.losses['clip_loss'] += clip_loss.item() + + total_loss += clip_loss + if mse_weight > 0: + mse_loss = torch.nn.functional.mse_loss( + pred_images.float(), target_img.float() + ) * mse_weight + + if 'mse_loss' not in self.losses: + self.losses['mse_loss'] = mse_loss.item() + else: + self.losses['mse_loss'] += mse_loss.item() + + total_loss += mse_loss + + if self.step % self.log_every == 0 and self.step > 0: + print(f"DFE losses:") + for key in self.losses: + self.losses[key] /= self.log_every + # print in 2.000e-01 format + print(f" - {key}: {self.losses[key]:.3e}") + self.losses[key] = 0.0 + + # total_loss += mse_loss + self.step += 1 + + return total_loss def load_dfe(model_path, vae=None) -> DiffusionFeatureExtractor: if model_path == "v3": dfe = DiffusionFeatureExtractor3(vae=vae) dfe.eval() return dfe + if model_path == "v4": + dfe = DiffusionFeatureExtractor4(vae=vae) + dfe.eval() + return dfe if not os.path.exists(model_path): raise FileNotFoundError(f"Model file not found: {model_path}") # if it ende with safetensors diff --git a/toolkit/models/wan21/autoencoder_kl_wan.py b/toolkit/models/wan21/autoencoder_kl_wan.py new file mode 100644 index 00000000..4f5b6ebd --- /dev/null +++ b/toolkit/models/wan21/autoencoder_kl_wan.py @@ -0,0 +1,865 @@ +# Copyright 2025 The Wan Team and The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import List, Optional, Tuple, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.checkpoint + +from diffusers.configuration_utils import ConfigMixin, register_to_config +from diffusers.utils import logging +from diffusers.utils.accelerate_utils import apply_forward_hook +from diffusers.models.activations import get_activation +from diffusers.models.modeling_outputs import AutoencoderKLOutput +from diffusers.models.modeling_utils import ModelMixin +from diffusers.models.autoencoders.vae import DecoderOutput, DiagonalGaussianDistribution +import copy + + +logger = logging.get_logger(__name__) # pylint: disable=invalid-name + +CACHE_T = 2 + + +class WanCausalConv3d(nn.Conv3d): + r""" + A custom 3D causal convolution layer with feature caching support. + + This layer extends the standard Conv3D layer by ensuring causality in the time dimension and handling feature + caching for efficient inference. + + Args: + in_channels (int): Number of channels in the input image + out_channels (int): Number of channels produced by the convolution + kernel_size (int or tuple): Size of the convolving kernel + stride (int or tuple, optional): Stride of the convolution. Default: 1 + padding (int or tuple, optional): Zero-padding added to all three sides of the input. Default: 0 + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + kernel_size: Union[int, Tuple[int, int, int]], + stride: Union[int, Tuple[int, int, int]] = 1, + padding: Union[int, Tuple[int, int, int]] = 0, + ) -> None: + super().__init__( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + ) + + # Set up causal padding + self._padding = (self.padding[2], self.padding[2], self.padding[1], self.padding[1], 2 * self.padding[0], 0) + self.padding = (0, 0, 0) + + def forward(self, x, cache_x=None): + padding = list(self._padding) + if cache_x is not None and self._padding[4] > 0: + cache_x = cache_x.to(x.device) + x = torch.cat([cache_x, x], dim=2) + padding[4] -= cache_x.shape[2] + x = F.pad(x, padding) + return super().forward(x) + + +class WanRMS_norm(nn.Module): + r""" + A custom RMS normalization layer. + + Args: + dim (int): The number of dimensions to normalize over. + channel_first (bool, optional): Whether the input tensor has channels as the first dimension. + Default is True. + images (bool, optional): Whether the input represents image data. Default is True. + bias (bool, optional): Whether to include a learnable bias term. Default is False. + """ + + def __init__(self, dim: int, channel_first: bool = True, images: bool = True, bias: bool = False) -> None: + super().__init__() + broadcastable_dims = (1, 1, 1) if not images else (1, 1) + shape = (dim, *broadcastable_dims) if channel_first else (dim,) + + self.channel_first = channel_first + self.scale = dim**0.5 + self.gamma = nn.Parameter(torch.ones(shape)) + self.bias = nn.Parameter(torch.zeros(shape)) if bias else 0.0 + + def forward(self, x): + return F.normalize(x, dim=(1 if self.channel_first else -1)) * self.scale * self.gamma + self.bias + + +class WanUpsample(nn.Upsample): + r""" + Perform upsampling while ensuring the output tensor has the same data type as the input. + + Args: + x (torch.Tensor): Input tensor to be upsampled. + + Returns: + torch.Tensor: Upsampled tensor with the same data type as the input. + """ + + def forward(self, x): + return super().forward(x.float()).type_as(x) + + +class WanResample(nn.Module): + r""" + A custom resampling module for 2D and 3D data. + + Args: + dim (int): The number of input/output channels. + mode (str): The resampling mode. Must be one of: + - 'none': No resampling (identity operation). + - 'upsample2d': 2D upsampling with nearest-exact interpolation and convolution. + - 'upsample3d': 3D upsampling with nearest-exact interpolation, convolution, and causal 3D convolution. + - 'downsample2d': 2D downsampling with zero-padding and convolution. + - 'downsample3d': 3D downsampling with zero-padding, convolution, and causal 3D convolution. + """ + + def __init__(self, dim: int, mode: str) -> None: + super().__init__() + self.dim = dim + self.mode = mode + + # layers + if mode == "upsample2d": + self.resample = nn.Sequential( + WanUpsample(scale_factor=(2.0, 2.0), mode="nearest-exact"), nn.Conv2d(dim, dim // 2, 3, padding=1) + ) + elif mode == "upsample3d": + self.resample = nn.Sequential( + WanUpsample(scale_factor=(2.0, 2.0), mode="nearest-exact"), nn.Conv2d(dim, dim // 2, 3, padding=1) + ) + self.time_conv = WanCausalConv3d(dim, dim * 2, (3, 1, 1), padding=(1, 0, 0)) + + elif mode == "downsample2d": + self.resample = nn.Sequential(nn.ZeroPad2d((0, 1, 0, 1)), nn.Conv2d(dim, dim, 3, stride=(2, 2))) + elif mode == "downsample3d": + self.resample = nn.Sequential(nn.ZeroPad2d((0, 1, 0, 1)), nn.Conv2d(dim, dim, 3, stride=(2, 2))) + self.time_conv = WanCausalConv3d(dim, dim, (3, 1, 1), stride=(2, 1, 1), padding=(0, 0, 0)) + + else: + self.resample = nn.Identity() + + def forward(self, x, feat_cache=None, feat_idx=[0]): + b, c, t, h, w = x.size() + if self.mode == "upsample3d": + if feat_cache is not None: + idx = feat_idx[0] + if feat_cache[idx] is None: + feat_cache[idx] = "Rep" + feat_idx[0] += 1 + else: + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None and feat_cache[idx] != "Rep": + # cache last frame of last two chunk + cache_x = torch.cat( + [feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2 + ) + if cache_x.shape[2] < 2 and feat_cache[idx] is not None and feat_cache[idx] == "Rep": + cache_x = torch.cat([torch.zeros_like(cache_x).to(cache_x.device), cache_x], dim=2) + if feat_cache[idx] == "Rep": + x = self.time_conv(x) + else: + x = self.time_conv(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + + x = x.reshape(b, 2, c, t, h, w) + x = torch.stack((x[:, 0, :, :, :, :], x[:, 1, :, :, :, :]), 3) + x = x.reshape(b, c, t * 2, h, w) + t = x.shape[2] + x = x.permute(0, 2, 1, 3, 4).reshape(b * t, c, h, w) + x = self.resample(x) + x = x.view(b, t, x.size(1), x.size(2), x.size(3)).permute(0, 2, 1, 3, 4) + + if self.mode == "downsample3d": + if feat_cache is not None: + idx = feat_idx[0] + if feat_cache[idx] is None: + feat_cache[idx] = x.clone() + feat_idx[0] += 1 + else: + cache_x = x[:, :, -1:, :, :].clone() + x = self.time_conv(torch.cat([feat_cache[idx][:, :, -1:, :, :], x], 2)) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + return x + + +class WanResidualBlock(nn.Module): + r""" + A custom residual block module. + + Args: + in_dim (int): Number of input channels. + out_dim (int): Number of output channels. + dropout (float, optional): Dropout rate for the dropout layer. Default is 0.0. + non_linearity (str, optional): Type of non-linearity to use. Default is "silu". + """ + + def __init__( + self, + in_dim: int, + out_dim: int, + dropout: float = 0.0, + non_linearity: str = "silu", + ) -> None: + super().__init__() + self.in_dim = in_dim + self.out_dim = out_dim + self.nonlinearity = get_activation(non_linearity) + + # layers + self.norm1 = WanRMS_norm(in_dim, images=False) + self.conv1 = WanCausalConv3d(in_dim, out_dim, 3, padding=1) + self.norm2 = WanRMS_norm(out_dim, images=False) + self.dropout = nn.Dropout(dropout) + self.conv2 = WanCausalConv3d(out_dim, out_dim, 3, padding=1) + self.conv_shortcut = WanCausalConv3d(in_dim, out_dim, 1) if in_dim != out_dim else nn.Identity() + + def forward(self, x, feat_cache=None, feat_idx=[0]): + # Apply shortcut connection + h = self.conv_shortcut(x) + + # First normalization and activation + x = self.norm1(x) + x = self.nonlinearity(x) + + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + + x = self.conv1(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv1(x) + + # Second normalization and activation + x = self.norm2(x) + x = self.nonlinearity(x) + + # Dropout + x = self.dropout(x) + + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + + x = self.conv2(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv2(x) + + # Add residual connection + return x + h + + +class WanAttentionBlock(nn.Module): + r""" + Causal self-attention with a single head. + + Args: + dim (int): The number of channels in the input tensor. + """ + + def __init__(self, dim): + super().__init__() + self.dim = dim + + # layers + self.norm = WanRMS_norm(dim) + self.to_qkv = nn.Conv2d(dim, dim * 3, 1) + self.proj = nn.Conv2d(dim, dim, 1) + + def forward(self, x): + identity = x + batch_size, channels, time, height, width = x.size() + + x = x.permute(0, 2, 1, 3, 4).reshape(batch_size * time, channels, height, width) + x = self.norm(x) + + # compute query, key, value + qkv = self.to_qkv(x) + qkv = qkv.reshape(batch_size * time, 1, channels * 3, -1) + qkv = qkv.permute(0, 1, 3, 2).contiguous() + q, k, v = qkv.chunk(3, dim=-1) + + # apply attention + x = F.scaled_dot_product_attention(q, k, v) + + x = x.squeeze(1).permute(0, 2, 1).reshape(batch_size * time, channels, height, width) + + # output projection + x = self.proj(x) + + # Reshape back: [(b*t), c, h, w] -> [b, c, t, h, w] + x = x.view(batch_size, time, channels, height, width) + x = x.permute(0, 2, 1, 3, 4) + + return x + identity + + +class WanMidBlock(nn.Module): + """ + Middle block for WanVAE encoder and decoder. + + Args: + dim (int): Number of input/output channels. + dropout (float): Dropout rate. + non_linearity (str): Type of non-linearity to use. + """ + + def __init__(self, dim: int, dropout: float = 0.0, non_linearity: str = "silu", num_layers: int = 1): + super().__init__() + self.dim = dim + + # Create the components + resnets = [WanResidualBlock(dim, dim, dropout, non_linearity)] + attentions = [] + for _ in range(num_layers): + attentions.append(WanAttentionBlock(dim)) + resnets.append(WanResidualBlock(dim, dim, dropout, non_linearity)) + self.attentions = nn.ModuleList(attentions) + self.resnets = nn.ModuleList(resnets) + + self.gradient_checkpointing = False + + def forward(self, x, feat_cache=None, feat_idx=[0]): + # First residual block + x = self.resnets[0](x, feat_cache, feat_idx) + + # Process through attention and residual blocks + for attn, resnet in zip(self.attentions, self.resnets[1:]): + if attn is not None: + x = attn(x) + + x = resnet(x, feat_cache, feat_idx) + + return x + + +class WanEncoder3d(nn.Module): + r""" + A 3D encoder module. + + Args: + dim (int): The base number of channels in the first layer. + z_dim (int): The dimensionality of the latent space. + dim_mult (list of int): Multipliers for the number of channels in each block. + num_res_blocks (int): Number of residual blocks in each block. + attn_scales (list of float): Scales at which to apply attention mechanisms. + temperal_downsample (list of bool): Whether to downsample temporally in each block. + dropout (float): Dropout rate for the dropout layers. + non_linearity (str): Type of non-linearity to use. + """ + + def __init__( + self, + dim=128, + z_dim=4, + dim_mult=[1, 2, 4, 4], + num_res_blocks=2, + attn_scales=[], + temperal_downsample=[True, True, False], + dropout=0.0, + non_linearity: str = "silu", + ): + super().__init__() + self.dim = dim + self.z_dim = z_dim + self.dim_mult = dim_mult + self.num_res_blocks = num_res_blocks + self.attn_scales = attn_scales + self.temperal_downsample = temperal_downsample + self.nonlinearity = get_activation(non_linearity) + + # dimensions + dims = [dim * u for u in [1] + dim_mult] + scale = 1.0 + + # init block + self.conv_in = WanCausalConv3d(3, dims[0], 3, padding=1) + + # downsample blocks + self.down_blocks = nn.ModuleList([]) + for i, (in_dim, out_dim) in enumerate(zip(dims[:-1], dims[1:])): + # residual (+attention) blocks + for _ in range(num_res_blocks): + self.down_blocks.append(WanResidualBlock(in_dim, out_dim, dropout)) + if scale in attn_scales: + self.down_blocks.append(WanAttentionBlock(out_dim)) + in_dim = out_dim + + # downsample block + if i != len(dim_mult) - 1: + mode = "downsample3d" if temperal_downsample[i] else "downsample2d" + self.down_blocks.append(WanResample(out_dim, mode=mode)) + scale /= 2.0 + + # middle blocks + self.mid_block = WanMidBlock(out_dim, dropout, non_linearity, num_layers=1) + + # output blocks + self.norm_out = WanRMS_norm(out_dim, images=False) + self.conv_out = WanCausalConv3d(out_dim, z_dim, 3, padding=1) + + self.gradient_checkpointing = False + + def forward(self, x, feat_cache=None, feat_idx=[0]): + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + # cache last frame of last two chunk + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + x = self.conv_in(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv_in(x) + + ## downsamples + for layer in self.down_blocks: + if feat_cache is not None: + x = layer(x, feat_cache, feat_idx) + else: + x = layer(x) + + ## middle + x = self.mid_block(x, feat_cache, feat_idx) + + ## head + x = self.norm_out(x) + x = self.nonlinearity(x) + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + # cache last frame of last two chunk + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + x = self.conv_out(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv_out(x) + return x + + +class WanUpBlock(nn.Module): + """ + A block that handles upsampling for the WanVAE decoder. + + Args: + in_dim (int): Input dimension + out_dim (int): Output dimension + num_res_blocks (int): Number of residual blocks + dropout (float): Dropout rate + upsample_mode (str, optional): Mode for upsampling ('upsample2d' or 'upsample3d') + non_linearity (str): Type of non-linearity to use + """ + + def __init__( + self, + in_dim: int, + out_dim: int, + num_res_blocks: int, + dropout: float = 0.0, + upsample_mode: Optional[str] = None, + non_linearity: str = "silu", + ): + super().__init__() + self.in_dim = in_dim + self.out_dim = out_dim + + # Create layers list + resnets = [] + # Add residual blocks and attention if needed + current_dim = in_dim + for _ in range(num_res_blocks + 1): + resnets.append(WanResidualBlock(current_dim, out_dim, dropout, non_linearity)) + current_dim = out_dim + + self.resnets = nn.ModuleList(resnets) + + # Add upsampling layer if needed + self.upsamplers = None + if upsample_mode is not None: + self.upsamplers = nn.ModuleList([WanResample(out_dim, mode=upsample_mode)]) + + self.gradient_checkpointing = False + + def forward(self, x, feat_cache=None, feat_idx=[0]): + """ + Forward pass through the upsampling block. + + Args: + x (torch.Tensor): Input tensor + feat_cache (list, optional): Feature cache for causal convolutions + feat_idx (list, optional): Feature index for cache management + + Returns: + torch.Tensor: Output tensor + """ + for resnet in self.resnets: + if feat_cache is not None: + x = resnet(x, feat_cache, feat_idx) + else: + x = resnet(x) + + if self.upsamplers is not None: + if feat_cache is not None: + x = self.upsamplers[0](x, feat_cache, feat_idx) + else: + x = self.upsamplers[0](x) + return x + + +class WanDecoder3d(nn.Module): + r""" + A 3D decoder module. + + Args: + dim (int): The base number of channels in the first layer. + z_dim (int): The dimensionality of the latent space. + dim_mult (list of int): Multipliers for the number of channels in each block. + num_res_blocks (int): Number of residual blocks in each block. + attn_scales (list of float): Scales at which to apply attention mechanisms. + temperal_upsample (list of bool): Whether to upsample temporally in each block. + dropout (float): Dropout rate for the dropout layers. + non_linearity (str): Type of non-linearity to use. + """ + + def __init__( + self, + dim=128, + z_dim=4, + dim_mult=[1, 2, 4, 4], + num_res_blocks=2, + attn_scales=[], + temperal_upsample=[False, True, True], + dropout=0.0, + non_linearity: str = "silu", + ): + super().__init__() + self.dim = dim + self.z_dim = z_dim + self.dim_mult = dim_mult + self.num_res_blocks = num_res_blocks + self.attn_scales = attn_scales + self.temperal_upsample = temperal_upsample + + self.nonlinearity = get_activation(non_linearity) + + # dimensions + dims = [dim * u for u in [dim_mult[-1]] + dim_mult[::-1]] + scale = 1.0 / 2 ** (len(dim_mult) - 2) + + # init block + self.conv_in = WanCausalConv3d(z_dim, dims[0], 3, padding=1) + + # middle blocks + self.mid_block = WanMidBlock(dims[0], dropout, non_linearity, num_layers=1) + + # upsample blocks + self.up_blocks = nn.ModuleList([]) + for i, (in_dim, out_dim) in enumerate(zip(dims[:-1], dims[1:])): + # residual (+attention) blocks + if i > 0: + in_dim = in_dim // 2 + + # Determine if we need upsampling + upsample_mode = None + if i != len(dim_mult) - 1: + upsample_mode = "upsample3d" if temperal_upsample[i] else "upsample2d" + + # Create and add the upsampling block + up_block = WanUpBlock( + in_dim=in_dim, + out_dim=out_dim, + num_res_blocks=num_res_blocks, + dropout=dropout, + upsample_mode=upsample_mode, + non_linearity=non_linearity, + ) + self.up_blocks.append(up_block) + + # Update scale for next iteration + if upsample_mode is not None: + scale *= 2.0 + + # output blocks + self.norm_out = WanRMS_norm(out_dim, images=False) + self.conv_out = WanCausalConv3d(out_dim, 3, 3, padding=1) + + self.gradient_checkpointing = False + + def forward(self, x, feat_cache=None, feat_idx=[0]): + ## conv1 + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + # cache last frame of last two chunk + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + x = self.conv_in(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv_in(x) + + ## middle + if torch.is_grad_enabled() and self.gradient_checkpointing: + # middle + x = self._gradient_checkpointing_func(self.mid_block, x, feat_cache, feat_idx) + + ## upsamples + for up_block in self.up_blocks: + x = self._gradient_checkpointing_func(up_block, x, feat_cache, feat_idx) + + else: + x = self.mid_block(x, feat_cache, feat_idx) + + ## upsamples + for up_block in self.up_blocks: + x = up_block(x, feat_cache, feat_idx) + + ## head + x = self.norm_out(x) + x = self.nonlinearity(x) + if feat_cache is not None: + idx = feat_idx[0] + cache_x = x[:, :, -CACHE_T:, :, :].clone() + if cache_x.shape[2] < 2 and feat_cache[idx] is not None: + # cache last frame of last two chunk + cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2) + x = self.conv_out(x, feat_cache[idx]) + feat_cache[idx] = cache_x + feat_idx[0] += 1 + else: + x = self.conv_out(x) + return x + + +class AutoencoderKLWan(ModelMixin, ConfigMixin): + r""" + A VAE model with KL loss for encoding videos into latents and decoding latent representations into videos. + Introduced in [Wan 2.1]. + + This model inherits from [`ModelMixin`]. Check the superclass documentation for it's generic methods implemented + for all models (such as downloading or saving). + """ + + _supports_gradient_checkpointing = True + + @register_to_config + def __init__( + self, + base_dim: int = 96, + z_dim: int = 16, + dim_mult: Tuple[int] = [1, 2, 4, 4], + num_res_blocks: int = 2, + attn_scales: List[float] = [], + temperal_downsample: List[bool] = [False, True, True], + dropout: float = 0.0, + latents_mean: List[float] = [ + -0.7571, + -0.7089, + -0.9113, + 0.1075, + -0.1745, + 0.9653, + -0.1517, + 1.5508, + 0.4134, + -0.0715, + 0.5517, + -0.3632, + -0.1922, + -0.9497, + 0.2503, + -0.2921, + ], + latents_std: List[float] = [ + 2.8184, + 1.4541, + 2.3275, + 2.6558, + 1.2196, + 1.7708, + 2.6052, + 2.0743, + 3.2687, + 2.1526, + 2.8652, + 1.5579, + 1.6382, + 1.1253, + 2.8251, + 1.9160, + ], + ) -> None: + super().__init__() + + self.z_dim = z_dim + self.temperal_downsample = temperal_downsample + self.temperal_upsample = temperal_downsample[::-1] + + self.encoder = WanEncoder3d( + base_dim, z_dim * 2, dim_mult, num_res_blocks, attn_scales, self.temperal_downsample, dropout + ) + self.quant_conv = WanCausalConv3d(z_dim * 2, z_dim * 2, 1) + self.post_quant_conv = WanCausalConv3d(z_dim, z_dim, 1) + + self.decoder = WanDecoder3d( + base_dim, z_dim, dim_mult, num_res_blocks, attn_scales, self.temperal_upsample, dropout + ) + + def clear_cache(self): + def _count_conv3d(model): + count = 0 + for m in model.modules(): + if isinstance(m, WanCausalConv3d): + count += 1 + return count + + self._conv_num = _count_conv3d(self.decoder) + self._conv_idx = [0] + self._feat_map = [None] * self._conv_num + # cache encode + self._enc_conv_num = _count_conv3d(self.encoder) + self._enc_conv_idx = [0] + self._enc_feat_map = [None] * self._enc_conv_num + + def _encode(self, x: torch.Tensor) -> torch.Tensor: + self.clear_cache() + ## cache + t = x.shape[2] + iter_ = 1 + (t - 1) // 4 + for i in range(iter_): + self._enc_conv_idx = [0] + if i == 0: + out = self.encoder(x[:, :, :1, :, :], feat_cache=self._enc_feat_map, feat_idx=self._enc_conv_idx) + else: + out_ = self.encoder( + x[:, :, 1 + 4 * (i - 1) : 1 + 4 * i, :, :], + feat_cache=self._enc_feat_map, + feat_idx=self._enc_conv_idx, + ) + out = torch.cat([out, out_], 2) + + enc = self.quant_conv(out) + mu, logvar = enc[:, : self.z_dim, :, :, :], enc[:, self.z_dim :, :, :, :] + enc = torch.cat([mu, logvar], dim=1) + self.clear_cache() + return enc + + @apply_forward_hook + def encode( + self, x: torch.Tensor, return_dict: bool = True + ) -> Union[AutoencoderKLOutput, Tuple[DiagonalGaussianDistribution]]: + r""" + Encode a batch of images into latents. + + Args: + x (`torch.Tensor`): Input batch of images. + return_dict (`bool`, *optional*, defaults to `True`): + Whether to return a [`~models.autoencoder_kl.AutoencoderKLOutput`] instead of a plain tuple. + + Returns: + The latent representations of the encoded videos. If `return_dict` is True, a + [`~models.autoencoder_kl.AutoencoderKLOutput`] is returned, otherwise a plain `tuple` is returned. + """ + h = self._encode(x) + posterior = DiagonalGaussianDistribution(h) + if not return_dict: + return (posterior,) + return AutoencoderKLOutput(latent_dist=posterior) + + def _decode(self, z: torch.Tensor, return_dict: bool = True) -> Union[DecoderOutput, torch.Tensor]: + self.clear_cache() + + iter_ = z.shape[2] + x = self.post_quant_conv(z) + for i in range(iter_): + + self._conv_idx = [0] + if i == 0: + out = self.decoder(x[:, :, i : i + 1, :, :], feat_cache=self._feat_map, feat_idx=self._conv_idx) + else: + out_ = self.decoder(x[:, :, i : i + 1, :, :], feat_cache=self._feat_map, feat_idx=self._conv_idx) + out = torch.cat([out, out_], 2) + + out = torch.clamp(out, min=-1.0, max=1.0) + self.clear_cache() + if not return_dict: + return (out,) + + return DecoderOutput(sample=out) + + @apply_forward_hook + def decode(self, z: torch.Tensor, return_dict: bool = True) -> Union[DecoderOutput, torch.Tensor]: + r""" + Decode a batch of images. + + Args: + z (`torch.Tensor`): Input batch of latent vectors. + return_dict (`bool`, *optional*, defaults to `True`): + Whether to return a [`~models.vae.DecoderOutput`] instead of a plain tuple. + + Returns: + [`~models.vae.DecoderOutput`] or `tuple`: + If return_dict is True, a [`~models.vae.DecoderOutput`] is returned, otherwise a plain `tuple` is + returned. + """ + decoded = self._decode(z).sample + if not return_dict: + return (decoded,) + + return DecoderOutput(sample=decoded) + + def forward( + self, + sample: torch.Tensor, + sample_posterior: bool = False, + return_dict: bool = True, + generator: Optional[torch.Generator] = None, + ) -> Union[DecoderOutput, torch.Tensor]: + """ + Args: + sample (`torch.Tensor`): Input sample. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`DecoderOutput`] instead of a plain tuple. + """ + x = sample + posterior = self.encode(x).latent_dist + if sample_posterior: + z = posterior.sample(generator=generator) + else: + z = posterior.mode() + dec = self.decode(z, return_dict=return_dict) + return dec diff --git a/toolkit/models/wan21/wan21.py b/toolkit/models/wan21/wan21.py index 57b556ed..9f029c7b 100644 --- a/toolkit/models/wan21/wan21.py +++ b/toolkit/models/wan21/wan21.py @@ -9,7 +9,8 @@ from toolkit.dequantize import patch_dequantization_on_save from toolkit.models.base_model import BaseModel from toolkit.prompt_utils import PromptEmbeds from transformers import AutoTokenizer, UMT5EncoderModel -from diffusers import AutoencoderKLWan, WanPipeline, WanTransformer3DModel +from diffusers import WanPipeline, WanTransformer3DModel, AutoencoderKL +from .autoencoder_kl_wan import AutoencoderKLWan import os import sys From 97e101522c55834309111d8131908230d3acf303 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 08:01:13 -0600 Subject: [PATCH 04/10] Increase ema feedback amount. Normalize the dfe 4 image embeds --- toolkit/ema.py | 3 ++- toolkit/models/diffusion_feature_extraction.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/toolkit/ema.py b/toolkit/ema.py index e3b3a7ea..b34554bb 100644 --- a/toolkit/ema.py +++ b/toolkit/ema.py @@ -137,7 +137,8 @@ class ExponentialMovingAverage: update_param = False if self.use_feedback: - param_float.add_(tmp) + # make feedback 10x decay + param_float.add_(tmp * 10) update_param = True if self.param_multiplier != 1.0: diff --git a/toolkit/models/diffusion_feature_extraction.py b/toolkit/models/diffusion_feature_extraction.py index e911484a..01d7f278 100644 --- a/toolkit/models/diffusion_feature_extraction.py +++ b/toolkit/models/diffusion_feature_extraction.py @@ -469,8 +469,9 @@ class DiffusionFeatureExtractor4(nn.Module): ) # embeds = id_embeds['hidden_states'][-2] # penultimate layer - embeds = id_embeds['pooler_output'] - return embeds + image_embeds = id_embeds['pooler_output'] + image_embeds = image_embeds / image_embeds.norm(p=2, dim=-1, keepdim=True) + return image_embeds def forward( self, From 517bc294fa5cfd51fae0aa43bd1cede3a317a88c Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 08:28:30 -0600 Subject: [PATCH 05/10] Update support link --- ui/src/components/Sidebar.tsx | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index 14ec4542..3f6dfcc5 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -33,31 +33,18 @@ const Sidebar = () => { ))} - +
- - - - - - - - + + +
-
Support me on Patreon
+
SUPPORT THIS PROJECT
); From 7317ed58afe789df5b9538e432f830ae90456632 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 08:40:51 -0600 Subject: [PATCH 06/10] Adjust the ui of the sidebar --- ui/src/components/Sidebar.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index 3f6dfcc5..324b6097 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -11,11 +11,12 @@ const Sidebar = () => { ]; return ( -
-
-

- Ostris AI Toolkit - Ostris - AI Toolkit +
+
+

+ Ostris AI Toolkit + Ostris + AI-Toolkit

- +
@@ -44,7 +45,7 @@ const Sidebar = () => {
-
SUPPORT THIS PROJECT
+
Support AI-Toolkit
); From f19f7f94863095c163485d8ae56557998d66f938 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 08:42:18 -0600 Subject: [PATCH 07/10] Fixed issue with wan2.1 training in ui. Name had a typo --- ui/src/app/jobs/new/options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/jobs/new/options.ts b/ui/src/app/jobs/new/options.ts index b35f32a4..53d63af8 100644 --- a/ui/src/app/jobs/new/options.ts +++ b/ui/src/app/jobs/new/options.ts @@ -96,7 +96,7 @@ export const modelArchs: ModelArch[] = [ isVideoModel: true, defaults: { // default updates when [selected, unselected] in the UI - 'config.process[0].model.name_or_path': ['Wan-AI/Wan2.1-T2V-14B-Diffuserss', defaultNameOrPath], + 'config.process[0].model.name_or_path': ['Wan-AI/Wan2.1-T2V-14B-Diffusers', defaultNameOrPath], 'config.process[0].model.quantize': [true, false], 'config.process[0].model.quantize_te': [true, false], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], From d5c547da435df7ec8185233f2ee914b481fbaafa Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 08:44:47 -0600 Subject: [PATCH 08/10] Fixed DOP typo --- ui/src/app/jobs/new/SimpleJob.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/app/jobs/new/SimpleJob.tsx b/ui/src/app/jobs/new/SimpleJob.tsx index b8ab6b93..e8ad1f38 100644 --- a/ui/src/app/jobs/new/SimpleJob.tsx +++ b/ui/src/app/jobs/new/SimpleJob.tsx @@ -345,7 +345,7 @@ export default function SimpleJob({ /> setJobConfig(value, 'config.process[0].train.diff_output_preservation_multiplier')} @@ -353,7 +353,7 @@ export default function SimpleJob({ min={0} /> setJobConfig(value, 'config.process[0].train.diff_output_preservation_class')} From f8fb3b9c453a27eb5cad8854d8099cbf5c79641b Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Tue, 10 Jun 2025 10:03:54 -0600 Subject: [PATCH 09/10] Added support for sdxl and sd1.5 to the ui. --- README.md | 9 +++ ui/src/app/jobs/new/SimpleJob.tsx | 106 +++++++++++++++++------------- ui/src/app/jobs/new/jobConfig.ts | 2 + ui/src/app/jobs/new/options.ts | 47 ++++++++++++- ui/src/components/formInputs.tsx | 18 +++-- ui/src/types.ts | 2 + 6 files changed, 131 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 697b7925..fa660c6a 100644 --- a/README.md +++ b/README.md @@ -414,3 +414,12 @@ To learn more about LoKr, read more about it at [KohakuBlueleaf/LyCORIS](https:/ Everything else should work the same including layer targeting. + +## Updates + +### June 10, 2024 +- Decided to keep track up updates in the readme +- Added support for SDXL in the UI +- Added support for SD 1.5 in the UI +- Fixed UI Wan 2.1 14b name bug +- Added support for for conv training in the UI for models that support it \ No newline at end of file diff --git a/ui/src/app/jobs/new/SimpleJob.tsx b/ui/src/app/jobs/new/SimpleJob.tsx index e8ad1f38..ca587564 100644 --- a/ui/src/app/jobs/new/SimpleJob.tsx +++ b/ui/src/app/jobs/new/SimpleJob.tsx @@ -33,7 +33,6 @@ export default function SimpleJob({ gpuList, datasetOptions, }: Props) { - const modelArch = useMemo(() => { return modelArchs.find(a => a.name === jobConfig.config.process[0].model.arch) as ModelArch; }, [jobConfig.config.process[0].model.arch]); @@ -104,8 +103,7 @@ export default function SimpleJob({ const newDataset = objectCopy(dataset); newDataset.controls = controls; return newDataset; - } - ); + }); setJobConfig(datasets, 'config.process[0].datasets'); }} options={ @@ -131,20 +129,22 @@ export default function SimpleJob({ placeholder="" required /> - -
- setJobConfig(value, 'config.process[0].model.quantize')} - /> - setJobConfig(value, 'config.process[0].model.quantize_te')} - /> -
-
+ {modelArch?.disableSections?.includes('model.quantize') ? null : ( + +
+ setJobConfig(value, 'config.process[0].model.quantize')} + /> + setJobConfig(value, 'config.process[0].model.quantize_te')} + /> +
+
+ )} )} {jobConfig.config.process[0].network?.type == 'lora' && ( - { - console.log('onChange', value); - setJobConfig(value, 'config.process[0].network.linear'); - setJobConfig(value, 'config.process[0].network.linear_alpha'); - }} - placeholder="eg. 16" - min={0} - max={1024} - required - /> + <> + { + console.log('onChange', value); + setJobConfig(value, 'config.process[0].network.linear'); + setJobConfig(value, 'config.process[0].network.linear_alpha'); + }} + placeholder="eg. 16" + min={0} + max={1024} + required + /> + { + modelArch?.disableSections?.includes('network.conv') ? null : ( + { + console.log('onChange', value); + setJobConfig(value, 'config.process[0].network.conv'); + setJobConfig(value, 'config.process[0].network.conv_alpha'); + }} + placeholder="eg. 16" + min={0} + max={1024} + /> + ) + } + )} @@ -276,16 +294,19 @@ export default function SimpleJob({ />

- setJobConfig(value, 'config.process[0].train.timestep_type')} - options={[ - { value: 'sigmoid', label: 'Sigmoid' }, - { value: 'linear', label: 'Linear' }, - { value: 'shift', label: 'Shift' }, - ]} - /> + {modelArch?.disableSections?.includes('train.timestep_type') ? null : ( + setJobConfig(value, 'config.process[0].train.timestep_type')} + options={[ + { value: 'sigmoid', label: 'Sigmoid' }, + { value: 'linear', label: 'Linear' }, + { value: 'shift', label: 'Shift' }, + ]} + /> + )} diff --git a/ui/src/app/jobs/new/jobConfig.ts b/ui/src/app/jobs/new/jobConfig.ts index 59268012..dd28461b 100644 --- a/ui/src/app/jobs/new/jobConfig.ts +++ b/ui/src/app/jobs/new/jobConfig.ts @@ -30,6 +30,8 @@ export const defaultJobConfig: JobConfig = { type: 'lora', linear: 32, linear_alpha: 32, + conv: 16, + conv_alpha: 16, lokr_full_rank: true, lokr_factor: -1, network_kwargs: { diff --git a/ui/src/app/jobs/new/options.ts b/ui/src/app/jobs/new/options.ts index 53d63af8..e84bc4a0 100644 --- a/ui/src/app/jobs/new/options.ts +++ b/ui/src/app/jobs/new/options.ts @@ -1,4 +1,3 @@ - type Control = 'depth' | 'line' | 'pose' | 'inpaint'; export interface ModelArch { @@ -6,11 +5,14 @@ export interface ModelArch { label: string; controls?: Control[]; isVideoModel?: boolean; - defaults?: { [key: string]: [any, any] }; + defaults?: { [key: string]: any }; + disableSections?: DisableableSections[]; } const defaultNameOrPath = ''; +type DisableableSections = 'model.quantize' | 'train.timestep_type' | 'network.conv'; + export const modelArchs: ModelArch[] = [ { name: 'flux', @@ -23,6 +25,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, + disableSections: ['network.conv'], }, { name: 'flex1', @@ -36,6 +39,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, + disableSections: ['network.conv'], }, { name: 'flex2', @@ -62,6 +66,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, + disableSections: ['network.conv'], }, { name: 'chroma', @@ -74,6 +79,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, + disableSections: ['network.conv'], }, { name: 'wan21:1b', @@ -89,6 +95,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.num_frames': [40, 1], 'config.process[0].sample.fps': [15, 1], }, + disableSections: ['network.conv'], }, { name: 'wan21:14b', @@ -104,6 +111,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.num_frames': [40, 1], 'config.process[0].sample.fps': [15, 1], }, + disableSections: ['network.conv'], }, { name: 'lumina2', @@ -116,6 +124,7 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, + disableSections: ['network.conv'], }, { name: 'hidream', @@ -131,5 +140,37 @@ export const modelArchs: ModelArch[] = [ 'config.process[0].train.timestep_type': ['shift', 'sigmoid'], 'config.process[0].network.network_kwargs.ignore_if_contains': [['ff_i.experts', 'ff_i.gate'], []], }, + disableSections: ['network.conv'], }, -]; + { + name: 'sdxl', + label: 'SDXL', + defaults: { + // default updates when [selected, unselected] in the UI + 'config.process[0].model.name_or_path': ['stabilityai/stable-diffusion-xl-base-1.0', defaultNameOrPath], + 'config.process[0].model.quantize': [false, false], + 'config.process[0].model.quantize_te': [false, false], + 'config.process[0].sample.sampler': ['ddpm', 'flowmatch'], + 'config.process[0].train.noise_scheduler': ['ddpm', 'flowmatch'], + 'config.process[0].sample.guidance_scale': [6, 4], + }, + disableSections: ['model.quantize', 'train.timestep_type'], + }, + { + name: 'sd15', + label: 'SD 1.5', + defaults: { + // default updates when [selected, unselected] in the UI + 'config.process[0].model.name_or_path': ['stable-diffusion-v1-5/stable-diffusion-v1-5', defaultNameOrPath], + 'config.process[0].sample.sampler': ['ddpm', 'flowmatch'], + 'config.process[0].train.noise_scheduler': ['ddpm', 'flowmatch'], + 'config.process[0].sample.width': [512, 1024], + 'config.process[0].sample.height': [512, 1024], + 'config.process[0].sample.guidance_scale': [6, 4], + }, + disableSections: ['model.quantize', 'train.timestep_type'], + }, +].sort((a, b) => { + // Sort by label, case-insensitive + return a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }) +}) as any; diff --git a/ui/src/components/formInputs.tsx b/ui/src/components/formInputs.tsx index 7f53e681..a9908bd0 100644 --- a/ui/src/components/formInputs.tsx +++ b/ui/src/components/formInputs.tsx @@ -2,8 +2,8 @@ import React, { forwardRef } from 'react'; import classNames from 'classnames'; -import dynamic from "next/dynamic"; -const Select = dynamic(() => import("react-select"), { ssr: false }); +import dynamic from 'next/dynamic'; +const Select = dynamic(() => import('react-select'), { ssr: false }); const labelClasses = 'block text-xs mb-1 mt-2 text-gray-300'; const inputClasses = @@ -42,7 +42,7 @@ export const TextInput = forwardRef( />
); - } + }, ); // 👇 Helpful for debugging @@ -114,6 +114,7 @@ export const NumberInput = (props: NumberInputProps) => { export interface SelectInputProps extends InputProps { value: string; + disabled?: boolean; onChange: (value: string) => void; options: { value: string; label: string }[]; } @@ -122,11 +123,16 @@ export const SelectInput = (props: SelectInputProps) => { const { label, value, onChange, options } = props; const selectedOption = options.find(option => option.value === value); return ( -
+
{label && } -