|
import torch |
|
import torch.nn as nn |
|
from torchvision import transforms |
|
from PIL import Image |
|
from transformers import BertTokenizer, BertModel |
|
import argparse |
|
import numpy as np |
|
import os |
|
import time |
|
|
|
|
|
from train import CVAE, TextEncoder, LATENT_DIM, HIDDEN_DIM |
|
|
|
|
|
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') |
|
|
|
def clean_image(image, threshold=0.75): |
|
""" |
|
Clean up the image by setting pixels with opacity <= threshold to 0% opacity |
|
and pixels above the threshold to 100% visibility. |
|
""" |
|
np_image = np.array(image) |
|
alpha_channel = np_image[:, :, 3] |
|
alpha_channel[alpha_channel <= int(threshold * 255)] = 0 |
|
alpha_channel[alpha_channel > int(threshold * 255)] = 255 |
|
return Image.fromarray(np_image) |
|
|
|
def generate_image(model, text_prompt, device, input_image=None, img_control=0.5): |
|
|
|
encoded_input = tokenizer(text_prompt, padding=True, truncation=True, return_tensors="pt") |
|
input_ids = encoded_input['input_ids'].to(device) |
|
attention_mask = encoded_input['attention_mask'].to(device) |
|
|
|
|
|
with torch.no_grad(): |
|
text_encoding = model.text_encoder(input_ids, attention_mask) |
|
|
|
|
|
z = torch.randn(1, LATENT_DIM).to(device) |
|
|
|
|
|
with torch.no_grad(): |
|
generated_image = model.decode(z, text_encoding) |
|
|
|
if input_image is not None: |
|
input_image = input_image.convert("RGBA").resize((16, 16), resample=Image.NEAREST) |
|
input_image = transforms.ToTensor()(input_image).unsqueeze(0).to(device) |
|
generated_image = img_control * input_image + (1 - img_control) * generated_image |
|
|
|
|
|
generated_image = generated_image.squeeze(0).cpu() |
|
generated_image = (generated_image + 1) / 2 |
|
generated_image = generated_image.clamp(0, 1) |
|
generated_image = transforms.ToPILImage()(generated_image) |
|
|
|
return generated_image |
|
|
|
def main(): |
|
parser = argparse.ArgumentParser(description="Generate an image from a text prompt using the trained CVAE model(s).") |
|
parser.add_argument("--prompt", type=str, help="Text prompt for image generation") |
|
parser.add_argument("--prompt_file", type=str, help="File containing prompts, one per line") |
|
parser.add_argument("--output", type=str, default="generated_images", help="Output directory or file for generated images") |
|
parser.add_argument("--model_paths", type=str, nargs='*', help="Paths to the trained model(s)") |
|
parser.add_argument("--model_path", type=str, help="Path to a single trained model") |
|
parser.add_argument("--clean", action="store_true", help="Clean up the image by removing low opacity pixels") |
|
parser.add_argument("--size", type=int, default=16, help="Size of the generated image") |
|
parser.add_argument("--input_image", type=str, help="Path to the input image for img2img generation") |
|
parser.add_argument("--img_control", type=float, default=0.5, help="Control how much the input image influences the output (0 to 1)") |
|
args = parser.parse_args() |
|
|
|
if not args.prompt and not args.prompt_file: |
|
parser.error("Either --prompt or --prompt_file must be provided") |
|
|
|
if args.model_paths and args.model_path: |
|
parser.error("Specify either --model_paths or --model_path, not both") |
|
|
|
model_paths = args.model_paths if args.model_paths else [args.model_path] |
|
|
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
|
|
|
is_folder_output = os.path.isdir(args.output) |
|
|
|
if is_folder_output: |
|
|
|
os.makedirs(args.output, exist_ok=True) |
|
|
|
|
|
input_image = None |
|
if args.input_image: |
|
input_image = Image.open(args.input_image).convert("RGBA") |
|
|
|
|
|
if args.prompt: |
|
prompts = [args.prompt] |
|
else: |
|
with open(args.prompt_file, 'r') as f: |
|
prompts = [line.strip() for line in f if line.strip()] |
|
|
|
for model_path in model_paths: |
|
|
|
text_encoder = TextEncoder(hidden_size=HIDDEN_DIM, output_size=HIDDEN_DIM) |
|
model = CVAE(text_encoder).to(device) |
|
|
|
|
|
model.load_state_dict(torch.load(model_path, map_location=device)) |
|
model.eval() |
|
|
|
model_name = os.path.splitext(os.path.basename(model_path))[0] |
|
|
|
for i, prompt in enumerate(prompts): |
|
start_time = time.time() |
|
|
|
|
|
generated_image = generate_image(model, prompt, device, input_image, args.img_control) |
|
|
|
|
|
end_time = time.time() |
|
generation_time = end_time - start_time |
|
|
|
|
|
if args.clean: |
|
generated_image = clean_image(generated_image) |
|
|
|
|
|
generated_image = generated_image.resize((args.size, args.size), resample=Image.NEAREST) |
|
|
|
if not is_folder_output: |
|
|
|
output_file = args.output |
|
else: |
|
|
|
output_file = os.path.join(args.output, f"{model_name}_{prompt}_{i:03d}.png") |
|
|
|
generated_image.save(output_file) |
|
print(f"Generated image for prompt '{prompt}' using model '{model_name}' saved as {output_file}") |
|
print(f"Generation time: {generation_time:.10f} seconds") |
|
|
|
if __name__ == "__main__": |
|
main() |