sd_vae_taesd.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. """
  2. Tiny AutoEncoder for Stable Diffusion
  3. (DNN for encoding / decoding SD's latent space)
  4. https://github.com/madebyollin/taesd
  5. """
  6. import os
  7. import torch
  8. import torch.nn as nn
  9. from modules import devices, paths_internal, shared
  10. sd_vae_taesd_models = {}
  11. def conv(n_in, n_out, **kwargs):
  12. return nn.Conv2d(n_in, n_out, 3, padding=1, **kwargs)
  13. class Clamp(nn.Module):
  14. @staticmethod
  15. def forward(x):
  16. return torch.tanh(x / 3) * 3
  17. class Block(nn.Module):
  18. def __init__(self, n_in, n_out):
  19. super().__init__()
  20. self.conv = nn.Sequential(conv(n_in, n_out), nn.ReLU(), conv(n_out, n_out), nn.ReLU(), conv(n_out, n_out))
  21. self.skip = nn.Conv2d(n_in, n_out, 1, bias=False) if n_in != n_out else nn.Identity()
  22. self.fuse = nn.ReLU()
  23. def forward(self, x):
  24. return self.fuse(self.conv(x) + self.skip(x))
  25. def decoder():
  26. return nn.Sequential(
  27. Clamp(), conv(4, 64), nn.ReLU(),
  28. Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False),
  29. Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False),
  30. Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False),
  31. Block(64, 64), conv(64, 3),
  32. )
  33. def encoder():
  34. return nn.Sequential(
  35. conv(3, 64), Block(64, 64),
  36. conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64),
  37. conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64),
  38. conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64),
  39. conv(64, 4),
  40. )
  41. class TAESDDecoder(nn.Module):
  42. latent_magnitude = 3
  43. latent_shift = 0.5
  44. def __init__(self, decoder_path="taesd_decoder.pth"):
  45. """Initialize pretrained TAESD on the given device from the given checkpoints."""
  46. super().__init__()
  47. self.decoder = decoder()
  48. self.decoder.load_state_dict(
  49. torch.load(decoder_path, map_location='cpu' if devices.device.type != 'cuda' else None))
  50. class TAESDEncoder(nn.Module):
  51. latent_magnitude = 3
  52. latent_shift = 0.5
  53. def __init__(self, encoder_path="taesd_encoder.pth"):
  54. """Initialize pretrained TAESD on the given device from the given checkpoints."""
  55. super().__init__()
  56. self.encoder = encoder()
  57. self.encoder.load_state_dict(
  58. torch.load(encoder_path, map_location='cpu' if devices.device.type != 'cuda' else None))
  59. def download_model(model_path, model_url):
  60. if not os.path.exists(model_path):
  61. os.makedirs(os.path.dirname(model_path), exist_ok=True)
  62. print(f'Downloading TAESD model to: {model_path}')
  63. torch.hub.download_url_to_file(model_url, model_path)
  64. def decoder_model():
  65. model_name = "taesdxl_decoder.pth" if getattr(shared.sd_model, 'is_sdxl', False) else "taesd_decoder.pth"
  66. loaded_model = sd_vae_taesd_models.get(model_name)
  67. if loaded_model is None:
  68. model_path = os.path.join(paths_internal.models_path, "VAE-taesd", model_name)
  69. download_model(model_path, 'https://github.com/madebyollin/taesd/raw/main/' + model_name)
  70. if os.path.exists(model_path):
  71. loaded_model = TAESDDecoder(model_path)
  72. loaded_model.eval()
  73. loaded_model.to(devices.device, devices.dtype)
  74. sd_vae_taesd_models[model_name] = loaded_model
  75. else:
  76. raise FileNotFoundError('TAESD model not found')
  77. return loaded_model.decoder
  78. def encoder_model():
  79. model_name = "taesdxl_encoder.pth" if getattr(shared.sd_model, 'is_sdxl', False) else "taesd_encoder.pth"
  80. loaded_model = sd_vae_taesd_models.get(model_name)
  81. if loaded_model is None:
  82. model_path = os.path.join(paths_internal.models_path, "VAE-taesd", model_name)
  83. download_model(model_path, 'https://github.com/madebyollin/taesd/raw/main/' + model_name)
  84. if os.path.exists(model_path):
  85. loaded_model = TAESDEncoder(model_path)
  86. loaded_model.eval()
  87. loaded_model.to(devices.device, devices.dtype)
  88. sd_vae_taesd_models[model_name] = loaded_model
  89. else:
  90. raise FileNotFoundError('TAESD model not found')
  91. return loaded_model.encoder