modules.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import torch
  2. import torch.nn as nn
  3. from functools import partial
  4. import clip
  5. from einops import rearrange, repeat
  6. from transformers import CLIPTokenizer, CLIPTextModel
  7. import kornia
  8. from ldm.modules.x_transformer import Encoder, TransformerWrapper # TODO: can we directly rely on lucidrains code and simply add this as a reuirement? --> test
  9. class AbstractEncoder(nn.Module):
  10. def __init__(self):
  11. super().__init__()
  12. def encode(self, *args, **kwargs):
  13. raise NotImplementedError
  14. class ClassEmbedder(nn.Module):
  15. def __init__(self, embed_dim, n_classes=1000, key='class'):
  16. super().__init__()
  17. self.key = key
  18. self.embedding = nn.Embedding(n_classes, embed_dim)
  19. def forward(self, batch, key=None):
  20. if key is None:
  21. key = self.key
  22. # this is for use in crossattn
  23. c = batch[key][:, None]
  24. c = self.embedding(c)
  25. return c
  26. class TransformerEmbedder(AbstractEncoder):
  27. """Some transformer encoder layers"""
  28. def __init__(self, n_embed, n_layer, vocab_size, max_seq_len=77, device="cuda" if torch.cuda.is_available() else "cpu"):
  29. super().__init__()
  30. self.device = device
  31. self.transformer = TransformerWrapper(num_tokens=vocab_size, max_seq_len=max_seq_len,
  32. attn_layers=Encoder(dim=n_embed, depth=n_layer))
  33. def forward(self, tokens):
  34. tokens = tokens.to(self.device) # meh
  35. z = self.transformer(tokens, return_embeddings=True)
  36. return z
  37. def encode(self, x):
  38. return self(x)
  39. class BERTTokenizer(AbstractEncoder):
  40. """ Uses a pretrained BERT tokenizer by huggingface. Vocab size: 30522 (?)"""
  41. def __init__(self, device="cuda" if torch.cuda.is_available() else "cpu", vq_interface=True, max_length=77):
  42. super().__init__()
  43. from transformers import BertTokenizerFast # TODO: add to reuquirements
  44. self.tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased")
  45. self.device = device
  46. self.vq_interface = vq_interface
  47. self.max_length = max_length
  48. def forward(self, text):
  49. batch_encoding = self.tokenizer(text, truncation=True, max_length=self.max_length, return_length=True,
  50. return_overflowing_tokens=False, padding="max_length", return_tensors="pt")
  51. tokens = batch_encoding["input_ids"].to(self.device)
  52. return tokens
  53. @torch.no_grad()
  54. def encode(self, text):
  55. tokens = self(text)
  56. if not self.vq_interface:
  57. return tokens
  58. return None, None, [None, None, tokens]
  59. def decode(self, text):
  60. return text
  61. class BERTEmbedder(AbstractEncoder):
  62. """Uses the BERT tokenizr model and add some transformer encoder layers"""
  63. def __init__(self, n_embed, n_layer, vocab_size=30522, max_seq_len=77,
  64. device="cuda" if torch.cuda.is_available() else "cpu", use_tokenizer=True, embedding_dropout=0.0):
  65. super().__init__()
  66. self.use_tknz_fn = use_tokenizer
  67. if self.use_tknz_fn:
  68. self.tknz_fn = BERTTokenizer(vq_interface=False, max_length=max_seq_len)
  69. self.device = device
  70. self.transformer = TransformerWrapper(num_tokens=vocab_size, max_seq_len=max_seq_len,
  71. attn_layers=Encoder(dim=n_embed, depth=n_layer),
  72. emb_dropout=embedding_dropout)
  73. def forward(self, text):
  74. if self.use_tknz_fn:
  75. tokens = self.tknz_fn(text)#.to(self.device)
  76. else:
  77. tokens = text
  78. z = self.transformer(tokens, return_embeddings=True)
  79. return z
  80. def encode(self, text):
  81. # output of length 77
  82. return self(text)
  83. class SpatialRescaler(nn.Module):
  84. def __init__(self,
  85. n_stages=1,
  86. method='bilinear',
  87. multiplier=0.5,
  88. in_channels=3,
  89. out_channels=None,
  90. bias=False):
  91. super().__init__()
  92. self.n_stages = n_stages
  93. assert self.n_stages >= 0
  94. assert method in ['nearest','linear','bilinear','trilinear','bicubic','area']
  95. self.multiplier = multiplier
  96. self.interpolator = partial(torch.nn.functional.interpolate, mode=method)
  97. self.remap_output = out_channels is not None
  98. if self.remap_output:
  99. print(f'Spatial Rescaler mapping from {in_channels} to {out_channels} channels after resizing.')
  100. self.channel_mapper = nn.Conv2d(in_channels,out_channels,1,bias=bias)
  101. def forward(self,x):
  102. for stage in range(self.n_stages):
  103. x = self.interpolator(x, scale_factor=self.multiplier)
  104. if self.remap_output:
  105. x = self.channel_mapper(x)
  106. return x
  107. def encode(self, x):
  108. return self(x)
  109. class FrozenCLIPEmbedder(AbstractEncoder):
  110. """Uses the CLIP transformer encoder for text (from Hugging Face)"""
  111. def __init__(self, version="openai/clip-vit-large-patch14", device="cuda" if torch.cuda.is_available() else "cpu", max_length=77):
  112. super().__init__()
  113. self.tokenizer = CLIPTokenizer.from_pretrained(version)
  114. self.transformer = CLIPTextModel.from_pretrained(version)
  115. self.device = device
  116. self.max_length = max_length
  117. self.freeze()
  118. def freeze(self):
  119. self.transformer = self.transformer.eval()
  120. for param in self.parameters():
  121. param.requires_grad = False
  122. def forward(self, text):
  123. batch_encoding = self.tokenizer(text, truncation=True, max_length=self.max_length, return_length=True,
  124. return_overflowing_tokens=False, padding="max_length", return_tensors="pt")
  125. tokens = batch_encoding["input_ids"].to(self.device)
  126. outputs = self.transformer(input_ids=tokens)
  127. z = outputs.last_hidden_state
  128. return z
  129. def encode(self, text):
  130. return self(text)
  131. class FrozenCLIPTextEmbedder(nn.Module):
  132. """
  133. Uses the CLIP transformer encoder for text.
  134. """
  135. def __init__(self, version='ViT-L/14', device="cuda", max_length=77, n_repeat=1, normalize=True):
  136. super().__init__()
  137. self.model, _ = clip.load(version, jit=False, device="cpu")
  138. self.device = device
  139. self.max_length = max_length
  140. self.n_repeat = n_repeat
  141. self.normalize = normalize
  142. def freeze(self):
  143. self.model = self.model.eval()
  144. for param in self.parameters():
  145. param.requires_grad = False
  146. def forward(self, text):
  147. tokens = clip.tokenize(text).to(self.device)
  148. z = self.model.encode_text(tokens)
  149. if self.normalize:
  150. z = z / torch.linalg.norm(z, dim=1, keepdim=True)
  151. return z
  152. def encode(self, text):
  153. z = self(text)
  154. if z.ndim==2:
  155. z = z[:, None, :]
  156. z = repeat(z, 'b 1 d -> b k d', k=self.n_repeat)
  157. return z
  158. class FrozenClipImageEmbedder(nn.Module):
  159. """
  160. Uses the CLIP image encoder.
  161. """
  162. def __init__(
  163. self,
  164. model,
  165. jit=False,
  166. device='cuda' if torch.cuda.is_available() else 'cpu',
  167. antialias=False,
  168. ):
  169. super().__init__()
  170. self.model, _ = clip.load(name=model, device=device, jit=jit)
  171. self.antialias = antialias
  172. self.register_buffer('mean', torch.Tensor([0.48145466, 0.4578275, 0.40821073]), persistent=False)
  173. self.register_buffer('std', torch.Tensor([0.26862954, 0.26130258, 0.27577711]), persistent=False)
  174. def preprocess(self, x):
  175. # normalize to [0,1]
  176. x = kornia.geometry.resize(x, (224, 224),
  177. interpolation='bicubic',align_corners=True,
  178. antialias=self.antialias)
  179. x = (x + 1.) / 2.
  180. # renormalize according to clip
  181. x = kornia.enhance.normalize(x, self.mean, self.std)
  182. return x
  183. def forward(self, x):
  184. # x is assumed to be in range [-1,1]
  185. return self.model.encode_image(self.preprocess(x))
  186. if __name__ == "__main__":
  187. from ldm.util import count_params
  188. model = FrozenCLIPEmbedder()
  189. count_params(model, verbose=True)