VinitT commited on
Commit
bb68da8
1 Parent(s): a9a9ddd

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -0
app.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch.utils.data import DataLoader, Dataset
3
+ from torchvision import transforms
4
+ from PIL import Image
5
+ from diffusers import StableDiffusionPipeline
6
+ import streamlit as st
7
+ from transformers import CLIPTokenizer
8
+
9
+ # Define the device
10
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
11
+
12
+ # Define your custom dataset
13
+ class CustomImageDataset(Dataset):
14
+ def __init__(self, images, prompts, transform=None):
15
+ self.images = images
16
+ self.prompts = prompts
17
+ self.transform = transform
18
+
19
+ def __len__(self):
20
+ return len(self.images)
21
+
22
+ def __getitem__(self, idx):
23
+ image = self.images[idx]
24
+ if self.transform:
25
+ image = self.transform(image)
26
+ prompt = self.prompts[idx]
27
+ return image, prompt
28
+
29
+ # Function to fine-tune the model
30
+ def fine_tune_model(images, prompts, num_epochs=3):
31
+ transform = transforms.Compose([
32
+ transforms.Resize((512, 512)),
33
+ transforms.ToTensor(),
34
+ transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
35
+ ])
36
+ dataset = CustomImageDataset(images, prompts, transform)
37
+ dataloader = DataLoader(dataset, batch_size=4, shuffle=True)
38
+
39
+ # Load Stable Diffusion model
40
+ pipeline = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4").to(device)
41
+
42
+ # Load model components
43
+ vae = pipeline.vae.to(device)
44
+ unet = pipeline.unet.to(device)
45
+ text_encoder = pipeline.text_encoder.to(device)
46
+ tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-base-patch32") # Ensure correct tokenizer is used
47
+ optimizer = torch.optim.AdamW(unet.parameters(), lr=5e-6) # Define the optimizer
48
+
49
+ # Define timestep range for training
50
+ timesteps = torch.linspace(0, 1, steps=5).to(device)
51
+
52
+ # Fine-tuning loop
53
+ for epoch in range(num_epochs):
54
+ for i, (images, prompts) in enumerate(dataloader):
55
+ images = images.to(device) # Move images to GPU if available
56
+
57
+ # Tokenize the prompts
58
+ inputs = tokenizer(list(prompts), padding=True, return_tensors="pt", truncation=True).to(device)
59
+
60
+ latents = vae.encode(images).latent_dist.sample() * 0.18215
61
+ text_embeddings = text_encoder(inputs.input_ids).last_hidden_state
62
+
63
+ noise = torch.randn_like(latents).to(device)
64
+ noisy_latents = latents + noise
65
+
66
+ # Pass text embeddings and timestep to UNet
67
+ timestep = torch.randint(0, len(timesteps), (latents.size(0),), device=device).float()
68
+ pred_noise = unet(noisy_latents, timestep=timestep, encoder_hidden_states=text_embeddings).sample
69
+
70
+ loss = torch.nn.functional.mse_loss(pred_noise, noise)
71
+ optimizer.zero_grad()
72
+ loss.backward()
73
+ optimizer.step()
74
+
75
+ if i % 10 == 0:
76
+ st.write(f"Epoch {epoch+1}/{num_epochs}, Step {i+1}/{len(dataloader)}, Loss: {loss.item()}")
77
+
78
+ st.success("Fine-tuning completed!")
79
+
80
+ # Function to convert tensor to PIL Image
81
+ def tensor_to_pil(tensor):
82
+ tensor = tensor.squeeze().cpu().clamp(0, 1) # Remove batch dimension if necessary
83
+ tensor = transforms.ToPILImage()(tensor)
84
+ return tensor
85
+
86
+ # Function to generate images
87
+ def generate_images(prompt):
88
+ pipeline = StableDiffusionPipeline.from_pretrained("path/to/fine-tuned/model").to(device)
89
+ with torch.no_grad():
90
+ output = pipeline(prompt)
91
+
92
+ # Check if the output contains images
93
+ if isinstance(output.images, list):
94
+ image_tensor = output.images[0] # Access image tensor from list
95
+ else:
96
+ raise TypeError("Expected output to be a list of images")
97
+
98
+ # Convert tensor to PIL Image
99
+ if isinstance(image_tensor, torch.Tensor):
100
+ image = tensor_to_pil(image_tensor)
101
+ elif isinstance(image_tensor, Image.Image):
102
+ image = image_tensor
103
+ else:
104
+ raise TypeError(f"Unexpected image format returned by the pipeline: {type(image_tensor)}")
105
+
106
+ return image
107
+
108
+ # Streamlit app layout
109
+ st.title("Fine-Tune Stable Diffusion with Your Images")
110
+
111
+ # Upload images
112
+ uploaded_files = st.file_uploader("Upload your images", accept_multiple_files=True, type=['png', 'jpg', 'jpeg'])
113
+
114
+ # Input prompts
115
+ prompts = []
116
+ images = []
117
+ if uploaded_files:
118
+ for file in uploaded_files:
119
+ image = Image.open(file).convert("RGB") # Convert uploaded file to PIL Image
120
+ images.append(image)
121
+ prompt = st.text_input(f"Enter a prompt for {file.name}")
122
+ prompts.append(prompt)
123
+
124
+ # Start fine-tuning
125
+ if st.button("Start Fine-Tuning") and uploaded_files and prompts:
126
+ fine_tune_model(images, prompts)
127
+
128
+ # Generate new images
129
+ st.subheader("Generate New Images")
130
+ new_prompt = st.text_input("Enter a prompt to generate a new image")
131
+ if st.button("Generate Image"):
132
+ if new_prompt:
133
+ with st.spinner("Generating image..."):
134
+ image = generate_images(new_prompt)
135
+ st.image(image, caption="Generated Image") # 'image' should be a PIL Image