sd_emphasis.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. from __future__ import annotations
  2. import torch
  3. class Emphasis:
  4. """Emphasis class decides how to death with (emphasized:1.1) text in prompts"""
  5. name: str = "Base"
  6. description: str = ""
  7. tokens: list[list[int]]
  8. """tokens from the chunk of the prompt"""
  9. multipliers: torch.Tensor
  10. """tensor with multipliers, once for each token"""
  11. z: torch.Tensor
  12. """output of cond transformers network (CLIP)"""
  13. def after_transformers(self):
  14. """Called after cond transformers network has processed the chunk of the prompt; this function should modify self.z to apply the emphasis"""
  15. pass
  16. class EmphasisNone(Emphasis):
  17. name = "None"
  18. description = "disable the mechanism entirely and treat (:.1.1) as literal characters"
  19. class EmphasisIgnore(Emphasis):
  20. name = "Ignore"
  21. description = "treat all empasised words as if they have no emphasis"
  22. class EmphasisOriginal(Emphasis):
  23. name = "Original"
  24. description = "the original emphasis implementation"
  25. def after_transformers(self):
  26. original_mean = self.z.mean()
  27. self.z = self.z * self.multipliers.reshape(self.multipliers.shape + (1,)).expand(self.z.shape)
  28. # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise
  29. new_mean = self.z.mean()
  30. self.z = self.z * (original_mean / new_mean)
  31. class EmphasisOriginalNoNorm(EmphasisOriginal):
  32. name = "No norm"
  33. description = "same as original, but without normalization (seems to work better for SDXL)"
  34. def after_transformers(self):
  35. self.z = self.z * self.multipliers.reshape(self.multipliers.shape + (1,)).expand(self.z.shape)
  36. def get_current_option(emphasis_option_name):
  37. return next(iter([x for x in options if x.name == emphasis_option_name]), EmphasisOriginal)
  38. def get_options_descriptions():
  39. return ", ".join(f"{x.name}: {x.description}" for x in options)
  40. options = [
  41. EmphasisNone,
  42. EmphasisIgnore,
  43. EmphasisOriginal,
  44. EmphasisOriginalNoNorm,
  45. ]