diff --git a/ldm/dream/generator/embiggen.py b/ldm/dream/generator/embiggen.py index cb9c029a66..64ba181346 100644 --- a/ldm/dream/generator/embiggen.py +++ b/ldm/dream/generator/embiggen.py @@ -5,9 +5,10 @@ and generates with ldm.dream.generator.img2img import torch import numpy as np -from PIL import Image +from tqdm import trange +from PIL import Image +from ldm.dream.devices import choose_autocast_device from ldm.dream.generator.base import Generator -from ldm.models.diffusion.ddim import DDIMSampler from ldm.dream.generator.img2img import Img2Img class Embiggen(Generator): @@ -15,6 +16,29 @@ class Embiggen(Generator): super().__init__(model) self.init_latent = None + # Replace generate because Embiggen doesn't need/use most of what it does normallly + def generate(self,prompt,iterations=1,seed=None, + image_callback=None, step_callback=None, + **kwargs): + device_type,scope = choose_autocast_device(self.model.device) + make_image = self.get_make_image( + prompt, + step_callback = step_callback, + **kwargs + ) + results = [] + seed = seed if seed else self.new_seed() + # Noise will be generated by the Img2Img generator when called + with scope(device_type), self.model.ema_scope(): + for n in trange(iterations, desc='Generating'): + # make_image will call Img2Img which will do the equivalent of get_noise itself + image = make_image() + results.append([image, seed]) + if image_callback is not None: + image_callback(image, seed) + seed = self.new_seed() + return results + @torch.no_grad() def get_make_image( self, @@ -143,7 +167,7 @@ class Embiggen(Generator): if distanceToLR > 255: distanceToLR = 255 #Place the pixel as invert of distance - agradientC.putpixel((x, y), int(255 - distanceToLR)) + agradientC.putpixel((x, y), round(255 - distanceToLR)) # Create alpha layers default fully white alphaLayerL = Image.new("L", (width, height), 255) @@ -213,7 +237,7 @@ class Embiggen(Generator): del agradientT del agradientC - def make_image(x_T): + def make_image(): # Make main tiles ------------------------------------------------- if embiggen_tiles: print(f'>> Making {len(embiggen_tiles)} Embiggen tiles...') @@ -221,7 +245,20 @@ class Embiggen(Generator): print(f'>> Making {(emb_tiles_x * emb_tiles_y)} Embiggen tiles ({emb_tiles_x}x{emb_tiles_y})...') emb_tile_store = [] + # Although we could use the same seed for every tile for determinism, at higher strengths this may + # produce duplicated structures for each tile and make the tiling effect more obvious + # instead track and iterate a local seed we pass to Img2Img + seed = self.seed + seedintlimit = np.iinfo(np.uint32).max - 1 # only retreive this one from numpy + for tile in range(emb_tiles_x * emb_tiles_y): + # Don't iterate on first tile + if tile != 0: + if seed < seedintlimit: + seed += 1 + else: + seed = 0 + # Determine if this is a re-run and replace if embiggen_tiles and not tile in embiggen_tiles: continue @@ -262,7 +299,7 @@ class Embiggen(Generator): tile_results = gen_img2img.generate( prompt, iterations = 1, - seed = self.seed, + seed = seed, sampler = sampler, steps = steps, cfg_scale = cfg_scale, @@ -272,7 +309,6 @@ class Embiggen(Generator): step_callback = step_callback, # called after each intermediate image is generated width = width, height = height, - init_img = init_img, # img2img doesn't need this, but it might in the future init_image = newinitimage, # notice that init_image is different from init_img mask_image = None, strength = strength,