russc821 frankleeeee commited on
Commit
cf7ecde
·
0 Parent(s):

Duplicate from hpcai-tech/vqvae

Browse files

Co-authored-by: Frank Lee <frankleeeee@users.noreply.huggingface.co>

Files changed (8) hide show
  1. .gitattributes +35 -0
  2. README.md +14 -0
  3. _utils.py +115 -0
  4. attention.py +596 -0
  5. config.json +21 -0
  6. configuration_vqvae.py +22 -0
  7. model.safetensors +3 -0
  8. modeling_vqvae.py +337 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz 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
README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ ---
4
+
5
+ # VQVAE
6
+
7
+ This repository is a clone of the [VideoGPT](https://github.com/wilson1yan/VideoGPT/tree/master) in order to convert the VQ-VAE model to the Hugging Face format for easier model loading.
8
+
9
+ Paper: [VideoGPT: Video Generation using VQ-VAE and Transformers](https://arxiv.org/abs/2104.10157)
10
+
11
+ ## License
12
+
13
+ We follow the MIT license distributed by the [VideoGPT](https://github.com/wilson1yan/VideoGPT/tree/master) project.
14
+
_utils.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2021 Wilson Yan
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+
25
+ This file is copied from https://github.com/wilson1yan/VideoGPT/blob/master/videogpt/utils.py
26
+ We adapted it to Hugging Face AutoModel for easier model loading.
27
+ """
28
+
29
+
30
+ # Shifts src_tf dim to dest dim
31
+ # i.e. shift_dim(x, 1, -1) would be (b, c, t, h, w) -> (b, t, h, w, c)
32
+ def shift_dim(x, src_dim=-1, dest_dim=-1, make_contiguous=True):
33
+ n_dims = len(x.shape)
34
+ if src_dim < 0:
35
+ src_dim = n_dims + src_dim
36
+ if dest_dim < 0:
37
+ dest_dim = n_dims + dest_dim
38
+
39
+ assert 0 <= src_dim < n_dims and 0 <= dest_dim < n_dims
40
+
41
+ dims = list(range(n_dims))
42
+ del dims[src_dim]
43
+
44
+ permutation = []
45
+ ctr = 0
46
+ for i in range(n_dims):
47
+ if i == dest_dim:
48
+ permutation.append(src_dim)
49
+ else:
50
+ permutation.append(dims[ctr])
51
+ ctr += 1
52
+ x = x.permute(permutation)
53
+ if make_contiguous:
54
+ x = x.contiguous()
55
+ return x
56
+
57
+ # reshapes tensor start from dim i (inclusive)
58
+ # to dim j (exclusive) to the desired shape
59
+ # e.g. if x.shape = (b, thw, c) then
60
+ # view_range(x, 1, 2, (t, h, w)) returns
61
+ # x of shape (b, t, h, w, c)
62
+ def view_range(x, i, j, shape):
63
+ shape = tuple(shape)
64
+
65
+ n_dims = len(x.shape)
66
+ if i < 0:
67
+ i = n_dims + i
68
+
69
+ if j is None:
70
+ j = n_dims
71
+ elif j < 0:
72
+ j = n_dims + j
73
+
74
+ assert 0 <= i < j <= n_dims
75
+
76
+ x_shape = x.shape
77
+ target_shape = x_shape[:i] + shape + x_shape[j:]
78
+ return x.view(target_shape)
79
+
80
+
81
+ def tensor_slice(x, begin, size):
82
+ assert all([b >= 0 for b in begin])
83
+ size = [l - b if s == -1 else s
84
+ for s, b, l in zip(size, begin, x.shape)]
85
+ assert all([s >= 0 for s in size])
86
+
87
+ slices = [slice(b, b + s) for b, s in zip(begin, size)]
88
+ return x[slices]
89
+
90
+
91
+ import math
92
+ import numpy as np
93
+ import skvideo.io
94
+ def save_video_grid(video, fname, nrow=None):
95
+ b, c, t, h, w = video.shape
96
+ video = video.permute(0, 2, 3, 4, 1)
97
+ video = (video.cpu().numpy() * 255).astype('uint8')
98
+
99
+ if nrow is None:
100
+ nrow = math.ceil(math.sqrt(b))
101
+ ncol = math.ceil(b / nrow)
102
+ padding = 1
103
+ video_grid = np.zeros((t, (padding + h) * nrow + padding,
104
+ (padding + w) * ncol + padding, c), dtype='uint8')
105
+ for i in range(b):
106
+ r = i // ncol
107
+ c = i % ncol
108
+
109
+ start_r = (padding + h) * r
110
+ start_c = (padding + w) * c
111
+ video_grid[:, start_r:start_r + h, start_c:start_c + w] = video[i]
112
+
113
+ skvideo.io.vwrite(fname, video_grid, inputdict={'-r': '5'})
114
+ print('saved videos to', fname)
115
+
attention.py ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2021 Wilson Yan
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+
25
+ This file is copied from https://github.com/wilson1yan/VideoGPT/blob/master/videogpt/attention.py
26
+ We adapted it to Hugging Face AutoModel for easier model loading.
27
+ """
28
+
29
+
30
+ import numpy as np
31
+
32
+ import torch
33
+ import torch.nn as nn
34
+ import torch.nn.functional as F
35
+ from torch.utils.checkpoint import checkpoint
36
+
37
+ from ._utils import shift_dim, view_range, tensor_slice
38
+
39
+
40
+ class AttentionStack(nn.Module):
41
+ def __init__(
42
+ self, shape, embd_dim, n_head, n_layer, dropout,
43
+ attn_type, attn_dropout, class_cond_dim, frame_cond_shape,
44
+ ):
45
+ super().__init__()
46
+ self.shape = shape
47
+ self.embd_dim = embd_dim
48
+ self.use_frame_cond = frame_cond_shape is not None
49
+
50
+ self.right_shift = RightShift(embd_dim)
51
+ self.pos_embd = AddBroadcastPosEmbed(
52
+ shape=shape, embd_dim=embd_dim
53
+ )
54
+
55
+ self.attn_nets = nn.ModuleList(
56
+ [
57
+ AttentionBlock(
58
+ shape=shape,
59
+ embd_dim=embd_dim,
60
+ n_head=n_head,
61
+ n_layer=n_layer,
62
+ dropout=dropout,
63
+ attn_type=attn_type,
64
+ attn_dropout=attn_dropout,
65
+ class_cond_dim=class_cond_dim,
66
+ frame_cond_shape=frame_cond_shape
67
+ )
68
+ for i in range(n_layer)
69
+ ]
70
+ )
71
+
72
+ def forward(self, x, cond, decode_step, decode_idx):
73
+ """
74
+ Args
75
+ ------
76
+ x: (b, d1, d2, ..., dn, embd_dim)
77
+ cond: a dictionary of conditioning tensors
78
+
79
+ (below is used only when sampling for fast decoding)
80
+ decode: the enumerated rasterscan order of the current idx being sampled
81
+ decode_step: a tuple representing the current idx being sampled
82
+ """
83
+ x = self.right_shift(x, decode_step)
84
+ x = self.pos_embd(x, decode_step, decode_idx)
85
+ for net in self.attn_nets:
86
+ x = net(x, cond, decode_step, decode_idx)
87
+
88
+ return x
89
+
90
+
91
+ class AttentionBlock(nn.Module):
92
+ def __init__(self, shape, embd_dim, n_head, n_layer, dropout,
93
+ attn_type, attn_dropout, class_cond_dim, frame_cond_shape):
94
+ super().__init__()
95
+ self.use_frame_cond = frame_cond_shape is not None
96
+
97
+ self.pre_attn_norm = LayerNorm(embd_dim, class_cond_dim)
98
+ self.post_attn_dp = nn.Dropout(dropout)
99
+ self.attn = MultiHeadAttention(shape, embd_dim, embd_dim, n_head,
100
+ n_layer, causal=True, attn_type=attn_type,
101
+ attn_kwargs=dict(attn_dropout=attn_dropout))
102
+
103
+ if frame_cond_shape is not None:
104
+ enc_len = np.prod(frame_cond_shape[:-1])
105
+ self.pre_enc_norm = LayerNorm(embd_dim, class_cond_dim)
106
+ self.post_enc_dp = nn.Dropout(dropout)
107
+ self.enc_attn = MultiHeadAttention(shape, embd_dim, frame_cond_shape[-1],
108
+ n_head, n_layer, attn_type='full',
109
+ attn_kwargs=dict(attn_dropout=0.), causal=False)
110
+
111
+ self.pre_fc_norm = LayerNorm(embd_dim, class_cond_dim)
112
+ self.post_fc_dp = nn.Dropout(dropout)
113
+ self.fc_block = nn.Sequential(
114
+ nn.Linear(in_features=embd_dim, out_features=embd_dim * 4),
115
+ GeLU2(),
116
+ nn.Linear(in_features=embd_dim * 4, out_features=embd_dim),
117
+ )
118
+
119
+ def forward(self, x, cond, decode_step, decode_idx):
120
+ h = self.pre_attn_norm(x, cond)
121
+ if self.training:
122
+ h = checkpoint(self.attn, h, h, h, decode_step, decode_idx)
123
+ else:
124
+ h = self.attn(h, h, h, decode_step, decode_idx)
125
+ h = self.post_attn_dp(h)
126
+ x = x + h
127
+
128
+ if self.use_frame_cond:
129
+ h = self.pre_enc_norm(x, cond)
130
+ if self.training:
131
+ h = checkpoint(self.enc_attn, h, cond['frame_cond'], cond['frame_cond'],
132
+ decode_step, decode_idx)
133
+ else:
134
+ h = self.enc_attn(h, cond['frame_cond'], cond['frame_cond'],
135
+ decode_step, decode_idx)
136
+ h = self.post_enc_dp(h)
137
+ x = x + h
138
+
139
+ h = self.pre_fc_norm(x, cond)
140
+ if self.training:
141
+ h = checkpoint(self.fc_block, h)
142
+ else:
143
+ h = self.fc_block(h)
144
+ h = self.post_fc_dp(h)
145
+ x = x + h
146
+
147
+ return x
148
+
149
+
150
+ class MultiHeadAttention(nn.Module):
151
+ def __init__(self, shape, dim_q, dim_kv, n_head, n_layer,
152
+ causal, attn_type, attn_kwargs):
153
+ super().__init__()
154
+ self.causal = causal
155
+ self.shape = shape
156
+
157
+ self.d_k = dim_q // n_head
158
+ self.d_v = dim_kv // n_head
159
+ self.n_head = n_head
160
+
161
+ self.w_qs = nn.Linear(dim_q, n_head * self.d_k, bias=False) # q
162
+ self.w_qs.weight.data.normal_(std=1.0 / np.sqrt(dim_q))
163
+
164
+ self.w_ks = nn.Linear(dim_kv, n_head * self.d_k, bias=False) # k
165
+ self.w_ks.weight.data.normal_(std=1.0 / np.sqrt(dim_kv))
166
+
167
+ self.w_vs = nn.Linear(dim_kv, n_head * self.d_v, bias=False) # v
168
+ self.w_vs.weight.data.normal_(std=1.0 / np.sqrt(dim_kv))
169
+
170
+ self.fc = nn.Linear(n_head * self.d_v, dim_q, bias=True) # c
171
+ self.fc.weight.data.normal_(std=1.0 / np.sqrt(dim_q * n_layer))
172
+
173
+ if attn_type == 'full':
174
+ self.attn = FullAttention(shape, causal, **attn_kwargs)
175
+ elif attn_type == 'axial':
176
+ assert not causal, 'causal axial attention is not supported'
177
+ self.attn = AxialAttention(len(shape), **attn_kwargs)
178
+ elif attn_type == 'sparse':
179
+ self.attn = SparseAttention(shape, n_head, causal, **attn_kwargs)
180
+
181
+ self.cache = None
182
+
183
+ def forward(self, q, k, v, decode_step=None, decode_idx=None):
184
+ """ Compute multi-head attention
185
+ Args
186
+ q, k, v: a [b, d1, ..., dn, c] tensor or
187
+ a [b, 1, ..., 1, c] tensor if decode_step is not None
188
+
189
+ Returns
190
+ The output after performing attention
191
+ """
192
+
193
+ # compute k, q, v
194
+ d_k, d_v, n_head = self.d_k, self.d_v, self.n_head
195
+ q = view_range(self.w_qs(q), -1, None, (n_head, d_k))
196
+ k = view_range(self.w_ks(k), -1, None, (n_head, d_k))
197
+ v = view_range(self.w_vs(v), -1, None, (n_head, d_v))
198
+
199
+ # b x n_head x seq_len x d
200
+ # (b, *d_shape, n_head, d) -> (b, n_head, *d_shape, d)
201
+ q = shift_dim(q, -2, 1)
202
+ k = shift_dim(k, -2, 1)
203
+ v = shift_dim(v, -2, 1)
204
+
205
+ # fast decoding
206
+ if decode_step is not None:
207
+ if decode_step == 0:
208
+ if self.causal:
209
+ k_shape = (q.shape[0], n_head, *self.shape, self.d_k)
210
+ v_shape = (q.shape[0], n_head, *self.shape, self.d_v)
211
+ self.cache = dict(k=torch.zeros(k_shape, dtype=k.dtype, device=q.device),
212
+ v=torch.zeros(v_shape, dtype=v.dtype, device=q.device))
213
+ else:
214
+ # cache only once in the non-causal case
215
+ self.cache = dict(k=k.clone(), v=v.clone())
216
+ if self.causal:
217
+ idx = (slice(None, None), slice(None, None), *[slice(i, i+ 1) for i in decode_idx])
218
+ self.cache['k'][idx] = k
219
+ self.cache['v'][idx] = v
220
+ k, v = self.cache['k'], self.cache['v']
221
+
222
+ a = self.attn(q, k, v, decode_step, decode_idx)
223
+
224
+ # (b, *d_shape, n_head, d) -> (b, *d_shape, n_head * d)
225
+ a = shift_dim(a, 1, -2).flatten(start_dim=-2)
226
+ a = self.fc(a) # (b x seq_len x embd_dim)
227
+
228
+ return a
229
+
230
+ ############## Attention #######################
231
+ class FullAttention(nn.Module):
232
+ def __init__(self, shape, causal, attn_dropout):
233
+ super().__init__()
234
+ self.causal = causal
235
+ self.attn_dropout = attn_dropout
236
+
237
+ seq_len = np.prod(shape)
238
+ if self.causal:
239
+ self.register_buffer('mask', torch.tril(torch.ones(seq_len, seq_len)))
240
+
241
+ def forward(self, q, k, v, decode_step, decode_idx):
242
+ mask = self.mask if self.causal else None
243
+ if decode_step is not None and mask is not None:
244
+ mask = mask[[decode_step]]
245
+
246
+ old_shape = q.shape[2:-1]
247
+ q = q.flatten(start_dim=2, end_dim=-2)
248
+ k = k.flatten(start_dim=2, end_dim=-2)
249
+ v = v.flatten(start_dim=2, end_dim=-2)
250
+
251
+ out = scaled_dot_product_attention(q, k, v, mask=mask,
252
+ attn_dropout=self.attn_dropout,
253
+ training=self.training)
254
+
255
+ return view_range(out, 2, 3, old_shape)
256
+
257
+ class AxialAttention(nn.Module):
258
+ def __init__(self, n_dim, axial_dim):
259
+ super().__init__()
260
+ if axial_dim < 0:
261
+ axial_dim = 2 + n_dim + 1 + axial_dim
262
+ else:
263
+ axial_dim += 2 # account for batch, head, dim
264
+ self.axial_dim = axial_dim
265
+
266
+ def forward(self, q, k, v, decode_step, decode_idx):
267
+ q = shift_dim(q, self.axial_dim, -2).flatten(end_dim=-3)
268
+ k = shift_dim(k, self.axial_dim, -2).flatten(end_dim=-3)
269
+ v = shift_dim(v, self.axial_dim, -2)
270
+ old_shape = list(v.shape)
271
+ v = v.flatten(end_dim=-3)
272
+
273
+ out = scaled_dot_product_attention(q, k, v, training=self.training)
274
+ out = out.view(*old_shape)
275
+ out = shift_dim(out, -2, self.axial_dim)
276
+ return out
277
+
278
+
279
+ class SparseAttention(nn.Module):
280
+ ops = dict()
281
+ attn_mask = dict()
282
+ block_layout = dict()
283
+
284
+ def __init__(self, shape, n_head, causal, num_local_blocks=4, block=32,
285
+ attn_dropout=0.): # does not use attn_dropout
286
+ super().__init__()
287
+ self.causal = causal
288
+ self.shape = shape
289
+
290
+ self.sparsity_config = StridedSparsityConfig(shape=shape, n_head=n_head,
291
+ causal=causal, block=block,
292
+ num_local_blocks=num_local_blocks)
293
+
294
+ if self.shape not in SparseAttention.block_layout:
295
+ SparseAttention.block_layout[self.shape] = self.sparsity_config.make_layout()
296
+ if causal and self.shape not in SparseAttention.attn_mask:
297
+ SparseAttention.attn_mask[self.shape] = self.sparsity_config.make_sparse_attn_mask()
298
+
299
+ def get_ops(self):
300
+ try:
301
+ from deepspeed.ops.sparse_attention import MatMul, Softmax
302
+ except:
303
+ raise Exception('Error importing deepspeed. Please install using `DS_BUILD_SPARSE_ATTN=1 pip install deepspeed`')
304
+ if self.shape not in SparseAttention.ops:
305
+ sparsity_layout = self.sparsity_config.make_layout()
306
+ sparse_dot_sdd_nt = MatMul(sparsity_layout,
307
+ self.sparsity_config.block,
308
+ 'sdd',
309
+ trans_a=False,
310
+ trans_b=True)
311
+
312
+ sparse_dot_dsd_nn = MatMul(sparsity_layout,
313
+ self.sparsity_config.block,
314
+ 'dsd',
315
+ trans_a=False,
316
+ trans_b=False)
317
+
318
+ sparse_softmax = Softmax(sparsity_layout, self.sparsity_config.block)
319
+
320
+ SparseAttention.ops[self.shape] = (sparse_dot_sdd_nt,
321
+ sparse_dot_dsd_nn,
322
+ sparse_softmax)
323
+ return SparseAttention.ops[self.shape]
324
+
325
+ def forward(self, q, k, v, decode_step, decode_idx):
326
+ if self.training and self.shape not in SparseAttention.ops:
327
+ self.get_ops()
328
+
329
+ SparseAttention.block_layout[self.shape] = SparseAttention.block_layout[self.shape].to(q)
330
+ if self.causal:
331
+ SparseAttention.attn_mask[self.shape] = SparseAttention.attn_mask[self.shape].to(q).type_as(q)
332
+ attn_mask = SparseAttention.attn_mask[self.shape] if self.causal else None
333
+
334
+ old_shape = q.shape[2:-1]
335
+ q = q.flatten(start_dim=2, end_dim=-2)
336
+ k = k.flatten(start_dim=2, end_dim=-2)
337
+ v = v.flatten(start_dim=2, end_dim=-2)
338
+
339
+ if decode_step is not None:
340
+ mask = self.sparsity_config.get_non_block_layout_row(SparseAttention.block_layout[self.shape], decode_step)
341
+ out = scaled_dot_product_attention(q, k, v, mask=mask, training=self.training)
342
+ else:
343
+ if q.shape != k.shape or k.shape != v.shape:
344
+ raise Exception('SparseAttention only support self-attention')
345
+ sparse_dot_sdd_nt, sparse_dot_dsd_nn, sparse_softmax = self.get_ops()
346
+ scaling = float(q.shape[-1]) ** -0.5
347
+
348
+ attn_output_weights = sparse_dot_sdd_nt(q, k)
349
+ if attn_mask is not None:
350
+ attn_output_weights = attn_output_weights.masked_fill(attn_mask == 0,
351
+ float('-inf'))
352
+ attn_output_weights = sparse_softmax(
353
+ attn_output_weights,
354
+ scale=scaling
355
+ )
356
+
357
+ out = sparse_dot_dsd_nn(attn_output_weights, v)
358
+
359
+ return view_range(out, 2, 3, old_shape)
360
+
361
+
362
+ class StridedSparsityConfig(object):
363
+ """
364
+ Strided Sparse configuration specified in https://arxiv.org/abs/1904.10509 that
365
+ generalizes to arbitrary dimensions
366
+ """
367
+ def __init__(self, shape, n_head, causal, block, num_local_blocks):
368
+ self.n_head = n_head
369
+ self.shape = shape
370
+ self.causal = causal
371
+ self.block = block
372
+ self.num_local_blocks = num_local_blocks
373
+
374
+ assert self.num_local_blocks >= 1, 'Must have at least 1 local block'
375
+ assert self.seq_len % self.block == 0, 'seq len must be divisible by block size'
376
+
377
+ self._block_shape = self._compute_block_shape()
378
+ self._block_shape_cum = self._block_shape_cum_sizes()
379
+
380
+ @property
381
+ def seq_len(self):
382
+ return np.prod(self.shape)
383
+
384
+ @property
385
+ def num_blocks(self):
386
+ return self.seq_len // self.block
387
+
388
+ def set_local_layout(self, layout):
389
+ num_blocks = self.num_blocks
390
+ for row in range(0, num_blocks):
391
+ end = min(row + self.num_local_blocks, num_blocks)
392
+ for col in range(
393
+ max(0, row - self.num_local_blocks),
394
+ (row + 1 if self.causal else end)):
395
+ layout[:, row, col] = 1
396
+ return layout
397
+
398
+ def set_global_layout(self, layout):
399
+ num_blocks = self.num_blocks
400
+ n_dim = len(self._block_shape)
401
+ for row in range(num_blocks):
402
+ assert self._to_flattened_idx(self._to_unflattened_idx(row)) == row
403
+ cur_idx = self._to_unflattened_idx(row)
404
+ # no strided attention over last dim
405
+ for d in range(n_dim - 1):
406
+ end = self._block_shape[d]
407
+ for i in range(0, (cur_idx[d] + 1 if self.causal else end)):
408
+ new_idx = list(cur_idx)
409
+ new_idx[d] = i
410
+ new_idx = tuple(new_idx)
411
+
412
+ col = self._to_flattened_idx(new_idx)
413
+ layout[:, row, col] = 1
414
+
415
+ return layout
416
+
417
+ def make_layout(self):
418
+ layout = torch.zeros((self.n_head, self.num_blocks, self.num_blocks), dtype=torch.int64)
419
+ layout = self.set_local_layout(layout)
420
+ layout = self.set_global_layout(layout)
421
+ return layout
422
+
423
+ def make_sparse_attn_mask(self):
424
+ block_layout = self.make_layout()
425
+ assert block_layout.shape[1] == block_layout.shape[2] == self.num_blocks
426
+
427
+ num_dense_blocks = block_layout.sum().item()
428
+ attn_mask = torch.ones(num_dense_blocks, self.block, self.block)
429
+ counter = 0
430
+ for h in range(self.n_head):
431
+ for i in range(self.num_blocks):
432
+ for j in range(self.num_blocks):
433
+ elem = block_layout[h, i, j].item()
434
+ if elem == 1:
435
+ assert i >= j
436
+ if i == j: # need to mask within block on diagonals
437
+ attn_mask[counter] = torch.tril(attn_mask[counter])
438
+ counter += 1
439
+ assert counter == num_dense_blocks
440
+
441
+ return attn_mask.unsqueeze(0)
442
+
443
+ def get_non_block_layout_row(self, block_layout, row):
444
+ block_row = row // self.block
445
+ block_row = block_layout[:, [block_row]] # n_head x 1 x n_blocks
446
+ block_row = block_row.repeat_interleave(self.block, dim=-1)
447
+ block_row[:, :, row + 1:] = 0.
448
+ return block_row
449
+
450
+ ############# Helper functions ##########################
451
+
452
+ def _compute_block_shape(self):
453
+ n_dim = len(self.shape)
454
+ cum_prod = 1
455
+ for i in range(n_dim - 1, -1, -1):
456
+ cum_prod *= self.shape[i]
457
+ if cum_prod > self.block:
458
+ break
459
+ assert cum_prod % self.block == 0
460
+ new_shape = (*self.shape[:i], cum_prod // self.block)
461
+
462
+ assert np.prod(new_shape) == np.prod(self.shape) // self.block
463
+
464
+ return new_shape
465
+
466
+ def _block_shape_cum_sizes(self):
467
+ bs = np.flip(np.array(self._block_shape))
468
+ return tuple(np.flip(np.cumprod(bs)[:-1])) + (1,)
469
+
470
+ def _to_flattened_idx(self, idx):
471
+ assert len(idx) == len(self._block_shape), f"{len(idx)} != {len(self._block_shape)}"
472
+ flat_idx = 0
473
+ for i in range(len(self._block_shape)):
474
+ flat_idx += idx[i] * self._block_shape_cum[i]
475
+ return flat_idx
476
+
477
+ def _to_unflattened_idx(self, flat_idx):
478
+ assert flat_idx < np.prod(self._block_shape)
479
+ idx = []
480
+ for i in range(len(self._block_shape)):
481
+ idx.append(flat_idx // self._block_shape_cum[i])
482
+ flat_idx %= self._block_shape_cum[i]
483
+ return tuple(idx)
484
+
485
+
486
+ ################ Spatiotemporal broadcasted positional embeddings ###############
487
+ class AddBroadcastPosEmbed(nn.Module):
488
+ def __init__(self, shape, embd_dim, dim=-1):
489
+ super().__init__()
490
+ assert dim in [-1, 1] # only first or last dim supported
491
+ self.shape = shape
492
+ self.n_dim = n_dim = len(shape)
493
+ self.embd_dim = embd_dim
494
+ self.dim = dim
495
+
496
+ assert embd_dim % n_dim == 0, f"{embd_dim} % {n_dim} != 0"
497
+ self.emb = nn.ParameterDict({
498
+ f'd_{i}': nn.Parameter(torch.randn(shape[i], embd_dim // n_dim) * 0.01
499
+ if dim == -1 else
500
+ torch.randn(embd_dim // n_dim, shape[i]) * 0.01)
501
+ for i in range(n_dim)
502
+ })
503
+
504
+ def forward(self, x, decode_step=None, decode_idx=None):
505
+ embs = []
506
+ for i in range(self.n_dim):
507
+ e = self.emb[f'd_{i}']
508
+ if self.dim == -1:
509
+ # (1, 1, ..., 1, self.shape[i], 1, ..., -1)
510
+ e = e.view(1, *((1,) * i), self.shape[i], *((1,) * (self.n_dim - i - 1)), -1)
511
+ e = e.expand(1, *self.shape, -1)
512
+ else:
513
+ e = e.view(1, -1, *((1,) * i), self.shape[i], *((1,) * (self.n_dim - i - 1)))
514
+ e = e.expand(1, -1, *self.shape)
515
+ embs.append(e)
516
+
517
+ embs = torch.cat(embs, dim=self.dim)
518
+ if decode_step is not None:
519
+ embs = tensor_slice(embs, [0, *decode_idx, 0],
520
+ [x.shape[0], *(1,) * self.n_dim, x.shape[-1]])
521
+
522
+ return x + embs
523
+
524
+ ################# Helper Functions ###################################
525
+ def scaled_dot_product_attention(q, k, v, mask=None, attn_dropout=0., training=True):
526
+ # Performs scaled dot-product attention over the second to last dimension dn
527
+
528
+ # (b, n_head, d1, ..., dn, d)
529
+ attn = torch.matmul(q, k.transpose(-1, -2))
530
+ attn = attn / np.sqrt(q.shape[-1])
531
+ if mask is not None:
532
+ attn = attn.masked_fill(mask == 0, float('-inf'))
533
+ attn_float = F.softmax(attn, dim=-1)
534
+ attn = attn_float.type_as(attn) # b x n_head x d1 x ... x dn x d
535
+ attn = F.dropout(attn, p=attn_dropout, training=training)
536
+
537
+ a = torch.matmul(attn, v) # b x n_head x d1 x ... x dn x d
538
+
539
+ return a
540
+
541
+
542
+ class RightShift(nn.Module):
543
+ def __init__(self, embd_dim):
544
+ super().__init__()
545
+ self.embd_dim = embd_dim
546
+ self.sos = nn.Parameter(torch.FloatTensor(embd_dim).normal_(std=0.02), requires_grad=True)
547
+
548
+ def forward(self, x, decode_step):
549
+ if decode_step is not None and decode_step > 0:
550
+ return x
551
+
552
+ x_shape = list(x.shape)
553
+ x = x.flatten(start_dim=1, end_dim=-2) # (b, seq_len, embd_dim)
554
+ sos = torch.ones(x_shape[0], 1, self.embd_dim, dtype=torch.float32).to(self.sos) * self.sos
555
+ sos = sos.type_as(x)
556
+ x = torch.cat([sos, x[:, :-1, :]], axis=1)
557
+ x = x.view(*x_shape)
558
+
559
+ return x
560
+
561
+
562
+ class GeLU2(nn.Module):
563
+ def forward(self, x):
564
+ return (1.702 * x).sigmoid() * x
565
+
566
+
567
+ class LayerNorm(nn.Module):
568
+ def __init__(self, embd_dim, class_cond_dim):
569
+ super().__init__()
570
+ self.conditional = class_cond_dim is not None
571
+
572
+ if self.conditional:
573
+ self.w = nn.Linear(class_cond_dim, embd_dim, bias=False)
574
+ nn.init.constant_(self.w.weight.data, 1. / np.sqrt(class_cond_dim))
575
+ self.wb = nn.Linear(class_cond_dim, embd_dim, bias=False)
576
+ else:
577
+ self.g = nn.Parameter(torch.ones(embd_dim, dtype=torch.float32), requires_grad=True)
578
+ self.b = nn.Parameter(torch.zeros(embd_dim, dtype=torch.float32), requires_grad=True)
579
+
580
+ def forward(self, x, cond):
581
+ if self.conditional: # (b, cond_dim)
582
+ g = 1 + self.w(cond['class_cond']).view(x.shape[0], *(1,)*(len(x.shape)-2), x.shape[-1]) # (b, ..., embd_dim)
583
+ b = self.wb(cond['class_cond']).view(x.shape[0], *(1,)*(len(x.shape)-2), x.shape[-1])
584
+ else:
585
+ g = self.g # (embd_dim,)
586
+ b = self.b
587
+
588
+ x_float = x.float()
589
+
590
+ mu = x_float.mean(dim=-1, keepdims=True)
591
+ s = (x_float - mu).square().mean(dim=-1, keepdims=True)
592
+ x_float = (x_float - mu) * (1e-5 + s.rsqrt()) # (b, ..., embd_dim)
593
+ x_float = x_float * g + b
594
+
595
+ x = x_float.type_as(x)
596
+ return x
config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "VQVAE"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_vqvae.VQVAEConfig",
7
+ "AutoModel": "modeling_vqvae.VQVAE"
8
+ },
9
+ "downsample": [
10
+ 2,
11
+ 4,
12
+ 4
13
+ ],
14
+ "embedding_dim": 256,
15
+ "model_type": "VQVAE",
16
+ "n_codes": 2048,
17
+ "n_hiddens": 240,
18
+ "n_res_layers": 4,
19
+ "torch_dtype": "float32",
20
+ "transformers_version": "4.37.2"
21
+ }
configuration_vqvae.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import PretrainedConfig
2
+ from typing import List
3
+
4
+
5
+ class VQVAEConfig(PretrainedConfig):
6
+ model_type = "VQVAE"
7
+
8
+ def __init__(
9
+ self,
10
+ embedding_dim: int = 256,
11
+ n_codes: int = 2048,
12
+ n_hiddens: int = 240,
13
+ n_res_layers: int = 4,
14
+ downsample: List[int] = [2, 4, 4],
15
+ **kwargs,
16
+ ):
17
+ self.embedding_dim = embedding_dim
18
+ self.n_codes = n_codes
19
+ self.n_hiddens = n_hiddens
20
+ self.n_res_layers = n_res_layers
21
+ self.downsample = downsample
22
+ super().__init__(**kwargs)
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b9fda02bdef17ca1378a9392adc5b1d9692fa194ccaabff3b8352ce7548af0de
3
+ size 88842260
modeling_vqvae.py ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2021 Wilson Yan
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+
25
+ This file is copied from https://github.com/wilson1yan/VideoGPT/blob/master/videogpt/vqvae.py
26
+ We adapted it to Hugging Face AutoModel for easier model loading.
27
+ """
28
+
29
+
30
+ import os
31
+ import math
32
+ import numpy as np
33
+
34
+ import torch
35
+ import torch.nn as nn
36
+ import torch.nn.functional as F
37
+ import torch.distributed as dist
38
+
39
+ from .attention import MultiHeadAttention
40
+ from ._utils import shift_dim
41
+ from transformers import PreTrainedModel
42
+ from .configuration_vqvae import VQVAEConfig
43
+
44
+
45
+ class VQVAE(PreTrainedModel):
46
+ config_class = VQVAEConfig
47
+
48
+ def __init__(self, config):
49
+ super().__init__(config)
50
+ self.embedding_dim = config.embedding_dim
51
+ self.n_codes = config.n_codes
52
+
53
+ self.encoder = Encoder(config.n_hiddens, config.n_res_layers, config.downsample)
54
+ self.decoder = Decoder(config.n_hiddens, config.n_res_layers, config.downsample)
55
+
56
+ self.pre_vq_conv = SamePadConv3d(config.n_hiddens, config.embedding_dim, 1)
57
+ self.post_vq_conv = SamePadConv3d(config.embedding_dim, config.n_hiddens, 1)
58
+
59
+ self.codebook = Codebook(config.n_codes, config.embedding_dim)
60
+
61
+ @property
62
+ def latent_shape(self):
63
+ input_shape = (self.args.sequence_length, self.args.resolution,
64
+ self.args.resolution)
65
+ return tuple([s // d for s, d in zip(input_shape,
66
+ self.args.downsample)])
67
+
68
+ def encode(self, x, include_embeddings=False):
69
+ h = self.pre_vq_conv(self.encoder(x))
70
+ vq_output = self.codebook(h)
71
+ if include_embeddings:
72
+ return vq_output['encodings'], vq_output['embeddings']
73
+ else:
74
+ return vq_output['encodings']
75
+
76
+ def decode(self, encodings):
77
+ h = F.embedding(encodings, self.codebook.embeddings)
78
+ h = self.post_vq_conv(shift_dim(h, -1, 1))
79
+ return self.decoder(h)
80
+
81
+ def decode_from_embeddings(self, embeddings):
82
+ # embeddings: [b, c, t, h, w]
83
+ encodings = self.codebook.search_indices(embeddings)
84
+ return self.decode(encodings)
85
+
86
+ def forward(self, x):
87
+ z = self.pre_vq_conv(self.encoder(x))
88
+ vq_output = self.codebook(z)
89
+ x_recon = self.decoder(self.post_vq_conv(vq_output['embeddings']))
90
+ recon_loss = F.mse_loss(x_recon, x) / 0.06
91
+
92
+ return recon_loss, x_recon, vq_output
93
+
94
+
95
+ class AxialBlock(nn.Module):
96
+ def __init__(self, n_hiddens, n_head):
97
+ super().__init__()
98
+ kwargs = dict(shape=(0,) * 3, dim_q=n_hiddens,
99
+ dim_kv=n_hiddens, n_head=n_head,
100
+ n_layer=1, causal=False, attn_type='axial')
101
+ self.attn_w = MultiHeadAttention(attn_kwargs=dict(axial_dim=-2),
102
+ **kwargs)
103
+ self.attn_h = MultiHeadAttention(attn_kwargs=dict(axial_dim=-3),
104
+ **kwargs)
105
+ self.attn_t = MultiHeadAttention(attn_kwargs=dict(axial_dim=-4),
106
+ **kwargs)
107
+
108
+ def forward(self, x):
109
+ x = shift_dim(x, 1, -1)
110
+ x = self.attn_w(x, x, x) + self.attn_h(x, x, x) + self.attn_t(x, x, x)
111
+ x = shift_dim(x, -1, 1)
112
+ return x
113
+
114
+
115
+ class AttentionResidualBlock(nn.Module):
116
+ def __init__(self, n_hiddens):
117
+ super().__init__()
118
+ self.block = nn.Sequential(
119
+ nn.BatchNorm3d(n_hiddens),
120
+ nn.ReLU(),
121
+ SamePadConv3d(n_hiddens, n_hiddens // 2, 3, bias=False),
122
+ nn.BatchNorm3d(n_hiddens // 2),
123
+ nn.ReLU(),
124
+ SamePadConv3d(n_hiddens // 2, n_hiddens, 1, bias=False),
125
+ nn.BatchNorm3d(n_hiddens),
126
+ nn.ReLU(),
127
+ AxialBlock(n_hiddens, 2)
128
+ )
129
+
130
+ def forward(self, x):
131
+ return x + self.block(x)
132
+
133
+ class Codebook(nn.Module):
134
+ def __init__(self, n_codes, embedding_dim):
135
+ super().__init__()
136
+ self.register_buffer('embeddings', torch.randn(n_codes, embedding_dim))
137
+ self.register_buffer('N', torch.zeros(n_codes))
138
+ self.register_buffer('z_avg', self.embeddings.data.clone())
139
+
140
+ self.n_codes = n_codes
141
+ self.embedding_dim = embedding_dim
142
+ self._need_init = True
143
+
144
+ def _tile(self, x):
145
+ d, ew = x.shape
146
+ if d < self.n_codes:
147
+ n_repeats = (self.n_codes + d - 1) // d
148
+ std = 0.01 / np.sqrt(ew)
149
+ x = x.repeat(n_repeats, 1)
150
+ x = x + torch.randn_like(x) * std
151
+ return x
152
+
153
+ def _init_embeddings(self, z):
154
+ # z: [b, c, t, h, w]
155
+ self._need_init = False
156
+ flat_inputs = shift_dim(z, 1, -1).flatten(end_dim=-2)
157
+ y = self._tile(flat_inputs)
158
+
159
+ d = y.shape[0]
160
+ _k_rand = y[torch.randperm(y.shape[0])][:self.n_codes]
161
+ if dist.is_initialized():
162
+ dist.broadcast(_k_rand, 0)
163
+ self.embeddings.data.copy_(_k_rand)
164
+ self.z_avg.data.copy_(_k_rand)
165
+ self.N.data.copy_(torch.ones(self.n_codes))
166
+
167
+ def search_indices(self, z):
168
+ # z: [b, c, t, h, w]
169
+ flat_inputs = shift_dim(z, 1, -1).flatten(end_dim=-2)
170
+ distances = (flat_inputs ** 2).sum(dim=1, keepdim=True) \
171
+ - 2 * flat_inputs @ self.embeddings.t() \
172
+ + (self.embeddings.t() ** 2).sum(dim=0, keepdim=True)
173
+
174
+ encoding_indices = torch.argmin(distances, dim=1)
175
+ encoding_indices = encoding_indices.view(z.shape[0], *z.shape[2:])
176
+ return encoding_indices
177
+
178
+
179
+ def forward(self, z):
180
+ # z: [b, c, t, h, w]
181
+ if self._need_init and self.training:
182
+ self._init_embeddings(z)
183
+ flat_inputs = shift_dim(z, 1, -1).flatten(end_dim=-2)
184
+ distances = (flat_inputs ** 2).sum(dim=1, keepdim=True) \
185
+ - 2 * flat_inputs @ self.embeddings.t() \
186
+ + (self.embeddings.t() ** 2).sum(dim=0, keepdim=True)
187
+
188
+ encoding_indices = torch.argmin(distances, dim=1)
189
+ encode_onehot = F.one_hot(encoding_indices, self.n_codes).type_as(flat_inputs)
190
+ encoding_indices = encoding_indices.view(z.shape[0], *z.shape[2:])
191
+
192
+ embeddings = F.embedding(encoding_indices, self.embeddings)
193
+ embeddings = shift_dim(embeddings, -1, 1)
194
+
195
+ commitment_loss = 0.25 * F.mse_loss(z, embeddings.detach())
196
+
197
+ # EMA codebook update
198
+ if self.training:
199
+ n_total = encode_onehot.sum(dim=0)
200
+ encode_sum = flat_inputs.t() @ encode_onehot
201
+ if dist.is_initialized():
202
+ dist.all_reduce(n_total)
203
+ dist.all_reduce(encode_sum)
204
+
205
+ self.N.data.mul_(0.99).add_(n_total, alpha=0.01)
206
+ self.z_avg.data.mul_(0.99).add_(encode_sum.t(), alpha=0.01)
207
+
208
+ n = self.N.sum()
209
+ weights = (self.N + 1e-7) / (n + self.n_codes * 1e-7) * n
210
+ encode_normalized = self.z_avg / weights.unsqueeze(1)
211
+ self.embeddings.data.copy_(encode_normalized)
212
+
213
+ y = self._tile(flat_inputs)
214
+ _k_rand = y[torch.randperm(y.shape[0])][:self.n_codes]
215
+ if dist.is_initialized():
216
+ dist.broadcast(_k_rand, 0)
217
+
218
+ usage = (self.N.view(self.n_codes, 1) >= 1).float()
219
+ self.embeddings.data.mul_(usage).add_(_k_rand * (1 - usage))
220
+
221
+ embeddings_st = (embeddings - z).detach() + z
222
+
223
+ avg_probs = torch.mean(encode_onehot, dim=0)
224
+ perplexity = torch.exp(-torch.sum(avg_probs * torch.log(avg_probs + 1e-10)))
225
+
226
+ return dict(embeddings=embeddings_st, encodings=encoding_indices,
227
+ commitment_loss=commitment_loss, perplexity=perplexity)
228
+
229
+ def dictionary_lookup(self, encodings):
230
+ embeddings = F.embedding(encodings, self.embeddings)
231
+ return embeddings
232
+
233
+ class Encoder(nn.Module):
234
+ def __init__(self, n_hiddens, n_res_layers, downsample):
235
+ super().__init__()
236
+ n_times_downsample = np.array([int(math.log2(d)) for d in downsample])
237
+ self.convs = nn.ModuleList()
238
+ max_ds = n_times_downsample.max()
239
+ for i in range(max_ds):
240
+ in_channels = 3 if i == 0 else n_hiddens
241
+ stride = tuple([2 if d > 0 else 1 for d in n_times_downsample])
242
+ conv = SamePadConv3d(in_channels, n_hiddens, 4, stride=stride)
243
+ self.convs.append(conv)
244
+ n_times_downsample -= 1
245
+ self.conv_last = SamePadConv3d(in_channels, n_hiddens, kernel_size=3)
246
+
247
+ self.res_stack = nn.Sequential(
248
+ *[AttentionResidualBlock(n_hiddens)
249
+ for _ in range(n_res_layers)],
250
+ nn.BatchNorm3d(n_hiddens),
251
+ nn.ReLU()
252
+ )
253
+
254
+ def forward(self, x):
255
+ h = x
256
+ for conv in self.convs:
257
+ h = F.relu(conv(h))
258
+ h = self.conv_last(h)
259
+ h = self.res_stack(h)
260
+ return h
261
+
262
+
263
+ class Decoder(nn.Module):
264
+ def __init__(self, n_hiddens, n_res_layers, upsample):
265
+ super().__init__()
266
+ self.res_stack = nn.Sequential(
267
+ *[AttentionResidualBlock(n_hiddens)
268
+ for _ in range(n_res_layers)],
269
+ nn.BatchNorm3d(n_hiddens),
270
+ nn.ReLU()
271
+ )
272
+
273
+ n_times_upsample = np.array([int(math.log2(d)) for d in upsample])
274
+ max_us = n_times_upsample.max()
275
+ self.convts = nn.ModuleList()
276
+ for i in range(max_us):
277
+ out_channels = 3 if i == max_us - 1 else n_hiddens
278
+ us = tuple([2 if d > 0 else 1 for d in n_times_upsample])
279
+ convt = SamePadConvTranspose3d(n_hiddens, out_channels, 4,
280
+ stride=us)
281
+ self.convts.append(convt)
282
+ n_times_upsample -= 1
283
+
284
+ def forward(self, x):
285
+ h = self.res_stack(x)
286
+ for i, convt in enumerate(self.convts):
287
+ h = convt(h)
288
+ if i < len(self.convts) - 1:
289
+ h = F.relu(h)
290
+ return h
291
+
292
+
293
+ # Does not support dilation
294
+ class SamePadConv3d(nn.Module):
295
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, bias=True):
296
+ super().__init__()
297
+ if isinstance(kernel_size, int):
298
+ kernel_size = (kernel_size,) * 3
299
+ if isinstance(stride, int):
300
+ stride = (stride,) * 3
301
+
302
+ # assumes that the input shape is divisible by stride
303
+ total_pad = tuple([k - s for k, s in zip(kernel_size, stride)])
304
+ pad_input = []
305
+ for p in total_pad[::-1]: # reverse since F.pad starts from last dim
306
+ pad_input.append((p // 2 + p % 2, p // 2))
307
+ pad_input = sum(pad_input, tuple())
308
+ self.pad_input = pad_input
309
+
310
+ self.conv = nn.Conv3d(in_channels, out_channels, kernel_size,
311
+ stride=stride, padding=0, bias=bias)
312
+
313
+ def forward(self, x):
314
+ return self.conv(F.pad(x, self.pad_input))
315
+
316
+
317
+ class SamePadConvTranspose3d(nn.Module):
318
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, bias=True):
319
+ super().__init__()
320
+ if isinstance(kernel_size, int):
321
+ kernel_size = (kernel_size,) * 3
322
+ if isinstance(stride, int):
323
+ stride = (stride,) * 3
324
+
325
+ total_pad = tuple([k - s for k, s in zip(kernel_size, stride)])
326
+ pad_input = []
327
+ for p in total_pad[::-1]: # reverse since F.pad starts from last dim
328
+ pad_input.append((p // 2 + p % 2, p // 2))
329
+ pad_input = sum(pad_input, tuple())
330
+ self.pad_input = pad_input
331
+
332
+ self.convt = nn.ConvTranspose3d(in_channels, out_channels, kernel_size,
333
+ stride=stride, bias=bias,
334
+ padding=tuple([k - 1 for k in kernel_size]))
335
+
336
+ def forward(self, x):
337
+ return self.convt(F.pad(x, self.pad_input))