flying101 commited on
Commit
1b34e16
·
verified ·
1 Parent(s): bc01292

Upload 31 files

Browse files

Implemented and trained a stable diffusion model from scratch (CLIP + VAE + UNet + Cross-Attention), optimizing schedulers (DDPM, DDIM, Euler Ancestral, DPM-Solver++) and attention mechanisms (Flash Attention, xFormers) to reduce generation time by 22% and improve image clarity using MPS on RunPod GPUs.

Files changed (32) hide show
  1. .gitattributes +14 -0
  2. pytorch-stablediffusion/.DS_Store +0 -0
  3. pytorch-stablediffusion/data/.DS_Store +0 -0
  4. pytorch-stablediffusion/data/merges.txt +0 -0
  5. pytorch-stablediffusion/data/v1-5-pruned-emaonly.ckpt +3 -0
  6. pytorch-stablediffusion/data/vocab.json +0 -0
  7. pytorch-stablediffusion/images/ddim_images/1_82.png +3 -0
  8. pytorch-stablediffusion/images/ddim_images/3_112.png +3 -0
  9. pytorch-stablediffusion/images/ddim_images/4_80.png +3 -0
  10. pytorch-stablediffusion/images/ddpm_images/1_1022.png +3 -0
  11. pytorch-stablediffusion/images/ddpm_images/3_114.png +3 -0
  12. pytorch-stablediffusion/images/ddpm_images/4_333.png +3 -0
  13. pytorch-stablediffusion/images/input_image +0 -0
  14. pytorch-stablediffusion/sd/.DS_Store +0 -0
  15. pytorch-stablediffusion/sd/100_97.png +3 -0
  16. pytorch-stablediffusion/sd/101_225.png +3 -0
  17. pytorch-stablediffusion/sd/1_114.png +3 -0
  18. pytorch-stablediffusion/sd/201_328.png +3 -0
  19. pytorch-stablediffusion/sd/201_948.png +3 -0
  20. pytorch-stablediffusion/sd/3_{time_process}.png +3 -0
  21. pytorch-stablediffusion/sd/4_114.png +3 -0
  22. pytorch-stablediffusion/sd/8_{time_process}.png +3 -0
  23. pytorch-stablediffusion/sd/attention.py +113 -0
  24. pytorch-stablediffusion/sd/clip.py +88 -0
  25. pytorch-stablediffusion/sd/decoder.py +177 -0
  26. pytorch-stablediffusion/sd/demo.ipynb +0 -0
  27. pytorch-stablediffusion/sd/diffusion.py +349 -0
  28. pytorch-stablediffusion/sd/encoder.py +96 -0
  29. pytorch-stablediffusion/sd/model_converter.py +0 -0
  30. pytorch-stablediffusion/sd/model_loader.py +28 -0
  31. pytorch-stablediffusion/sd/pipeline.py +181 -0
  32. pytorch-stablediffusion/sd/sampler.py +198 -0
.gitattributes CHANGED
@@ -33,3 +33,17 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ pytorch-stablediffusion/images/ddim_images/1_82.png filter=lfs diff=lfs merge=lfs -text
37
+ pytorch-stablediffusion/images/ddim_images/3_112.png filter=lfs diff=lfs merge=lfs -text
38
+ pytorch-stablediffusion/images/ddim_images/4_80.png filter=lfs diff=lfs merge=lfs -text
39
+ pytorch-stablediffusion/images/ddpm_images/1_1022.png filter=lfs diff=lfs merge=lfs -text
40
+ pytorch-stablediffusion/images/ddpm_images/3_114.png filter=lfs diff=lfs merge=lfs -text
41
+ pytorch-stablediffusion/images/ddpm_images/4_333.png filter=lfs diff=lfs merge=lfs -text
42
+ pytorch-stablediffusion/sd/1_114.png filter=lfs diff=lfs merge=lfs -text
43
+ pytorch-stablediffusion/sd/100_97.png filter=lfs diff=lfs merge=lfs -text
44
+ pytorch-stablediffusion/sd/101_225.png filter=lfs diff=lfs merge=lfs -text
45
+ pytorch-stablediffusion/sd/201_328.png filter=lfs diff=lfs merge=lfs -text
46
+ pytorch-stablediffusion/sd/201_948.png filter=lfs diff=lfs merge=lfs -text
47
+ pytorch-stablediffusion/sd/3_{time_process}.png filter=lfs diff=lfs merge=lfs -text
48
+ pytorch-stablediffusion/sd/4_114.png filter=lfs diff=lfs merge=lfs -text
49
+ pytorch-stablediffusion/sd/8_{time_process}.png filter=lfs diff=lfs merge=lfs -text
pytorch-stablediffusion/.DS_Store ADDED
Binary file (6.15 kB). View file
 
pytorch-stablediffusion/data/.DS_Store ADDED
Binary file (6.15 kB). View file
 
pytorch-stablediffusion/data/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
pytorch-stablediffusion/data/v1-5-pruned-emaonly.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cc6cb27103417325ff94f52b7a5d2dde45a7515b25c255d8e396c90014281516
3
+ size 4265380512
pytorch-stablediffusion/data/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
pytorch-stablediffusion/images/ddim_images/1_82.png ADDED

Git LFS Details

  • SHA256: 3622f8b86b3a79ba29d95c5952c5d8e89910ff6b7d56d3f07ede1cf8d509aafc
  • Pointer size: 131 Bytes
  • Size of remote file: 514 kB
pytorch-stablediffusion/images/ddim_images/3_112.png ADDED

Git LFS Details

  • SHA256: 62d0393dc3a8927f0264589b5aaa5f510696aa3971dd0e12c0d119c981be3b28
  • Pointer size: 131 Bytes
  • Size of remote file: 495 kB
pytorch-stablediffusion/images/ddim_images/4_80.png ADDED

Git LFS Details

  • SHA256: caa88d7a1e42461e3c105f9425eb6f731bf7d099f8c4370a14bf45d9480d0954
  • Pointer size: 131 Bytes
  • Size of remote file: 498 kB
pytorch-stablediffusion/images/ddpm_images/1_1022.png ADDED

Git LFS Details

  • SHA256: 1e88b0675406e9b4c8ac43b93dbbd436898428e2ffb971b4f1e76062d511cb8a
  • Pointer size: 131 Bytes
  • Size of remote file: 387 kB
pytorch-stablediffusion/images/ddpm_images/3_114.png ADDED

Git LFS Details

  • SHA256: 9c6cceec7b547cedabb582c261252ffb14864f11588be76a021adcfc37151685
  • Pointer size: 131 Bytes
  • Size of remote file: 337 kB
pytorch-stablediffusion/images/ddpm_images/4_333.png ADDED

Git LFS Details

  • SHA256: 8e4915a1ee66b5e09cdea640dd94e5d57a388db0f5d254d0bb29963a625a2add
  • Pointer size: 131 Bytes
  • Size of remote file: 419 kB
pytorch-stablediffusion/images/input_image ADDED
File without changes
pytorch-stablediffusion/sd/.DS_Store ADDED
Binary file (6.15 kB). View file
 
pytorch-stablediffusion/sd/100_97.png ADDED

Git LFS Details

  • SHA256: 35732701be44896ed113c58f27f0804a8c63c06bab43ce0385c3cb4086d37445
  • Pointer size: 131 Bytes
  • Size of remote file: 535 kB
pytorch-stablediffusion/sd/101_225.png ADDED

Git LFS Details

  • SHA256: 35732701be44896ed113c58f27f0804a8c63c06bab43ce0385c3cb4086d37445
  • Pointer size: 131 Bytes
  • Size of remote file: 535 kB
pytorch-stablediffusion/sd/1_114.png ADDED

Git LFS Details

  • SHA256: 8e4915a1ee66b5e09cdea640dd94e5d57a388db0f5d254d0bb29963a625a2add
  • Pointer size: 131 Bytes
  • Size of remote file: 419 kB
pytorch-stablediffusion/sd/201_328.png ADDED

Git LFS Details

  • SHA256: 7549ac1b46d801429be29de3521e69830cf3e1bb9a6c1073643aa550472ca9ec
  • Pointer size: 131 Bytes
  • Size of remote file: 417 kB
pytorch-stablediffusion/sd/201_948.png ADDED

Git LFS Details

  • SHA256: ff74f9ec261d14c1e090786b297ca8ef4ebc6e29e8a5b278c4d97e609cfea3e2
  • Pointer size: 131 Bytes
  • Size of remote file: 486 kB
pytorch-stablediffusion/sd/3_{time_process}.png ADDED

