From d52a096607895fdd6e53102d830e198e3b3171db Mon Sep 17 00:00:00 2001 From: Mary Hipp Date: Thu, 24 Aug 2023 13:29:53 -0400 Subject: [PATCH 01/29] enable preselected image actions --- .../frontend/web/src/app/components/App.tsx | 18 ++++- .../web/src/app/components/InvokeAIUI.tsx | 11 ++- .../parameters/hooks/usePreselectedImage.ts | 81 +++++++++++++++++++ 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index c2cc4645b8..a4a0997443 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -12,24 +12,34 @@ import { languageSelector } from 'features/system/store/systemSelectors'; import InvokeTabs from 'features/ui/components/InvokeTabs'; import i18n from 'i18n'; import { size } from 'lodash-es'; -import { ReactNode, memo, useCallback, useEffect } from 'react'; +import { ReactNode, memo, useCallback, useEffect, useMemo } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; import GlobalHotkeys from './GlobalHotkeys'; import Toaster from './Toaster'; +import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage'; const DEFAULT_CONFIG = {}; interface Props { config?: PartialAppConfig; headerComponent?: ReactNode; + selectedImage?: { + imageName: string; + action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; + }; } -const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => { +const App = ({ + config = DEFAULT_CONFIG, + headerComponent, + selectedImage, +}: Props) => { const language = useAppSelector(languageSelector); const logger = useLogger('system'); const dispatch = useAppDispatch(); + const { handlePreselectedImage } = usePreselectedImage(); const handleReset = useCallback(() => { localStorage.clear(); location.reload(); @@ -51,6 +61,10 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => { dispatch(appStarted()); }, [dispatch]); + useEffect(() => { + handlePreselectedImage(selectedImage); + }, [handlePreselectedImage, selectedImage]); + return ( { useEffect(() => { // configure API client token @@ -81,7 +86,11 @@ const InvokeAIUI = ({ }> - + diff --git a/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts new file mode 100644 index 0000000000..fa310a66ad --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts @@ -0,0 +1,81 @@ +import { skipToken } from '@reduxjs/toolkit/dist/query'; +import { useCallback, useMemo, useState } from 'react'; +import { + useGetImageDTOQuery, + useGetImageMetadataQuery, +} from '../../../services/api/endpoints/images'; +import { useAppDispatch } from '../../../app/store/storeHooks'; +import { setInitialCanvasImage } from '../../canvas/store/canvasSlice'; +import { setActiveTab } from '../../ui/store/uiSlice'; +import { useRecallParameters } from './useRecallParameters'; +import { initialImageSelected } from '../store/actions'; +import { useAppToaster } from '../../../app/components/Toaster'; +import { t } from 'i18next'; + +type SelectedImage = { + imageName: string; + action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; +}; + +export const usePreselectedImage = () => { + const dispatch = useAppDispatch(); + const [imageNameForDto, setImageNameForDto] = useState(); + const [imageNameForMetadata, setImageNameForMetadata] = useState< + string | undefined + >(); + const { recallAllParameters } = useRecallParameters(); + const toaster = useAppToaster(); + + const { currentData: selectedImageDto, isError } = useGetImageDTOQuery( + imageNameForDto ?? skipToken + ); + + const { currentData: selectedImageMetadata } = useGetImageMetadataQuery( + imageNameForMetadata ?? skipToken + ); + + const handlePreselectedImage = useCallback( + (selectedImage?: SelectedImage) => { + if (!selectedImage) { +return; +} + + if (selectedImage.action === 'sendToCanvas') { + setImageNameForDto(selectedImage?.imageName); + if (selectedImageDto) { + dispatch(setInitialCanvasImage(selectedImageDto)); + dispatch(setActiveTab('unifiedCanvas')); + toaster({ + title: t('toast.sentToUnifiedCanvas'), + status: 'info', + duration: 2500, + isClosable: true, + }); + } + } + + if (selectedImage.action === 'sendToImg2Img') { + setImageNameForDto(selectedImage?.imageName); + if (selectedImageDto) { + dispatch(initialImageSelected(selectedImageDto)); + } + } + + if (selectedImage.action === 'useAllParameters') { + setImageNameForMetadata(selectedImage?.imageName); + if (selectedImageMetadata) { + recallAllParameters(selectedImageMetadata.metadata); + } + } + }, + [ + dispatch, + selectedImageDto, + selectedImageMetadata, + recallAllParameters, + toaster, + ] + ); + + return { handlePreselectedImage }; +}; From 95883c2efd7393356ac04cf7c277b307d320fcbe Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 12:29:11 -0400 Subject: [PATCH 02/29] Add Initial (non-working) Seamless Implementation --- invokeai/app/invocations/latent.py | 198 +++++++++++++++++++++-------- 1 file changed, 145 insertions(+), 53 deletions(-) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 314301663b..cd2dcc24a2 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -21,6 +21,8 @@ from torchvision.transforms.functional import resize as tv_resize from invokeai.app.invocations.metadata import CoreMetadata from invokeai.app.invocations.primitives import ( + DenoiseMaskField, + DenoiseMaskOutput, ImageField, ImageOutput, LatentsField, @@ -31,8 +33,8 @@ from invokeai.app.util.controlnet_utils import prepare_control_image from invokeai.app.util.step_callback import stable_diffusion_step_callback from invokeai.backend.model_management.models import ModelType, SilenceWarnings -from ...backend.model_management.models import BaseModelType from ...backend.model_management.lora import ModelPatcher +from ...backend.model_management.models import BaseModelType from ...backend.stable_diffusion import PipelineIntermediateState from ...backend.stable_diffusion.diffusers_pipeline import ( ConditioningData, @@ -44,16 +46,7 @@ from ...backend.stable_diffusion.diffusion.shared_invokeai_diffusion import Post from ...backend.stable_diffusion.schedulers import SCHEDULER_MAP from ...backend.util.devices import choose_precision, choose_torch_device from ..models.image import ImageCategory, ResourceOrigin -from .baseinvocation import ( - BaseInvocation, - FieldDescriptions, - Input, - InputField, - InvocationContext, - UIType, - tags, - title, -) +from .baseinvocation import BaseInvocation, FieldDescriptions, Input, InputField, InvocationContext, UIType, tags, title from .compel import ConditioningField from .controlnet_image_processors import ControlField from .model import ModelInfo, UNetField, VaeField @@ -64,6 +57,72 @@ DEFAULT_PRECISION = choose_precision(choose_torch_device()) SAMPLER_NAME_VALUES = Literal[tuple(list(SCHEDULER_MAP.keys()))] +@title("Create Denoise Mask") +@tags("mask", "denoise") +class CreateDenoiseMaskInvocation(BaseInvocation): + """Creates mask for denoising model run.""" + + # Metadata + type: Literal["create_denoise_mask"] = "create_denoise_mask" + + # Inputs + vae: VaeField = InputField(description=FieldDescriptions.vae, input=Input.Connection, ui_order=0) + image: Optional[ImageField] = InputField(default=None, description="Image which will be masked", ui_order=1) + mask: ImageField = InputField(description="The mask to use when pasting", ui_order=2) + tiled: bool = InputField(default=False, description=FieldDescriptions.tiled, ui_order=3) + fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32, ui_order=4) + + def prep_mask_tensor(self, mask_image): + if mask_image.mode != "L": + mask_image = mask_image.convert("L") + mask_tensor = image_resized_to_grid_as_tensor(mask_image, normalize=False) + if mask_tensor.dim() == 3: + mask_tensor = mask_tensor.unsqueeze(0) + # if shape is not None: + # mask_tensor = tv_resize(mask_tensor, shape, T.InterpolationMode.BILINEAR) + return mask_tensor + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> DenoiseMaskOutput: + if self.image is not None: + image = context.services.images.get_pil_image(self.image.image_name) + image = image_resized_to_grid_as_tensor(image.convert("RGB")) + if image.dim() == 3: + image = image.unsqueeze(0) + else: + image = None + + mask = self.prep_mask_tensor( + context.services.images.get_pil_image(self.mask.image_name), + ) + + if image is not None: + vae_info = context.services.model_manager.get_model( + **self.vae.vae.dict(), + context=context, + ) + + img_mask = tv_resize(mask, image.shape[-2:], T.InterpolationMode.BILINEAR) + masked_image = image * torch.where(img_mask < 0.5, 0.0, 1.0) + # TODO: + masked_latents = ImageToLatentsInvocation.vae_encode(vae_info, self.fp32, self.tiled, masked_image.clone()) + + masked_latents_name = f"{context.graph_execution_state_id}__{self.id}_masked_latents" + context.services.latents.save(masked_latents_name, masked_latents) + else: + masked_latents_name = None + + mask_name = f"{context.graph_execution_state_id}__{self.id}_mask" + context.services.latents.save(mask_name, mask) + + return DenoiseMaskOutput( + denoise_mask=DenoiseMaskField( + mask_name=mask_name, + masked_latents_name=masked_latents_name, + ), + ) + + def get_scheduler( context: InvocationContext, scheduler_info: ModelInfo, @@ -126,13 +185,13 @@ class DenoiseLatentsInvocation(BaseInvocation): control: Union[ControlField, list[ControlField]] = InputField( default=None, description=FieldDescriptions.control, input=Input.Connection, ui_order=5 ) - latents: Optional[LatentsField] = InputField( - description=FieldDescriptions.latents, input=Input.Connection, ui_order=4 - ) - mask: Optional[ImageField] = InputField( + latents: Optional[LatentsField] = InputField(description=FieldDescriptions.latents, input=Input.Connection) + denoise_mask: Optional[DenoiseMaskField] = InputField( default=None, description=FieldDescriptions.mask, ) + seamless: bool = InputField(default=False, description="Enable or disable seamless padding") + seamless_axes: str = InputField(default="xy", description="Specify which axes are seamless: 'x', 'y', or 'xy'") @validator("cfg_scale") def ge_one(cls, v): @@ -199,17 +258,46 @@ class DenoiseLatentsInvocation(BaseInvocation): ) return conditioning_data + + def configure_model_padding(self, model): + """ + Modifies the 2D convolution layers to use a circular padding mode based on the `seamless` and `seamless_axes` options. + """ + + def _conv_forward_asymmetric(self, input, weight, bias): + """ + Patch for Conv2d._conv_forward that supports asymmetric padding + """ + working = torch.nn.functional.pad(input, self.asymmetric_padding['x'], mode=self.asymmetric_padding_mode['x']) + working = torch.nn.functional.pad(working, self.asymmetric_padding['y'], mode=self.asymmetric_padding_mode['y']) + return torch.nn.functional.conv2d(working, weight, bias, self.stride, torch.nn.modules.utils._pair(0), self.dilation, self.groups) + + for m in model.modules(): + if isinstance(m, (torch.nn.Conv2d, torch.nn.ConvTranspose2d)): + if self.seamless: + m.asymmetric_padding_mode = {} + m.asymmetric_padding = {} + m.asymmetric_padding_mode['x'] = 'circular' if ('x' in self.seamless_axes) else 'constant' + m.asymmetric_padding['x'] = (m._reversed_padding_repeated_twice[0], m._reversed_padding_repeated_twice[1], 0, 0) + m.asymmetric_padding_mode['y'] = 'circular' if ('y' in self.seamless_axes) else 'constant' + m.asymmetric_padding['y'] = (0, 0, m._reversed_padding_repeated_twice[2], m._reversed_padding_repeated_twice[3]) + m._conv_forward = _conv_forward_asymmetric.__get__(m, torch.nn.Conv2d) + else: + m._conv_forward = torch.nn.Conv2d._conv_forward.__get__(m, torch.nn.Conv2d) + if hasattr(m, 'asymmetric_padding_mode'): + del m.asymmetric_padding_mode + if hasattr(m, 'asymmetric_padding'): + del m.asymmetric_padding + def create_pipeline( self, unet, scheduler, ) -> StableDiffusionGeneratorPipeline: - # TODO: - # configure_model_padding( - # unet, - # self.seamless, - # self.seamless_axes, - # ) + + self.configure_model_padding( + unet + ) class FakeVae: class FakeVaeConfig: @@ -342,19 +430,18 @@ class DenoiseLatentsInvocation(BaseInvocation): return num_inference_steps, timesteps, init_timestep - def prep_mask_tensor(self, mask, context, lantents): - if mask is None: - return None + def prep_inpaint_mask(self, context, latents): + if self.denoise_mask is None: + return None, None - mask_image = context.services.images.get_pil_image(mask.image_name) - if mask_image.mode != "L": - # FIXME: why do we get passed an RGB image here? We can only use single-channel. - mask_image = mask_image.convert("L") - mask_tensor = image_resized_to_grid_as_tensor(mask_image, normalize=False) - if mask_tensor.dim() == 3: - mask_tensor = mask_tensor.unsqueeze(0) - mask_tensor = tv_resize(mask_tensor, lantents.shape[-2:], T.InterpolationMode.BILINEAR) - return 1 - mask_tensor + mask = context.services.latents.get(self.denoise_mask.mask_name) + mask = tv_resize(mask, latents.shape[-2:], T.InterpolationMode.BILINEAR) + if self.denoise_mask.masked_latents_name is not None: + masked_latents = context.services.latents.get(self.denoise_mask.masked_latents_name) + else: + masked_latents = None + + return 1 - mask, masked_latents @torch.no_grad() def invoke(self, context: InvocationContext) -> LatentsOutput: @@ -375,7 +462,7 @@ class DenoiseLatentsInvocation(BaseInvocation): if seed is None: seed = 0 - mask = self.prep_mask_tensor(self.mask, context, latents) + mask, masked_latents = self.prep_inpaint_mask(context, latents) # Get the source node id (we are invoking the prepared node) graph_execution_state = context.services.graph_execution_manager.get(context.graph_execution_state_id) @@ -406,6 +493,8 @@ class DenoiseLatentsInvocation(BaseInvocation): noise = noise.to(device=unet.device, dtype=unet.dtype) if mask is not None: mask = mask.to(device=unet.device, dtype=unet.dtype) + if masked_latents is not None: + masked_latents = masked_latents.to(device=unet.device, dtype=unet.dtype) scheduler = get_scheduler( context=context, @@ -442,6 +531,7 @@ class DenoiseLatentsInvocation(BaseInvocation): noise=noise, seed=seed, mask=mask, + masked_latents=masked_latents, num_inference_steps=num_inference_steps, conditioning_data=conditioning_data, control_data=control_data, # list[ControlNetData] @@ -663,26 +753,11 @@ class ImageToLatentsInvocation(BaseInvocation): tiled: bool = InputField(default=False, description=FieldDescriptions.tiled) fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32) - @torch.no_grad() - def invoke(self, context: InvocationContext) -> LatentsOutput: - # image = context.services.images.get( - # self.image.image_type, self.image.image_name - # ) - image = context.services.images.get_pil_image(self.image.image_name) - - # vae_info = context.services.model_manager.get_model(**self.vae.vae.dict()) - vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), - context=context, - ) - - image_tensor = image_resized_to_grid_as_tensor(image.convert("RGB")) - if image_tensor.dim() == 3: - image_tensor = einops.rearrange(image_tensor, "c h w -> 1 c h w") - + @staticmethod + def vae_encode(vae_info, upcast, tiled, image_tensor): with vae_info as vae: orig_dtype = vae.dtype - if self.fp32: + if upcast: vae.to(dtype=torch.float32) use_torch_2_0_or_xformers = isinstance( @@ -707,7 +782,7 @@ class ImageToLatentsInvocation(BaseInvocation): vae.to(dtype=torch.float16) # latents = latents.half() - if self.tiled: + if tiled: vae.enable_tiling() else: vae.disable_tiling() @@ -721,6 +796,23 @@ class ImageToLatentsInvocation(BaseInvocation): latents = vae.config.scaling_factor * latents latents = latents.to(dtype=orig_dtype) + return latents + + @torch.no_grad() + def invoke(self, context: InvocationContext) -> LatentsOutput: + image = context.services.images.get_pil_image(self.image.image_name) + + vae_info = context.services.model_manager.get_model( + **self.vae.vae.dict(), + context=context, + ) + + image_tensor = image_resized_to_grid_as_tensor(image.convert("RGB")) + if image_tensor.dim() == 3: + image_tensor = einops.rearrange(image_tensor, "c h w -> 1 c h w") + + latents = self.vae_encode(vae_info, self.fp32, self.tiled, image_tensor) + name = f"{context.graph_execution_state_id}__{self.id}" latents = latents.to("cpu") context.services.latents.save(name, latents) From 3de45af73424f537b67736d892bdd49e27ed0b54 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:13:00 -0400 Subject: [PATCH 03/29] updates --- invokeai/app/invocations/model.py | 43 +++++++++++++ invokeai/backend/model_management/seamless.py | 60 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 invokeai/backend/model_management/seamless.py diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 3cae4b3383..1bb67b8c91 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -33,6 +33,7 @@ class UNetField(BaseModel): unet: ModelInfo = Field(description="Info to load unet submodel") scheduler: ModelInfo = Field(description="Info to load scheduler submodel") loras: List[LoraInfo] = Field(description="Loras to apply on model loading") + seamless_axes: List[str] = Field(default_factory=list, description="Axes(\"x\" and \"y\") to which apply seamless") class ClipField(BaseModel): @@ -388,3 +389,45 @@ class VaeLoaderInvocation(BaseInvocation): ) ) ) + + +class SeamlessModeOutput(BaseInvocationOutput): + """Modified Seamless Model output""" + + type: Literal["seamless_output"] = "seamless_output" + + # Outputs + unet: UNetField = OutputField(description=FieldDescriptions.unet, title="UNet") + +@title("Seamless") +@tags("seamless", "model") +class SeamlessModeInvocation(BaseInvocation): + """Apply seamless mode to unet.""" + + type: Literal["seamless"] = "seamless" + + # Inputs + unet: UNetField = InputField( + description=FieldDescriptions.unet, input=Input.Connection, title="UNet" + ) + + seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") + seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") + + + def invoke(self, context: InvocationContext) -> SeamlessModeOutput: + # Conditionally append 'x' and 'y' based on seamless_x and seamless_y + unet = copy.deepcopy(self.unet) + + seamless_axes_list = [] + + if self.seamless_x: + seamless_axes_list.append('x') + if self.seamless_y: + seamless_axes_list.append('y') + + unet.seamless_axes = seamless_axes_list + + return SeamlessModeOutput( + unet=unet, + ) \ No newline at end of file diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py new file mode 100644 index 0000000000..0568c68ac2 --- /dev/null +++ b/invokeai/backend/model_management/seamless.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from contextlib import contextmanager + +import torch.nn as nn +from diffusers.models import UNet2DModel + +def _conv_forward_asymmetric(self, input, weight, bias): + """ + Patch for Conv2d._conv_forward that supports asymmetric padding + """ + working = nn.functional.pad(input, self.asymmetric_padding["x"], mode=self.asymmetric_padding_mode["x"]) + working = nn.functional.pad(working, self.asymmetric_padding["y"], mode=self.asymmetric_padding_mode["y"]) + return nn.functional.conv2d( + working, + weight, + bias, + self.stride, + nn.modules.utils._pair(0), + self.dilation, + self.groups, + ) + + +@contextmanager +def set_unet_seamless(model: UNet2DModel, seamless: bool, seamless_axes): + try: + to_restore = dict() + if seamless: + for m in model.modules(): + if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): + m.asymmetric_padding_mode = {} + m.asymmetric_padding = {} + m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" + m.asymmetric_padding["x"] = ( + m._reversed_padding_repeated_twice[0], + m._reversed_padding_repeated_twice[1], + 0, + 0, + ) + m.asymmetric_padding_mode["y"] = "circular" if ("y" in seamless_axes) else "constant" + m.asymmetric_padding["y"] = ( + 0, + 0, + m._reversed_padding_repeated_twice[2], + m._reversed_padding_repeated_twice[3], + ) + + to_restore.append((m, m._conv_forward)) + m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) + + yield + + finally: + for module, orig_conv_forward in to_restore: + module._conv_forward = orig_conv_forward + if hasattr(m, "asymmetric_padding_mode"): + del m.asymmetric_padding_mode + if hasattr(m, "asymmetric_padding"): + del m.asymmetric_padding \ No newline at end of file From c6d00387a772eedcdb8688c92594886df18e509e Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:15:37 -0400 Subject: [PATCH 04/29] Revert old latent changes, update seamless --- invokeai/app/invocations/latent.py | 201 ++++++++--------------------- 1 file changed, 55 insertions(+), 146 deletions(-) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index cd2dcc24a2..708dfe81b9 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -21,8 +21,6 @@ from torchvision.transforms.functional import resize as tv_resize from invokeai.app.invocations.metadata import CoreMetadata from invokeai.app.invocations.primitives import ( - DenoiseMaskField, - DenoiseMaskOutput, ImageField, ImageOutput, LatentsField, @@ -33,8 +31,9 @@ from invokeai.app.util.controlnet_utils import prepare_control_image from invokeai.app.util.step_callback import stable_diffusion_step_callback from invokeai.backend.model_management.models import ModelType, SilenceWarnings -from ...backend.model_management.lora import ModelPatcher from ...backend.model_management.models import BaseModelType +from ...backend.model_management.lora import ModelPatcher +from ...backend.model_management.seamless import set_unet_seamless from ...backend.stable_diffusion import PipelineIntermediateState from ...backend.stable_diffusion.diffusers_pipeline import ( ConditioningData, @@ -46,7 +45,16 @@ from ...backend.stable_diffusion.diffusion.shared_invokeai_diffusion import Post from ...backend.stable_diffusion.schedulers import SCHEDULER_MAP from ...backend.util.devices import choose_precision, choose_torch_device from ..models.image import ImageCategory, ResourceOrigin -from .baseinvocation import BaseInvocation, FieldDescriptions, Input, InputField, InvocationContext, UIType, tags, title +from .baseinvocation import ( + BaseInvocation, + FieldDescriptions, + Input, + InputField, + InvocationContext, + UIType, + tags, + title, +) from .compel import ConditioningField from .controlnet_image_processors import ControlField from .model import ModelInfo, UNetField, VaeField @@ -57,72 +65,6 @@ DEFAULT_PRECISION = choose_precision(choose_torch_device()) SAMPLER_NAME_VALUES = Literal[tuple(list(SCHEDULER_MAP.keys()))] -@title("Create Denoise Mask") -@tags("mask", "denoise") -class CreateDenoiseMaskInvocation(BaseInvocation): - """Creates mask for denoising model run.""" - - # Metadata - type: Literal["create_denoise_mask"] = "create_denoise_mask" - - # Inputs - vae: VaeField = InputField(description=FieldDescriptions.vae, input=Input.Connection, ui_order=0) - image: Optional[ImageField] = InputField(default=None, description="Image which will be masked", ui_order=1) - mask: ImageField = InputField(description="The mask to use when pasting", ui_order=2) - tiled: bool = InputField(default=False, description=FieldDescriptions.tiled, ui_order=3) - fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32, ui_order=4) - - def prep_mask_tensor(self, mask_image): - if mask_image.mode != "L": - mask_image = mask_image.convert("L") - mask_tensor = image_resized_to_grid_as_tensor(mask_image, normalize=False) - if mask_tensor.dim() == 3: - mask_tensor = mask_tensor.unsqueeze(0) - # if shape is not None: - # mask_tensor = tv_resize(mask_tensor, shape, T.InterpolationMode.BILINEAR) - return mask_tensor - - @torch.no_grad() - def invoke(self, context: InvocationContext) -> DenoiseMaskOutput: - if self.image is not None: - image = context.services.images.get_pil_image(self.image.image_name) - image = image_resized_to_grid_as_tensor(image.convert("RGB")) - if image.dim() == 3: - image = image.unsqueeze(0) - else: - image = None - - mask = self.prep_mask_tensor( - context.services.images.get_pil_image(self.mask.image_name), - ) - - if image is not None: - vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), - context=context, - ) - - img_mask = tv_resize(mask, image.shape[-2:], T.InterpolationMode.BILINEAR) - masked_image = image * torch.where(img_mask < 0.5, 0.0, 1.0) - # TODO: - masked_latents = ImageToLatentsInvocation.vae_encode(vae_info, self.fp32, self.tiled, masked_image.clone()) - - masked_latents_name = f"{context.graph_execution_state_id}__{self.id}_masked_latents" - context.services.latents.save(masked_latents_name, masked_latents) - else: - masked_latents_name = None - - mask_name = f"{context.graph_execution_state_id}__{self.id}_mask" - context.services.latents.save(mask_name, mask) - - return DenoiseMaskOutput( - denoise_mask=DenoiseMaskField( - mask_name=mask_name, - masked_latents_name=masked_latents_name, - ), - ) - - def get_scheduler( context: InvocationContext, scheduler_info: ModelInfo, @@ -185,13 +127,13 @@ class DenoiseLatentsInvocation(BaseInvocation): control: Union[ControlField, list[ControlField]] = InputField( default=None, description=FieldDescriptions.control, input=Input.Connection, ui_order=5 ) - latents: Optional[LatentsField] = InputField(description=FieldDescriptions.latents, input=Input.Connection) - denoise_mask: Optional[DenoiseMaskField] = InputField( + latents: Optional[LatentsField] = InputField( + description=FieldDescriptions.latents, input=Input.Connection, ui_order=4 + ) + mask: Optional[ImageField] = InputField( default=None, description=FieldDescriptions.mask, ) - seamless: bool = InputField(default=False, description="Enable or disable seamless padding") - seamless_axes: str = InputField(default="xy", description="Specify which axes are seamless: 'x', 'y', or 'xy'") @validator("cfg_scale") def ge_one(cls, v): @@ -258,46 +200,17 @@ class DenoiseLatentsInvocation(BaseInvocation): ) return conditioning_data - - def configure_model_padding(self, model): - """ - Modifies the 2D convolution layers to use a circular padding mode based on the `seamless` and `seamless_axes` options. - """ - - def _conv_forward_asymmetric(self, input, weight, bias): - """ - Patch for Conv2d._conv_forward that supports asymmetric padding - """ - working = torch.nn.functional.pad(input, self.asymmetric_padding['x'], mode=self.asymmetric_padding_mode['x']) - working = torch.nn.functional.pad(working, self.asymmetric_padding['y'], mode=self.asymmetric_padding_mode['y']) - return torch.nn.functional.conv2d(working, weight, bias, self.stride, torch.nn.modules.utils._pair(0), self.dilation, self.groups) - - for m in model.modules(): - if isinstance(m, (torch.nn.Conv2d, torch.nn.ConvTranspose2d)): - if self.seamless: - m.asymmetric_padding_mode = {} - m.asymmetric_padding = {} - m.asymmetric_padding_mode['x'] = 'circular' if ('x' in self.seamless_axes) else 'constant' - m.asymmetric_padding['x'] = (m._reversed_padding_repeated_twice[0], m._reversed_padding_repeated_twice[1], 0, 0) - m.asymmetric_padding_mode['y'] = 'circular' if ('y' in self.seamless_axes) else 'constant' - m.asymmetric_padding['y'] = (0, 0, m._reversed_padding_repeated_twice[2], m._reversed_padding_repeated_twice[3]) - m._conv_forward = _conv_forward_asymmetric.__get__(m, torch.nn.Conv2d) - else: - m._conv_forward = torch.nn.Conv2d._conv_forward.__get__(m, torch.nn.Conv2d) - if hasattr(m, 'asymmetric_padding_mode'): - del m.asymmetric_padding_mode - if hasattr(m, 'asymmetric_padding'): - del m.asymmetric_padding - def create_pipeline( self, unet, scheduler, ) -> StableDiffusionGeneratorPipeline: - - self.configure_model_padding( - unet - ) + # TODO: + # configure_model_padding( + # unet, + # self.seamless, + # self.seamless_axes, + # ) class FakeVae: class FakeVaeConfig: @@ -430,18 +343,19 @@ class DenoiseLatentsInvocation(BaseInvocation): return num_inference_steps, timesteps, init_timestep - def prep_inpaint_mask(self, context, latents): - if self.denoise_mask is None: - return None, None + def prep_mask_tensor(self, mask, context, lantents): + if mask is None: + return None - mask = context.services.latents.get(self.denoise_mask.mask_name) - mask = tv_resize(mask, latents.shape[-2:], T.InterpolationMode.BILINEAR) - if self.denoise_mask.masked_latents_name is not None: - masked_latents = context.services.latents.get(self.denoise_mask.masked_latents_name) - else: - masked_latents = None - - return 1 - mask, masked_latents + mask_image = context.services.images.get_pil_image(mask.image_name) + if mask_image.mode != "L": + # FIXME: why do we get passed an RGB image here? We can only use single-channel. + mask_image = mask_image.convert("L") + mask_tensor = image_resized_to_grid_as_tensor(mask_image, normalize=False) + if mask_tensor.dim() == 3: + mask_tensor = mask_tensor.unsqueeze(0) + mask_tensor = tv_resize(mask_tensor, lantents.shape[-2:], T.InterpolationMode.BILINEAR) + return 1 - mask_tensor @torch.no_grad() def invoke(self, context: InvocationContext) -> LatentsOutput: @@ -462,7 +376,7 @@ class DenoiseLatentsInvocation(BaseInvocation): if seed is None: seed = 0 - mask, masked_latents = self.prep_inpaint_mask(context, latents) + mask = self.prep_mask_tensor(self.mask, context, latents) # Get the source node id (we are invoking the prepared node) graph_execution_state = context.services.graph_execution_manager.get(context.graph_execution_state_id) @@ -487,14 +401,12 @@ class DenoiseLatentsInvocation(BaseInvocation): ) with ExitStack() as exit_stack, ModelPatcher.apply_lora_unet( unet_info.context.model, _lora_loader() - ), unet_info as unet: + ), set_unet_seamless(unet_info.context.model, self.unet.seamless_axes), unet_info as unet: latents = latents.to(device=unet.device, dtype=unet.dtype) if noise is not None: noise = noise.to(device=unet.device, dtype=unet.dtype) if mask is not None: mask = mask.to(device=unet.device, dtype=unet.dtype) - if masked_latents is not None: - masked_latents = masked_latents.to(device=unet.device, dtype=unet.dtype) scheduler = get_scheduler( context=context, @@ -531,7 +443,6 @@ class DenoiseLatentsInvocation(BaseInvocation): noise=noise, seed=seed, mask=mask, - masked_latents=masked_latents, num_inference_steps=num_inference_steps, conditioning_data=conditioning_data, control_data=control_data, # list[ControlNetData] @@ -753,11 +664,26 @@ class ImageToLatentsInvocation(BaseInvocation): tiled: bool = InputField(default=False, description=FieldDescriptions.tiled) fp32: bool = InputField(default=DEFAULT_PRECISION == "float32", description=FieldDescriptions.fp32) - @staticmethod - def vae_encode(vae_info, upcast, tiled, image_tensor): + @torch.no_grad() + def invoke(self, context: InvocationContext) -> LatentsOutput: + # image = context.services.images.get( + # self.image.image_type, self.image.image_name + # ) + image = context.services.images.get_pil_image(self.image.image_name) + + # vae_info = context.services.model_manager.get_model(**self.vae.vae.dict()) + vae_info = context.services.model_manager.get_model( + **self.vae.vae.dict(), + context=context, + ) + + image_tensor = image_resized_to_grid_as_tensor(image.convert("RGB")) + if image_tensor.dim() == 3: + image_tensor = einops.rearrange(image_tensor, "c h w -> 1 c h w") + with vae_info as vae: orig_dtype = vae.dtype - if upcast: + if self.fp32: vae.to(dtype=torch.float32) use_torch_2_0_or_xformers = isinstance( @@ -782,7 +708,7 @@ class ImageToLatentsInvocation(BaseInvocation): vae.to(dtype=torch.float16) # latents = latents.half() - if tiled: + if self.tiled: vae.enable_tiling() else: vae.disable_tiling() @@ -796,23 +722,6 @@ class ImageToLatentsInvocation(BaseInvocation): latents = vae.config.scaling_factor * latents latents = latents.to(dtype=orig_dtype) - return latents - - @torch.no_grad() - def invoke(self, context: InvocationContext) -> LatentsOutput: - image = context.services.images.get_pil_image(self.image.image_name) - - vae_info = context.services.model_manager.get_model( - **self.vae.vae.dict(), - context=context, - ) - - image_tensor = image_resized_to_grid_as_tensor(image.convert("RGB")) - if image_tensor.dim() == 3: - image_tensor = einops.rearrange(image_tensor, "c h w -> 1 c h w") - - latents = self.vae_encode(vae_info, self.fp32, self.tiled, image_tensor) - name = f"{context.graph_execution_state_id}__{self.id}" latents = latents.to("cpu") context.services.latents.save(name, latents) From 0d2e19421349a796484d5d5af2e4f50d082f69bd Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:21:56 -0400 Subject: [PATCH 05/29] Fixed dict error --- invokeai/backend/model_management/seamless.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 0568c68ac2..ea4037077e 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -23,31 +23,31 @@ def _conv_forward_asymmetric(self, input, weight, bias): @contextmanager -def set_unet_seamless(model: UNet2DModel, seamless: bool, seamless_axes): +def set_unet_seamless(model: UNet2DModel, seamless_axes): try: - to_restore = dict() - if seamless: - for m in model.modules(): - if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): - m.asymmetric_padding_mode = {} - m.asymmetric_padding = {} - m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" - m.asymmetric_padding["x"] = ( - m._reversed_padding_repeated_twice[0], - m._reversed_padding_repeated_twice[1], - 0, - 0, - ) - m.asymmetric_padding_mode["y"] = "circular" if ("y" in seamless_axes) else "constant" - m.asymmetric_padding["y"] = ( - 0, - 0, - m._reversed_padding_repeated_twice[2], - m._reversed_padding_repeated_twice[3], - ) + to_restore = [] + + for m in model.modules(): + if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): + m.asymmetric_padding_mode = {} + m.asymmetric_padding = {} + m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" + m.asymmetric_padding["x"] = ( + m._reversed_padding_repeated_twice[0], + m._reversed_padding_repeated_twice[1], + 0, + 0, + ) + m.asymmetric_padding_mode["y"] = "circular" if ("y" in seamless_axes) else "constant" + m.asymmetric_padding["y"] = ( + 0, + 0, + m._reversed_padding_repeated_twice[2], + m._reversed_padding_repeated_twice[3], + ) - to_restore.append((m, m._conv_forward)) - m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) + to_restore.append((m, m._conv_forward)) + m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) yield From ea40a7844a5f2227a6fdece9c425d51ecb2bc362 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:53:57 -0400 Subject: [PATCH 06/29] add VAE --- invokeai/app/invocations/latent.py | 4 +- invokeai/app/invocations/model.py | 11 +++++- invokeai/backend/model_management/seamless.py | 38 ++++++++++++++++++- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 708dfe81b9..80f90157df 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -33,7 +33,7 @@ from invokeai.backend.model_management.models import ModelType, SilenceWarnings from ...backend.model_management.models import BaseModelType from ...backend.model_management.lora import ModelPatcher -from ...backend.model_management.seamless import set_unet_seamless +from ...backend.model_management.seamless import set_unet_seamless, set_vae_seamless from ...backend.stable_diffusion import PipelineIntermediateState from ...backend.stable_diffusion.diffusers_pipeline import ( ConditioningData, @@ -491,7 +491,7 @@ class LatentsToImageInvocation(BaseInvocation): context=context, ) - with vae_info as vae: + with set_vae_seamless(vae_info.context.model, self.vae.seamless_axes), vae_info as vae: latents = latents.to(vae.device) if self.fp32: vae.to(dtype=torch.float32) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 1bb67b8c91..eac3638ad3 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -46,6 +46,7 @@ class ClipField(BaseModel): class VaeField(BaseModel): # TODO: better naming? vae: ModelInfo = Field(description="Info to load vae submodel") + seamless_axes: List[str] = Field(default_factory=list, description="Axes(\"x\" and \"y\") to which apply seamless") class ModelLoaderOutput(BaseInvocationOutput): @@ -398,6 +399,7 @@ class SeamlessModeOutput(BaseInvocationOutput): # Outputs unet: UNetField = OutputField(description=FieldDescriptions.unet, title="UNet") + vae: VaeField = OutputField(description=FieldDescriptions.vae, title="VAE") @title("Seamless") @tags("seamless", "model") @@ -410,7 +412,9 @@ class SeamlessModeInvocation(BaseInvocation): unet: UNetField = InputField( description=FieldDescriptions.unet, input=Input.Connection, title="UNet" ) - + vae_model: VAEModelField = InputField( + description=FieldDescriptions.vae_model, input=Input.Direct, ui_type=UIType.VaeModel, title="VAE" + ) seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") @@ -418,6 +422,7 @@ class SeamlessModeInvocation(BaseInvocation): def invoke(self, context: InvocationContext) -> SeamlessModeOutput: # Conditionally append 'x' and 'y' based on seamless_x and seamless_y unet = copy.deepcopy(self.unet) + vae = copy.deepcopy(self.vae) seamless_axes_list = [] @@ -427,7 +432,9 @@ class SeamlessModeInvocation(BaseInvocation): seamless_axes_list.append('y') unet.seamless_axes = seamless_axes_list - + vae.seamless_axes = seamless_axes_list + return SeamlessModeOutput( unet=unet, + vae=vae ) \ No newline at end of file diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index ea4037077e..49770b4281 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -3,7 +3,7 @@ from __future__ import annotations from contextlib import contextmanager import torch.nn as nn -from diffusers.models import UNet2DModel +from diffusers.models import UNet2DModel, AutoencoderKL def _conv_forward_asymmetric(self, input, weight, bias): """ @@ -51,6 +51,42 @@ def set_unet_seamless(model: UNet2DModel, seamless_axes): yield + finally: + for module, orig_conv_forward in to_restore: + module._conv_forward = orig_conv_forward + if hasattr(m, "asymmetric_padding_mode"): + del m.asymmetric_padding_mode + if hasattr(m, "asymmetric_padding"): + del m.asymmetric_padding + +def set_vae_seamless(model: AutoencoderKL, seamless_axes): + try: + to_restore = [] + + for m in model.modules(): + if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): + m.asymmetric_padding_mode = {} + m.asymmetric_padding = {} + m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" + m.asymmetric_padding["x"] = ( + m._reversed_padding_repeated_twice[0], + m._reversed_padding_repeated_twice[1], + 0, + 0, + ) + m.asymmetric_padding_mode["y"] = "circular" if ("y" in seamless_axes) else "constant" + m.asymmetric_padding["y"] = ( + 0, + 0, + m._reversed_padding_repeated_twice[2], + m._reversed_padding_repeated_twice[3], + ) + + to_restore.append((m, m._conv_forward)) + m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) + + yield + finally: for module, orig_conv_forward in to_restore: module._conv_forward = orig_conv_forward From 19e0f360e7a724a698a62501857c3ccd85d86643 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 15:05:10 -0400 Subject: [PATCH 07/29] Fix vae fields --- invokeai/app/invocations/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index eac3638ad3..c5bf4b1262 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -412,8 +412,8 @@ class SeamlessModeInvocation(BaseInvocation): unet: UNetField = InputField( description=FieldDescriptions.unet, input=Input.Connection, title="UNet" ) - vae_model: VAEModelField = InputField( - description=FieldDescriptions.vae_model, input=Input.Direct, ui_type=UIType.VaeModel, title="VAE" + vae: VaeField = InputField( + description=FieldDescriptions.vae_model, input=Input.Any, title="VAE" ) seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") From 5fdd25501bd7b4adb35ef8a2a409c2e5a9315ea4 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Sun, 27 Aug 2023 22:54:53 -0400 Subject: [PATCH 08/29] updates per stalkers comments --- invokeai/app/invocations/latent.py | 6 +-- invokeai/app/invocations/model.py | 4 +- invokeai/backend/model_management/seamless.py | 39 ++----------------- 3 files changed, 8 insertions(+), 41 deletions(-) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 80f90157df..c1918a981a 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -33,7 +33,7 @@ from invokeai.backend.model_management.models import ModelType, SilenceWarnings from ...backend.model_management.models import BaseModelType from ...backend.model_management.lora import ModelPatcher -from ...backend.model_management.seamless import set_unet_seamless, set_vae_seamless +from ...backend.model_management.seamless import set_seamless from ...backend.stable_diffusion import PipelineIntermediateState from ...backend.stable_diffusion.diffusers_pipeline import ( ConditioningData, @@ -401,7 +401,7 @@ class DenoiseLatentsInvocation(BaseInvocation): ) with ExitStack() as exit_stack, ModelPatcher.apply_lora_unet( unet_info.context.model, _lora_loader() - ), set_unet_seamless(unet_info.context.model, self.unet.seamless_axes), unet_info as unet: + ), set_seamless(unet_info.context.model, self.unet.seamless_axes), unet_info as unet: latents = latents.to(device=unet.device, dtype=unet.dtype) if noise is not None: noise = noise.to(device=unet.device, dtype=unet.dtype) @@ -491,7 +491,7 @@ class LatentsToImageInvocation(BaseInvocation): context=context, ) - with set_vae_seamless(vae_info.context.model, self.vae.seamless_axes), vae_info as vae: + with set_seamless(vae_info.context.model, self.vae.seamless_axes), vae_info as vae: latents = latents.to(vae.device) if self.fp32: vae.to(dtype=torch.float32) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index c5bf4b1262..ca76ce7d51 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -398,8 +398,8 @@ class SeamlessModeOutput(BaseInvocationOutput): type: Literal["seamless_output"] = "seamless_output" # Outputs - unet: UNetField = OutputField(description=FieldDescriptions.unet, title="UNet") - vae: VaeField = OutputField(description=FieldDescriptions.vae, title="VAE") + unet: Optional[UNetField] = OutputField(description=FieldDescriptions.unet, title="UNet") + vae: Optional[VaeField] = OutputField(description=FieldDescriptions.vae, title="VAE") @title("Seamless") @tags("seamless", "model") diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 49770b4281..db0274c3f7 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager - +from typing import TypeVar, Union import torch.nn as nn from diffusers.models import UNet2DModel, AutoencoderKL @@ -23,43 +23,10 @@ def _conv_forward_asymmetric(self, input, weight, bias): @contextmanager -def set_unet_seamless(model: UNet2DModel, seamless_axes): - try: - to_restore = [] - - for m in model.modules(): - if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): - m.asymmetric_padding_mode = {} - m.asymmetric_padding = {} - m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" - m.asymmetric_padding["x"] = ( - m._reversed_padding_repeated_twice[0], - m._reversed_padding_repeated_twice[1], - 0, - 0, - ) - m.asymmetric_padding_mode["y"] = "circular" if ("y" in seamless_axes) else "constant" - m.asymmetric_padding["y"] = ( - 0, - 0, - m._reversed_padding_repeated_twice[2], - m._reversed_padding_repeated_twice[3], - ) - to_restore.append((m, m._conv_forward)) - m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) +ModelType = TypeVar('ModelType', UNet2DModel, AutoencoderKL) - yield - - finally: - for module, orig_conv_forward in to_restore: - module._conv_forward = orig_conv_forward - if hasattr(m, "asymmetric_padding_mode"): - del m.asymmetric_padding_mode - if hasattr(m, "asymmetric_padding"): - del m.asymmetric_padding - -def set_vae_seamless(model: AutoencoderKL, seamless_axes): +def set_seamless(model: ModelType, seamless_axes): try: to_restore = [] From 1f476692dad6629f0138f08c6478233fc73da01c Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Mon, 28 Aug 2023 00:10:46 -0400 Subject: [PATCH 09/29] Seamless fixes --- invokeai/app/invocations/model.py | 2 +- invokeai/backend/model_management/seamless.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index ca76ce7d51..e794423fa1 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -404,7 +404,7 @@ class SeamlessModeOutput(BaseInvocationOutput): @title("Seamless") @tags("seamless", "model") class SeamlessModeInvocation(BaseInvocation): - """Apply seamless mode to unet.""" + """Applies the seamless transformation to the Model UNet and VAE.""" type: Literal["seamless"] = "seamless" diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index db0274c3f7..b56b64f1de 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -1,7 +1,8 @@ from __future__ import annotations from contextlib import contextmanager -from typing import TypeVar, Union +from typing import TypeVar +import diffusers import torch.nn as nn from diffusers.models import UNet2DModel, AutoencoderKL @@ -22,10 +23,9 @@ def _conv_forward_asymmetric(self, input, weight, bias): ) -@contextmanager - ModelType = TypeVar('ModelType', UNet2DModel, AutoencoderKL) +@contextmanager def set_seamless(model: ModelType, seamless_axes): try: to_restore = [] @@ -51,6 +51,8 @@ def set_seamless(model: ModelType, seamless_axes): to_restore.append((m, m._conv_forward)) m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) + if isinstance(m, diffusers.models.lora.LoRACompatibleConv) and m.lora_layer is None: + m.forward = nn.Conv2d.forward.__get__(m, nn.Conv2d) yield @@ -60,4 +62,6 @@ def set_seamless(model: ModelType, seamless_axes): if hasattr(m, "asymmetric_padding_mode"): del m.asymmetric_padding_mode if hasattr(m, "asymmetric_padding"): - del m.asymmetric_padding \ No newline at end of file + del m.asymmetric_padding + if isinstance(m, diffusers.models.lora.LoRACompatibleConv): + m.forward = diffusers.models.lora.LoRACompatibleConv.forward.__get__(m,diffusers.models.lora.LoRACompatibleConv) \ No newline at end of file From 3ef36707a8a09d42526fa04daa9f0b1628e4cf6f Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Mon, 28 Aug 2023 23:10:00 +1200 Subject: [PATCH 10/29] chore: Black lint --- invokeai/app/invocations/model.py | 29 +++++++------------ invokeai/backend/model_management/seamless.py | 12 +++++--- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index e794423fa1..89b292d223 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -33,7 +33,7 @@ class UNetField(BaseModel): unet: ModelInfo = Field(description="Info to load unet submodel") scheduler: ModelInfo = Field(description="Info to load scheduler submodel") loras: List[LoraInfo] = Field(description="Loras to apply on model loading") - seamless_axes: List[str] = Field(default_factory=list, description="Axes(\"x\" and \"y\") to which apply seamless") + seamless_axes: List[str] = Field(default_factory=list, description='Axes("x" and "y") to which apply seamless') class ClipField(BaseModel): @@ -46,7 +46,7 @@ class ClipField(BaseModel): class VaeField(BaseModel): # TODO: better naming? vae: ModelInfo = Field(description="Info to load vae submodel") - seamless_axes: List[str] = Field(default_factory=list, description="Axes(\"x\" and \"y\") to which apply seamless") + seamless_axes: List[str] = Field(default_factory=list, description='Axes("x" and "y") to which apply seamless') class ModelLoaderOutput(BaseInvocationOutput): @@ -401,6 +401,7 @@ class SeamlessModeOutput(BaseInvocationOutput): unet: Optional[UNetField] = OutputField(description=FieldDescriptions.unet, title="UNet") vae: Optional[VaeField] = OutputField(description=FieldDescriptions.vae, title="VAE") + @title("Seamless") @tags("seamless", "model") class SeamlessModeInvocation(BaseInvocation): @@ -409,32 +410,24 @@ class SeamlessModeInvocation(BaseInvocation): type: Literal["seamless"] = "seamless" # Inputs - unet: UNetField = InputField( - description=FieldDescriptions.unet, input=Input.Connection, title="UNet" - ) - vae: VaeField = InputField( - description=FieldDescriptions.vae_model, input=Input.Any, title="VAE" - ) + unet: UNetField = InputField(description=FieldDescriptions.unet, input=Input.Connection, title="UNet") + vae: VaeField = InputField(description=FieldDescriptions.vae_model, input=Input.Any, title="VAE") seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") - def invoke(self, context: InvocationContext) -> SeamlessModeOutput: - # Conditionally append 'x' and 'y' based on seamless_x and seamless_y + # Conditionally append 'x' and 'y' based on seamless_x and seamless_y unet = copy.deepcopy(self.unet) vae = copy.deepcopy(self.vae) - + seamless_axes_list = [] if self.seamless_x: - seamless_axes_list.append('x') + seamless_axes_list.append("x") if self.seamless_y: - seamless_axes_list.append('y') + seamless_axes_list.append("y") unet.seamless_axes = seamless_axes_list vae.seamless_axes = seamless_axes_list - - return SeamlessModeOutput( - unet=unet, - vae=vae - ) \ No newline at end of file + + return SeamlessModeOutput(unet=unet, vae=vae) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index b56b64f1de..1801c6e057 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -6,6 +6,7 @@ import diffusers import torch.nn as nn from diffusers.models import UNet2DModel, AutoencoderKL + def _conv_forward_asymmetric(self, input, weight, bias): """ Patch for Conv2d._conv_forward that supports asymmetric padding @@ -23,13 +24,14 @@ def _conv_forward_asymmetric(self, input, weight, bias): ) -ModelType = TypeVar('ModelType', UNet2DModel, AutoencoderKL) +ModelType = TypeVar("ModelType", UNet2DModel, AutoencoderKL) + @contextmanager def set_seamless(model: ModelType, seamless_axes): try: - to_restore = [] - + to_restore = [] + for m in model.modules(): if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): m.asymmetric_padding_mode = {} @@ -64,4 +66,6 @@ def set_seamless(model: ModelType, seamless_axes): if hasattr(m, "asymmetric_padding"): del m.asymmetric_padding if isinstance(m, diffusers.models.lora.LoRACompatibleConv): - m.forward = diffusers.models.lora.LoRACompatibleConv.forward.__get__(m,diffusers.models.lora.LoRACompatibleConv) \ No newline at end of file + m.forward = diffusers.models.lora.LoRACompatibleConv.forward.__get__( + m, diffusers.models.lora.LoRACompatibleConv + ) From 421f5b7d75f4cd1eba0e7725eba1d5471905e4c0 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Mon, 28 Aug 2023 08:43:08 -0400 Subject: [PATCH 11/29] Seamless Updates --- invokeai/app/invocations/model.py | 10 ++++++---- invokeai/backend/model_management/seamless.py | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 89b292d223..a2cc4eb349 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -410,8 +410,8 @@ class SeamlessModeInvocation(BaseInvocation): type: Literal["seamless"] = "seamless" # Inputs - unet: UNetField = InputField(description=FieldDescriptions.unet, input=Input.Connection, title="UNet") - vae: VaeField = InputField(description=FieldDescriptions.vae_model, input=Input.Any, title="VAE") + unet: Optional[UNetField] = InputField(default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet") + vae: Optional[VaeField] = InputField(default=None, description=FieldDescriptions.vae_model, input=Input.Any, title="VAE") seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") @@ -427,7 +427,9 @@ class SeamlessModeInvocation(BaseInvocation): if self.seamless_y: seamless_axes_list.append("y") - unet.seamless_axes = seamless_axes_list - vae.seamless_axes = seamless_axes_list + if unet is not None: + unet.seamless_axes = seamless_axes_list + if vae is not None: + vae.seamless_axes = seamless_axes_list return SeamlessModeOutput(unet=unet, vae=vae) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 1801c6e057..ec81ed9a74 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import TypeVar +from typing import Union import diffusers import torch.nn as nn from diffusers.models import UNet2DModel, AutoencoderKL @@ -24,7 +24,7 @@ def _conv_forward_asymmetric(self, input, weight, bias): ) -ModelType = TypeVar("ModelType", UNet2DModel, AutoencoderKL) +ModelType = Union[UNet2DModel, AutoencoderKL] @contextmanager From e60af40c8d2af363ffdfbb0c62ad33bc47c266e7 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 01:11:55 +1200 Subject: [PATCH 12/29] chore: lint fixes --- invokeai/frontend/web/src/app/components/App.tsx | 4 ++-- .../parameters/hooks/usePreselectedImage.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index a4a0997443..a70ed03fda 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -12,12 +12,12 @@ import { languageSelector } from 'features/system/store/systemSelectors'; import InvokeTabs from 'features/ui/components/InvokeTabs'; import i18n from 'i18n'; import { size } from 'lodash-es'; -import { ReactNode, memo, useCallback, useEffect, useMemo } from 'react'; +import { ReactNode, memo, useCallback, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; +import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage'; import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; import GlobalHotkeys from './GlobalHotkeys'; import Toaster from './Toaster'; -import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage'; const DEFAULT_CONFIG = {}; diff --git a/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts index fa310a66ad..6f7ac46f25 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/usePreselectedImage.ts @@ -1,16 +1,16 @@ import { skipToken } from '@reduxjs/toolkit/dist/query'; -import { useCallback, useMemo, useState } from 'react'; +import { t } from 'i18next'; +import { useCallback, useState } from 'react'; +import { useAppToaster } from '../../../app/components/Toaster'; +import { useAppDispatch } from '../../../app/store/storeHooks'; import { useGetImageDTOQuery, useGetImageMetadataQuery, } from '../../../services/api/endpoints/images'; -import { useAppDispatch } from '../../../app/store/storeHooks'; import { setInitialCanvasImage } from '../../canvas/store/canvasSlice'; import { setActiveTab } from '../../ui/store/uiSlice'; -import { useRecallParameters } from './useRecallParameters'; import { initialImageSelected } from '../store/actions'; -import { useAppToaster } from '../../../app/components/Toaster'; -import { t } from 'i18next'; +import { useRecallParameters } from './useRecallParameters'; type SelectedImage = { imageName: string; @@ -26,7 +26,7 @@ export const usePreselectedImage = () => { const { recallAllParameters } = useRecallParameters(); const toaster = useAppToaster(); - const { currentData: selectedImageDto, isError } = useGetImageDTOQuery( + const { currentData: selectedImageDto } = useGetImageDTOQuery( imageNameForDto ?? skipToken ); @@ -37,8 +37,8 @@ export const usePreselectedImage = () => { const handlePreselectedImage = useCallback( (selectedImage?: SelectedImage) => { if (!selectedImage) { -return; -} + return; + } if (selectedImage.action === 'sendToCanvas') { setImageNameForDto(selectedImage?.imageName); From bb085c5fba856ce93fbf708c6634bcc5539cafaa Mon Sep 17 00:00:00 2001 From: Sergey Borisov Date: Mon, 28 Aug 2023 18:29:49 +0300 Subject: [PATCH 13/29] Move monkeypatch for diffusers/torch bug to hotfixes.py --- invokeai/backend/model_management/seamless.py | 13 ++----------- invokeai/backend/util/hotfixes.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index ec81ed9a74..4e9587a86f 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import Union +from typing import Union, List import diffusers import torch.nn as nn from diffusers.models import UNet2DModel, AutoencoderKL @@ -24,11 +24,8 @@ def _conv_forward_asymmetric(self, input, weight, bias): ) -ModelType = Union[UNet2DModel, AutoencoderKL] - - @contextmanager -def set_seamless(model: ModelType, seamless_axes): +def set_seamless(model: Union[UNet2DModel, AutoencoderKL], seamless_axes: List[str]): try: to_restore = [] @@ -53,8 +50,6 @@ def set_seamless(model: ModelType, seamless_axes): to_restore.append((m, m._conv_forward)) m._conv_forward = _conv_forward_asymmetric.__get__(m, nn.Conv2d) - if isinstance(m, diffusers.models.lora.LoRACompatibleConv) and m.lora_layer is None: - m.forward = nn.Conv2d.forward.__get__(m, nn.Conv2d) yield @@ -65,7 +60,3 @@ def set_seamless(model: ModelType, seamless_axes): del m.asymmetric_padding_mode if hasattr(m, "asymmetric_padding"): del m.asymmetric_padding - if isinstance(m, diffusers.models.lora.LoRACompatibleConv): - m.forward = diffusers.models.lora.LoRACompatibleConv.forward.__get__( - m, diffusers.models.lora.LoRACompatibleConv - ) diff --git a/invokeai/backend/util/hotfixes.py b/invokeai/backend/util/hotfixes.py index 3d7f278f86..3d64d8a42c 100644 --- a/invokeai/backend/util/hotfixes.py +++ b/invokeai/backend/util/hotfixes.py @@ -761,3 +761,18 @@ class ControlNetModel(ModelMixin, ConfigMixin, FromOriginalControlnetMixin): diffusers.ControlNetModel = ControlNetModel diffusers.models.controlnet.ControlNetModel = ControlNetModel + + +# patch LoRACompatibleConv to use original Conv2D forward function +# this needed to make work seamless patch +# NOTE: with this patch, torch.compile crashes on 2.0 torch(already fixed in nightly) +# https://github.com/huggingface/diffusers/pull/4315 +# https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/lora.py#L96C18-L96C18 +def new_LoRACompatibleConv_forward(self, x): + if self.lora_layer is None: + return super(diffusers.models.lora.LoRACompatibleConv, self).forward(x) + else: + return super(diffusers.models.lora.LoRACompatibleConv, self).forward(x) + self.lora_layer(x) + + +diffusers.models.lora.LoRACompatibleConv.forward = new_LoRACompatibleConv_forward From 594e547c3bba04e909ef02515d417e34f1c0a73a Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:01:04 +1200 Subject: [PATCH 14/29] feat: Add Seamless to T2I / I2I / SDXL T2I / I2I + Refiner --- .../graphBuilders/addSDXLRefinerToGraph.ts | 60 ++++++++-- .../graphBuilders/addSeamlessToLinearGraph.ts | 79 +++++++++++++ .../buildLinearImageToImageGraph.ts | 16 ++- .../buildLinearSDXLImageToImageGraph.ts | 20 +++- .../buildLinearSDXLTextToImageGraph.ts | 19 ++- .../buildLinearTextToImageGraph.ts | 12 +- .../nodes/util/graphBuilders/constants.ts | 2 + .../SDXLImageToImageTabParameters.tsx | 2 + .../SDXLTextToImageTabParameters.tsx | 2 + .../src/features/system/store/configSlice.ts | 1 - .../frontend/web/src/services/api/schema.d.ts | 109 +++++++++++++++--- .../frontend/web/src/services/api/types.ts | 1 + 12 files changed, 290 insertions(+), 33 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts index 3edea0b3c0..9474a8df4e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts @@ -1,11 +1,15 @@ import { RootState } from 'app/store/store'; -import { MetadataAccumulatorInvocation } from 'services/api/types'; +import { + MetadataAccumulatorInvocation, + SeamlessModeInvocation, +} from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; import { CANVAS_OUTPUT, LATENTS_TO_IMAGE, MASK_BLUR, METADATA_ACCUMULATOR, + REFINER_SEAMLESS, SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, SDXL_CANVAS_INPAINT_GRAPH, SDXL_CANVAS_OUTPAINT_GRAPH, @@ -21,7 +25,8 @@ import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; export const addSDXLRefinerToGraph = ( state: RootState, graph: NonNullableGraph, - baseNodeId: string + baseNodeId: string, + modelLoaderNodeId?: string ): void => { const { refinerModel, @@ -33,6 +38,8 @@ export const addSDXLRefinerToGraph = ( refinerStart, } = state.sdxl; + const { seamlessXAxis, seamlessYAxis } = state.generation; + if (!refinerModel) { return; } @@ -53,6 +60,10 @@ export const addSDXLRefinerToGraph = ( metadataAccumulator.refiner_steps = refinerSteps; } + const modelLoaderId = modelLoaderNodeId + ? modelLoaderNodeId + : SDXL_MODEL_LOADER; + // Construct Style Prompt const { craftedPositiveStylePrompt, craftedNegativeStylePrompt } = craftSDXLStylePrompt(state, true); @@ -65,10 +76,7 @@ export const addSDXLRefinerToGraph = ( graph.edges = graph.edges.filter( (e) => - !( - e.source.node_id === SDXL_MODEL_LOADER && - ['vae'].includes(e.source.field) - ) + !(e.source.node_id === modelLoaderId && ['vae'].includes(e.source.field)) ); graph.nodes[SDXL_REFINER_MODEL_LOADER] = { @@ -98,8 +106,39 @@ export const addSDXLRefinerToGraph = ( denoising_end: 1, }; - graph.edges.push( - { + // Add Seamless To Refiner + if (seamlessXAxis || seamlessYAxis) { + graph.nodes[REFINER_SEAMLESS] = { + id: REFINER_SEAMLESS, + type: 'seamless', + seamless_x: seamlessXAxis, + seamless_y: seamlessYAxis, + } as SeamlessModeInvocation; + + graph.edges.push( + { + source: { + node_id: SDXL_REFINER_MODEL_LOADER, + field: 'unet', + }, + destination: { + node_id: REFINER_SEAMLESS, + field: 'unet', + }, + }, + { + source: { + node_id: REFINER_SEAMLESS, + field: 'unet', + }, + destination: { + node_id: SDXL_REFINER_DENOISE_LATENTS, + field: 'unet', + }, + } + ); + } else { + graph.edges.push({ source: { node_id: SDXL_REFINER_MODEL_LOADER, field: 'unet', @@ -108,7 +147,10 @@ export const addSDXLRefinerToGraph = ( node_id: SDXL_REFINER_DENOISE_LATENTS, field: 'unet', }, - }, + }); + } + + graph.edges.push( { source: { node_id: SDXL_REFINER_MODEL_LOADER, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts new file mode 100644 index 0000000000..4cb298a626 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -0,0 +1,79 @@ +import { RootState } from 'app/store/store'; +import { SeamlessModeInvocation } from 'services/api/types'; +import { NonNullableGraph } from '../../types/types'; +import { + DENOISE_LATENTS, + IMAGE_TO_IMAGE_GRAPH, + SDXL_IMAGE_TO_IMAGE_GRAPH, + SDXL_TEXT_TO_IMAGE_GRAPH, + SEAMLESS, + TEXT_TO_IMAGE_GRAPH, +} from './constants'; + +export const addSeamlessToLinearGraph = ( + state: RootState, + graph: NonNullableGraph, + modelLoaderNodeId: string +): void => { + // Remove Existing UNet Connections + const { seamlessXAxis, seamlessYAxis } = state.generation; + + graph.nodes[SEAMLESS] = { + id: SEAMLESS, + type: 'seamless', + seamless_x: seamlessXAxis, + seamless_y: seamlessYAxis, + } as SeamlessModeInvocation; + + graph.edges = graph.edges.filter( + (e) => + !( + e.source.node_id === modelLoaderNodeId && + ['unet'].includes(e.source.field) + ) && + !( + e.source.node_id === modelLoaderNodeId && + ['vae'].includes(e.source.field) + ) + ); + + if ( + graph.id === TEXT_TO_IMAGE_GRAPH || + graph.id === IMAGE_TO_IMAGE_GRAPH || + graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || + graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH + ) { + graph.edges.push( + { + source: { + node_id: modelLoaderNodeId, + field: 'unet', + }, + destination: { + node_id: SEAMLESS, + field: 'unet', + }, + }, + { + source: { + node_id: modelLoaderNodeId, + field: 'vae', + }, + destination: { + node_id: SEAMLESS, + field: 'vae', + }, + }, + { + source: { + node_id: SEAMLESS, + field: 'unet', + }, + destination: { + node_id: DENOISE_LATENTS, + field: 'unet', + }, + } + ); + } +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index 982a09357f..a514f0ead9 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -24,6 +25,7 @@ import { NOISE, POSITIVE_CONDITIONING, RESIZE, + SEAMLESS, } from './constants'; /** @@ -49,6 +51,8 @@ export const buildLinearImageToImageGraph = ( shouldUseCpuNoise, shouldUseNoiseSettings, vaePrecision, + seamlessXAxis, + seamlessYAxis, } = state.generation; // TODO: add batch functionality @@ -80,6 +84,8 @@ export const buildLinearImageToImageGraph = ( throw new Error('No model found in state'); } + let modelLoaderNodeId = MAIN_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : initialGenerationState.shouldUseCpuNoise; @@ -338,11 +344,17 @@ export const buildLinearImageToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // optionally add custom VAE - addVAEToGraph(state, graph, MAIN_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addLoRAsToGraph(state, graph, DENOISE_LATENTS); + addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId); // add dynamic prompts - also sets up core iteration and seed addDynamicPromptsToGraph(state, graph); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 42ea07c923..553cf0f548 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -11,6 +11,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -20,10 +21,12 @@ import { NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, + REFINER_SEAMLESS, RESIZE, SDXL_DENOISE_LATENTS, SDXL_IMAGE_TO_IMAGE_GRAPH, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -49,6 +52,8 @@ export const buildLinearSDXLImageToImageGraph = ( shouldUseCpuNoise, shouldUseNoiseSettings, vaePrecision, + seamlessXAxis, + seamlessYAxis, } = state.generation; const { @@ -79,6 +84,9 @@ export const buildLinearSDXLImageToImageGraph = ( throw new Error('No model found in state'); } + // Model Loader ID + let modelLoaderNodeId = SDXL_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : initialGenerationState.shouldUseCpuNoise; @@ -351,15 +359,23 @@ export const buildLinearSDXLImageToImageGraph = ( }, }); - addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } // Add Refiner if enabled if (shouldUseSDXLRefiner) { addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS); + modelLoaderNodeId = REFINER_SEAMLESS; } // optionally add custom VAE - addVAEToGraph(state, graph, SDXL_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); + + // Add LoRA Support + addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index a74884f23b..e5a4460d5b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -7,6 +7,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -15,9 +16,11 @@ import { NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, + REFINER_SEAMLESS, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, SDXL_TEXT_TO_IMAGE_GRAPH, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -38,6 +41,8 @@ export const buildLinearSDXLTextToImageGraph = ( shouldUseCpuNoise, shouldUseNoiseSettings, vaePrecision, + seamlessXAxis, + seamlessYAxis, } = state.generation; const { @@ -61,6 +66,9 @@ export const buildLinearSDXLTextToImageGraph = ( const { craftedPositiveStylePrompt, craftedNegativeStylePrompt } = craftSDXLStylePrompt(state, shouldConcatSDXLStylePrompt); + // Model Loader ID + let modelLoaderNodeId = SDXL_MODEL_LOADER; + /** * The easiest way to build linear graphs is to do it in the node editor, then copy and paste the * full graph here as a template. Then use the parameters from app state and set friendlier node @@ -244,16 +252,23 @@ export const buildLinearSDXLTextToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add Refiner if enabled if (shouldUseSDXLRefiner) { addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS); + modelLoaderNodeId = REFINER_SEAMLESS; } // optionally add custom VAE - addVAEToGraph(state, graph, SDXL_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER); + addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts index 99a1ec7420..d07534bdd9 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -22,6 +23,7 @@ import { NOISE, ONNX_MODEL_LOADER, POSITIVE_CONDITIONING, + SEAMLESS, TEXT_TO_IMAGE_GRAPH, } from './constants'; @@ -42,6 +44,8 @@ export const buildLinearTextToImageGraph = ( shouldUseCpuNoise, shouldUseNoiseSettings, vaePrecision, + seamlessXAxis, + seamlessYAxis, } = state.generation; const use_cpu = shouldUseNoiseSettings @@ -55,7 +59,7 @@ export const buildLinearTextToImageGraph = ( const isUsingOnnxModel = model.model_type === 'onnx'; - const modelLoaderNodeId = isUsingOnnxModel + let modelLoaderNodeId = isUsingOnnxModel ? ONNX_MODEL_LOADER : MAIN_MODEL_LOADER; @@ -258,6 +262,12 @@ export const buildLinearTextToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // optionally add custom VAE addVAEToGraph(state, graph, modelLoaderNodeId); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts index c701386898..8ada7393dd 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts @@ -56,6 +56,8 @@ export const SDXL_REFINER_POSITIVE_CONDITIONING = export const SDXL_REFINER_NEGATIVE_CONDITIONING = 'sdxl_refiner_negative_conditioning'; export const SDXL_REFINER_DENOISE_LATENTS = 'sdxl_refiner_denoise_latents'; +export const SEAMLESS = 'seamless'; +export const REFINER_SEAMLESS = 'refiner_seamless'; // friendly graph ids export const TEXT_TO_IMAGE_GRAPH = 'text_to_image_graph'; diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx index 4667ca63c0..2b40eca382 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabParameters.tsx @@ -2,6 +2,7 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; +import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import { memo } from 'react'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse'; @@ -17,6 +18,7 @@ const SDXLImageToImageTabParameters = () => { + ); }; diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx index 084c12af61..ff47a42207 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx @@ -2,6 +2,7 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; +import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters'; import { memo } from 'react'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; @@ -17,6 +18,7 @@ const SDXLTextToImageTabParameters = () => { + ); }; diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts index 6cff92a136..9bdc16ce77 100644 --- a/invokeai/frontend/web/src/features/system/store/configSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts @@ -9,7 +9,6 @@ export const initialConfigState: AppConfig = { disabledFeatures: ['lightbox', 'faceRestore', 'batches'], disabledSDFeatures: [ 'variation', - 'seamless', 'symmetry', 'hires', 'perlinNoise', diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index c089798721..6dee0fdaa2 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -2092,7 +2092,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; + [key: string]: components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; }; /** * Edges @@ -2135,7 +2135,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["BooleanOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]; + [key: string]: components["schemas"]["BooleanOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]; }; /** * Errors @@ -5707,6 +5707,73 @@ export type components = { * @enum {string} */ SchedulerPredictionType: "epsilon" | "v_prediction" | "sample"; + /** + * Seamless + * @description Applies the seamless transformation to the Model UNet and VAE. + */ + SeamlessModeInvocation: { + /** + * Id + * @description The id of this node. Must be unique among all nodes. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this node is an intermediate node. + * @default false + */ + is_intermediate?: boolean; + /** + * Type + * @default seamless + * @enum {string} + */ + type: "seamless"; + /** + * UNet + * @description UNet (scheduler, LoRAs) + */ + unet?: components["schemas"]["UNetField"]; + /** + * VAE + * @description VAE model to load + */ + vae?: components["schemas"]["VaeField"]; + /** + * Seamless Y + * @description Specify whether Y axis is seamless + * @default true + */ + seamless_y?: boolean; + /** + * Seamless X + * @description Specify whether X axis is seamless + * @default true + */ + seamless_x?: boolean; + }; + /** + * SeamlessModeOutput + * @description Modified Seamless Model output + */ + SeamlessModeOutput: { + /** + * Type + * @default seamless_output + * @enum {string} + */ + type: "seamless_output"; + /** + * UNet + * @description UNet (scheduler, LoRAs) + */ + unet?: components["schemas"]["UNetField"]; + /** + * VAE + * @description VAE + */ + vae?: components["schemas"]["VaeField"]; + }; /** * Segment Anything Processor * @description Applies segment anything processing to image @@ -6196,6 +6263,11 @@ export type components = { * @description Loras to apply on model loading */ loras: components["schemas"]["LoraInfo"][]; + /** + * Seamless Axes + * @description Axes("x" and "y") to which apply seamless + */ + seamless_axes?: string[]; }; /** Upscaler */ Upscaler: { @@ -6230,6 +6302,11 @@ export type components = { * @description Info to load vae submodel */ vae: components["schemas"]["ModelInfo"]; + /** + * Seamless Axes + * @description Axes("x" and "y") to which apply seamless + */ + seamless_axes?: string[]; }; /** * VAE @@ -6412,18 +6489,6 @@ export type components = { * @enum {string} */ StableDiffusionOnnxModelFormat: "olive" | "onnx"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. @@ -6436,6 +6501,18 @@ export type components = { * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -6552,7 +6629,7 @@ export type operations = { }; requestBody: { content: { - "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; + "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; }; }; responses: { @@ -6593,7 +6670,7 @@ export type operations = { }; requestBody: { content: { - "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; + "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]; }; }; responses: { diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 6b064edab3..51e2459b7f 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -130,6 +130,7 @@ export type ESRGANInvocation = s['ESRGANInvocation']; export type DivideInvocation = s['DivideInvocation']; export type ImageNSFWBlurInvocation = s['ImageNSFWBlurInvocation']; export type ImageWatermarkInvocation = s['ImageWatermarkInvocation']; +export type SeamlessModeInvocation = s['SeamlessModeInvocation']; // ControlNet Nodes export type ControlNetInvocation = s['ControlNetInvocation']; From ef58635a7676cda44b09dfa92623c71a993523c0 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:04:03 +1200 Subject: [PATCH 15/29] chore: black lint --- invokeai/app/invocations/model.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index a2cc4eb349..86936db93f 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -410,8 +410,12 @@ class SeamlessModeInvocation(BaseInvocation): type: Literal["seamless"] = "seamless" # Inputs - unet: Optional[UNetField] = InputField(default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet") - vae: Optional[VaeField] = InputField(default=None, description=FieldDescriptions.vae_model, input=Input.Any, title="VAE") + unet: Optional[UNetField] = InputField( + default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" + ) + vae: Optional[VaeField] = InputField( + default=None, description=FieldDescriptions.vae_model, input=Input.Any, title="VAE" + ) seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") From 6db19a8deea5389afdf33862808aca3bfd49f31a Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:15:15 +1200 Subject: [PATCH 16/29] fix: Connection type on Seamless Node VAE Input --- invokeai/app/invocations/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 86936db93f..31d04cfd37 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -8,8 +8,8 @@ from .baseinvocation import ( BaseInvocation, BaseInvocationOutput, FieldDescriptions, - InputField, Input, + InputField, InvocationContext, OutputField, UIType, @@ -414,7 +414,7 @@ class SeamlessModeInvocation(BaseInvocation): default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" ) vae: Optional[VaeField] = InputField( - default=None, description=FieldDescriptions.vae_model, input=Input.Any, title="VAE" + default=None, description=FieldDescriptions.vae_model, input=Input.Connection, title="VAE" ) seamless_y: bool = InputField(default=True, input=Input.Any, description="Specify whether Y axis is seamless") seamless_x: bool = InputField(default=True, input=Input.Any, description="Specify whether X axis is seamless") From 0ea67050f1ed00191c99a4f35719da7467852c30 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:18:45 +1200 Subject: [PATCH 17/29] fix: Seamless not correctly plugged to SDXL Denoise Latents --- .../graphBuilders/addSeamlessToLinearGraph.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts index 4cb298a626..a4f08b2f7a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -2,8 +2,13 @@ import { RootState } from 'app/store/store'; import { SeamlessModeInvocation } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; import { + CANVAS_IMAGE_TO_IMAGE_GRAPH, + CANVAS_TEXT_TO_IMAGE_GRAPH, DENOISE_LATENTS, IMAGE_TO_IMAGE_GRAPH, + SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, + SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH, + SDXL_DENOISE_LATENTS, SDXL_IMAGE_TO_IMAGE_GRAPH, SDXL_TEXT_TO_IMAGE_GRAPH, SEAMLESS, @@ -25,6 +30,15 @@ export const addSeamlessToLinearGraph = ( seamless_y: seamlessYAxis, } as SeamlessModeInvocation; + let denoisingNodeId = DENOISE_LATENTS; + + if ( + graph.id === 'SDXL_TEXT_TO_IMAGE_GRAPH' || + graph.id === 'SDXL_IMAGE_TO_IMAGE_GRAPH' + ) { + denoisingNodeId = SDXL_DENOISE_LATENTS; + } + graph.edges = graph.edges.filter( (e) => !( @@ -41,7 +55,11 @@ export const addSeamlessToLinearGraph = ( graph.id === TEXT_TO_IMAGE_GRAPH || graph.id === IMAGE_TO_IMAGE_GRAPH || graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || - graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH + graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH || + graph.id === CANVAS_TEXT_TO_IMAGE_GRAPH || + graph.id === CANVAS_IMAGE_TO_IMAGE_GRAPH || + graph.id === SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH || + graph.id == SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH ) { graph.edges.push( { @@ -70,7 +88,7 @@ export const addSeamlessToLinearGraph = ( field: 'unet', }, destination: { - node_id: DENOISE_LATENTS, + node_id: denoisingNodeId, field: 'unet', }, } From a08d22587bf994c53aa92b7ed358ec8188752335 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:21:11 +1200 Subject: [PATCH 18/29] fix: Incorrect node ID's for Seamless plugging --- .../nodes/util/graphBuilders/addSeamlessToLinearGraph.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts index a4f08b2f7a..e506d2e5bb 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -33,8 +33,8 @@ export const addSeamlessToLinearGraph = ( let denoisingNodeId = DENOISE_LATENTS; if ( - graph.id === 'SDXL_TEXT_TO_IMAGE_GRAPH' || - graph.id === 'SDXL_IMAGE_TO_IMAGE_GRAPH' + graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || + graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH ) { denoisingNodeId = SDXL_DENOISE_LATENTS; } From b5dac994115e34a310c2e77e6cd03de8a51c909e Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:26:11 +1200 Subject: [PATCH 19/29] feat: Add Seamless To Canvas Text To Image / Image To Image + SDXL + Refiner --- .../buildCanvasImageToImageGraph.ts | 14 ++++++++++++- .../buildCanvasSDXLImageToImageGraph.ts | 21 ++++++++++++++++--- .../buildCanvasSDXLTextToImageGraph.ts | 14 ++++++++++++- .../buildCanvasTextToImageGraph.ts | 12 ++++++++++- .../SDXLUnifiedCanvasTabParameters.tsx | 2 ++ .../UnifiedCanvas/UnifiedCanvasParameters.tsx | 2 ++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index d3334d31c3..51fe0ab733 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -7,6 +7,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -22,6 +23,7 @@ import { NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, + SEAMLESS, } from './constants'; /** @@ -44,6 +46,8 @@ export const buildCanvasImageToImageGraph = ( clipSkip, shouldUseCpuNoise, shouldUseNoiseSettings, + seamlessXAxis, + seamlessYAxis, } = state.generation; // The bounding box determines width and height, not the width and height params @@ -64,6 +68,8 @@ export const buildCanvasImageToImageGraph = ( throw new Error('No model found in state'); } + let modelLoaderNodeId = MAIN_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : initialGenerationState.shouldUseCpuNoise; @@ -340,11 +346,17 @@ export const buildCanvasImageToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // add LoRA support addLoRAsToGraph(state, graph, DENOISE_LATENTS); // optionally add custom VAE - addVAEToGraph(state, graph, MAIN_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add dynamic prompts - also sets up core iteration and seed addDynamicPromptsToGraph(state, graph); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index ea46e8a956..ba1fe46675 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -8,6 +8,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -19,9 +20,11 @@ import { NEGATIVE_CONDITIONING, NOISE, POSITIVE_CONDITIONING, + REFINER_SEAMLESS, SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -44,6 +47,8 @@ export const buildCanvasSDXLImageToImageGraph = ( clipSkip, shouldUseCpuNoise, shouldUseNoiseSettings, + seamlessXAxis, + seamlessYAxis, } = state.generation; const { @@ -71,6 +76,9 @@ export const buildCanvasSDXLImageToImageGraph = ( throw new Error('No model found in state'); } + // Model Loader ID + let modelLoaderNodeId = SDXL_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : initialGenerationState.shouldUseCpuNoise; @@ -351,16 +359,23 @@ export const buildCanvasSDXLImageToImageGraph = ( }, }); - // add LoRA support - addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } // Add Refiner if enabled if (shouldUseSDXLRefiner) { addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS); + modelLoaderNodeId = REFINER_SEAMLESS; } // optionally add custom VAE - addVAEToGraph(state, graph, SDXL_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); + + // add LoRA support + addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId); // add dynamic prompts - also sets up core iteration and seed addDynamicPromptsToGraph(state, graph); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index bdfc60fe00..afefa53645 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -11,6 +11,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -21,9 +22,11 @@ import { NOISE, ONNX_MODEL_LOADER, POSITIVE_CONDITIONING, + REFINER_SEAMLESS, SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -45,6 +48,8 @@ export const buildCanvasSDXLTextToImageGraph = ( clipSkip, shouldUseCpuNoise, shouldUseNoiseSettings, + seamlessXAxis, + seamlessYAxis, } = state.generation; // The bounding box determines width and height, not the width and height params @@ -74,7 +79,7 @@ export const buildCanvasSDXLTextToImageGraph = ( const isUsingOnnxModel = model.model_type === 'onnx'; - const modelLoaderNodeId = isUsingOnnxModel + let modelLoaderNodeId = isUsingOnnxModel ? ONNX_MODEL_LOADER : SDXL_MODEL_LOADER; @@ -334,9 +339,16 @@ export const buildCanvasSDXLTextToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add Refiner if enabled if (shouldUseSDXLRefiner) { addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS); + modelLoaderNodeId = REFINER_SEAMLESS; } // add LoRA support diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts index 1ceb23b71e..b25c266d66 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts @@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -24,6 +25,7 @@ import { NOISE, ONNX_MODEL_LOADER, POSITIVE_CONDITIONING, + SEAMLESS, } from './constants'; /** @@ -44,6 +46,8 @@ export const buildCanvasTextToImageGraph = ( clipSkip, shouldUseCpuNoise, shouldUseNoiseSettings, + seamlessXAxis, + seamlessYAxis, } = state.generation; // The bounding box determines width and height, not the width and height params @@ -70,7 +74,7 @@ export const buildCanvasTextToImageGraph = ( const isUsingOnnxModel = model.model_type === 'onnx'; - const modelLoaderNodeId = isUsingOnnxModel + let modelLoaderNodeId = isUsingOnnxModel ? ONNX_MODEL_LOADER : MAIN_MODEL_LOADER; @@ -321,6 +325,12 @@ export const buildCanvasTextToImageGraph = ( }, }); + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // optionally add custom VAE addVAEToGraph(state, graph, modelLoaderNodeId); diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx index 00432bcec8..8fc4a3181c 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabParameters.tsx @@ -5,6 +5,7 @@ import ParamMaskAdjustmentCollapse from 'features/parameters/components/Paramete import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse'; +import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import ParamSDXLPromptArea from './ParamSDXLPromptArea'; import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse'; import SDXLUnifiedCanvasTabCoreParameters from './SDXLUnifiedCanvasTabCoreParameters'; @@ -22,6 +23,7 @@ export default function SDXLUnifiedCanvasTabParameters() { + ); } diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx index 1c3d3cd270..a640e1bae4 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx @@ -6,6 +6,7 @@ import ParamMaskAdjustmentCollapse from 'features/parameters/components/Paramete import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea'; +import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse'; import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; import { memo } from 'react'; import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters'; @@ -22,6 +23,7 @@ const UnifiedCanvasParameters = () => { + ); From fcb60a7a59e08ded2672c01d1a430fe03bdce1fe Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:33:22 +1200 Subject: [PATCH 20/29] chore: Update var names that were not updated --- .../graphBuilders/buildCanvasImageToImageGraph.ts | 8 ++++---- .../buildCanvasSDXLImageToImageGraph.ts | 14 +++++++------- .../graphBuilders/buildLinearImageToImageGraph.ts | 8 ++++---- .../buildLinearSDXLImageToImageGraph.ts | 14 +++++++------- .../buildLinearSDXLTextToImageGraph.ts | 14 +++++++------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index 51fe0ab733..63a7eac56b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -87,9 +87,9 @@ export const buildCanvasImageToImageGraph = ( const graph: NonNullableGraph = { id: CANVAS_IMAGE_TO_IMAGE_GRAPH, nodes: { - [MAIN_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'main_model_loader', - id: MAIN_MODEL_LOADER, + id: modelLoaderNodeId, is_intermediate: true, model, }, @@ -148,7 +148,7 @@ export const buildCanvasImageToImageGraph = ( // Connect Model Loader to CLIP Skip and UNet { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -158,7 +158,7 @@ export const buildCanvasImageToImageGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index ba1fe46675..e5a14c3f8a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -100,9 +100,9 @@ export const buildCanvasSDXLImageToImageGraph = ( const graph: NonNullableGraph = { id: SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, nodes: { - [SDXL_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'sdxl_model_loader', - id: SDXL_MODEL_LOADER, + id: modelLoaderNodeId, model, }, [POSITIVE_CONDITIONING]: { @@ -152,7 +152,7 @@ export const buildCanvasSDXLImageToImageGraph = ( // Connect Model Loader To UNet & CLIP { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -162,7 +162,7 @@ export const buildCanvasSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -172,7 +172,7 @@ export const buildCanvasSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { @@ -182,7 +182,7 @@ export const buildCanvasSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -192,7 +192,7 @@ export const buildCanvasSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index a514f0ead9..7c1764ae65 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -94,9 +94,9 @@ export const buildLinearImageToImageGraph = ( const graph: NonNullableGraph = { id: IMAGE_TO_IMAGE_GRAPH, nodes: { - [MAIN_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'main_model_loader', - id: MAIN_MODEL_LOADER, + id: modelLoaderNodeId, model, }, [CLIP_SKIP]: { @@ -147,7 +147,7 @@ export const buildLinearImageToImageGraph = ( // Connect Model Loader to UNet and CLIP Skip { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -157,7 +157,7 @@ export const buildLinearImageToImageGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 553cf0f548..17f1052384 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -99,9 +99,9 @@ export const buildLinearSDXLImageToImageGraph = ( const graph: NonNullableGraph = { id: SDXL_IMAGE_TO_IMAGE_GRAPH, nodes: { - [SDXL_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'sdxl_model_loader', - id: SDXL_MODEL_LOADER, + id: modelLoaderNodeId, model, }, [POSITIVE_CONDITIONING]: { @@ -151,7 +151,7 @@ export const buildLinearSDXLImageToImageGraph = ( // Connect Model Loader to UNet, CLIP & VAE { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -161,7 +161,7 @@ export const buildLinearSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -171,7 +171,7 @@ export const buildLinearSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { @@ -181,7 +181,7 @@ export const buildLinearSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -191,7 +191,7 @@ export const buildLinearSDXLImageToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index e5a4460d5b..2af37fd905 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -82,9 +82,9 @@ export const buildLinearSDXLTextToImageGraph = ( const graph: NonNullableGraph = { id: SDXL_TEXT_TO_IMAGE_GRAPH, nodes: { - [SDXL_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'sdxl_model_loader', - id: SDXL_MODEL_LOADER, + id: modelLoaderNodeId, model, }, [POSITIVE_CONDITIONING]: { @@ -125,7 +125,7 @@ export const buildLinearSDXLTextToImageGraph = ( // Connect Model Loader to UNet, VAE & CLIP { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -135,7 +135,7 @@ export const buildLinearSDXLTextToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -145,7 +145,7 @@ export const buildLinearSDXLTextToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { @@ -155,7 +155,7 @@ export const buildLinearSDXLTextToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -165,7 +165,7 @@ export const buildLinearSDXLTextToImageGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { From 87bb4d8f6e66d3bb21db60a6197b77a30e3cacb2 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 04:52:41 +1200 Subject: [PATCH 21/29] fix: Seamless not working with SDXL on Canvas --- .../graphBuilders/addSeamlessToLinearGraph.ts | 96 ++++++++++--------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts index e506d2e5bb..e4816d9c87 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -2,17 +2,18 @@ import { RootState } from 'app/store/store'; import { SeamlessModeInvocation } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; import { - CANVAS_IMAGE_TO_IMAGE_GRAPH, - CANVAS_TEXT_TO_IMAGE_GRAPH, + CANVAS_COHERENCE_DENOISE_LATENTS, + CANVAS_INPAINT_GRAPH, + CANVAS_OUTPAINT_GRAPH, DENOISE_LATENTS, - IMAGE_TO_IMAGE_GRAPH, SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH, + SDXL_CANVAS_INPAINT_GRAPH, + SDXL_CANVAS_OUTPAINT_GRAPH, SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH, SDXL_DENOISE_LATENTS, SDXL_IMAGE_TO_IMAGE_GRAPH, SDXL_TEXT_TO_IMAGE_GRAPH, SEAMLESS, - TEXT_TO_IMAGE_GRAPH, } from './constants'; export const addSeamlessToLinearGraph = ( @@ -34,7 +35,9 @@ export const addSeamlessToLinearGraph = ( if ( graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || - graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH + graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH || + graph.id === SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH || + graph.id === SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH ) { denoisingNodeId = SDXL_DENOISE_LATENTS; } @@ -51,47 +54,54 @@ export const addSeamlessToLinearGraph = ( ) ); + graph.edges.push( + { + source: { + node_id: modelLoaderNodeId, + field: 'unet', + }, + destination: { + node_id: SEAMLESS, + field: 'unet', + }, + }, + { + source: { + node_id: modelLoaderNodeId, + field: 'vae', + }, + destination: { + node_id: SEAMLESS, + field: 'vae', + }, + }, + { + source: { + node_id: SEAMLESS, + field: 'unet', + }, + destination: { + node_id: denoisingNodeId, + field: 'unet', + }, + } + ); + if ( - graph.id === TEXT_TO_IMAGE_GRAPH || - graph.id === IMAGE_TO_IMAGE_GRAPH || - graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || - graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH || - graph.id === CANVAS_TEXT_TO_IMAGE_GRAPH || - graph.id === CANVAS_IMAGE_TO_IMAGE_GRAPH || - graph.id === SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH || - graph.id == SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH + graph.id == CANVAS_INPAINT_GRAPH || + graph.id === CANVAS_OUTPAINT_GRAPH || + graph.id === SDXL_CANVAS_INPAINT_GRAPH || + graph.id === SDXL_CANVAS_OUTPAINT_GRAPH ) { - graph.edges.push( - { - source: { - node_id: modelLoaderNodeId, - field: 'unet', - }, - destination: { - node_id: SEAMLESS, - field: 'unet', - }, + graph.edges.push({ + source: { + node_id: SEAMLESS, + field: 'unet', }, - { - source: { - node_id: modelLoaderNodeId, - field: 'vae', - }, - destination: { - node_id: SEAMLESS, - field: 'vae', - }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'unet', }, - { - source: { - node_id: SEAMLESS, - field: 'unet', - }, - destination: { - node_id: denoisingNodeId, - field: 'unet', - }, - } - ); + }); } }; From 50a266e064abe8460e477f62df34373c489f64cd Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:11:22 +1200 Subject: [PATCH 22/29] feat: Add Seamless to Inpaint & Outpaint --- .../graphBuilders/buildCanvasInpaintGraph.ts | 26 ++++++++---- .../graphBuilders/buildCanvasOutpaintGraph.ts | 26 ++++++++---- .../buildCanvasSDXLInpaintGraph.ts | 41 ++++++++++++++----- .../buildCanvasSDXLOutpaintGraph.ts | 25 +++++++++-- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index b4e974dadd..6eafd1fc06 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -13,6 +13,7 @@ import { import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -38,6 +39,7 @@ import { POSITIVE_CONDITIONING, RANDOM_INT, RANGE_OF_SIZE, + SEAMLESS, } from './constants'; /** @@ -68,6 +70,8 @@ export const buildCanvasInpaintGraph = ( canvasCoherenceSteps, canvasCoherenceStrength, clipSkip, + seamlessXAxis, + seamlessYAxis, } = state.generation; if (!model) { @@ -85,6 +89,8 @@ export const buildCanvasInpaintGraph = ( shouldAutoSave, } = state.canvas; + let modelLoaderNodeId = MAIN_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : shouldUseCpuNoise; @@ -92,9 +98,9 @@ export const buildCanvasInpaintGraph = ( const graph: NonNullableGraph = { id: CANVAS_INPAINT_GRAPH, nodes: { - [MAIN_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'main_model_loader', - id: MAIN_MODEL_LOADER, + id: modelLoaderNodeId, is_intermediate: true, model, }, @@ -204,7 +210,7 @@ export const buildCanvasInpaintGraph = ( // Connect Model Loader to CLIP Skip and UNet { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -214,7 +220,7 @@ export const buildCanvasInpaintGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -349,7 +355,7 @@ export const buildCanvasInpaintGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -595,11 +601,17 @@ export const buildCanvasInpaintGraph = ( (graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed; } + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add VAE - addVAEToGraph(state, graph, MAIN_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addLoRAsToGraph(state, graph, DENOISE_LATENTS, MAIN_MODEL_LOADER); + addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, DENOISE_LATENTS); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 8916dd0652..aec9d1c035 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -14,6 +14,7 @@ import { import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addLoRAsToGraph } from './addLoRAsToGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -43,6 +44,7 @@ import { POSITIVE_CONDITIONING, RANDOM_INT, RANGE_OF_SIZE, + SEAMLESS, } from './constants'; /** @@ -75,6 +77,8 @@ export const buildCanvasOutpaintGraph = ( tileSize, infillMethod, clipSkip, + seamlessXAxis, + seamlessYAxis, } = state.generation; if (!model) { @@ -92,6 +96,8 @@ export const buildCanvasOutpaintGraph = ( shouldAutoSave, } = state.canvas; + let modelLoaderNodeId = MAIN_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : shouldUseCpuNoise; @@ -99,9 +105,9 @@ export const buildCanvasOutpaintGraph = ( const graph: NonNullableGraph = { id: CANVAS_OUTPAINT_GRAPH, nodes: { - [MAIN_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'main_model_loader', - id: MAIN_MODEL_LOADER, + id: modelLoaderNodeId, is_intermediate: true, model, }, @@ -222,7 +228,7 @@ export const buildCanvasOutpaintGraph = ( // Connect Model Loader To UNet & Clip Skip { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -232,7 +238,7 @@ export const buildCanvasOutpaintGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -389,7 +395,7 @@ export const buildCanvasOutpaintGraph = ( }, { source: { - node_id: MAIN_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -732,11 +738,17 @@ export const buildCanvasOutpaintGraph = ( (graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed; } + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add VAE - addVAEToGraph(state, graph, MAIN_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addLoRAsToGraph(state, graph, DENOISE_LATENTS, MAIN_MODEL_LOADER); + addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, DENOISE_LATENTS); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index f51c2444d4..4b2ffdb7ca 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -14,6 +14,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -35,9 +36,11 @@ import { POSITIVE_CONDITIONING, RANDOM_INT, RANGE_OF_SIZE, + REFINER_SEAMLESS, SDXL_CANVAS_INPAINT_GRAPH, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -67,6 +70,8 @@ export const buildCanvasSDXLInpaintGraph = ( maskBlurMethod, canvasCoherenceSteps, canvasCoherenceStrength, + seamlessXAxis, + seamlessYAxis, } = state.generation; const { @@ -91,6 +96,8 @@ export const buildCanvasSDXLInpaintGraph = ( shouldAutoSave, } = state.canvas; + let modelLoaderNodeId = SDXL_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : shouldUseCpuNoise; @@ -102,9 +109,9 @@ export const buildCanvasSDXLInpaintGraph = ( const graph: NonNullableGraph = { id: SDXL_CANVAS_INPAINT_GRAPH, nodes: { - [SDXL_MODEL_LOADER]: { + [modelLoaderNodeId]: { type: 'sdxl_model_loader', - id: SDXL_MODEL_LOADER, + id: modelLoaderNodeId, model, }, [POSITIVE_CONDITIONING]: { @@ -209,7 +216,7 @@ export const buildCanvasSDXLInpaintGraph = ( // Connect Model Loader to UNet and CLIP { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -219,7 +226,7 @@ export const buildCanvasSDXLInpaintGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -229,7 +236,7 @@ export const buildCanvasSDXLInpaintGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { @@ -239,7 +246,7 @@ export const buildCanvasSDXLInpaintGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip', }, destination: { @@ -249,7 +256,7 @@ export const buildCanvasSDXLInpaintGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'clip2', }, destination: { @@ -363,7 +370,7 @@ export const buildCanvasSDXLInpaintGraph = ( }, { source: { - node_id: SDXL_MODEL_LOADER, + node_id: modelLoaderNodeId, field: 'unet', }, destination: { @@ -609,16 +616,28 @@ export const buildCanvasSDXLInpaintGraph = ( (graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed; } + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add Refiner if enabled if (shouldUseSDXLRefiner) { - addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS); + addSDXLRefinerToGraph( + state, + graph, + CANVAS_COHERENCE_DENOISE_LATENTS, + modelLoaderNodeId + ); + modelLoaderNodeId = REFINER_SEAMLESS; } // optionally add custom VAE - addVAEToGraph(state, graph, SDXL_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER); + addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index 05432f0274..0c075beb4a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -15,6 +15,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph'; import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph'; import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph'; +import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph'; import { addVAEToGraph } from './addVAEToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { @@ -40,9 +41,11 @@ import { POSITIVE_CONDITIONING, RANDOM_INT, RANGE_OF_SIZE, + REFINER_SEAMLESS, SDXL_CANVAS_OUTPAINT_GRAPH, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; @@ -74,6 +77,8 @@ export const buildCanvasSDXLOutpaintGraph = ( canvasCoherenceStrength, tileSize, infillMethod, + seamlessXAxis, + seamlessYAxis, } = state.generation; const { @@ -98,6 +103,8 @@ export const buildCanvasSDXLOutpaintGraph = ( shouldAutoSave, } = state.canvas; + let modelLoaderNodeId = SDXL_MODEL_LOADER; + const use_cpu = shouldUseNoiseSettings ? shouldUseCpuNoise : shouldUseCpuNoise; @@ -747,16 +754,28 @@ export const buildCanvasSDXLOutpaintGraph = ( (graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed; } + // Add Seamless To Graph + if (seamlessXAxis || seamlessYAxis) { + addSeamlessToLinearGraph(state, graph, modelLoaderNodeId); + modelLoaderNodeId = SEAMLESS; + } + // Add Refiner if enabled if (shouldUseSDXLRefiner) { - addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS); + addSDXLRefinerToGraph( + state, + graph, + CANVAS_COHERENCE_DENOISE_LATENTS, + modelLoaderNodeId + ); + modelLoaderNodeId = REFINER_SEAMLESS; } // optionally add custom VAE - addVAEToGraph(state, graph, SDXL_MODEL_LOADER); + addVAEToGraph(state, graph, modelLoaderNodeId); // add LoRA support - addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER); + addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId); // add controlnet, mutating `graph` addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS); From 99475ab8003459468aaa5f3994ee6fec522bf2d0 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:16:23 +1200 Subject: [PATCH 23/29] chore: pyflake lint fixes --- invokeai/backend/image_util/seamless.py | 3 ++- invokeai/backend/model_management/seamless.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/image_util/seamless.py b/invokeai/backend/image_util/seamless.py index 6fb2617901..8a2580bfcc 100644 --- a/invokeai/backend/image_util/seamless.py +++ b/invokeai/backend/image_util/seamless.py @@ -20,7 +20,8 @@ def _conv_forward_asymmetric(self, input, weight, bias): def configure_model_padding(model, seamless, seamless_axes): """ - Modifies the 2D convolution layers to use a circular padding mode based on the `seamless` and `seamless_axes` options. + Modifies the 2D convolution layers to use a circular padding mode based on + the `seamless` and `seamless_axes` options. """ # TODO: get an explicit interface for this in diffusers: https://github.com/huggingface/diffusers/issues/556 for m in model.modules(): diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 4e9587a86f..997ff3563f 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -1,10 +1,10 @@ from __future__ import annotations from contextlib import contextmanager -from typing import Union, List -import diffusers +from typing import List, Union + import torch.nn as nn -from diffusers.models import UNet2DModel, AutoencoderKL +from diffusers.models import AutoencoderKL, UNet2DModel def _conv_forward_asymmetric(self, input, weight, bias): From 5133825efbd4b2bdce96937751d26048190df81e Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:17:46 +1200 Subject: [PATCH 24/29] fix: Incorrect plug in Dynamic Prompt Graph --- .../nodes/util/graphBuilders/addDynamicPromptsToGraph.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts index 9c71de5516..acb091a06b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts @@ -63,7 +63,7 @@ export const addDynamicPromptsToGraph = ( { source: { node_id: DYNAMIC_PROMPT, - field: 'prompt_collection', + field: 'collection', }, destination: { node_id: ITERATE, From 56ed76fd95b95ed3a0670a01bed0cd24936a83f6 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:19:51 +1200 Subject: [PATCH 25/29] fix: useMultiSelect file named incorrectly --- .../src/features/gallery/components/ImageGrid/GalleryImage.tsx | 2 +- .../gallery/hooks/{useMultiselect.ts.ts => useMultiselect.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename invokeai/frontend/web/src/features/gallery/hooks/{useMultiselect.ts.ts => useMultiselect.ts} (100%) diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx index 40af91d53a..35d6cc3361 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx @@ -8,7 +8,7 @@ import { ImageDraggableData, TypesafeDraggableData, } from 'features/dnd/types'; -import { useMultiselect } from 'features/gallery/hooks/useMultiselect.ts'; +import { useMultiselect } from 'features/gallery/hooks/useMultiselect'; import { MouseEvent, memo, useCallback, useMemo, useState } from 'react'; import { FaTrash } from 'react-icons/fa'; import { MdStar, MdStarBorder } from 'react-icons/md'; diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts.ts b/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts similarity index 100% rename from invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts.ts rename to invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts From aaae471910a6e8bdc8b64ca18abee615d9240aca Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:42:00 +1200 Subject: [PATCH 26/29] fix: SDXL Canvas Inpaint & Outpaint being broken --- .../nodes/util/graphBuilders/addSeamlessToLinearGraph.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts index e4816d9c87..bdbaacd384 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSeamlessToLinearGraph.ts @@ -37,7 +37,9 @@ export const addSeamlessToLinearGraph = ( graph.id === SDXL_TEXT_TO_IMAGE_GRAPH || graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH || graph.id === SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH || - graph.id === SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH + graph.id === SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH || + graph.id === SDXL_CANVAS_INPAINT_GRAPH || + graph.id === SDXL_CANVAS_OUTPAINT_GRAPH ) { denoisingNodeId = SDXL_DENOISE_LATENTS; } From 577464091c785dfd887ddbb09cbcd046c8eb7855 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 06:44:18 +1200 Subject: [PATCH 27/29] fix: SDXL LoRA's not working with seamless --- .../util/graphBuilders/addSDXLLoRAstoGraph.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts index a52264ca8e..61562534a5 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts @@ -11,9 +11,11 @@ import { METADATA_ACCUMULATOR, NEGATIVE_CONDITIONING, POSITIVE_CONDITIONING, + REFINER_SEAMLESS, SDXL_CANVAS_INPAINT_GRAPH, SDXL_CANVAS_OUTPAINT_GRAPH, SDXL_MODEL_LOADER, + SEAMLESS, } from './constants'; export const addSDXLLoRAsToGraph = ( @@ -36,20 +38,25 @@ export const addSDXLLoRAsToGraph = ( | MetadataAccumulatorInvocation | undefined; + // Handle Seamless Plugs + const unetLoaderId = modelLoaderNodeId; + let clipLoaderId = modelLoaderNodeId; + if ([SEAMLESS, REFINER_SEAMLESS].includes(modelLoaderNodeId)) { + clipLoaderId = SDXL_MODEL_LOADER; + } + if (loraCount > 0) { // Remove modelLoaderNodeId unet/clip/clip2 connections to feed it to LoRAs graph.edges = graph.edges.filter( (e) => !( - e.source.node_id === modelLoaderNodeId && - ['unet'].includes(e.source.field) + e.source.node_id === unetLoaderId && ['unet'].includes(e.source.field) ) && !( - e.source.node_id === modelLoaderNodeId && - ['clip'].includes(e.source.field) + e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field) ) && !( - e.source.node_id === modelLoaderNodeId && + e.source.node_id === clipLoaderId && ['clip2'].includes(e.source.field) ) ); @@ -88,7 +95,7 @@ export const addSDXLLoRAsToGraph = ( // first lora = start the lora chain, attach directly to model loader graph.edges.push({ source: { - node_id: modelLoaderNodeId, + node_id: unetLoaderId, field: 'unet', }, destination: { @@ -99,7 +106,7 @@ export const addSDXLLoRAsToGraph = ( graph.edges.push({ source: { - node_id: modelLoaderNodeId, + node_id: clipLoaderId, field: 'clip', }, destination: { @@ -110,7 +117,7 @@ export const addSDXLLoRAsToGraph = ( graph.edges.push({ source: { - node_id: modelLoaderNodeId, + node_id: clipLoaderId, field: 'clip2', }, destination: { From 2a1d7342a768758149bdf2a51646e44b7be93ee0 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:46:49 -0400 Subject: [PATCH 28/29] Seamless Patch from Stalker --- invokeai/backend/model_management/seamless.py | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index 997ff3563f..b2215e41fc 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -4,7 +4,7 @@ from contextlib import contextmanager from typing import List, Union import torch.nn as nn -from diffusers.models import AutoencoderKL, UNet2DModel +from diffusers.models import AutoencoderKL, UNet2DConditionModel def _conv_forward_asymmetric(self, input, weight, bias): @@ -25,12 +25,56 @@ def _conv_forward_asymmetric(self, input, weight, bias): @contextmanager -def set_seamless(model: Union[UNet2DModel, AutoencoderKL], seamless_axes: List[str]): +def set_seamless(model: Union[UNet2DConditionModel, AutoencoderKL], seamless_axes: List[str]): try: to_restore = [] - for m in model.modules(): + #print("try seamless") + + for m_name, m in model.named_modules(): + + if isinstance(model, UNet2DConditionModel): + if ".attentions." in m_name: + continue + + if ".resnets." in m_name: + if ".conv2" in m_name: + continue + if ".conv_shortcut" in m_name: + continue + + """ + if isinstance(model, UNet2DConditionModel): + if False and ".upsamplers." in m_name: + continue + + if False and ".downsamplers." in m_name: + continue + + if True and ".resnets." in m_name: + if True and ".conv1" in m_name: + if False and "down_blocks" in m_name: + continue + if False and "mid_block" in m_name: + continue + if False and "up_blocks" in m_name: + continue + + if True and ".conv2" in m_name: + continue + + if True and ".conv_shortcut" in m_name: + continue + + if True and ".attentions." in m_name: + continue + + if False and m_name in ["conv_in", "conv_out"]: + continue + """ + if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): + print(f"applied - {m_name}") m.asymmetric_padding_mode = {} m.asymmetric_padding = {} m.asymmetric_padding_mode["x"] = "circular" if ("x" in seamless_axes) else "constant" From 605e13eac06637bab91aa92a68ad41d944a76650 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 29 Aug 2023 07:50:17 +1200 Subject: [PATCH 29/29] chore: black fix --- invokeai/backend/model_management/seamless.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/invokeai/backend/model_management/seamless.py b/invokeai/backend/model_management/seamless.py index b2215e41fc..54885769ad 100644 --- a/invokeai/backend/model_management/seamless.py +++ b/invokeai/backend/model_management/seamless.py @@ -29,10 +29,7 @@ def set_seamless(model: Union[UNet2DConditionModel, AutoencoderKL], seamless_axe try: to_restore = [] - #print("try seamless") - for m_name, m in model.named_modules(): - if isinstance(model, UNet2DConditionModel): if ".attentions." in m_name: continue