Skip to content

Commit 892fe62

Browse files
JPPhotopsychedelicious
authored andcommitted
Add Ideal Size node to core nodes
The Ideal Size node is useful for High-Res Optimization as it gives the optimum size for creating an initial generation with minimal artifacts (duplication and other strangeness) from today's models. After inclusion, front end graph generation can be simplified by offloading calculations for HRO initial generation to this node.
1 parent 3c79476 commit 892fe62

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

invokeai/app/invocations/latent.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright (c) 2023 Kyle Schouviller (https://github.com/kyle0654)
22

3+
import math
34
from contextlib import ExitStack
45
from functools import singledispatchmethod
56
from typing import List, Literal, Optional, Union
@@ -1228,3 +1229,54 @@ def invoke(self, context: InvocationContext) -> LatentsOutput:
12281229
context.services.latents.save(name, cropped_latents)
12291230

12301231
return build_latents_output(latents_name=name, latents=cropped_latents)
1232+
1233+
1234+
@invocation_output("ideal_size_output")
1235+
class IdealSizeOutput(BaseInvocationOutput):
1236+
"""Base class for invocations that output an image"""
1237+
1238+
width: int = OutputField(description="The ideal width of the image in pixels")
1239+
height: int = OutputField(description="The ideal height of the image in pixels")
1240+
1241+
1242+
@invocation(
1243+
"ideal_size",
1244+
title="Ideal Size",
1245+
tags=["latents", "math", "ideal_size"],
1246+
version="1.0.2",
1247+
)
1248+
class IdealSizeInvocation(BaseInvocation):
1249+
"""Calculates the ideal size for generation to avoid duplication"""
1250+
1251+
width: int = InputField(default=1024, description="Target width")
1252+
height: int = InputField(default=576, description="Target height")
1253+
unet: UNetField = InputField(default=None, description="UNet submodel")
1254+
multiplier: float = InputField(default=1.0, description="Dimensional multiplier")
1255+
1256+
def trim_to_multiple_of(self, *args, multiple_of=LATENT_SCALE_FACTOR):
1257+
return tuple((x - x % multiple_of) for x in args)
1258+
1259+
def invoke(self, context: InvocationContext) -> IdealSizeOutput:
1260+
aspect = self.width / self.height
1261+
dimension = 512
1262+
if self.unet.unet.base_model == BaseModelType.StableDiffusion2:
1263+
dimension = 768
1264+
elif self.unet.unet.base_model == BaseModelType.StableDiffusionXL:
1265+
dimension = 1024
1266+
dimension = dimension * self.multiplier
1267+
min_dimension = math.floor(dimension * 0.5)
1268+
model_area = dimension * dimension # hardcoded for now since all models are trained on square images
1269+
1270+
if aspect > 1.0:
1271+
init_height = max(min_dimension, math.sqrt(model_area / aspect))
1272+
init_width = init_height * aspect
1273+
else:
1274+
init_width = max(min_dimension, math.sqrt(model_area * aspect))
1275+
init_height = init_width / aspect
1276+
1277+
scaled_width, scaled_height = self.trim_to_multiple_of(
1278+
math.floor(init_width),
1279+
math.floor(init_height),
1280+
)
1281+
1282+
return IdealSizeOutput(width=scaled_width, height=scaled_height)

0 commit comments

Comments
 (0)