InvokeAI 6.10.0rc1__py3-none-any.whl → 6.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. invokeai/app/api/routers/model_manager.py +43 -1
  2. invokeai/app/invocations/fields.py +1 -1
  3. invokeai/app/invocations/flux2_denoise.py +499 -0
  4. invokeai/app/invocations/flux2_klein_model_loader.py +222 -0
  5. invokeai/app/invocations/flux2_klein_text_encoder.py +222 -0
  6. invokeai/app/invocations/flux2_vae_decode.py +106 -0
  7. invokeai/app/invocations/flux2_vae_encode.py +88 -0
  8. invokeai/app/invocations/flux_denoise.py +77 -3
  9. invokeai/app/invocations/flux_lora_loader.py +1 -1
  10. invokeai/app/invocations/flux_model_loader.py +2 -5
  11. invokeai/app/invocations/ideal_size.py +6 -1
  12. invokeai/app/invocations/metadata.py +4 -0
  13. invokeai/app/invocations/metadata_linked.py +47 -0
  14. invokeai/app/invocations/model.py +1 -0
  15. invokeai/app/invocations/pbr_maps.py +59 -0
  16. invokeai/app/invocations/z_image_denoise.py +244 -84
  17. invokeai/app/invocations/z_image_image_to_latents.py +9 -1
  18. invokeai/app/invocations/z_image_latents_to_image.py +9 -1
  19. invokeai/app/invocations/z_image_seed_variance_enhancer.py +110 -0
  20. invokeai/app/services/config/config_default.py +3 -1
  21. invokeai/app/services/invocation_stats/invocation_stats_common.py +6 -6
  22. invokeai/app/services/invocation_stats/invocation_stats_default.py +9 -4
  23. invokeai/app/services/model_manager/model_manager_default.py +7 -0
  24. invokeai/app/services/model_records/model_records_base.py +4 -2
  25. invokeai/app/services/shared/invocation_context.py +15 -0
  26. invokeai/app/services/shared/sqlite/sqlite_util.py +2 -0
  27. invokeai/app/services/shared/sqlite_migrator/migrations/migration_25.py +61 -0
  28. invokeai/app/util/step_callback.py +58 -2
  29. invokeai/backend/flux/denoise.py +338 -118
  30. invokeai/backend/flux/dype/__init__.py +31 -0
  31. invokeai/backend/flux/dype/base.py +260 -0
  32. invokeai/backend/flux/dype/embed.py +116 -0
  33. invokeai/backend/flux/dype/presets.py +148 -0
  34. invokeai/backend/flux/dype/rope.py +110 -0
  35. invokeai/backend/flux/extensions/dype_extension.py +91 -0
  36. invokeai/backend/flux/schedulers.py +62 -0
  37. invokeai/backend/flux/util.py +35 -1
  38. invokeai/backend/flux2/__init__.py +4 -0
  39. invokeai/backend/flux2/denoise.py +280 -0
  40. invokeai/backend/flux2/ref_image_extension.py +294 -0
  41. invokeai/backend/flux2/sampling_utils.py +209 -0
  42. invokeai/backend/image_util/pbr_maps/architecture/block.py +367 -0
  43. invokeai/backend/image_util/pbr_maps/architecture/pbr_rrdb_net.py +70 -0
  44. invokeai/backend/image_util/pbr_maps/pbr_maps.py +141 -0
  45. invokeai/backend/image_util/pbr_maps/utils/image_ops.py +93 -0
  46. invokeai/backend/model_manager/configs/factory.py +19 -1
  47. invokeai/backend/model_manager/configs/lora.py +36 -0
  48. invokeai/backend/model_manager/configs/main.py +395 -3
  49. invokeai/backend/model_manager/configs/qwen3_encoder.py +116 -7
  50. invokeai/backend/model_manager/configs/vae.py +104 -2
  51. invokeai/backend/model_manager/load/model_cache/model_cache.py +107 -2
  52. invokeai/backend/model_manager/load/model_loaders/cogview4.py +2 -1
  53. invokeai/backend/model_manager/load/model_loaders/flux.py +1020 -8
  54. invokeai/backend/model_manager/load/model_loaders/generic_diffusers.py +4 -2
  55. invokeai/backend/model_manager/load/model_loaders/onnx.py +1 -0
  56. invokeai/backend/model_manager/load/model_loaders/stable_diffusion.py +2 -1
  57. invokeai/backend/model_manager/load/model_loaders/z_image.py +158 -31
  58. invokeai/backend/model_manager/starter_models.py +141 -4
  59. invokeai/backend/model_manager/taxonomy.py +31 -4
  60. invokeai/backend/model_manager/util/select_hf_files.py +3 -2
  61. invokeai/backend/patches/lora_conversions/z_image_lora_conversion_utils.py +39 -5
  62. invokeai/backend/quantization/gguf/ggml_tensor.py +15 -4
  63. invokeai/backend/util/vae_working_memory.py +0 -2
  64. invokeai/backend/z_image/extensions/regional_prompting_extension.py +10 -12
  65. invokeai/frontend/web/dist/assets/App-D13dX7be.js +161 -0
  66. invokeai/frontend/web/dist/assets/{browser-ponyfill-DHZxq1nk.js → browser-ponyfill-u_ZjhQTI.js} +1 -1
  67. invokeai/frontend/web/dist/assets/index-BB0nHmDe.js +530 -0
  68. invokeai/frontend/web/dist/index.html +1 -1
  69. invokeai/frontend/web/dist/locales/en-GB.json +1 -0
  70. invokeai/frontend/web/dist/locales/en.json +85 -6
  71. invokeai/frontend/web/dist/locales/it.json +135 -15
  72. invokeai/frontend/web/dist/locales/ru.json +11 -11
  73. invokeai/version/invokeai_version.py +1 -1
  74. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/METADATA +8 -2
  75. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/RECORD +81 -57
  76. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/WHEEL +1 -1
  77. invokeai/frontend/web/dist/assets/App-CYhlZO3Q.js +0 -161
  78. invokeai/frontend/web/dist/assets/index-dgSJAY--.js +0 -530
  79. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/entry_points.txt +0 -0
  80. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/licenses/LICENSE +0 -0
  81. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/licenses/LICENSE-SD1+SD2.txt +0 -0
  82. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/licenses/LICENSE-SDXL.txt +0 -0
  83. {invokeai-6.10.0rc1.dist-info → invokeai-6.11.0.dist-info}/top_level.txt +0 -0
