Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d188a3764b | ||
|
|
f1d0630729 |
@@ -1,3 +1,10 @@
|
||||
## [1.9.1](https://github.com/Artificial-Sweetener/SimpleSyrup/compare/v1.9.0...v1.9.1) (2026-09-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **contextual-diffusion:** project reference latents into views ([4cd780a](https://github.com/Artificial-Sweetener/SimpleSyrup/commit/4cd780a2451aa472ce826834e4426b65693c46e8))
|
||||
|
||||
# [1.9.0](https://github.com/Artificial-Sweetener/SimpleSyrup/compare/v1.8.0...v1.9.0) (2026-09-19)
|
||||
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "simple-syrup-comfyui",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "simple-syrup-comfyui",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-syrup-comfyui",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"type": "module",
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
||||
[project]
|
||||
name = "SimpleSyrup"
|
||||
description = "Workflow-focused ComfyUI extensions for image generation."
|
||||
version = "1.9.0"
|
||||
version = "1.9.1"
|
||||
license = "AGPL-3.0-or-later"
|
||||
license-files = ["LICENSE"]
|
||||
requires-python = ">=3.11"
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__version__ = "1.9.0"
|
||||
__version__ = "1.9.1"
|
||||
|
||||
__all__: list[str] = ["__version__"]
|
||||
|
||||
@@ -49,6 +49,7 @@ class ContextualDiffusionModelWrapper:
|
||||
self._tile_predictions = TilePredictionAccumulator(
|
||||
plan.tile_plan,
|
||||
diffusion_mode=diffusion_mode,
|
||||
project_canvas_reference_latents=True,
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -110,6 +111,7 @@ class ContextualDiffusionModelWrapper:
|
||||
global_args = make_spatial_view_model_args(
|
||||
args=args,
|
||||
layout=global_layout,
|
||||
project_canvas_reference_latents=True,
|
||||
)
|
||||
global_prediction = self._call_original(apply_model, global_args)
|
||||
global_view = self._plan.global_view
|
||||
|
||||
@@ -34,8 +34,9 @@ def make_tiled_model_args(
|
||||
input_batch_size: int,
|
||||
latent_height: int,
|
||||
latent_width: int,
|
||||
project_canvas_reference_latents: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Create apply-model args for one spatial tile batch."""
|
||||
"""Create tile arguments with optional canvas-reference projection."""
|
||||
|
||||
layout = tiled_batch_layout(
|
||||
tiles=tiles,
|
||||
@@ -63,6 +64,7 @@ def make_tiled_model_args(
|
||||
conditioning=conditioning,
|
||||
layout=layout,
|
||||
view_timestep=tiled_timestep,
|
||||
project_canvas_reference_latents=project_canvas_reference_latents,
|
||||
)
|
||||
tiled_args = args.copy()
|
||||
tiled_args["input"] = tiled_x
|
||||
@@ -114,8 +116,9 @@ def make_spatial_view_model_args(
|
||||
*,
|
||||
args: dict[str, Any],
|
||||
layout: SpatialBatchLayout,
|
||||
project_canvas_reference_latents: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Create apply-model arguments for equally shaped spatial views."""
|
||||
"""Create equal-view arguments with optional canvas-reference projection."""
|
||||
|
||||
target_shape = (layout.views[0].model_height, layout.views[0].model_width)
|
||||
if any(
|
||||
@@ -149,6 +152,7 @@ def make_spatial_view_model_args(
|
||||
conditioning=conditioning,
|
||||
layout=layout,
|
||||
view_timestep=view_timestep,
|
||||
project_canvas_reference_latents=project_canvas_reference_latents,
|
||||
)
|
||||
view_args = args.copy()
|
||||
view_args["input"] = view_x
|
||||
@@ -172,14 +176,18 @@ def spatial_view_conditioning(
|
||||
conditioning: dict[str, Any],
|
||||
layout: SpatialBatchLayout,
|
||||
view_timestep: torch.Tensor,
|
||||
project_canvas_reference_latents: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Resize spatial conditioning alongside arbitrary latent views."""
|
||||
"""Project spatial conditioning and optionally canvas-aligned references."""
|
||||
|
||||
transformed: dict[str, Any] = {}
|
||||
for key, value in conditioning.items():
|
||||
if key == "transformer_options":
|
||||
continue
|
||||
if key in SPATIAL_INVARIANT_CONDITIONING_KEYS:
|
||||
if (
|
||||
key in SPATIAL_INVARIANT_CONDITIONING_KEYS
|
||||
and not project_canvas_reference_latents
|
||||
):
|
||||
transformed[key] = repeat_spatial_invariant_value(
|
||||
value,
|
||||
view_count=layout.view_count,
|
||||
|
||||
@@ -158,11 +158,18 @@ class TileBlendWeightCache:
|
||||
class TilePredictionAccumulator:
|
||||
"""Evaluate tiled model views and combine them with one selected policy."""
|
||||
|
||||
def __init__(self, plan: TiledDiffusionPlan, *, diffusion_mode: str) -> None:
|
||||
"""Bind an immutable plan to its overlap weighting policy."""
|
||||
def __init__(
|
||||
self,
|
||||
plan: TiledDiffusionPlan,
|
||||
*,
|
||||
diffusion_mode: str,
|
||||
project_canvas_reference_latents: bool = False,
|
||||
) -> None:
|
||||
"""Bind a plan to its weighting and reference-projection policies."""
|
||||
|
||||
self._plan = plan
|
||||
self._blend_weights = TileBlendWeightCache(plan, diffusion_mode)
|
||||
self._project_canvas_reference_latents = project_canvas_reference_latents
|
||||
|
||||
def predict(
|
||||
self,
|
||||
@@ -183,6 +190,9 @@ class TilePredictionAccumulator:
|
||||
input_batch_size=input_batch_size,
|
||||
latent_height=self._plan.latent_height,
|
||||
latent_width=self._plan.latent_width,
|
||||
project_canvas_reference_latents=(
|
||||
self._project_canvas_reference_latents
|
||||
),
|
||||
)
|
||||
tile_output = evaluate(tiled_args)
|
||||
for index, tile in enumerate(batch):
|
||||
|
||||
@@ -182,11 +182,16 @@ def test_global_call_uses_one_full_source_reduced_model_layout(
|
||||
*,
|
||||
args: dict[str, Any],
|
||||
layout: SpatialBatchLayout,
|
||||
project_canvas_reference_latents: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Capture and apply the global model-argument layout."""
|
||||
|
||||
layouts.append(layout)
|
||||
return transform(args=args, layout=layout)
|
||||
return transform(
|
||||
args=args,
|
||||
layout=layout,
|
||||
project_canvas_reference_latents=project_canvas_reference_latents,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
wrapper_module,
|
||||
@@ -389,8 +394,8 @@ def test_weighted_correction_formula_is_exact_for_both_local_fusion_modes(
|
||||
assert torch.allclose(output[:, :, 1::2], torch.full((1, 1, 8, 32), 0.5))
|
||||
|
||||
|
||||
def test_local_and_global_calls_receive_complete_reference_latents() -> None:
|
||||
"""Keep independent reference images intact through both spatial views."""
|
||||
def test_local_and_global_calls_project_canvas_reference_latents() -> None:
|
||||
"""Give every Contextual Diffusion view its spatially aligned reference."""
|
||||
|
||||
reference = torch.arange(1 * 4 * 16 * 32, dtype=torch.float32).reshape(
|
||||
(1, 4, 16, 32)
|
||||
@@ -419,8 +424,16 @@ def test_local_and_global_calls_receive_complete_reference_latents() -> None:
|
||||
)
|
||||
|
||||
assert len(received) == 2
|
||||
assert torch.equal(received[0], torch.cat((reference, reference), dim=0))
|
||||
assert torch.equal(received[1], reference)
|
||||
assert torch.equal(
|
||||
received[0],
|
||||
torch.cat((reference[..., :16], reference[..., 16:]), dim=0),
|
||||
)
|
||||
expected_global = torch.nn.functional.interpolate(
|
||||
reference.reshape(-1, 1, 16, 32),
|
||||
size=(8, 16),
|
||||
mode="nearest-exact",
|
||||
).reshape(1, 4, 8, 16)
|
||||
assert torch.equal(received[1], expected_global)
|
||||
|
||||
|
||||
def test_one_tile_plan_delegates_to_one_original_evaluation() -> None:
|
||||
|
||||
@@ -144,6 +144,37 @@ def test_spatial_args_preserve_batch_metadata_references_and_source_args() -> No
|
||||
assert "spatial_batch_layout" not in existing_namespace
|
||||
|
||||
|
||||
def test_spatial_args_project_canvas_reference_latents_when_requested() -> None:
|
||||
"""Crop canvas-aligned references while preserving independent references."""
|
||||
|
||||
canvas_reference = torch.arange(1 * 2 * 4 * 8, dtype=torch.float32).reshape(
|
||||
(1, 2, 4, 8)
|
||||
)
|
||||
independent_reference = torch.full((1, 2, 3, 5), 7.0)
|
||||
layout = _layout(_left_right_views(), input_batch_size=1)
|
||||
|
||||
transformed = make_spatial_view_model_args(
|
||||
args={
|
||||
"input": torch.zeros((1, 1, 4, 8)),
|
||||
"timestep": torch.ones((1,)),
|
||||
"c": {"ref_latents": [canvas_reference, independent_reference]},
|
||||
},
|
||||
layout=layout,
|
||||
project_canvas_reference_latents=True,
|
||||
)
|
||||
|
||||
references = transformed["c"]["ref_latents"]
|
||||
assert isinstance(references, list)
|
||||
assert torch.equal(
|
||||
references[0],
|
||||
torch.cat((canvas_reference[..., :4], canvas_reference[..., 4:]), dim=0),
|
||||
)
|
||||
assert torch.equal(
|
||||
references[1],
|
||||
torch.cat((independent_reference, independent_reference), dim=0),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("transformer_options", "message"),
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user