sd_vae_taesd.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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(latent_channels=4):
  26. return nn.Sequential(
  27. Clamp(), conv(latent_channels, 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(latent_channels=4):
  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, latent_channels),
  40. )
  41. class TAESDDecoder(nn.Module):
  42. latent_magnitude = 3
  43. latent_shift = 0.5
  44. def __init__(self, decoder_path="taesd_decoder.pth", latent_channels=None):
  45. """Initialize pretrained TAESD on the given device from the given checkpoints."""
  46. super().__init__()
  47. if latent_channels is None:
  48. latent_channels = 16 if "taesd3" in str(decoder_path) else 4
  49. self.decoder = decoder(latent_channels)
  50. self.decoder.load_state_dict(
  51. torch.load(decoder_path, map_location='cpu' if devices.device.type != 'cuda' else None))
  52. class TAESDEncoder(nn.Module):
  53. latent_magnitude = 3
  54. latent_shift = 0.5
  55. def __init__(self, encoder_path="taesd_encoder.pth", latent_channels=None):
  56. """Initialize pretrained TAESD on the given device from the given checkpoints."""
  57. super().__init__()
  58. if latent_channels is None:
  59. latent_channels = 16 if "taesd3" in str(encoder_path) else 4
  60. self.encoder = encoder(latent_channels)
  61. self.encoder.load_state_dict(
  62. torch.load(encoder_path, map_location='cpu' if devices.device.type != 'cuda' else None))
  63. def download_model(model_path, model_url):
  64. if not os.path.exists(model_path):
  65. os.makedirs(os.path.dirname(model_path), exist_ok=True)
  66. print(f'Downloading TAESD model to: {model_path}')
  67. torch.hub.download_url_to_file(model_url, model_path)
  68. def decoder_model():
  69. if shared.sd_model.is_sd3:
  70. model_name = "taesd3_decoder.pth"
  71. elif shared.sd_model.is_sdxl:
  72. model_name = "taesdxl_decoder.pth"
  73. else:
  74. model_name = "taesd_decoder.pth"
  75. loaded_model = sd_vae_taesd_models.get(model_name)
  76. if loaded_model is None:
  77. model_path = os.path.join(paths_internal.models_path, "VAE-taesd", model_name)
  78. download_model(model_path, 'https://github.com/madebyollin/taesd/raw/main/' + model_name)
  79. if os.path.exists(model_path):
  80. loaded_model = TAESDDecoder(model_path)
  81. loaded_model.eval()
  82. loaded_model.to(devices.device, devices.dtype)
  83. sd_vae_taesd_models[model_name] = loaded_model
  84. else:
  85. raise FileNotFoundError('TAESD model not found')
  86. return loaded_model.decoder
  87. def encoder_model():
  88. if shared.sd_model.is_sd3:
  89. model_name = "taesd3_encoder.pth"
  90. elif shared.sd_model.is_sdxl:
  91. model_name = "taesdxl_encoder.pth"
  92. else:
  93. model_name = "taesd_encoder.pth"
  94. loaded_model = sd_vae_taesd_models.get(model_name)
  95. if loaded_model is None:
  96. model_path = os.path.join(paths_internal.models_path, "VAE-taesd", model_name)
  97. download_model(model_path, 'https://github.com/madebyollin/taesd/raw/main/' + model_name)
  98. if os.path.exists(model_path):
  99. loaded_model = TAESDEncoder(model_path)
  100. loaded_model.eval()
  101. loaded_model.to(devices.device, devices.dtype)
  102. sd_vae_taesd_models[model_name] = loaded_model
  103. else:
  104. raise FileNotFoundError('TAESD model not found')
  105. return loaded_model.encoder