sd_vae_approx.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import os
  2. import torch
  3. from torch import nn
  4. from modules import devices, paths, shared
  5. sd_vae_approx_models = {}
  6. class VAEApprox(nn.Module):
  7. def __init__(self):
  8. super(VAEApprox, self).__init__()
  9. self.conv1 = nn.Conv2d(4, 8, (7, 7))
  10. self.conv2 = nn.Conv2d(8, 16, (5, 5))
  11. self.conv3 = nn.Conv2d(16, 32, (3, 3))
  12. self.conv4 = nn.Conv2d(32, 64, (3, 3))
  13. self.conv5 = nn.Conv2d(64, 32, (3, 3))
  14. self.conv6 = nn.Conv2d(32, 16, (3, 3))
  15. self.conv7 = nn.Conv2d(16, 8, (3, 3))
  16. self.conv8 = nn.Conv2d(8, 3, (3, 3))
  17. def forward(self, x):
  18. extra = 11
  19. x = nn.functional.interpolate(x, (x.shape[2] * 2, x.shape[3] * 2))
  20. x = nn.functional.pad(x, (extra, extra, extra, extra))
  21. for layer in [self.conv1, self.conv2, self.conv3, self.conv4, self.conv5, self.conv6, self.conv7, self.conv8, ]:
  22. x = layer(x)
  23. x = nn.functional.leaky_relu(x, 0.1)
  24. return x
  25. def download_model(model_path, model_url):
  26. if not os.path.exists(model_path):
  27. os.makedirs(os.path.dirname(model_path), exist_ok=True)
  28. print(f'Downloading VAEApprox model to: {model_path}')
  29. torch.hub.download_url_to_file(model_url, model_path)
  30. def model():
  31. model_name = "vaeapprox-sdxl.pt" if getattr(shared.sd_model, 'is_sdxl', False) else "model.pt"
  32. loaded_model = sd_vae_approx_models.get(model_name)
  33. if loaded_model is None:
  34. model_path = os.path.join(paths.models_path, "VAE-approx", model_name)
  35. if not os.path.exists(model_path):
  36. model_path = os.path.join(paths.script_path, "models", "VAE-approx", model_name)
  37. if not os.path.exists(model_path):
  38. model_path = os.path.join(paths.models_path, "VAE-approx", model_name)
  39. download_model(model_path, 'https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/download/v1.0.0-pre/' + model_name)
  40. loaded_model = VAEApprox()
  41. loaded_model.load_state_dict(torch.load(model_path, map_location='cpu' if devices.device.type != 'cuda' else None))
  42. loaded_model.eval()
  43. loaded_model.to(devices.device, devices.dtype)
  44. sd_vae_approx_models[model_name] = loaded_model
  45. return loaded_model
  46. def cheap_approximation(sample):
  47. # https://discuss.huggingface.co/t/decoding-latents-to-rgb-without-upscaling/23204/2
  48. if shared.sd_model.is_sdxl:
  49. coeffs = [
  50. [ 0.3448, 0.4168, 0.4395],
  51. [-0.1953, -0.0290, 0.0250],
  52. [ 0.1074, 0.0886, -0.0163],
  53. [-0.3730, -0.2499, -0.2088],
  54. ]
  55. else:
  56. coeffs = [
  57. [ 0.298, 0.207, 0.208],
  58. [ 0.187, 0.286, 0.173],
  59. [-0.158, 0.189, 0.264],
  60. [-0.184, -0.271, -0.473],
  61. ]
  62. coefs = torch.tensor(coeffs).to(sample.device)
  63. x_sample = torch.einsum("lxy,lr -> rxy", sample, coefs)
  64. return x_sample