Git LFS Details

  • SHA256: 63603789e162a41168e9e45d289765bc0fdd34805794d67f6f7788122a6e377b
  • Pointer size: 131 Bytes
  • Size of remote file: 509 kB
pytorch-stablediffusion/sd/4_114.png ADDED

Git LFS Details

  • SHA256: 2c67d595129372d5f530ad1ed3a383369bb8edcfbaa5f26ef55594491d2295b0
  • Pointer size: 131 Bytes
  • Size of remote file: 473 kB
pytorch-stablediffusion/sd/8_{time_process}.png ADDED

Git LFS Details

  • SHA256: 35732701be44896ed113c58f27f0804a8c63c06bab43ce0385c3cb4086d37445
  • Pointer size: 131 Bytes
  • Size of remote file: 535 kB
pytorch-stablediffusion/sd/attention.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+ import math
5
+
6
+ class SelfAttention(nn.Module):
7
+ def __init__(self, n_heads: int, d_embed: int, in_proj_bias=True, out_proj_bias=True):
8
+ super().__init__()
9
+
10
+ self.in_proj = nn.Linear(d_embed, 3 * d_embed, bias=in_proj_bias)
11
+ self.out_proj = nn.Linear(d_embed, d_embed, bias=out_proj_bias)
12
+ self.n_heads = n_heads
13
+ self.d_head = d_embed // n_heads #embedding divided by number of heads
14
+
15
+ def forward(self, x: torch.Tensor, causal_mask=False):
16
+ # x: (Batch_Size, Seq_Len, Dim)
17
+
18
+ input_shape = x.shape
19
+ batch_size, sequence_length, d_embed = input_shape
20
+
21
+ intermim_shape = (batch_size, sequence_length, self.n_heads, self.d_head)
22
+
23
+ # (Batch_Size, Seq_Len, Dim) -> (Batch_Size, Seq_Len, Dim * 3) -> 3 tensors of shape (Batch_Size, Seq_Len, Dim)
24
+ q, k, v = self.in_proj(x).chunk(3, dim=-1)
25
+
26
+ # (Batch_Size, Seq_len, Dim) -> (Batch_Size, Seq_Len, H, Dim / H) -> (Batch_Size, H, Seq_Len, Dim / H)
27
+ # Each head will watch the full sequence but only a part of the embedding of each pizel
28
+ q = q.view(intermim_shape).transpose(1, 2)
29
+ k = k.view(intermim_shape).transpose(1, 2)
30
+ v = v.view(intermim_shape).transpose(1, 2)
31
+
32
+ # (Batch_Size, H, Seq_Len, Seq_Len)
33
+ weight = q @ k.transpose(-1, -2)
34
+
35
+ if causal_mask:
36
+ # Mask where the upper triangle (above the principle diagonal) is made up of 1
37
+ mask = torch.ones_like(weight, dtype=torch.bool).triu(1)
38
+ weight.masked_fill_(mask, -torch.inf)
39
+
40
+ weight /= math.sqrt(self.d_head)
41
+
42
+ weight = F.softmax(weight, dim=-1)
43
+
44
+ # (Batch_Size, H, Seq_Len, Seq_Len) @ (Batch_Size, H, Seq_Len, Dim / H) -> (Batch_Size, H, Seq_Len, Dim / H)
45
+ output = weight @ v
46
+
47
+ #(Batch_Size, H, Seq_Len, Dim / H) -> (Batch_Size, Seq_Len, H, Dim / H)
48
+ output = output.transpose(1, 2)
49
+
50
+ output = output.reshape(input_shape)
51
+
52
+ output = self.out_proj(output)
53
+
54
+ # (Batch_Size, Seq_Len, Dim)
55
+ return output
56
+
57
+ class CrossAttention(nn.Module):
58
+ def __init__(self, n_heads, d_embed, d_cross, in_proj_bias=True, out_proj_bias=True):
59
+ super().__init__()
60
+ self.q_proj = nn.Linear(d_embed, d_embed, bias=in_proj_bias)
61
+ self.k_proj = nn.Linear(d_cross, d_embed, bias=in_proj_bias)
62
+ self.v_proj = nn.Linear(d_cross, d_embed, bias=in_proj_bias)
63
+ self.out_proj = nn.Linear(d_embed, d_embed, bias=out_proj_bias)
64
+ self.n_heads = n_heads
65
+ self.d_head = d_embed // n_heads
66
+
67
+ def forward(self, x, y):
68
+ # x (latent): # (Batch_Size, Seq_Len_Q, Dim_Q)
69
+ # y (context): # (Batch_Size, Seq_Len_KV, Dim_KV) = (Batch_Size, 77, 768)
70
+
71
+ input_shape = x.shape
72
+ batch_size, sequence_length, d_embed = input_shape
73
+ # Divide each embedding of Q into multiple heads such that d_heads * n_heads = Dim_Q
74
+ interim_shape = (batch_size, -1, self.n_heads, self.d_head)
75
+
76
+ # (Batch_Size, Seq_Len_Q, Dim_Q) -> (Batch_Size, Seq_Len_Q, Dim_Q)
77
+ q = self.q_proj(x)
78
+ # (Batch_Size, Seq_Len_KV, Dim_KV) -> (Batch_Size, Seq_Len_KV, Dim_Q)
79
+ k = self.k_proj(y)
80
+ # (Batch_Size, Seq_Len_KV, Dim_KV) -> (Batch_Size, Seq_Len_KV, Dim_Q)
81
+ v = self.v_proj(y)
82
+
83
+ # (Batch_Size, Seq_Len_Q, Dim_Q) -> (Batch_Size, Seq_Len_Q, H, Dim_Q / H) -> (Batch_Size, H, Seq_Len_Q, Dim_Q / H)
84
+ q = q.view(interim_shape).transpose(1, 2)
85
+ # (Batch_Size, Seq_Len_KV, Dim_Q) -> (Batch_Size, Seq_Len_KV, H, Dim_Q / H) -> (Batch_Size, H, Seq_Len_KV, Dim_Q / H)
86
+ k = k.view(interim_shape).transpose(1, 2)
87
+ # (Batch_Size, Seq_Len_KV, Dim_Q) -> (Batch_Size, Seq_Len_KV, H, Dim_Q / H) -> (Batch_Size, H, Seq_Len_KV, Dim_Q / H)
88
+ v = v.view(interim_shape).transpose(1, 2)
89
+
90
+ # (Batch_Size, H, Seq_Len_Q, Dim_Q / H) @ (Batch_Size, H, Dim_Q / H, Seq_Len_KV) -> (Batch_Size, H, Seq_Len_Q, Seq_Len_KV)
91
+ weight = q @ k.transpose(-1, -2)
92
+
93
+ # (Batch_Size, H, Seq_Len_Q, Seq_Len_KV)
94
+ weight /= math.sqrt(self.d_head)
95
+
96
+ # (Batch_Size, H, Seq_Len_Q, Seq_Len_KV)
97
+ weight = F.softmax(weight, dim=-1)
98
+
99
+ # (Batch_Size, H, Seq_Len_Q, Seq_Len_KV) @ (Batch_Size, H, Seq_Len_KV, Dim_Q / H) -> (Batch_Size, H, Seq_Len_Q, Dim_Q / H)
100
+ output = weight @ v
101
+
102
+ # (Batch_Size, H, Seq_Len_Q, Dim_Q / H) -> (Batch_Size, Seq_Len_Q, H, Dim_Q / H)
103
+ output = output.transpose(1, 2).contiguous()
104
+
105
+ # (Batch_Size, Seq_Len_Q, H, Dim_Q / H) -> (Batch_Size, Seq_Len_Q, Dim_Q)
106
+ output = output.view(input_shape)
107
+
108
+ # (Batch_Size, Seq_Len_Q, Dim_Q) -> (Batch_Size, Seq_Len_Q, Dim_Q)
109
+ output = self.out_proj(output)
110
+
111
+ # (Batch_Size, Seq_Len_Q, Dim_Q)
112
+ return output
113
+
pytorch-stablediffusion/sd/clip.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+ from attention import SelfAttention
5
+
6
+ #CLIP is similar to encoded layer of the Transformer, input embedding, multi head attentino, feed forward, add and norm in between
7
+
8
+ class CLIPEmbedding(nn.Module):
9
+
10
+ def __init__(self, n_vocab: int, n_embd: int, n_tokens: int):
11
+ super().__init__()
12
+
13
+ self.token_embedding = nn.Embedding(n_vocab, n_embd)
14
+ self.position_embedding = nn.Parameter(torch.zeros(n_tokens, n_embd))
15
+
16
+ def forward(self, tokens):
17
+ # (Batch_Size, Seq_Len) -> (Batch_Size, Seq_Len, Dim)
18
+ x = self.token_embedding(tokens)
19
+
20
+ x += self.position_embedding
21
+
22
+ return x
23
+
24
+ class CLIPLayer(nn.Module):
25
+
26
+ def __init__(self, n_head: int, n_embd: int):
27
+ super().__init__()
28
+
29
+ self.layernorm_1 = nn.LayerNorm(n_embd)
30
+ self.attention = SelfAttention(n_head, n_embd)
31
+ self.layernorm_2 = nn.LayerNorm(n_embd)
32
+ self.linear_1 = nn.Linear(n_embd, 4 * n_embd)
33
+ self.linear_2 = nn.Linear(4 * n_embd, n_embd)
34
+
35
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
36
+ # (Batch_Size, Seq_Len, Dim)
37
+ residue = x
38
+
39
+ ##SELF ATTENTION
40
+
41
+ x = self.layernorm_1(x)
42
+
43
+ x = self.attention(x, causal_mask=True)
44
+
45
+ x += residue
46
+
47
+ ## FEEDFORWARD LAYER
48
+
49
+ residue = x
50
+
51
+ x = self.layernorm_2(x)
52
+
53
+ x = self.linear_1(x)
54
+
55
+ x = x * torch.sigmoid(1.702 * x) #QuickGELU activation function
56
+
57
+ x = self.linear_2(x)
58
+
59
+ x += residue
60
+
61
+ return x
62
+ class CLIP(nn.Module):
63
+
64
+ def __init__(self):
65
+ super().__init__()
66
+ self.embedding = CLIPEmbedding(49408, 768, 77) #vocab size, embedding size,max sequence length (padding)
67
+
68
+ self.layers = nn.ModuleList([
69
+ CLIPLayer(12, 768) for i in range(12) #number of heads in multi head attention, embedding size, layers
70
+ ])
71
+
72
+ self.layernorm = nn.LayerNorm(768) #number of features
73
+
74
+ def forward(self, tokens: torch.LongTensor) -> torch.FloatTensor:
75
+ tokens = tokens.type(torch.long)
76
+
77
+ # (Batch_Size, Seq_Len) -> (Batch_Size, Seq_Len, Dim)
78
+ state = self.embedding(tokens)
79
+
80
+ for layer in self.layers:
81
+ state = layer(state)
82
+
83
+ # (Batch_Size, Seq_Len, Dim)
84
+ output = self.layernorm(state)
85
+
86
+ return output
87
+
88
+
pytorch-stablediffusion/sd/decoder.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+ from attention import SelfAttention
5
+
6
+ class VAE_AttentionBlock(nn.Module):
7
+ def __init__(self, channels):
8
+ super().__init__()
9
+ self.groupnorm = nn.GroupNorm(32, channels)
10
+ self.attention = SelfAttention(1, channels)
11
+
12
+ def forward(self, x):
13
+ # x: (Batch_Size, Features, Height, Width)
14
+
15
+ residue = x
16
+
17
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height, Width)
18
+ x = self.groupnorm(x)
19
+
20
+ n, c, h, w = x.shape
21
+
22
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height * Width)
23
+ x = x.view((n, c, h * w))
24
+
25
+ # (Batch_Size, Features, Height * Width) -> (Batch_Size, Height * Width, Features). Each pixel becomes a feature of size "Features", the sequence length is "Height * Width".
26
+ x = x.transpose(-1, -2)
27
+
28
+ # Perform self-attention WITHOUT mask
29
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
30
+ x = self.attention(x)
31
+
32
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Features, Height * Width)
33
+ x = x.transpose(-1, -2)
34
+
35
+ # (Batch_Size, Features, Height * Width) -> (Batch_Size, Features, Height, Width)
36
+ x = x.view((n, c, h, w))
37
+
38
+ # (Batch_Size, Features, Height, Width) + (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height, Width)
39
+ x += residue
40
+
41
+ # (Batch_Size, Features, Height, Width)
42
+ return x
43
+
44
+ class VAE_ResidualBlock(nn.Module):
45
+ def __init__(self, in_channels, out_channels):
46
+ super().__init__()
47
+ self.groupnorm_1 = nn.GroupNorm(32, in_channels)
48
+ self.conv_1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
49
+
50
+ self.groupnorm_2 = nn.GroupNorm(32, out_channels)
51
+ self.conv_2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)
52
+
53
+ if in_channels == out_channels:
54
+ self.residual_layer = nn.Identity()
55
+ else:
56
+ self.residual_layer = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)
57
+
58
+ def forward(self, x):
59
+ # x: (Batch_Size, In_Channels, Height, Width)
60
+
61
+ residue = x
62
+
63
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, In_Channels, Height, Width)
64
+ x = self.groupnorm_1(x)
65
+
66
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, In_Channels, Height, Width)
67
+ x = F.silu(x)
68
+
69
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
70
+ x = self.conv_1(x)
71
+
72
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
73
+ x = self.groupnorm_2(x)
74
+
75
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
76
+ x = F.silu(x)
77
+
78
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
79
+ x = self.conv_2(x)
80
+
81
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
82
+ return x + self.residual_layer(residue)
83
+
84
+ class VAE_Decoder(nn.Sequential):
85
+ def __init__(self):
86
+ super().__init__(
87
+ # (Batch_Size, 4, Height / 8, Width / 8) -> (Batch_Size, 4, Height / 8, Width / 8)
88
+ nn.Conv2d(4, 4, kernel_size=1, padding=0),
89
+
90
+ # (Batch_Size, 4, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
91
+ nn.Conv2d(4, 512, kernel_size=3, padding=1),
92
+
93
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
94
+ VAE_ResidualBlock(512, 512),
95
+
96
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
97
+ VAE_AttentionBlock(512),
98
+
99
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
100
+ VAE_ResidualBlock(512, 512),
101
+
102
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
103
+ VAE_ResidualBlock(512, 512),
104
+
105
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
106
+ VAE_ResidualBlock(512, 512),
107
+
108
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 8, Width / 8)
109
+ VAE_ResidualBlock(512, 512),
110
+
111
+ # Repeats the rows and columns of the data by scale_factor (like when you resize an image by doubling its size).
112
+ # (Batch_Size, 512, Height / 8, Width / 8) -> (Batch_Size, 512, Height / 4, Width / 4)
113
+ nn.Upsample(scale_factor=2),
114
+
115
+ # (Batch_Size, 512, Height / 4, Width / 4) -> (Batch_Size, 512, Height / 4, Width / 4)
116
+ nn.Conv2d(512, 512, kernel_size=3, padding=1),
117
+
118
+ # (Batch_Size, 512, Height / 4, Width / 4) -> (Batch_Size, 512, Height / 4, Width / 4)
119
+ VAE_ResidualBlock(512, 512),
120
+
121
+ # (Batch_Size, 512, Height / 4, Width / 4) -> (Batch_Size, 512, Height / 4, Width / 4)
122
+ VAE_ResidualBlock(512, 512),
123
+
124
+ # (Batch_Size, 512, Height / 4, Width / 4) -> (Batch_Size, 512, Height / 4, Width / 4)
125
+ VAE_ResidualBlock(512, 512),
126
+
127
+ # (Batch_Size, 512, Height / 4, Width / 4) -> (Batch_Size, 512, Height / 2, Width / 2)
128
+ nn.Upsample(scale_factor=2),
129
+
130
+ # (Batch_Size, 512, Height / 2, Width / 2) -> (Batch_Size, 512, Height / 2, Width / 2)
131
+ nn.Conv2d(512, 512, kernel_size=3, padding=1),
132
+
133
+ # (Batch_Size, 512, Height / 2, Width / 2) -> (Batch_Size, 256, Height / 2, Width / 2)
134
+ VAE_ResidualBlock(512, 256),
135
+
136
+ # (Batch_Size, 256, Height / 2, Width / 2) -> (Batch_Size, 256, Height / 2, Width / 2)
137
+ VAE_ResidualBlock(256, 256),
138
+
139
+ # (Batch_Size, 256, Height / 2, Width / 2) -> (Batch_Size, 256, Height / 2, Width / 2)
140
+ VAE_ResidualBlock(256, 256),
141
+
142
+ # (Batch_Size, 256, Height / 2, Width / 2) -> (Batch_Size, 256, Height, Width)
143
+ nn.Upsample(scale_factor=2),
144
+
145
+ # (Batch_Size, 256, Height, Width) -> (Batch_Size, 256, Height, Width)
146
+ nn.Conv2d(256, 256, kernel_size=3, padding=1),
147
+
148
+ # (Batch_Size, 256, Height, Width) -> (Batch_Size, 128, Height, Width)
149
+ VAE_ResidualBlock(256, 128),
150
+
151
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
152
+ VAE_ResidualBlock(128, 128),
153
+
154
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
155
+ VAE_ResidualBlock(128, 128),
156
+
157
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
158
+ nn.GroupNorm(32, 128),
159
+
160
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
161
+ nn.SiLU(),
162
+
163
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 3, Height, Width)
164
+ nn.Conv2d(128, 3, kernel_size=3, padding=1),
165
+ )
166
+
167
+ def forward(self, x):
168
+ # x: (Batch_Size, 4, Height / 8, Width / 8)
169
+
170
+ # Remove the scaling added by the Encoder.
171
+ x /= 0.18215
172
+
173
+ for module in self:
174
+ x = module(x)
175
+
176
+ # (Batch_Size, 3, Height, Width)
177
+ return x
pytorch-stablediffusion/sd/demo.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
pytorch-stablediffusion/sd/diffusion.py ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+ from attention import SelfAttention, CrossAttention
5
+
6
+ class TimeEmbedding(nn.Module):
7
+ def __init__(self, n_embd):
8
+ super().__init__()
9
+ self.linear_1 = nn.Linear(n_embd, 4 * n_embd)
10
+ self.linear_2 = nn.Linear(4 * n_embd, 4 * n_embd)
11
+
12
+ def forward(self, x):
13
+ # x: (1, 320)
14
+
15
+ # (1, 320) -> (1, 1280)
16
+ x = self.linear_1(x)
17
+
18
+ # (1, 1280) -> (1, 1280)
19
+ x = F.silu(x)
20
+
21
+ # (1, 1280) -> (1, 1280)
22
+ x = self.linear_2(x)
23
+
24
+ return x
25
+
26
+ class UNET_ResidualBlock(nn.Module):
27
+ def __init__(self, in_channels, out_channels, n_time=1280):
28
+ super().__init__()
29
+ self.groupnorm_feature = nn.GroupNorm(32, in_channels)
30
+ self.conv_feature = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
31
+ self.linear_time = nn.Linear(n_time, out_channels)
32
+
33
+ self.groupnorm_merged = nn.GroupNorm(32, out_channels)
34
+ self.conv_merged = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)
35
+
36
+ if in_channels == out_channels:
37
+ self.residual_layer = nn.Identity()
38
+ else:
39
+ self.residual_layer = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)
40
+
41
+ def forward(self, feature, time):
42
+ # feature: (Batch_Size, In_Channels, Height, Width)
43
+ # time: (1, 1280)
44
+
45
+ residue = feature
46
+
47
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, In_Channels, Height, Width)
48
+ feature = self.groupnorm_feature(feature)
49
+
50
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, In_Channels, Height, Width)
51
+ feature = F.silu(feature)
52
+
53
+ # (Batch_Size, In_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
54
+ feature = self.conv_feature(feature)
55
+
56
+ # (1, 1280) -> (1, 1280)
57
+ time = F.silu(time)
58
+
59
+ # (1, 1280) -> (1, Out_Channels)
60
+ time = self.linear_time(time)
61
+
62
+ # Add width and height dimension to time.
63
+ # (Batch_Size, Out_Channels, Height, Width) + (1, Out_Channels, 1, 1) -> (Batch_Size, Out_Channels, Height, Width)
64
+ merged = feature + time.unsqueeze(-1).unsqueeze(-1)
65
+
66
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
67
+ merged = self.groupnorm_merged(merged)
68
+
69
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
70
+ merged = F.silu(merged)
71
+
72
+ # (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
73
+ merged = self.conv_merged(merged)
74
+
75
+ # (Batch_Size, Out_Channels, Height, Width) + (Batch_Size, Out_Channels, Height, Width) -> (Batch_Size, Out_Channels, Height, Width)
76
+ return merged + self.residual_layer(residue)
77
+
78
+ class UNET_AttentionBlock(nn.Module):
79
+ def __init__(self, n_head: int, n_embd: int, d_context=768):
80
+ super().__init__()
81
+ channels = n_head * n_embd
82
+
83
+ self.groupnorm = nn.GroupNorm(32, channels, eps=1e-6)
84
+ self.conv_input = nn.Conv2d(channels, channels, kernel_size=1, padding=0)
85
+
86
+ self.layernorm_1 = nn.LayerNorm(channels)
87
+ self.attention_1 = SelfAttention(n_head, channels, in_proj_bias=False)
88
+ self.layernorm_2 = nn.LayerNorm(channels)
89
+ self.attention_2 = CrossAttention(n_head, channels, d_context, in_proj_bias=False)
90
+ self.layernorm_3 = nn.LayerNorm(channels)
91
+ self.linear_geglu_1 = nn.Linear(channels, 4 * channels * 2)
92
+ self.linear_geglu_2 = nn.Linear(4 * channels, channels)
93
+
94
+ self.conv_output = nn.Conv2d(channels, channels, kernel_size=1, padding=0)
95
+
96
+ def forward(self, x, context):
97
+ # x: (Batch_Size, Features, Height, Width)
98
+ # context: (Batch_Size, Seq_Len, Dim)
99
+
100
+ residue_long = x
101
+
102
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height, Width)
103
+ x = self.groupnorm(x)
104
+
105
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height, Width)
106
+ x = self.conv_input(x)
107
+
108
+ n, c, h, w = x.shape
109
+
110
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height * Width)
111
+ x = x.view((n, c, h * w))
112
+
113
+ # (Batch_Size, Features, Height * Width) -> (Batch_Size, Height * Width, Features)
114
+ x = x.transpose(-1, -2)
115
+
116
+ # Normalization + Self-Attention with skip connection
117
+
118
+ # (Batch_Size, Height * Width, Features)
119
+ residue_short = x
120
+
121
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
122
+ x = self.layernorm_1(x)
123
+
124
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
125
+ x = self.attention_1(x)
126
+
127
+ # (Batch_Size, Height * Width, Features) + (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
128
+ x += residue_short
129
+
130
+ # (Batch_Size, Height * Width, Features)
131
+ residue_short = x
132
+
133
+ # Normalization + Cross-Attention with skip connection
134
+
135
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
136
+ x = self.layernorm_2(x)
137
+
138
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
139
+ x = self.attention_2(x, context)
140
+
141
+ # (Batch_Size, Height * Width, Features) + (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
142
+ x += residue_short
143
+
144
+ # (Batch_Size, Height * Width, Features)
145
+ residue_short = x
146
+
147
+ # Normalization + FFN with GeGLU and skip connection
148
+
149
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
150
+ x = self.layernorm_3(x)
151
+
152
+ # GeGLU as implemented in the original code: https://github.com/CompVis/stable-diffusion/blob/21f890f9da3cfbeaba8e2ac3c425ee9e998d5229/ldm/modules/attention.py#L37C10-L37C10
153
+ # (Batch_Size, Height * Width, Features) -> two tensors of shape (Batch_Size, Height * Width, Features * 4)
154
+ x, gate = self.linear_geglu_1(x).chunk(2, dim=-1)
155
+
156
+ # Element-wise product: (Batch_Size, Height * Width, Features * 4) * (Batch_Size, Height * Width, Features * 4) -> (Batch_Size, Height * Width, Features * 4)
157
+ x = x * F.gelu(gate)
158
+
159
+ # (Batch_Size, Height * Width, Features * 4) -> (Batch_Size, Height * Width, Features)
160
+ x = self.linear_geglu_2(x)
161
+
162
+ # (Batch_Size, Height * Width, Features) + (Batch_Size, Height * Width, Features) -> (Batch_Size, Height * Width, Features)
163
+ x += residue_short
164
+
165
+ # (Batch_Size, Height * Width, Features) -> (Batch_Size, Features, Height * Width)
166
+ x = x.transpose(-1, -2)
167
+
168
+ # (Batch_Size, Features, Height * Width) -> (Batch_Size, Features, Height, Width)
169
+ x = x.view((n, c, h, w))
170
+
171
+ # Final skip connection between initial input and output of the block
172
+ # (Batch_Size, Features, Height, Width) + (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height, Width)
173
+ return self.conv_output(x) + residue_long
174
+
175
+ class Upsample(nn.Module):
176
+ def __init__(self, channels):
177
+ super().__init__()
178
+ self.conv = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
179
+
180
+ def forward(self, x):
181
+ # (Batch_Size, Features, Height, Width) -> (Batch_Size, Features, Height * 2, Width * 2)
182
+ x = F.interpolate(x, scale_factor=2, mode='nearest')
183
+ return self.conv(x)
184
+
185
+ class SwitchSequential(nn.Sequential):
186
+ def forward(self, x, context, time):
187
+ for layer in self:
188
+ if isinstance(layer, UNET_AttentionBlock):
189
+ x = layer(x, context)
190
+ elif isinstance(layer, UNET_ResidualBlock):
191
+ x = layer(x, time)
192
+ else:
193
+ x = layer(x)
194
+ return x
195
+
196
+ class UNET(nn.Module):
197
+ def __init__(self):
198
+ super().__init__()
199
+ self.encoders = nn.ModuleList([
200
+ # (Batch_Size, 4, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
201
+ SwitchSequential(nn.Conv2d(4, 320, kernel_size=3, padding=1)),
202
+
203
+ # (Batch_Size, 320, Height / 8, Width / 8) -> # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
204
+ SwitchSequential(UNET_ResidualBlock(320, 320), UNET_AttentionBlock(8, 40)),
205
+
206
+ # (Batch_Size, 320, Height / 8, Width / 8) -> # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
207
+ SwitchSequential(UNET_ResidualBlock(320, 320), UNET_AttentionBlock(8, 40)),
208
+
209
+ # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 16, Width / 16)
210
+ SwitchSequential(nn.Conv2d(320, 320, kernel_size=3, stride=2, padding=1)),
211
+
212
+ # (Batch_Size, 320, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16)
213
+ SwitchSequential(UNET_ResidualBlock(320, 640), UNET_AttentionBlock(8, 80)),
214
+
215
+ # (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16)
216
+ SwitchSequential(UNET_ResidualBlock(640, 640), UNET_AttentionBlock(8, 80)),
217
+
218
+ # (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 32, Width / 32)
219
+ SwitchSequential(nn.Conv2d(640, 640, kernel_size=3, stride=2, padding=1)),
220
+
221
+ # (Batch_Size, 640, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32)
222
+ SwitchSequential(UNET_ResidualBlock(640, 1280), UNET_AttentionBlock(8, 160)),
223
+
224
+ # (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32)
225
+ SwitchSequential(UNET_ResidualBlock(1280, 1280), UNET_AttentionBlock(8, 160)),
226
+
227
+ # (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 64, Width / 64)
228
+ SwitchSequential(nn.Conv2d(1280, 1280, kernel_size=3, stride=2, padding=1)),
229
+
230
+ # (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
231
+ SwitchSequential(UNET_ResidualBlock(1280, 1280)),
232
+
233
+ # (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
234
+ SwitchSequential(UNET_ResidualBlock(1280, 1280)),
235
+ ])
236
+
237
+ self.bottleneck = SwitchSequential(
238
+ # (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
239
+ UNET_ResidualBlock(1280, 1280),
240
+
241
+ # (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
242
+ UNET_AttentionBlock(8, 160),
243
+
244
+ # (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
245
+ UNET_ResidualBlock(1280, 1280),
246
+ )
247
+
248
+ self.decoders = nn.ModuleList([
249
+ # (Batch_Size, 2560, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
250
+ SwitchSequential(UNET_ResidualBlock(2560, 1280)),
251
+
252
+ # (Batch_Size, 2560, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64)
253
+ SwitchSequential(UNET_ResidualBlock(2560, 1280)),
254
+
255
+ # (Batch_Size, 2560, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 64, Width / 64) -> (Batch_Size, 1280, Height / 32, Width / 32)
256
+ SwitchSequential(UNET_ResidualBlock(2560, 1280), Upsample(1280)),
257
+
258
+ # (Batch_Size, 2560, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32)
259
+ SwitchSequential(UNET_ResidualBlock(2560, 1280), UNET_AttentionBlock(8, 160)),
260
+
261
+ # (Batch_Size, 2560, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32)
262
+ SwitchSequential(UNET_ResidualBlock(2560, 1280), UNET_AttentionBlock(8, 160)),
263
+
264
+ # (Batch_Size, 1920, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 32, Width / 32) -> (Batch_Size, 1280, Height / 16, Width / 16)
265
+ SwitchSequential(UNET_ResidualBlock(1920, 1280), UNET_AttentionBlock(8, 160), Upsample(1280)),
266
+
267
+ # (Batch_Size, 1920, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16)
268
+ SwitchSequential(UNET_ResidualBlock(1920, 640), UNET_AttentionBlock(8, 80)),
269
+
270
+ # (Batch_Size, 1280, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16)
271
+ SwitchSequential(UNET_ResidualBlock(1280, 640), UNET_AttentionBlock(8, 80)),
272
+
273
+ # (Batch_Size, 960, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 16, Width / 16) -> (Batch_Size, 640, Height / 8, Width / 8)
274
+ SwitchSequential(UNET_ResidualBlock(960, 640), UNET_AttentionBlock(8, 80), Upsample(640)),
275
+
276
+ # (Batch_Size, 960, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
277
+ SwitchSequential(UNET_ResidualBlock(960, 320), UNET_AttentionBlock(8, 40)),
278
+
279
+ # (Batch_Size, 640, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
280
+ SwitchSequential(UNET_ResidualBlock(640, 320), UNET_AttentionBlock(8, 40)),
281
+
282
+ # (Batch_Size, 640, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
283
+ SwitchSequential(UNET_ResidualBlock(640, 320), UNET_AttentionBlock(8, 40)),
284
+ ])
285
+
286
+ def forward(self, x, context, time):
287
+ # x: (Batch_Size, 4, Height / 8, Width / 8)
288
+ # context: (Batch_Size, Seq_Len, Dim)
289
+ # time: (1, 1280)
290
+
291
+ skip_connections = []
292
+ for layers in self.encoders:
293
+ x = layers(x, context, time)
294
+ skip_connections.append(x)
295
+
296
+ x = self.bottleneck(x, context, time)
297
+
298
+ for layers in self.decoders:
299
+ # Since we always concat with the skip connection of the encoder, the number of features increases before being sent to the decoder's layer
300
+ x = torch.cat((x, skip_connections.pop()), dim=1)
301
+ x = layers(x, context, time)
302
+
303
+ return x
304
+
305
+
306
+ class UNET_OutputLayer(nn.Module):
307
+ def __init__(self, in_channels, out_channels):
308
+ super().__init__()
309
+ self.groupnorm = nn.GroupNorm(32, in_channels)
310
+ self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
311
+
312
+ def forward(self, x):
313
+ # x: (Batch_Size, 320, Height / 8, Width / 8)
314
+
315
+ # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
316
+ x = self.groupnorm(x)
317
+
318
+ # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 320, Height / 8, Width / 8)
319
+ x = F.silu(x)
320
+
321
+ # (Batch_Size, 320, Height / 8, Width / 8) -> (Batch_Size, 4, Height / 8, Width / 8)
322
+ x = self.conv(x)
323
+
324
+ # (Batch_Size, 4, Height / 8, Width / 8)
325
+ return x
326
+
327
+ class Diffusion(nn.Module):
328
+ def __init__(self):
329
+ super().__init__()
330
+ self.time_embedding = TimeEmbedding(320)
331
+ self.unet = UNET()
332
+ self.final = UNET_OutputLayer(320, 4)
333
+
334
+ def forward(self, latent, context, time):
335
+ # latent: (Batch_Size, 4, Height / 8, Width / 8)
336
+ # context: (Batch_Size, Seq_Len, Dim)
337
+ # time: (1, 320)
338
+
339
+ # (1, 320) -> (1, 1280)
340
+ time = self.time_embedding(time)
341
+
342
+ # (Batch, 4, Height / 8, Width / 8) -> (Batch, 320, Height / 8, Width / 8)
343
+ output = self.unet(latent, context, time)
344
+
345
+ # (Batch, 320, Height / 8, Width / 8) -> (Batch, 4, Height / 8, Width / 8)
346
+ output = self.final(output)
347
+
348
+ # (Batch, 4, Height / 8, Width / 8)
349
+ return output
pytorch-stablediffusion/sd/encoder.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Variational Encoder
2
+ import torch
3
+ from torch import nn
4
+ from torch.nn import functional as F
5
+ from decoder import VAE_AttentionBlock, VAE_ResidualBlock
6
+
7
+ class VAE_Encoder(nn.Sequential): #encoder is a sequence of submodels
8
+ def __init__(self):
9
+ super().__init__( #each model reduces the dimension of data and increases the number of features
10
+ #convert from 3 to 128 channels
11
+ #(Batch_Size, Channel, Height, Width) -> (Batch_Size, 128, Height, Width)
12
+ nn.Conv2d(3, 128, kernel_size=3, padding=1),
13
+
14
+ #Residual block, combination of convolutions and normalization
15
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
16
+ VAE_ResidualBlock(128, 128),
17
+
18
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height, Width)
19
+ VAE_ResidualBlock(128, 128),
20
+
21
+ # (Batch_Size, 128, Height, Width) -> (Batch_Size, 128, Height/2, Width/2)
22
+ nn.Conv2d(128, 128, kernel_size=3, stride=2, padding=0),
23
+
24
+ # (Batch_Size, 128, Height/2, Width/2) -> (Batch_Size, 256, Height/2, Width/2)
25
+ VAE_ResidualBlock(128, 256),
26
+
27
+ # (Batch_Size, 256, Height/2, Width/2) -> (Batch_Size, 256, Height/2, Width/2)
28
+ VAE_ResidualBlock(256, 256),
29
+
30
+ # (Batch_Size, 256, Height/2, Width/2) -> (Batch_Size, 256, Height/4, Width/4)
31
+ nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=0),
32
+
33
+ # (Batch_Size, 256, Height/4, Width/4) -> (Batch_Size, 512, Height/4, Width/4)
34
+ VAE_ResidualBlock(256, 512),
35
+
36
+ # (Batch_Size, 512, Height/4, Width/4) -> (Batch_Size, 512, Height/4, Width/4)
37
+ VAE_ResidualBlock(512, 512),
38
+
39
+ # (Batch_Size, 512, Height/4, Width/4) -> (Batch_Size, 512, Height/8, Width/8)
40
+ nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=0),
41
+
42
+ # (Batch_Size, 512, Height/4, Width/4) -> (Batch_Size, 512, Height/8, Width/8)
43
+ VAE_ResidualBlock(512, 512),
44
+
45
+ VAE_ResidualBlock(512, 512),
46
+
47
+ # (Batch_Size, 512, Height/8, Width/8) -> (Batch_Size, 512, Height/8, Width/8)
48
+ VAE_ResidualBlock(512, 512),
49
+
50
+ #self attention over each pixel, relate pixels to each other
51
+ # (Batch_Size, 512, Height/8, Width/8) -> (Batch_Size, 512, Height/8, Width/8)
52
+ VAE_AttentionBlock(512),
53
+
54
+ # (Batch_Size, 512, Height/8, Width/8) -> (Batch_Size, 512, Height/8, Width/8)
55
+ VAE_ResidualBlock(512, 512),
56
+
57
+ #Group normalization (Batch_Size, 512, Height/8, Width/8) -> (Batch_Size, 512, Height/8, Width/8)
58
+ nn.GroupNorm(32, 512), #32 groups, 512 channels
59
+
60
+ nn.SiLU(), #activation function, sigmoid linear unit, similar to ReLU
61
+
62
+ # (Batch_Size, 512, Height/8, Width/8) -> (Batch_Size, 512, Height/8, Width/8)
63
+ nn.Conv2d(512, 8, kernel_size=3, padding=1),
64
+
65
+ # (Batch_Size, 8, Height/8, Width/8) -> (Batch_Size, 8, Height/8, Width/8)
66
+ nn.Conv2d(8, 8, kernel_size=1, padding=0)
67
+ )
68
+ def forward(self, x: torch.Tensor, noise: torch.Tensor) -> torch.Tensor:
69
+ # x: (Batch_Size, Channel, Height, Width)
70
+ # noise: (Batch_Size, Out_Channels, Height / 8, Width / 8)
71
+
72
+ #VAE learns the mu and the sigma which is the mean and variance of the distribution
73
+ for module in self:
74
+ if getattr(module, 'stride', None) == (2, 2): #apply to convolutions that only have stride 2
75
+ # (Padding_Left, Padding_Right, Padding-Top, Padding_Bottom)
76
+ x = F.pad(x, (0, 1, 0, 1))
77
+ x = module(x)
78
+ # (Batch_Size, 8, Height, Height / 8, Width / 8) -> two tensors of shape (Batch_Size, 4, Height / 8, Width / 8)
79
+ mean, log_variance = torch.chunk(x, 2, dim=1)
80
+
81
+ log_variance = torch.clamp(log_variance, -30, 20)
82
+
83
+ variance = log_variance.exp()
84
+
85
+ stdev = variance.sqrt()
86
+
87
+ # Z -> N(0,1) -> N(mean, variance)?
88
+ #X = mean + stdev*Z
89
+ x = mean + stdev * noise
90
+
91
+ #Scale the output by a constant
92
+ x *= 0.18215
93
+
94
+ return x
95
+
96
+
pytorch-stablediffusion/sd/model_converter.py ADDED
The diff for this file is too large to render. See raw diff
 