@@ -52,8 +52,9 @@ class InvocationStatsService(InvocationStatsServiceBase):
52
52
  # Record state before the invocation.
53
53
  start_time = time.time()
54
54
  start_ram = psutil.Process().memory_info().rss
55
- if torch.cuda.is_available():
56
- torch.cuda.reset_peak_memory_stats()
55
+
56
+ # Remember current VRAM usage
57
+ vram_in_use = torch.cuda.memory_allocated() if torch.cuda.is_available() else 0.0
57
58
 
58
59
  assert services.model_manager.load is not None
59
60
  services.model_manager.load.ram_cache.stats = self._cache_stats[graph_execution_state_id]
@@ -62,14 +63,16 @@ class InvocationStatsService(InvocationStatsServiceBase):
62
63
  # Let the invocation run.
63
64
  yield None
64
65
  finally:
65
- # Record state after the invocation.
66
+ # Record delta VRAM
67
+ delta_vram_gb = ((torch.cuda.memory_allocated() - vram_in_use) / GB) if torch.cuda.is_available() else 0.0
68
+
66
69
  node_stats = NodeExecutionStats(
67
70
  invocation_type=invocation.get_type(),
68
71
  start_time=start_time,
69
72
  end_time=time.time(),
70
73
  start_ram_gb=start_ram / GB,
71
74
  end_ram_gb=psutil.Process().memory_info().rss / GB,
72
- peak_vram_gb=torch.cuda.max_memory_allocated() / GB if torch.cuda.is_available() else 0.0,
75
+ delta_vram_gb=delta_vram_gb,
73
76
  )
74
77
  self._stats[graph_execution_state_id].add_node_execution_stats(node_stats)
75
78
 
@@ -81,6 +84,8 @@ class InvocationStatsService(InvocationStatsServiceBase):
81
84
  graph_stats_summary = self._get_graph_summary(graph_execution_state_id)
82
85
  node_stats_summaries = self._get_node_summaries(graph_execution_state_id)
83
86
  model_cache_stats_summary = self._get_model_cache_summary(graph_execution_state_id)
