Sean Powell commited on
Commit
a9ae6bb
·
1 Parent(s): fc4590f

Extract and refactor diamond crop img2img procedure.

Browse files
experiments/diamond-crop-img2img.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils import filenames, images, wallpaper, pipes
2
+
3
+ prompt = "seamless pattern of parrots. black and white, drawing, white background, seamless, ornament."
4
+ generation_dir = "./generations/diamond_crop_img2img"
5
+
6
+ sdxl_pipe = pipes.create_stable_diffusion_xl_pipeline()
7
+
8
+ original_image = sdxl_pipe(prompt=prompt, num_inference_steps=20).images[0]
9
+ original_image_filename = filenames.generate_filename(f"{generation_dir}/originals", prompt)
10
+ original_image.save(original_image_filename)
11
+ print("generated image generated", original_image_filename)
12
+
13
+ inner_rotated_tile = images.extract_inner_rotated_tile_from_image(original_image)
14
+ inner_rotated_tile_filename = filenames.generate_filename(f"{generation_dir}/inner_rotated_tiles", prompt,
15
+ "-inner-rotated")
16
+ inner_rotated_tile.save(inner_rotated_tile_filename)
17
+ print("generated inner rotated tile", inner_rotated_tile_filename)
18
+
19
+ sdxl_img2img_pipe = pipes.create_stable_diffusion_xl_img2img_pipe()
20
+
21
+ tileable_image = sdxl_img2img_pipe(prompt, image=inner_rotated_tile.convert("RGB"), num_inference_steps=20).images[0]
22
+ tileable_image_filename = filenames.generate_filename(f"{generation_dir}/tiles", prompt, "-tile")
23
+ tileable_image.save(tileable_image_filename)
24
+ print("generated tileable image", tileable_image_filename)
25
+
26
+ half_drop = wallpaper.convert_tile_to_half_drop(tileable_image)
27
+ half_drop_filename = filenames.generate_filename(f"{generation_dir}//half_drops", prompt, "_half-drop-tile")
28
+ half_drop.save(half_drop_filename)
29
+ print("generated half drop tile", tileable_image_filename)
30
+
31
+ half_drop_tiled = wallpaper.generate_tile_test_arrangement(half_drop)
32
+ half_drop_tiled_filename = filenames.generate_filename(f"{generation_dir}/half_drop_demo", prompt,
33
+ "_half-drop-demo")
34
+ half_drop_tiled.save(half_drop_tiled_filename)
35
+ print("generated half drop tiled image", tileable_image_filename)
generations/diamond_crop_img2img/half_drop_demo/.gitkeep ADDED
File without changes
generations/diamond_crop_img2img/half_drops/.gitkeep ADDED
File without changes
generations/diamond_crop_img2img/inner_rotated_tiles/.gitkeep ADDED
File without changes
generations/diamond_crop_img2img/originals/.gitkeep ADDED
File without changes
generations/diamond_crop_img2img/tiles/.gitkeep ADDED
File without changes
utils/pipes.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from diffusers import StableDiffusionXLImg2ImgPipeline, StableDiffusionXLPipeline
3
+
4
+ from utils import tiling
5
+
6
+
7
+ def create_stable_diffusion_xl_pipeline():
8
+ pipe = StableDiffusionXLPipeline.from_pretrained(
9
+ "stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
10
+ )
11
+ pipe = pipe.to("mps")
12
+ pipe.vae.disable_tiling()
13
+ tiling.enable_circular_tiling([pipe.vae, pipe.text_encoder, pipe.unet])
14
+ return pipe
15
+
16
+
17
+ def create_stable_diffusion_xl_img2img_pipe():
18
+ pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained(
19
+ "stabilityai/stable-diffusion-xl-refiner-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
20
+ )
21
+ pipe = pipe.to("mps")
22
+ pipe.vae.disable_tiling()
23
+ tiling.enable_circular_tiling([pipe.vae, pipe.text_encoder_2, pipe.unet])
24
+ return pipe
utils/tiling.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ import diffusers
4
+ import torch
5
+ from torch import Tensor
6
+ from torch.nn import functional as F
7
+ from torch.nn.modules.utils import _pair
8
+
9
+
10
+ def asymmetric_conv2d_conv_forward(self, input: Tensor, weight: Tensor, bias: Optional[Tensor]):
11
+ """
12
+ Perform a forward pass of a custom 2D convolution with asymmetric circular padding.
13
+
14
+ This method modifies the standard 2D convolution by applying asymmetric padding
15
+ to the input tensor before performing the convolution. The padding is circular,
16
+ meaning the input tensor wraps around itself.
17
+
18
+ Args:
19
+ self: An instance of the class containing convolution parameters.
20
+ input (Tensor): The input tensor to be convolved.
21
+ weight (Tensor): The weight tensor of the convolution kernel.
22
+ bias (Optional[Tensor]): An optional bias tensor for the convolution.
23
+
24
+ Returns:
25
+ Tensor: The output tensor after applying the asymmetric circular padding and 2D convolution.
26
+ """
27
+ self
28
+ self.paddingX = (self._reversed_padding_repeated_twice[0], self._reversed_padding_repeated_twice[1], 0, 0)
29
+ self.paddingY = (0, 0, self._reversed_padding_repeated_twice[2], self._reversed_padding_repeated_twice[3])
30
+ working = F.pad(input, self.paddingX, mode='circular')
31
+ working = F.pad(working, self.paddingY, mode='circular')
32
+ return F.conv2d(working, weight, bias, self.stride, _pair(0), self.dilation, self.groups)
33
+
34
+
35
+ def enable_circular_tiling(targets):
36
+ """
37
+ Enable circular tiling on convolutional layers within the given targets.
38
+
39
+ This function iterates through the given targets (which are parts of a neural
40
+ network model) and modifies each convolutional layer to use a custom asymmetric
41
+ convolution with circular padding. It is specifically designed for use with
42
+ the StableDiffusionXLPipeline to modify its convolution layers for circular tiling.
43
+
44
+ Args:
45
+ targets (list): A list of neural network components (e.g., layers or entire models)
46
+ from which to find and modify Conv2d layers.
47
+
48
+ Returns:
49
+ None: The function modifies the convolutional layers in-place.
50
+ """
51
+ conv_layers = []
52
+ for target in targets:
53
+ for module in target.modules():
54
+ if isinstance(module, torch.nn.Conv2d):
55
+ conv_layers.append(module)
56
+
57
+ for cl in conv_layers:
58
+ if isinstance(cl, diffusers.models.lora.LoRACompatibleConv) and cl.lora_layer is None:
59
+ cl.lora_layer = lambda *x: 0
60
+
61
+ cl._conv_forward = asymmetric_conv2d_conv_forward.__get__(cl, torch.nn.Conv2d)