From 7b5efc2203a00f1ca58ff6046fd418e008390bc3 Mon Sep 17 00:00:00 2001 From: David Burnett Date: Sun, 27 Oct 2024 14:18:12 +0000 Subject: [PATCH 01/10] Flux Vae broke for float16, force bfloat16 or float32 were compatible --- invokeai/backend/flux/modules/autoencoder.py | 7 +++++++ invokeai/backend/model_manager/load/load_default.py | 1 + .../backend/model_manager/load/model_loaders/flux.py | 10 +++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/flux/modules/autoencoder.py b/invokeai/backend/flux/modules/autoencoder.py index 6b072a82f63..3533165f755 100644 --- a/invokeai/backend/flux/modules/autoencoder.py +++ b/invokeai/backend/flux/modules/autoencoder.py @@ -318,6 +318,13 @@ def encode(self, x: Tensor, sample: bool = True, generator: torch.Generator | No def decode(self, z: Tensor) -> Tensor: z = z / self.scale_factor + self.shift_factor + + # VAE is broken in float16, use same logic in model loading to pick bfloat16 or float32 + if z.dtype == torch.float16: + try: + z = z.to(torch.bfloat16) + except TypeError: + z = z.to(torch.float32) return self.decoder(z) def forward(self, x: Tensor) -> Tensor: diff --git a/invokeai/backend/model_manager/load/load_default.py b/invokeai/backend/model_manager/load/load_default.py index 333aae78e37..c46e94bccb7 100644 --- a/invokeai/backend/model_manager/load/load_default.py +++ b/invokeai/backend/model_manager/load/load_default.py @@ -35,6 +35,7 @@ def __init__( self._logger = logger self._ram_cache = ram_cache self._torch_dtype = TorchDevice.choose_torch_dtype() + self._torch_device = TorchDevice.choose_torch_device() def load_model(self, model_config: AnyModelConfig, submodel_type: Optional[SubModelType] = None) -> LoadedModel: """ diff --git a/invokeai/backend/model_manager/load/model_loaders/flux.py b/invokeai/backend/model_manager/load/model_loaders/flux.py index a6fb9b853b5..d218fe10465 100644 --- a/invokeai/backend/model_manager/load/model_loaders/flux.py +++ b/invokeai/backend/model_manager/load/model_loaders/flux.py @@ -84,7 +84,15 @@ def _load_model( model = AutoEncoder(ae_params[config.config_path]) sd = load_file(model_path) model.load_state_dict(sd, assign=True) - model.to(dtype=self._torch_dtype) + # VAE is broken in float16, which mps defaults too + if self._torch_dtype == torch.float16: + try: + vae_dtype = torch.tensor([1.0], dtype=torch.bfloat16, device=self._torch_device).dtype + except TypeError: + vae_dtype = torch.tensor([1.0], dtype=torch.float32, device=self._torch_device).dtype + else: + vae_dtype = self._torch_dtype + model.to(vae_dtype) return model From 496b02a3bc7563f1466ea7b3b4887999a93b3ede Mon Sep 17 00:00:00 2001 From: David Burnett Date: Mon, 28 Oct 2024 22:32:55 +0000 Subject: [PATCH 02/10] Same issue affects image2image, so do the same again --- invokeai/backend/flux/modules/autoencoder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/invokeai/backend/flux/modules/autoencoder.py b/invokeai/backend/flux/modules/autoencoder.py index 3533165f755..554d7990756 100644 --- a/invokeai/backend/flux/modules/autoencoder.py +++ b/invokeai/backend/flux/modules/autoencoder.py @@ -312,6 +312,12 @@ def encode(self, x: Tensor, sample: bool = True, generator: torch.Generator | No Tensor: Encoded latent tensor. Shape: (batch_size, z_channels, latent_height, latent_width). """ + # VAE is broken in float16, use same logic in model loading to pick bfloat16 or float32 + if x.dtype == torch.float16: + try: + x = x.to(torch.bfloat16) + except TypeError: + x = x.to(torch.float32) z = self.reg(self.encoder(x), sample=sample, generator=generator) z = self.scale_factor * (z - self.shift_factor) return z From 1337c33ad3536406816f92868c9c2a149ef2c324 Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Wed, 6 Nov 2024 14:59:55 -0500 Subject: [PATCH 03/10] fix: Avoid downloading unsafe .bin files if a safetensors file is available --- invokeai/backend/model_manager/util/select_hf_files.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/invokeai/backend/model_manager/util/select_hf_files.py b/invokeai/backend/model_manager/util/select_hf_files.py index 1c43711249b..0f5cc763b20 100644 --- a/invokeai/backend/model_manager/util/select_hf_files.py +++ b/invokeai/backend/model_manager/util/select_hf_files.py @@ -85,6 +85,7 @@ def _filter_by_variant(files: List[Path], variant: ModelRepoVariant) -> Set[Path """Select the proper variant files from a list of HuggingFace repo_id paths.""" result: set[Path] = set() subfolder_weights: dict[Path, list[SubfolderCandidate]] = {} + safetensors_detected = False for path in files: if path.suffix in [".onnx", ".pb", ".onnx_data"]: if variant == ModelRepoVariant.ONNX: @@ -119,10 +120,16 @@ def _filter_by_variant(files: List[Path], variant: ModelRepoVariant) -> Set[Path # We prefer safetensors over other file formats and an exact variant match. We'll score each file based on # variant and format and select the best one. + if safetensors_detected and path.suffix == ".bin": + continue + parent = path.parent score = 0 if path.suffix == ".safetensors": + safetensors_detected = True + if parent in subfolder_weights: + subfolder_weights[parent] = [sfc for sfc in subfolder_weights[parent] if sfc.path.suffix != ".bin"] score += 1 candidate_variant_label = path.suffixes[0] if len(path.suffixes) == 2 else None From f4b0b6a93dda0d0beb1d7b00779d86e661d08f1b Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Wed, 6 Nov 2024 13:16:10 -0500 Subject: [PATCH 04/10] fix: Look in known subfolders for configs for clip variants --- invokeai/backend/model_manager/util/model_util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/invokeai/backend/model_manager/util/model_util.py b/invokeai/backend/model_manager/util/model_util.py index bf28a31d4be..e218124fb8a 100644 --- a/invokeai/backend/model_manager/util/model_util.py +++ b/invokeai/backend/model_manager/util/model_util.py @@ -172,6 +172,8 @@ def get_clip_variant_type(location: str) -> Optional[ClipVariantType]: try: path = Path(location) config_path = path / "config.json" + if not config_path.exists(): + config_path = path / "text_encoder" / "config.json" if not config_path.exists(): return ClipVariantType.L with open(config_path) as file: From 8a683f5a3c6a2d0db56f7fd3ede3cb61690d4b22 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:24:02 +1000 Subject: [PATCH 05/10] feat(ui): updated whats new handling and v5.4.1 items --- invokeai/frontend/web/public/locales/en.json | 6 ++- .../src/features/ui/components/WhatsNew.tsx | 46 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index e9617accbf5..35644728938 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -2102,8 +2102,10 @@ }, "whatsNew": { "whatsNewInInvoke": "What's New in Invoke", - "line1": "Layer Merging: New Merge Down and improved Merge Visible for all layers, with special handling for Regional Guidance and Control Layers.", - "line2": "HF Token Support: Upload models that require Hugging Face authentication.", + "items": [ + "SD 3.5: Support for Text-to-Image in Workflows with SD 3.5 Medium and Large.", + "Canvas: Streamlined Control Layer processing and improved default Control settings." + ], "readReleaseNotes": "Read Release Notes", "watchRecentReleaseVideos": "Watch Recent Release Videos", "watchUiUpdatesOverview": "Watch UI Updates Overview" diff --git a/invokeai/frontend/web/src/features/ui/components/WhatsNew.tsx b/invokeai/frontend/web/src/features/ui/components/WhatsNew.tsx index 4fe2e11deec..6dd1579cb79 100644 --- a/invokeai/frontend/web/src/features/ui/components/WhatsNew.tsx +++ b/invokeai/frontend/web/src/features/ui/components/WhatsNew.tsx @@ -2,45 +2,41 @@ import { ExternalLink, Flex, ListItem, Text, UnorderedList } from '@invoke-ai/ui import { createSelector } from '@reduxjs/toolkit'; import { useAppSelector } from 'app/store/storeHooks'; import { selectConfigSlice } from 'features/system/store/configSlice'; +import type { ReactNode } from 'react'; import { useMemo } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { useGetAppVersionQuery } from 'services/api/endpoints/appInfo'; const selectIsLocal = createSelector(selectConfigSlice, (config) => config.isLocal); +const components = { + StrongComponent: , +}; + export const WhatsNew = () => { const { t } = useTranslation(); const { data } = useGetAppVersionQuery(); const isLocal = useAppSelector(selectIsLocal); - const highlights = useMemo(() => (data?.highlights ? data.highlights : []), [data]); + const items = useMemo(() => { + if (data?.highlights?.length) { + return data.highlights.map((highlight, index) => {highlight}); + } + + const tKeys = t('whatsNew.items', { + returnObjects: true, + }); + + return tKeys.map((key, index) => ( + + + + )); + }, [data?.highlights, t]); return ( - - {highlights.length ? ( - highlights.map((highlight, index) => {highlight}) - ) : ( - <> - - , - }} - /> - - - , - }} - /> - - - )} - + {items} Date: Thu, 7 Nov 2024 10:24:09 +1000 Subject: [PATCH 06/10] chore(ui): bump version to v5.4.1rc1 --- invokeai/version/invokeai_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/version/invokeai_version.py b/invokeai/version/invokeai_version.py index fc30498faa2..b4700008f6d 100644 --- a/invokeai/version/invokeai_version.py +++ b/invokeai/version/invokeai_version.py @@ -1 +1 @@ -__version__ = "5.4.0" +__version__ = "5.4.1rc1" From aa40161f269b593047f71a9ef7d3bd995a024202 Mon Sep 17 00:00:00 2001 From: Jonathan <34005131+JPPhoto@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:23:19 -0600 Subject: [PATCH 07/10] Update flux_denoise.py Added a bool to allow the node user to add noise in to initial latents (default) or to leave them alone. --- invokeai/app/invocations/flux_denoise.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/invokeai/app/invocations/flux_denoise.py b/invokeai/app/invocations/flux_denoise.py index c9907ce4082..9e197626b53 100644 --- a/invokeai/app/invocations/flux_denoise.py +++ b/invokeai/app/invocations/flux_denoise.py @@ -56,7 +56,7 @@ title="FLUX Denoise", tags=["image", "flux"], category="image", - version="3.2.0", + version="3.2.1", classification=Classification.Prototype, ) class FluxDenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): @@ -81,6 +81,7 @@ class FluxDenoiseInvocation(BaseInvocation, WithMetadata, WithBoard): description=FieldDescriptions.denoising_start, ) denoising_end: float = InputField(default=1.0, ge=0, le=1, description=FieldDescriptions.denoising_end) + add_noise: bool = InputField(default=True, description="Add noise based on denoising start.") transformer: TransformerField = InputField( description=FieldDescriptions.flux_model, input=Input.Connection, @@ -207,9 +208,12 @@ def _run_diffusion( "to be poor. Consider using a FLUX dev model instead." ) - # Noise the orig_latents by the appropriate amount for the first timestep. - t_0 = timesteps[0] - x = t_0 * noise + (1.0 - t_0) * init_latents + if self.add_noise: + # Noise the orig_latents by the appropriate amount for the first timestep. + t_0 = timesteps[0] + x = t_0 * noise + (1.0 - t_0) * init_latents + else: + x = init_latents else: # init_latents are not provided, so we are not doing image-to-image (i.e. we are starting from pure noise). if self.denoising_start > 1e-5: From bb3cedddd5a9e07fb4efc9f5e687a87c41b5ba3c Mon Sep 17 00:00:00 2001 From: David Burnett Date: Fri, 8 Nov 2024 10:27:47 +0000 Subject: [PATCH 08/10] Rework change based on comments --- invokeai/app/invocations/flux_vae_decode.py | 3 ++- invokeai/app/invocations/flux_vae_encode.py | 3 ++- invokeai/backend/flux/modules/autoencoder.py | 13 ------------- .../model_manager/load/model_loaders/flux.py | 4 ++-- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/invokeai/app/invocations/flux_vae_decode.py b/invokeai/app/invocations/flux_vae_decode.py index bfe6501bddf..05cfd6f3558 100644 --- a/invokeai/app/invocations/flux_vae_decode.py +++ b/invokeai/app/invocations/flux_vae_decode.py @@ -41,7 +41,8 @@ class FluxVaeDecodeInvocation(BaseInvocation, WithMetadata, WithBoard): def _vae_decode(self, vae_info: LoadedModel, latents: torch.Tensor) -> Image.Image: with vae_info as vae: assert isinstance(vae, AutoEncoder) - latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=TorchDevice.choose_torch_dtype()) + vae_dtype = next(iter(vae.state_dict().items()))[1].dtype + latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=vae_dtype) img = vae.decode(latents) img = img.clamp(-1, 1) diff --git a/invokeai/app/invocations/flux_vae_encode.py b/invokeai/app/invocations/flux_vae_encode.py index 1fee7145f50..9261c1ee0a7 100644 --- a/invokeai/app/invocations/flux_vae_encode.py +++ b/invokeai/app/invocations/flux_vae_encode.py @@ -44,8 +44,9 @@ def vae_encode(vae_info: LoadedModel, image_tensor: torch.Tensor) -> torch.Tenso generator = torch.Generator(device=TorchDevice.choose_torch_device()).manual_seed(0) with vae_info as vae: assert isinstance(vae, AutoEncoder) + vae_dtype = next(iter(vae.state_dict().items()))[1].dtype image_tensor = image_tensor.to( - device=TorchDevice.choose_torch_device(), dtype=TorchDevice.choose_torch_dtype() + device=TorchDevice.choose_torch_device(), dtype=vae_dtype ) latents = vae.encode(image_tensor, sample=True, generator=generator) return latents diff --git a/invokeai/backend/flux/modules/autoencoder.py b/invokeai/backend/flux/modules/autoencoder.py index 554d7990756..6b072a82f63 100644 --- a/invokeai/backend/flux/modules/autoencoder.py +++ b/invokeai/backend/flux/modules/autoencoder.py @@ -312,25 +312,12 @@ def encode(self, x: Tensor, sample: bool = True, generator: torch.Generator | No Tensor: Encoded latent tensor. Shape: (batch_size, z_channels, latent_height, latent_width). """ - # VAE is broken in float16, use same logic in model loading to pick bfloat16 or float32 - if x.dtype == torch.float16: - try: - x = x.to(torch.bfloat16) - except TypeError: - x = x.to(torch.float32) z = self.reg(self.encoder(x), sample=sample, generator=generator) z = self.scale_factor * (z - self.shift_factor) return z def decode(self, z: Tensor) -> Tensor: z = z / self.scale_factor + self.shift_factor - - # VAE is broken in float16, use same logic in model loading to pick bfloat16 or float32 - if z.dtype == torch.float16: - try: - z = z.to(torch.bfloat16) - except TypeError: - z = z.to(torch.float32) return self.decoder(z) def forward(self, x: Tensor) -> Tensor: diff --git a/invokeai/backend/model_manager/load/model_loaders/flux.py b/invokeai/backend/model_manager/load/model_loaders/flux.py index d218fe10465..edf14ec48cc 100644 --- a/invokeai/backend/model_manager/load/model_loaders/flux.py +++ b/invokeai/backend/model_manager/load/model_loaders/flux.py @@ -84,12 +84,12 @@ def _load_model( model = AutoEncoder(ae_params[config.config_path]) sd = load_file(model_path) model.load_state_dict(sd, assign=True) - # VAE is broken in float16, which mps defaults too + # VAE is broken in float16, which mps defaults to if self._torch_dtype == torch.float16: try: vae_dtype = torch.tensor([1.0], dtype=torch.bfloat16, device=self._torch_device).dtype except TypeError: - vae_dtype = torch.tensor([1.0], dtype=torch.float32, device=self._torch_device).dtype + vae_dtype = torch.float32 else: vae_dtype = self._torch_dtype model.to(vae_dtype) From 2618ed0ae7a4e1edb1bf395442a7d7fa06fed78f Mon Sep 17 00:00:00 2001 From: David Burnett Date: Fri, 8 Nov 2024 10:31:53 +0000 Subject: [PATCH 09/10] ruff complained --- invokeai/app/invocations/flux_vae_encode.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/invokeai/app/invocations/flux_vae_encode.py b/invokeai/app/invocations/flux_vae_encode.py index 9261c1ee0a7..f389985dea4 100644 --- a/invokeai/app/invocations/flux_vae_encode.py +++ b/invokeai/app/invocations/flux_vae_encode.py @@ -45,9 +45,7 @@ def vae_encode(vae_info: LoadedModel, image_tensor: torch.Tensor) -> torch.Tenso with vae_info as vae: assert isinstance(vae, AutoEncoder) vae_dtype = next(iter(vae.state_dict().items()))[1].dtype - image_tensor = image_tensor.to( - device=TorchDevice.choose_torch_device(), dtype=vae_dtype - ) + image_tensor = image_tensor.to(device=TorchDevice.choose_torch_device(), dtype=vae_dtype) latents = vae.encode(image_tensor, sample=True, generator=generator) return latents From eaf4e08c44a960f1aceebb894fce9b068f50e1a4 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Wed, 13 Nov 2024 23:32:40 +0000 Subject: [PATCH 10/10] Use vae.parameters() for more efficient access of the first model parameter. --- invokeai/app/invocations/flux_vae_decode.py | 2 +- invokeai/app/invocations/flux_vae_encode.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/flux_vae_decode.py b/invokeai/app/invocations/flux_vae_decode.py index 05cfd6f3558..7732f1f9812 100644 --- a/invokeai/app/invocations/flux_vae_decode.py +++ b/invokeai/app/invocations/flux_vae_decode.py @@ -41,7 +41,7 @@ class FluxVaeDecodeInvocation(BaseInvocation, WithMetadata, WithBoard): def _vae_decode(self, vae_info: LoadedModel, latents: torch.Tensor) -> Image.Image: with vae_info as vae: assert isinstance(vae, AutoEncoder) - vae_dtype = next(iter(vae.state_dict().items()))[1].dtype + vae_dtype = next(iter(vae.parameters())).dtype latents = latents.to(device=TorchDevice.choose_torch_device(), dtype=vae_dtype) img = vae.decode(latents) diff --git a/invokeai/app/invocations/flux_vae_encode.py b/invokeai/app/invocations/flux_vae_encode.py index f389985dea4..ab7ed584c0b 100644 --- a/invokeai/app/invocations/flux_vae_encode.py +++ b/invokeai/app/invocations/flux_vae_encode.py @@ -44,7 +44,7 @@ def vae_encode(vae_info: LoadedModel, image_tensor: torch.Tensor) -> torch.Tenso generator = torch.Generator(device=TorchDevice.choose_torch_device()).manual_seed(0) with vae_info as vae: assert isinstance(vae, AutoEncoder) - vae_dtype = next(iter(vae.state_dict().items()))[1].dtype + vae_dtype = next(iter(vae.parameters())).dtype image_tensor = image_tensor.to(device=TorchDevice.choose_torch_device(), dtype=vae_dtype) latents = vae.encode(image_tensor, sample=True, generator=generator) return latents