pytorch-stablediffusion/sd/model_loader.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from clip import CLIP
2
+ from encoder import VAE_Encoder
3
+ from decoder import VAE_Decoder
4
+ from diffusion import Diffusion
5
+
6
+ import model_converter
7
+ #the ckpt file is a dictionary that contains many keys where each key corresponds to one matrix of the model
8
+ def preload_models_from_standard_weights(ckpt_path, device):
9
+ state_dict = model_converter.load_from_standard_weights(ckpt_path, device)
10
+
11
+ encoder = VAE_Encoder().to(device)
12
+ encoder.load_state_dict(state_dict['encoder'], strict=True)
13
+
14
+ decoder = VAE_Decoder().to(device)
15
+ decoder.load_state_dict(state_dict['decoder'], strict=True)
16
+
17
+ diffusion = Diffusion().to(device)
18
+ diffusion.load_state_dict(state_dict['diffusion'], strict=True)
19
+
20
+ clip = CLIP().to(device)
21
+ clip.load_state_dict(state_dict['clip'], strict=True)
22
+
23
+ return {
24
+ 'clip': clip,
25
+ 'encoder': encoder,
26
+ 'decoder': decoder,
27
+ 'diffusion': diffusion,
28
+ }
pytorch-stablediffusion/sd/pipeline.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ from tqdm import tqdm
4
+ from sampler import Sampler
5
+
6
+ WIDTH = 512 #stable diffusion only takes in this dimension
7
+ HEIGHT = 512
8
+ LATENTS_WIDTH = WIDTH // 8
9
+ LATENTS_HEIGHT = HEIGHT // 8
10
+
11
+ #strength is how much attention we want to put into the starting image
12
+ def generate(prompt: str,
13
+ uncond_prompt: str, # Negative prompt or empty string
14
+ input_image=None,
15
+ strength=0.8,
16
+ do_cfg=True,
17
+ cfg_scale=7.5,
18
+ sampler_name="ddpm",
19
+ n_inference_steps=50,
20
+ models={},
21
+ seed=None,
22
+ device=None,
23
+ idle_device=None,
24
+ tokenizer=None,
25
+ eta = 0.0):
26
+ with torch.no_grad():
27
+ if not (0 < strength <= 1):
28
+ raise ValueError("strength must be between 0 and 1")
29
+ if idle_device:
30
+ to_idle = lambda x: x.to(idle_device)
31
+ else:
32
+ to_idle = lambda x: x
33
+ generator = torch.Generator(device=device)
34
+ if seed is None:
35
+ generator.seed()
36
+ else:
37
+ generator.manual_seed(seed)
38
+
39
+ clip = models["clip"]
40
+ clip.to(device)
41
+
42
+ if do_cfg:
43
+ # Convert the prompt into tokens using tokenizer
44
+ cond_tokens = tokenizer.batch_encode_plus(
45
+ [prompt], padding="max_length", max_length=77
46
+ ).input_ids
47
+ # (Batch_Size, Seq_Len)
48
+ cond_tokens = torch.tensor(cond_tokens, dtype=torch.long, device=device)
49
+ # (Batch_Size, Seq_Len) -> (Batch_Size, Seq_Len, Dim)
50
+ cond_context = clip(cond_tokens)
51
+
52
+ #with no conditioins now
53
+ uncond_tokens = tokenizer.batch_encode_plus(
54
+ [uncond_prompt], padding="max_length", max_length=77
55
+ ).input_ids
56
+ uncond_tokens = torch.tensor(uncond_tokens, dtype=torch.long, device=device)
57
+ uncond_context = clip(uncond_tokens)
58
+
59
+ # (Batch_2, Seq_Len, Dim) = (2, 77, 768)
60
+ context = torch.cat([cond_context, uncond_context])
61
+ else:
62
+ # Convert it into a list of tokens
63
+ tokens = tokenizer.batch_encode_plus(
64
+ [prompt], padding="max_length", max_length=77
65
+ ).input_ids
66
+ tokens = torch.tensor(tokens, dtype=torch.long, device=device)
67
+ # (1, 77, 768)
68
+ context = clip(tokens)
69
+ to_idle(clip) #very useful if you have a limited gpu and want to offload to cpu
70
+
71
+ if sampler_name in ["ddpm", "ddim", "euler", "dpm_solver"]:
72
+ sampler = Sampler(generator)
73
+ sampler.set_inference_timesteps(n_inference_steps)
74
+ else:
75
+ raise ValueError(f"Unknown sampler name")
76
+
77
+ latents_shape = (1, 4, LATENTS_HEIGHT, LATENTS_WIDTH)
78
+
79
+ if input_image:
80
+ encoder = models["encoder"]
81
+ encoder.to(device)
82
+
83
+ input_image_tensor = input_image.resize((WIDTH, HEIGHT))
84
+ input_image_tensor = np.array(input_image_tensor)
85
+ # (Height, Width, Channel)
86
+ input_image_tensor = torch.tensor(input_image_tensor, dtype=torch.float32, device=device)
87
+ input_image_tensor = rescale(input_image_tensor, (0,255), (-1,1))
88
+ # (Height, Width, Channel) -> (Batch_Size, Height, Width, Channel)
89
+ input_image_tensor = input_image_tensor.unsqueeze(0)
90
+ # (Batch_Size, Height, Width, Channel) -> (Batch_Size, Channel, Height, Width)
91
+ input_image_tensor = input_image_tensor.permute(0,3,1,2)
92
+
93
+ encoder_noise = torch.randn(latents_shape, generator=generator, device=device)
94
+ #run the image through the encoder of the VAE
95
+ latents = encoder(input_image_tensor, encoder_noise)
96
+
97
+ #Add noise to the latent, the more the strength, the stronger the noise, making the model more creative
98
+ sampler.set_strength(strength=strength)
99
+ latents = sampler.add_noise(latents, sampler.timesteps[0])
100
+
101
+ to_idle(encoder)
102
+ else:
103
+ # If we are doing text to image, start with random noise N(0,1)
104
+ latents = torch.randn(latents_shape, generator=generator, device=device)
105
+
106
+ #999...0
107
+ #1000 980 940 920 900 880....0, each of these time steps indicates a nosie level
108
+ #can tell the scheduler to reduce noise according to particular time steps, defined by n_inference_steps
109
+ diffusion = models["diffusion"]
110
+ diffusion.to(device)
111
+
112
+ timesteps = tqdm(sampler.timesteps)
113
+ for i, timestep in enumerate(timesteps):
114
+ # (1, 320)
115
+ time_embedding = get_time_embedding(timestep).to(device)
116
+
117
+ # (Batch_Size, 4, Latents_Height, Latents_Width)
118
+ model_input = latents
119
+
120
+ if do_cfg:
121
+ # (Batch_Size, 4, Latents_Height, Latents_Width) -> (4 * Batch_Size, 4, Latents_Height, Latents_Width)
122
+ model_input = model_input.repeat(2, 1, 1, 1)
123
+
124
+ # model_output is the predicted noise by the UNET
125
+ model_output = diffusion(model_input, context, time_embedding)
126
+
127
+ if do_cfg:
128
+ output_cond, output_uncond = model_output.chunk(2)
129
+ model_output = cfg_scale * (output_cond - output_uncond) + output_uncond
130
+
131
+ # how to remove the noise from image? using the scheduler
132
+ #Remove noise predicted by the UNET
133
+ if sampler_name == "ddpm":
134
+ latents = sampler.ddpm_step(timestep, latents, model_output)
135
+ elif sampler_name == "ddim":
136
+ latents = sampler.ddim_step(timestep, latents, model_output, eta=eta)
137
+ elif sampler_name == "euler":
138
+ latents = sampler.euler_ancestral_step(timestep, latents, model_output, eta=eta)
139
+ elif sampler_name == "dpm_solver":
140
+ latents = sampler.dpm_solver_pp_2m_step(timestep, latents, model_output)
141
+ else:
142
+ raise ValueError(f"Unknown sampler name {sampler_name}")
143
+
144
+ to_idle(diffusion)
145
+
146
+ decoder = models["decoder"]
147
+ decoder.to(device)
148
+
149
+ images = decoder(latents)
150
+ to_idle(decoder)
151
+
152
+ images = rescale(images, (-1, 1), (0, 255), clamp=True)
153
+ # (Batch_Size, Channel, Height, Width) -> (Batch_Size, Height, Width, Channel)
154
+ images = images.permute(0, 2, 3, 1)
155
+ images = images.to("cpu", torch.uint8).numpy()
156
+ return images[0]
157
+
158
+ def rescale(x, old_range, new_range, clamp=False):
159
+ old_min, old_max = old_range
160
+ new_min, new_max = new_range
161
+ x -= old_min
162
+ x *= (new_max - new_min) / (old_max - old_min)
163
+ x += new_min
164
+ if clamp:
165
+ x = x.clamp(new_min, new_max)
166
+ return x
167
+
168
+ def get_time_embedding(timestep):
169
+ freqs = torch.pow(10000, -torch.arange(start=0, end=160, dtype=torch.float32) / 160)
170
+ # (1, 160)
171
+ x = torch.tensor([timestep], dtype=torch.float32)[:, None] * freqs[None]
172
+ # (1, 320)
173
+ return torch.cat([torch.cos(x), torch.sin(x)], dim=-1)
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
pytorch-stablediffusion/sd/sampler.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+
4
+ class Sampler:
5
+
6
+ def __init__(self, generator: torch.Generator, num_training_steps=1000, beta_start: float = 0.00085, beta_end: float=0.0120):
7
+ #beta is a series of numbers that indicates the variance of the noise that we add with each of these steps
8
+ # the start and end values were a choice made by the authors
9
+ # will be using a linear scheduler, 1000 numbers between start and end
10
+
11
+ self.betas = torch.linspace(beta_start ** 0.5, beta_end ** 0.5, num_training_steps, dtype=torch.float32) ** 2
12
+
13
+ # alpha bar is the product of alpha going from 1 to T
14
+ self.alphas = 1.0 - self.betas
15
+ self.alphas_cumprod = torch.cumprod(self.alphas, 0)
16
+ self.one = torch.tensor(1.0)
17
+
18
+ self.generator = generator
19
+ self.num_training_steps = num_training_steps
20
+ self.timesteps = torch.from_numpy(np.arange(0, num_training_steps)[::-1].copy())
21
+
22
+ def set_inference_timesteps(self, num_inference_steps=50):
23
+ self.num_inference_steps = num_inference_steps
24
+ # 999, 998, 997, ... 0 = 1000 steps
25
+ # 999, 999-20, 999-40, ... 0 = 50 steps
26
+ step_ratio = self.num_training_steps // num_inference_steps
27
+ timesteps = (np.arange(0, num_inference_steps) * step_ratio).round()[::-1].copy().astype(np.int64)
28
+ self.timesteps = torch.from_numpy(timesteps)
29
+
30
+ def _get_previous_timestep(self, timestep:int) -> int:
31
+ prev_t = timestep - (self.num_training_steps // self.num_inference_steps)
32
+ return prev_t
33
+
34
+ def _get_variance(self, timestep: int) -> torch.Tensor:
35
+ prev_t = self._get_previous_timestep(timestep)
36
+
37
+ alpha_prod_t = self.alphas_cumprod[timestep]
38
+ alpha_prod_t_prev = self.alphas_cumprod[prev_t] if prev_t >= 0 else self.one
39
+ current_beta_t = 1 - alpha_prod_t / alpha_prod_t_prev
40
+
41
+ # Computed using formula (7) of the DDPM paper
42
+ variance = (1 - alpha_prod_t_prev) / (1 - alpha_prod_t) * current_beta_t
43
+ variance = torch.clamp(variance, min=1e-20)
44
+
45
+ return variance
46
+
47
+ def set_strength(self, strength=1):
48
+ start_step = self.num_inference_steps - int(self.num_inference_steps * strength)
49
+ self.timesteps = self.timesteps[start_step:]
50
+ self.start_step = start_step
51
+
52
+ def ddpm_step(self, timestep: int, latents: torch.Tensor, model_output: torch.Tensor):
53
+ t = timestep
54
+ prev_t = self._get_previous_timestep(t)
55
+
56
+ alpha_prod_t = self.alphas_cumprod[t]
57
+ alpha_prod_t_prev = self.alphas_cumprod[prev_t] if prev_t >= 0 else self.one
58
+ beta_prod_t = 1 - alpha_prod_t
59
+ beta_prod_t_prev = 1 - alpha_prod_t_prev
60
+ current_alpha_t = alpha_prod_t / alpha_prod_t_prev
61
+ current_beta_t = 1 - current_alpha_t
62
+
63
+ # Compute the predicted original sample using formula (15) of the DDPM paper
64
+ pred_original_sample = (latents - beta_prod_t ** 0.5 * model_output) / alpha_prod_t ** 0.5
65
+
66
+ # Compute the coefficient for pred_original_sample and current sample x_t
67
+ pred_original_sample_coeff = (alpha_prod_t_prev ** 0.5 * current_beta_t) / beta_prod_t
68
+ current_sample_coeff = current_alpha_t ** 0.5 * beta_prod_t_prev / beta_prod_t
69
+
70
+ # Compute the predicted previous sample mean
71
+ pred_prev_sample = pred_original_sample_coeff * pred_original_sample + current_sample_coeff * latents
72
+
73
+ variance = 0
74
+ if t > 0:
75
+ device = model_output.device
76
+ noise = torch.randn(model_output.shape, generator=self.generator, device=device, dtype=model_output.dtype)
77
+ variance = (self._get_variance(t) ** 0.5) * noise
78
+
79
+ # N(0,1) --> N(mu, sigma)
80
+ # X = mu + sigma * Z where Z ~ N(0, 1)
81
+ pred_prev_sample = pred_prev_sample + variance
82
+ return pred_prev_sample
83
+
84
+ def ddim_step(self, timestep: int, latents: torch.Tensor, model_output: torch.Tensor, eta=0.0):
85
+ t = timestep
86
+ prev_t = self._get_previous_timestep(t)
87
+
88
+ alpha_t = self.alphas_cumprod[t]
89
+ alpha_prev = self.alphas_cumprod[prev_t] if prev_t >= 0 else torch.tensor(1.0, device=latents.device, dtype=latents.dtype)
90
+
91
+ # Predicted original clean sample x_0
92
+ pred_original_sample = (latents - torch.sqrt(1 - alpha_t) * model_output) / torch.sqrt(alpha_t)
93
+
94
+ # Direction pointing to x_t
95
+ #dir_xt = torch.sqrt(1 - alpha_prev - (eta ** 2) * ((1 - alpha_prev) / (1 - alpha_t)) * (1 - alpha_t / alpha_prev)) * model_output
96
+
97
+ # Noise term
98
+ noise = torch.randn_like(latents) if eta > 0 else torch.zeros_like(latents)
99
+
100
+ sigma_t = eta * torch.sqrt((1 - alpha_prev) / (1 - alpha_t)) * torch.sqrt(1 - alpha_t / alpha_prev)
101
+
102
+ # Compute previous latent x_{t-1}
103
+ #prev_latent = torch.sqrt(alpha_prev) * pred_original_sample + dir_xt + sigma_t * noise
104
+ prev_latent = torch.sqrt(alpha_prev) * pred_original_sample + torch.sqrt(1 - alpha_prev - sigma_t ** 2) * model_output + sigma_t * noise
105
+
106
+
107
+ return prev_latent
108
+
109
+ def euler_ancestral_step(self, timestep: int, latents: torch.Tensor, model_output: torch.Tensor, eta=1.0):
110
+ t = timestep
111
+ prev_t = self._get_previous_timestep(t)
112
+
113
+ # Convert alphas to sigmas (standard deviation of noise at each timestep)
114
+ alpha_t = self.alphas_cumprod[t]
115
+ alpha_prev = self.alphas_cumprod[prev_t] if prev_t >= 0 else torch.tensor(1.0, device=latents.device, dtype=latents.dtype)
116
+
117
+ sigma_t = torch.sqrt(1 - alpha_t)
118
+ sigma_prev = torch.sqrt(1 - alpha_prev)
119
+
120
+ # Predict x_0
121
+ x0_pred = (latents - sigma_t * model_output) / torch.sqrt(alpha_t)
122
+
123
+ # Euler drift step (toward next timestep)
124
+ dt = sigma_prev - sigma_t
125
+ x_drift = latents + dt * model_output
126
+
127
+ # Stochastic noise addition
128
+ if eta > 0.0:
129
+ noise = torch.randn_like(latents)
130
+ sigma = torch.sqrt(torch.clamp(eta * (sigma_prev**2 - sigma_t**2), min=1e-20))
131
+ x_drift += sigma * noise
132
+
133
+ return x_drift
134
+
135
+ def dpm_solver_pp_2m_step(self, timestep: int, latents: torch.Tensor, model_output: torch.Tensor):
136
+ """
137
+ One DPM-Solver++(2M) step with DDIM-style signature.
138
+
139
+ Args:
140
+ timestep: Current timestep index t.
141
+ latents: Latents at current timestep x_t.
142
+ model_output: Model prediction ε_θ(x_t, t).
143
+
144
+ Returns:
145
+ x_{t-1}: Estimated latent at previous timestep.
146
+ """
147
+ t = self.timesteps[timestep]
148
+ prev_t = self.timesteps[timestep + 1] if timestep + 1 < len(self.timesteps) else 0.0 # t_{prev}
149
+
150
+ h = prev_t - t # Note: time goes backward
151
+
152
+ # Extract alpha and sigma for current and previous timesteps
153
+ alpha_t = self.alphas_cumprod[timestep] ** 0.5
154
+ alpha_prev = self.alphas_cumprod[timestep + 1] ** 0.5 if timestep + 1 < len(self.alphas_cumprod) else self.one
155
+ sigma_t = (1 - self.alphas_cumprod[timestep]) ** 0.5
156
+ sigma_prev = (1 - self.alphas_cumprod[timestep + 1]) ** 0.5 if timestep + 1 < len(self.alphas_cumprod) else self.zero
157
+
158
+ # Store previous model output if not already done
159
+ if not hasattr(self, "_prev_model_output"):
160
+ self._prev_model_output = model_output # Just initialize on first call
161
+
162
+ model_output_t = model_output
163
+ model_output_prev = self._prev_model_output
164
+
165
+ # Compute x0_t and x0_prev estimates
166
+ x0_t = (latents - sigma_t * model_output_t) / alpha_t
167
+ x0_prev = (latents - sigma_t * model_output_prev) / alpha_t
168
+
169
+ # 2nd-order multistep estimate
170
+ x0_hat = x0_t + 0.5 * h * (model_output_t - model_output_prev)
171
+
172
+ # Estimate x_{t-1}
173
+ x_prev = alpha_prev * x0_hat + sigma_prev * model_output_prev
174
+
175
+ # Update previous model output for next step
176
+ self._prev_model_output = model_output
177
+
178
+ return x_prev
179
+
180
+
181
+ def add_noise(self, original_samples: torch.FloatTensor, timesteps: torch.IntTensor) -> torch.FloatTensor:
182
+ #at what time we want to add the timestep
183
+ alpha_cumprod = self.alphas_cumprod.to(device=original_samples.device, dtype=original_samples.dtype)
184
+ timesteps = timesteps.to(original_samples.device)
185
+
186
+ sqrt_alpha_prod = alpha_cumprod[timesteps] ** 0.5
187
+ sqrt_alpha_prod = sqrt_alpha_prod.flatten()
188
+ while len(sqrt_alpha_prod.shape) < len(original_samples.shape):
189
+ sqrt_alpha_prod = sqrt_alpha_prod.unsqueeze(-1) #adds a new dimension with length one at a specific pos within tensors shape
190
+ sqrt_one_minus_alpha_prod = (1 - alpha_cumprod[timesteps]) ** 0.5 #standard deviation
191
+ sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.flatten()
192
+ while len(sqrt_one_minus_alpha_prod) < len(original_samples.shape):
193
+ sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1)
194
+
195
+ # According to the euation (4) of the DDM paper
196
+ noise = torch.randn(original_samples.shape, generator=self.generator, device=original_samples.device, dtype=original_samples.dtype)
197
+ noisy_samples = (sqrt_alpha_prod * original_samples) + (sqrt_one_minus_alpha_prod) * noise
198
+