sd-v5 / components /model.py
flappybird1084's picture
sorta working v3
b51df53
Raw
History Blame Contribute Delete
6.23 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
from transformers import CLIPProcessor, CLIPModel, CLIPTextModelWithProjection
class Encoder(nn.Module): # accepts B,3,256,256
def __init__(self):
super(Encoder, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1) # B,64,128,128
self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1) # B,128,64,64
self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1) # B,256,32,32
self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1) # B,512,16,16
self.norm = nn.LayerNorm([512, 16*16])
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.relu(self.conv2(x))
x = (self.conv3(x))
x = (self.conv4(x))
x = x.view(x.size(0), 512, -1) # B,512,256
x = self.norm(x)
return x # B,512,16,16 -> B,512,256 -> dim=256
class Decoder(nn.Module):
def __init__(self):
super(Decoder, self).__init__()
self.deconv1 = nn.ConvTranspose2d(512, 256, kernel_size=4, stride=2, padding=1) # B,256,32,32
self.deconv2 = nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1) # B,128,64,64
self.deconv3 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1) # B,64,128,128
self.deconv4 = nn.ConvTranspose2d(64, 3, kernel_size=4, stride=2, padding=1) # B,3,256,256
def forward(self, x):
x = x.view(x.size(0), 512, 16, 16) # B,512,256 -> B,512,16,16
x = F.relu(self.deconv1(x))
x = F.relu(self.deconv2(x))
x = F.relu(self.deconv3(x))
x = torch.sigmoid(self.deconv4(x)) # Use sigmoid to get output in range [0, 1]
return x
class JointAttention(nn.Module):
def __init__(self, d_model=256):
super().__init__()
self.dim = d_model
self.image_q, self.image_v, self.image_k = nn.Linear(d_model, d_model), nn.Linear(d_model, d_model), nn.Linear(d_model, d_model)
self.prompt_q, self.prompt_v, self.prompt_k = nn.Linear(d_model, d_model), nn.Linear(d_model, d_model), nn.Linear(d_model, d_model)
self.mlp = nn.Sequential(
nn.Linear(d_model, d_model*4),
nn.ReLU(),
nn.Linear(d_model*4, d_model)
)
half_dim = d_model //2
freq = torch.exp(
-math.log(10000) * torch.arange(0, half_dim, dtype=torch.float32) / half_dim
)
self.register_buffer("timestep_freq", freq)
self.image_emb = nn.Embedding(512,self.dim)
self.register_buffer("pos_ids", torch.arange(512))
self.ln1 = nn.LayerNorm(self.dim)
self.ln2 = nn.LayerNorm(self.dim)
def timestep_embedding(self,t):
freqs = self.timestep_freq.unsqueeze(0)
# emb = t.unsqueeze(1) * freqs
emb = t * freqs * 1000
emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1)
return emb
def forward(self, image, prompt, timestep):
timestep_emb = self.timestep_embedding(timestep) # B,1,256
# shapes: image: B,512,256; prompt: B,2,256; timestep_emb: B,1,256
# print(f"sanity: image: {image.shape}, prompt: {prompt.shape}, timestep_emb: {timestep_emb.shape}")
image = image+timestep_emb #B,512,256
image = image+self.image_emb(self.pos_ids)
prompt = prompt+timestep_emb #B,2,256
# print(f"sanity: image: {image.shape}, prompt: {prompt.shape}, timestep_emb: {timestep_emb.shape}")
image_norm, prompt_norm = self.ln1(image), self.ln1(prompt)
image_q, image_k, image_v = self.image_q(image_norm), self.image_k(image_norm), self.image_v(image_norm) # B,512,256
prompt_q, prompt_k, prompt_v = self.prompt_q(prompt_norm), self.prompt_k(prompt_norm), self.prompt_v(prompt_norm) # B,2,256
Q = torch.cat([image_q, prompt_q], dim=1) # B,514,256
K = torch.cat([image_k, prompt_k], dim=1) # B,514,256
V = torch.cat([image_v, prompt_v], dim=1) # B,514,256
out_resid = torch.cat([image, prompt], dim=1) # B,514,256
attn_out = F.scaled_dot_product_attention(Q, K, V) # B,514,256
out = self.mlp(attn_out) + out_resid # B,514,256
out = self.ln2(out) # B,514,256
out_image, out_prompt = out[:,:512,:], out[:,512:,:] # B,512,256; B,2,256
return out_image, out_prompt
class DiffusionModel(nn.Module):
def __init__(self, dim=256, num_layers=4):
super(DiffusionModel, self).__init__()
self.encoder = Encoder()
self.decoder = Decoder()
self.attn_layers = nn.ModuleList([JointAttention(dim) for _ in range(num_layers)])
self.processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
model_id="openai/clip-vit-base-patch32"
self.clip_model = CLIPTextModelWithProjection.from_pretrained(model_id)
def embed_text(self, text):
# inputs = tokenizer([text], return_tensors="pt")
inputs = self.processor(text=[text], return_tensors="pt", padding=True)
# print(type(inputs))
with torch.inference_mode():
# outputs = clip_model(**inputs)
outputs = self.clip_model(**inputs)
embeds=outputs.text_embeds.unsqueeze(1) # B,1,256
chunks = torch.chunk(embeds, chunks=2, dim=2)# tuple: B,1,256 each
embeds = torch.cat(chunks, dim=1) # B,2,256
return embeds
def encode(self, image):
return self.encoder(image)
def decode(self, image_emb):
return self.decoder(image_emb)
def forward(self, image_enc, prompt_enc, timestep):
resid_image_enc, resid_prompt_enc = image_enc, prompt_enc
for layer in self.attn_layers:
image_enc, prompt_enc = layer(image_enc, prompt_enc, timestep)
image_enc, prompt_enc = image_enc+resid_image_enc, prompt_enc+resid_prompt_enc
resid_image_enc, resid_prompt_enc = image_enc, prompt_enc
# return image_enc, prompt_enc
return image_enc # velocity pred
if __name__ == "__main__":
model = DiffusionModel()
image = torch.randn(1,3,256,256)
text = "a cat on a skateboard"
image_emb = model.encode(image)
prompt_emb = model.embed_text(text)
# print(f"image_emb shape: {image_emb.shape}, prompt_emb shape: {prompt_emb.shape}")
out_image_emb, out_prompt_emb = model(image_emb, prompt_emb, timestep=torch.tensor([10.0]))
# print(f"out_image_emb shape: {out_image_emb.shape}, out_prompt_emb shape: {out_prompt_emb.shape}")
out_image = model.decode(out_image_emb)
print(out_image.shape)