87
+ # Note: We use memory_allocated() here (not memory_reserved()) because we want to show
88
+ # the current actively-used VRAM, not the total reserved memory including PyTorch's cache.
84
89
  vram_usage_gb = torch.cuda.memory_allocated() / GB if torch.cuda.is_available() else None
85
90
 
86
91
  return InvocationStatsSummary(
@@ -60,6 +60,10 @@ class ModelManagerService(ModelManagerServiceBase):
60
60
  service.start(invoker)
61
61
 
62
62
  def stop(self, invoker: Invoker) -> None:
63
+ # Shutdown the model cache to cancel any pending timers
64
+ if hasattr(self._load, "ram_cache"):
65
+ self._load.ram_cache.shutdown()
66
+
63
67
  for service in [self._store, self._install, self._load]:
64
68
  if hasattr(service, "stop"):
65
69
  service.stop(invoker)
@@ -88,7 +92,10 @@ class ModelManagerService(ModelManagerServiceBase):
88
92
  max_ram_cache_size_gb=app_config.max_cache_ram_gb,
89
93
  max_vram_cache_size_gb=app_config.max_cache_vram_gb,
90
94
  execution_device=execution_device or TorchDevice.choose_torch_device(),
95
+ storage_device="cpu",
96
+ log_memory_usage=app_config.log_memory_usage,
91
97
  logger=logger,
98
+ keep_alive_minutes=app_config.model_cache_keep_alive_min,
92
99
  )
