Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add image to image vae compile demo #406

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add image to image controlnet
  • Loading branch information
strint committed Dec 7, 2023
commit b16e09ea89791589ba807e16f5a6f6bd65b1d034
119 changes: 119 additions & 0 deletions examples/image_to_image_controlnet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import argparse

from diffusers import (
StableDiffusionControlNetImg2ImgPipeline,
ControlNetModel,
UniPCMultistepScheduler,
)

from diffusers.utils import load_image
import numpy as np
import torch

import cv2
from PIL import Image

parser = argparse.ArgumentParser()
parser.add_argument("--base", type=str, default="stabilityai/sd-turbo")
parser.add_argument("--controlnet", type=str, default="thibaud/controlnet-sd21-canny-diffusers")
parser.add_argument(
"--input_image",
type=str,
default="https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png",
)
parser.add_argument(
"--prompt", type=str, default="chinese painting style women",
)
parser.add_argument("--height", type=int, default=512)
parser.add_argument("--width", type=int, default=512)
parser.add_argument("--n_steps", type=int, default=7)
parser.add_argument(
"--saved_image", type=str, required=False, default="i2i_controlnet-out.png"
)
parser.add_argument("--seed", type=int, default=1)
parser.add_argument("--warmup", type=int, default=1)
parser.add_argument("--run", type=int, default=3)
parser.add_argument(
"--compile_unet", type=(lambda x: str(x).lower() in ["true", "1", "yes"]), default=True
)
parser.add_argument(
"--compile_vae", type=(lambda x: str(x).lower() in ["true", "1", "yes"]), default=True
)
parser.add_argument(
"--compile_ctrlnet",
type=(lambda x: str(x).lower() in ["true", "1", "yes"]),
default=True,
)
args = parser.parse_args()

# load an image
image = load_image(args.input_image)
image = np.array(image)

# get canny image
image = cv2.Canny(image, 100, 200)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
canny_image = Image.fromarray(image)

# load control net and stable diffusion
# reference: https://huggingface.co/docs/diffusers/main/en/api/pipelines/controlnet
controlnet = ControlNetModel.from_pretrained(args.controlnet, torch_dtype=torch.float16)
pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
args.base, controlnet=controlnet, torch_dtype=torch.float16
)

# speed up diffusion process with faster scheduler
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.to("cuda")

if args.compile_unet:
from onediff.infer_compiler import oneflow_compile
pipe.unet = oneflow_compile(pipe.unet)

if args.compile_vae:
from onediff.infer_compiler import oneflow_compile
#pipe.vae = oneflow_compile(pipe.vae)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related work takes my time: #394

But it's not trivial to compile the encode and decode in one graph.

# ImageToImage has encoder and decoder, so we need to compile them seperately.
strint marked this conversation as resolved.
Show resolved Hide resolved
strint marked this conversation as resolved.
Show resolved Hide resolved
pipe.vae.encoder = oneflow_compile(pipe.vae.encoder)
pipe.vae.decoder = oneflow_compile(pipe.vae.decoder)
Copy link
Collaborator Author

@strint strint Dec 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compile the encoder and decoder separately

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there an automatic way to detect and report the cause of inappropriately compiling encoder and decoder together?

Copy link
Collaborator Author

@strint strint Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there an automatic way to detect and report the cause of inappropriately compiling encoder and decoder together?

Yes, we are working on it in another PR: directly compile the full vae.


if args.compile_ctrlnet:
from onediff.infer_compiler import oneflow_compile
pipe.controlnet = oneflow_compile(pipe.controlnet)


# generate image
generator = torch.manual_seed(args.seed)

print("Warmup")
for i in range(args.warmup):
images = pipe(
args.prompt,
height=args.height,
width=args.width,
num_inference_steps=args.n_steps,
generator=generator,
image=image,
control_image=canny_image,
).images

print("Run")
from tqdm import tqdm
import time
for i in tqdm(range(args.run), desc="Pipe processing", unit="i"):
start_t = time.time()
image = pipe(
args.prompt,
height=args.height,
width=args.width,
num_inference_steps=args.n_steps,
generator=generator,
image=image,
control_image=canny_image,
).images[0]
torch.cuda.synchronize()
end_t = time.time()
print(f"e2e {i} ) elapsed: {end_t - start_t} s")

image.save(f"{i=}th_{args.saved_image}.png")
Loading