93
100
  loader = ModelLoadService(
94
101
  app_config=app_config,
@@ -19,11 +19,13 @@ from invokeai.backend.model_manager.configs.main import MainModelDefaultSettings
19
19
  from invokeai.backend.model_manager.taxonomy import (
20
20
  BaseModelType,
21
21
  ClipVariantType,
22
+ Flux2VariantType,
22
23
  FluxVariantType,
23
24
  ModelFormat,
24
25
  ModelSourceType,
25
26
  ModelType,
26
27
  ModelVariantType,
28
+ Qwen3VariantType,
27
29
  SchedulerPredictionType,
28
30
  )
29
31
 
@@ -89,8 +91,8 @@ class ModelRecordChanges(BaseModelExcludeNull):
89
91
 
90
92
  # Checkpoint-specific changes
91
93
  # TODO(MM2): Should we expose these? Feels footgun-y...
92
- variant: Optional[ModelVariantType | ClipVariantType | FluxVariantType] = Field(
93
- description="The variant of the model.", default=None
94
+ variant: Optional[ModelVariantType | ClipVariantType | FluxVariantType | Flux2VariantType | Qwen3VariantType] = (
95
+ Field(description="The variant of the model.", default=None)
94
96
  )
95
97
  prediction_type: Optional[SchedulerPredictionType] = Field(
96
98
  description="The prediction type of the model.", default=None
@@ -630,6 +630,21 @@ class UtilInterface(InvocationContextInterface):
630
630
  is_canceled=self.is_canceled,
631
631
  )
632
632
 
633
+ def flux2_step_callback(self, intermediate_state: PipelineIntermediateState) -> None:
634
+ """
635
+ The step callback for FLUX.2 Klein models (32-channel VAE).
636
+
637
+ Args:
638
+ intermediate_state: The intermediate state of the diffusion pipeline.
639
+ """
640
+
641
+ diffusion_step_callback(
642
+ signal_progress=self.signal_progress,
643
+ intermediate_state=intermediate_state,
644
+ base_model=BaseModelType.Flux2,
645
+ is_canceled=self.is_canceled,
646
+ )
647
+
633
648
  def signal_progress(
634
649
  self,
635
650
  message: str,
@@ -27,6 +27,7 @@ from invokeai.app.services.shared.sqlite_migrator.migrations.migration_21 import
27
27
  from invokeai.app.services.shared.sqlite_migrator.migrations.migration_22 import build_migration_22
28
28
  from invokeai.app.services.shared.sqlite_migrator.migrations.migration_23 import build_migration_23
29
29
  from invokeai.app.services.shared.sqlite_migrator.migrations.migration_24 import build_migration_24
30
+ from invokeai.app.services.shared.sqlite_migrator.migrations.migration_25 import build_migration_25
30
31
  from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_impl import SqliteMigrator
31
32
 
32
33
 
@@ -71,6 +72,7 @@ def init_db(config: InvokeAIAppConfig, logger: Logger, image_files: ImageFileSto
71
72
  migrator.register_migration(build_migration_22(app_config=config, logger=logger))
72
73
  migrator.register_migration(build_migration_23(app_config=config, logger=logger))
73
74
  migrator.register_migration(build_migration_24(app_config=config, logger=logger))
75
+ migrator.register_migration(build_migration_25(app_config=config, logger=logger))
74
76
  migrator.run_migrations()
75
77
 
76
78
  return db
@@ -0,0 +1,61 @@
1
+ import json
2
+ import sqlite3
3
+ from logging import Logger
4
+ from typing import Any
5
+
6
+ from invokeai.app.services.config import InvokeAIAppConfig
7
+ from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_common import Migration
8
+ from invokeai.backend.model_manager.taxonomy import ModelType, Qwen3VariantType
9
+
10
+
11
+ class Migration25Callback:
12
+ def __init__(self, app_config: InvokeAIAppConfig, logger: Logger) -> None:
13
+ self._app_config = app_config
14
+ self._logger = logger
15
+
16
+ def __call__(self, cursor: sqlite3.Cursor) -> None:
17
+ cursor.execute("SELECT id, config FROM models;")
18
+ rows = cursor.fetchall()
19
+
20
+ migrated_count = 0
21
+
22
+ for model_id, config_json in rows:
23
+ try:
24
+ config_dict: dict[str, Any] = json.loads(config_json)
25
+
26
+ if config_dict.get("type") != ModelType.Qwen3Encoder.value:
27
+ continue
28
+
29
+ if "variant" in config_dict:
30
+ continue
31
+
32
+ config_dict["variant"] = Qwen3VariantType.Qwen3_4B.value
33
+
34
+ cursor.execute(
35
+ "UPDATE models SET config = ? WHERE id = ?;",
36
+ (json.dumps(config_dict), model_id),
37
+ )
38
+ migrated_count += 1
39
+
40
+ except json.JSONDecodeError as e:
41
+ self._logger.error("Invalid config JSON for model %s: %s", model_id, e)
42
+ raise
43
+
44
+ if migrated_count > 0:
45
+ self._logger.info(f"Migration complete: {migrated_count} Qwen3 encoder configs updated with variant field")
46
+ else:
47
+ self._logger.info("Migration complete: no Qwen3 encoder configs needed migration")
48
+
49
+
50
+ def build_migration_25(app_config: InvokeAIAppConfig, logger: Logger) -> Migration:
51
+ """Builds the migration object for migrating from version 24 to version 25.
52
+
53
+ This migration adds the variant field to existing Qwen3 encoder models.
54
+ Models installed before the variant field was added will default to Qwen3_4B (for Z-Image compatibility).
55
+ """
56
+
57
+ return Migration(
58
+ from_version=24,
59
+ to_version=25,
60
+ callback=Migration25Callback(app_config=app_config, logger=logger),
61
+ )
@@ -93,14 +93,60 @@ COGVIEW4_LATENT_RGB_FACTORS = [
93
93
  [-0.00955853, -0.00980067, -0.00977842],
94
94
  ]
95
95
 
96
+ # FLUX.2 uses 32 latent channels.
97
+ # Factors from ComfyUI: https://github.com/Comfy-Org/ComfyUI/blob/main/comfy/latent_formats.py
98
+ FLUX2_LATENT_RGB_FACTORS = [
99
+ # R G B
100
+ [0.0058, 0.0113, 0.0073],
101
+ [0.0495, 0.0443, 0.0836],
102
+ [-0.0099, 0.0096, 0.0644],
103
+ [0.2144, 0.3009, 0.3652],
104
+ [0.0166, -0.0039, -0.0054],
105
+ [0.0157, 0.0103, -0.0160],
106
+ [-0.0398, 0.0902, -0.0235],
107
+ [-0.0052, 0.0095, 0.0109],
108
+ [-0.3527, -0.2712, -0.1666],
109
+ [-0.0301, -0.0356, -0.0180],
110
+ [-0.0107, 0.0078, 0.0013],
111
+ [0.0746, 0.0090, -0.0941],
112
+ [0.0156, 0.0169, 0.0070],
113
+ [-0.0034, -0.0040, -0.0114],
114
+ [0.0032, 0.0181, 0.0080],
115
+ [-0.0939, -0.0008, 0.0186],
116
+ [0.0018, 0.0043, 0.0104],
117
+ [0.0284, 0.0056, -0.0127],
118
+ [-0.0024, -0.0022, -0.0030],
119
+ [0.1207, -0.0026, 0.0065],
120
+ [0.0128, 0.0101, 0.0142],
121
+ [0.0137, -0.0072, -0.0007],
122
+ [0.0095, 0.0092, -0.0059],
123
+ [0.0000, -0.0077, -0.0049],
124
+ [-0.0465, -0.0204, -0.0312],
125
+ [0.0095, 0.0012, -0.0066],
126
+ [0.0290, -0.0034, 0.0025],
127
+ [0.0220, 0.0169, -0.0048],
128
+ [-0.0332, -0.0457, -0.0468],
129
+ [-0.0085, 0.0389, 0.0609],
130
+ [-0.0076, 0.0003, -0.0043],
131
+ [-0.0111, -0.0460, -0.0614],
132
+ ]
133
+
134
+ FLUX2_LATENT_RGB_BIAS = [-0.0329, -0.0718, -0.0851]
135
+
96
136
 
97
137
  def sample_to_lowres_estimated_image(
98
- samples: torch.Tensor, latent_rgb_factors: torch.Tensor, smooth_matrix: Optional[torch.Tensor] = None
138
+ samples: torch.Tensor,
139
+ latent_rgb_factors: torch.Tensor,
140
+ smooth_matrix: Optional[torch.Tensor] = None,
141
+ latent_rgb_bias: Optional[torch.Tensor] = None,
99
142
  ):
100
143
  if samples.dim() == 4:
101
144
  samples = samples[0]
102
145
  latent_image = samples.permute(1, 2, 0) @ latent_rgb_factors
103
146
 
147
+ if latent_rgb_bias is not None:
148
+ latent_image = latent_image + latent_rgb_bias
149
+
104
150
  if smooth_matrix is not None:
105
151
  latent_image = latent_image.unsqueeze(0).permute(3, 0, 1, 2)
106
152
  latent_image = torch.nn.functional.conv2d(latent_image, smooth_matrix.reshape((1, 1, 3, 3)), padding=1)
@@ -153,6 +199,7 @@ def diffusion_step_callback(
153
199
  sample = intermediate_state.latents
154
200
 
155
201
  smooth_matrix: list[list[float]] | None = None
202
+ latent_rgb_bias: list[float] | None = None
156
203
  if base_model in [BaseModelType.StableDiffusion1, BaseModelType.StableDiffusion2]:
157
204
  latent_rgb_factors = SD1_5_LATENT_RGB_FACTORS
158
205
  elif base_model in [BaseModelType.StableDiffusionXL, BaseModelType.StableDiffusionXLRefiner]:
@@ -164,6 +211,9 @@ def diffusion_step_callback(
164
211
  latent_rgb_factors = COGVIEW4_LATENT_RGB_FACTORS
165
212
  elif base_model == BaseModelType.Flux:
166
213
  latent_rgb_factors = FLUX_LATENT_RGB_FACTORS
214
+ elif base_model == BaseModelType.Flux2:
215
+ latent_rgb_factors = FLUX2_LATENT_RGB_FACTORS
216
+ latent_rgb_bias = FLUX2_LATENT_RGB_BIAS
167
217
  elif base_model == BaseModelType.ZImage:
168
218
  # Z-Image uses FLUX-compatible VAE with 16 latent channels
169
219
  latent_rgb_factors = FLUX_LATENT_RGB_FACTORS
@@ -174,8 +224,14 @@ def diffusion_step_callback(
174
224
  smooth_matrix_torch = (
175
225
  torch.tensor(smooth_matrix, dtype=sample.dtype, device=sample.device) if smooth_matrix else None
176
226
  )
227
+ latent_rgb_bias_torch = (
228
+ torch.tensor(latent_rgb_bias, dtype=sample.dtype, device=sample.device) if latent_rgb_bias else None
229
+ )
177
230
  image = sample_to_lowres_estimated_image(
178
- samples=sample, latent_rgb_factors=latent_rgb_factors_torch, smooth_matrix=smooth_matrix_torch
231
+ samples=sample,
232
+ latent_rgb_factors=latent_rgb_factors_torch,
233
+ smooth_matrix=smooth_matrix_torch,
234
+ latent_rgb_bias=latent_rgb_bias_torch,
179
235
  )
180
236
 
181
237
  width = image.width * 8