vector-quantize-pytorch 1.15.6__tar.gz → 1.16.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/PKG-INFO +12 -1
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/README.md +11 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/pyproject.toml +1 -1
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/tests/test_readme.py +19 -8
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/residual_vq.py +123 -6
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/vector_quantize_pytorch.py +82 -30
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.github/workflows/build.yml +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.github/workflows/python-publish.yml +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.github/workflows/test.yml +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.gitignore +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/LICENSE +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/examples/autoencoder.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/examples/autoencoder_fsq.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/examples/autoencoder_lfq.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/images/fsq.png +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/images/lfq.png +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/images/vq.png +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/ruff.toml +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/tests/test_latent_quantization.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/__init__.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/finite_scalar_quantization.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/latent_quantization.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/lookup_free_quantization.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/random_projection_quantizer.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/residual_fsq.py +0 -0
- {vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/vector_quantize_pytorch/residual_lfq.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: vector-quantize-pytorch
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.2
|
|
4
4
|
Summary: Vector Quantization - Pytorch
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/vector-quantize-pytorch/
|
|
6
6
|
Project-URL: Repository, https://github.com/lucidrains/vector-quantizer-pytorch
|
|
@@ -732,3 +732,14 @@ assert loss.item() >= 0
|
|
|
732
732
|
url = {https://api.semanticscholar.org/CorpusID:256901024}
|
|
733
733
|
}
|
|
734
734
|
```
|
|
735
|
+
|
|
736
|
+
```bibtex
|
|
737
|
+
@article{Huijben2024ResidualQW,
|
|
738
|
+
title = {Residual Quantization with Implicit Neural Codebooks},
|
|
739
|
+
author = {Iris Huijben and Matthijs Douze and Matthew Muckley and Ruud van Sloun and Jakob Verbeek},
|
|
740
|
+
journal = {ArXiv},
|
|
741
|
+
year = {2024},
|
|
742
|
+
volume = {abs/2401.14732},
|
|
743
|
+
url = {https://api.semanticscholar.org/CorpusID:267301189}
|
|
744
|
+
}
|
|
745
|
+
```
|
|
@@ -688,3 +688,14 @@ assert loss.item() >= 0
|
|
|
688
688
|
url = {https://api.semanticscholar.org/CorpusID:256901024}
|
|
689
689
|
}
|
|
690
690
|
```
|
|
691
|
+
|
|
692
|
+
```bibtex
|
|
693
|
+
@article{Huijben2024ResidualQW,
|
|
694
|
+
title = {Residual Quantization with Implicit Neural Codebooks},
|
|
695
|
+
author = {Iris Huijben and Matthijs Douze and Matthew Muckley and Ruud van Sloun and Jakob Verbeek},
|
|
696
|
+
journal = {ArXiv},
|
|
697
|
+
year = {2024},
|
|
698
|
+
volume = {abs/2401.14732},
|
|
699
|
+
url = {https://api.semanticscholar.org/CorpusID:267301189}
|
|
700
|
+
}
|
|
701
|
+
```
|
|
@@ -62,19 +62,31 @@ def test_vq_mask():
|
|
|
62
62
|
assert (mask_quantized[:, 512:] == 0.).all()
|
|
63
63
|
assert (mask_indices[:, 512:] == -1).all()
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
@pytest.mark.parametrize('implicit_neural_codebook', (True, False))
|
|
66
|
+
@pytest.mark.parametrize('use_cosine_sim', (True, False))
|
|
67
|
+
@pytest.mark.parametrize('train', (True, False))
|
|
68
|
+
def test_residual_vq(
|
|
69
|
+
implicit_neural_codebook,
|
|
70
|
+
use_cosine_sim,
|
|
71
|
+
train
|
|
72
|
+
):
|
|
66
73
|
from vector_quantize_pytorch import ResidualVQ
|
|
67
74
|
|
|
68
75
|
residual_vq = ResidualVQ(
|
|
69
|
-
dim =
|
|
70
|
-
num_quantizers = 8,
|
|
71
|
-
codebook_size =
|
|
76
|
+
dim = 32,
|
|
77
|
+
num_quantizers = 8,
|
|
78
|
+
codebook_size = 128,
|
|
79
|
+
implicit_neural_codebook = implicit_neural_codebook,
|
|
80
|
+
use_cosine_sim = use_cosine_sim,
|
|
72
81
|
)
|
|
73
82
|
|
|
74
|
-
x = torch.randn(1,
|
|
83
|
+
x = torch.randn(1, 256, 32)
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
residual_vq.train(train)
|
|
86
|
+
|
|
87
|
+
quantized, indices, commit_loss = residual_vq(x, freeze_codebook = train and not implicit_neural_codebook)
|
|
88
|
+
quantized_out = residual_vq.get_output_from_indices(indices)
|
|
89
|
+
assert torch.allclose(quantized, quantized_out, atol = 1e-6)
|
|
78
90
|
|
|
79
91
|
def test_residual_vq2():
|
|
80
92
|
from vector_quantize_pytorch import ResidualVQ
|
|
@@ -91,7 +103,6 @@ def test_residual_vq2():
|
|
|
91
103
|
x = torch.randn(1, 1024, 256)
|
|
92
104
|
quantized, indices, commit_loss = residual_vq(x)
|
|
93
105
|
|
|
94
|
-
|
|
95
106
|
def test_grouped_residual_vq():
|
|
96
107
|
from vector_quantize_pytorch import GroupedResidualVQ
|
|
97
108
|
|
|
@@ -22,6 +22,9 @@ from einx import get_at
|
|
|
22
22
|
def exists(val):
|
|
23
23
|
return val is not None
|
|
24
24
|
|
|
25
|
+
def first(it):
|
|
26
|
+
return it[0]
|
|
27
|
+
|
|
25
28
|
def default(val, d):
|
|
26
29
|
return val if exists(val) else d
|
|
27
30
|
|
|
@@ -34,6 +37,64 @@ def round_up_multiple(num, mult):
|
|
|
34
37
|
def is_distributed():
|
|
35
38
|
return dist.is_initialized() and dist.get_world_size() > 1
|
|
36
39
|
|
|
40
|
+
# the mlp for generating the neural implicit codebook
|
|
41
|
+
# from Huijben et al. https://arxiv.org/abs/2401.14732
|
|
42
|
+
|
|
43
|
+
class MLP(Module):
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
dim,
|
|
47
|
+
dim_hidden = None,
|
|
48
|
+
depth = 4, # they used 4 layers in the paper
|
|
49
|
+
l2norm_output = False
|
|
50
|
+
):
|
|
51
|
+
super().__init__()
|
|
52
|
+
dim_hidden = default(dim_hidden, dim)
|
|
53
|
+
|
|
54
|
+
self.proj_in = nn.Linear(2 * dim, dim)
|
|
55
|
+
|
|
56
|
+
layers = ModuleList([])
|
|
57
|
+
|
|
58
|
+
for _ in range(depth):
|
|
59
|
+
layers.append(nn.Sequential(
|
|
60
|
+
nn.Linear(dim, dim_hidden),
|
|
61
|
+
nn.SiLU(),
|
|
62
|
+
nn.Linear(dim_hidden, dim)
|
|
63
|
+
))
|
|
64
|
+
|
|
65
|
+
self.layers = layers
|
|
66
|
+
self.l2norm_output = l2norm_output
|
|
67
|
+
|
|
68
|
+
def forward(
|
|
69
|
+
self,
|
|
70
|
+
codes,
|
|
71
|
+
*,
|
|
72
|
+
condition
|
|
73
|
+
):
|
|
74
|
+
one_headed = codes.ndim == 2
|
|
75
|
+
|
|
76
|
+
if one_headed:
|
|
77
|
+
codes = rearrange(codes, 'c d -> 1 c d')
|
|
78
|
+
|
|
79
|
+
heads, num_codes, batch, seq_len = codes.shape[0], codes.shape[-2], condition.shape[0], condition.shape[-2]
|
|
80
|
+
|
|
81
|
+
codes = repeat(codes, 'h c d -> h b n c d', n = seq_len, b = batch)
|
|
82
|
+
condition = repeat(condition, 'b n d -> h b n c d', c = num_codes, h = heads)
|
|
83
|
+
|
|
84
|
+
x = torch.cat((condition, codes), dim = -1)
|
|
85
|
+
x = self.proj_in(x)
|
|
86
|
+
|
|
87
|
+
for layer in self.layers:
|
|
88
|
+
x = layer(x) + x
|
|
89
|
+
|
|
90
|
+
if self.l2norm_output:
|
|
91
|
+
x = F.normalize(x, dim = -1)
|
|
92
|
+
|
|
93
|
+
if not one_headed:
|
|
94
|
+
return x
|
|
95
|
+
|
|
96
|
+
return rearrange(x, '1 ... -> ...')
|
|
97
|
+
|
|
37
98
|
# main class
|
|
38
99
|
|
|
39
100
|
class ResidualVQ(Module):
|
|
@@ -50,7 +111,9 @@ class ResidualVQ(Module):
|
|
|
50
111
|
quantize_dropout_cutoff_index = 0,
|
|
51
112
|
quantize_dropout_multiple_of = 1,
|
|
52
113
|
accept_image_fmap = False,
|
|
53
|
-
|
|
114
|
+
implicit_neural_codebook = False, # QINCo from https://arxiv.org/abs/2401.14732
|
|
115
|
+
mlp_kwargs: dict = dict(),
|
|
116
|
+
**vq_kwargs
|
|
54
117
|
):
|
|
55
118
|
super().__init__()
|
|
56
119
|
assert heads == 1, 'residual vq is not compatible with multi-headed codes'
|
|
@@ -65,7 +128,16 @@ class ResidualVQ(Module):
|
|
|
65
128
|
self.num_quantizers = num_quantizers
|
|
66
129
|
|
|
67
130
|
self.accept_image_fmap = accept_image_fmap
|
|
68
|
-
|
|
131
|
+
|
|
132
|
+
self.implicit_neural_codebook = implicit_neural_codebook
|
|
133
|
+
|
|
134
|
+
if implicit_neural_codebook:
|
|
135
|
+
vq_kwargs.update(
|
|
136
|
+
learnable_codebook = True,
|
|
137
|
+
ema_update = False
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
self.layers = ModuleList([VectorQuantize(dim = codebook_dim, codebook_dim = codebook_dim, accept_image_fmap = accept_image_fmap, **vq_kwargs) for _ in range(num_quantizers)])
|
|
69
141
|
|
|
70
142
|
assert all([not vq.has_projections for vq in self.layers])
|
|
71
143
|
|
|
@@ -76,6 +148,12 @@ class ResidualVQ(Module):
|
|
|
76
148
|
self.quantize_dropout_cutoff_index = quantize_dropout_cutoff_index
|
|
77
149
|
self.quantize_dropout_multiple_of = quantize_dropout_multiple_of # encodec paper proposes structured dropout, believe this was set to 4
|
|
78
150
|
|
|
151
|
+
# setting up the MLPs for implicit neural codebooks
|
|
152
|
+
|
|
153
|
+
self.mlps = ModuleList([MLP(dim = codebook_dim, l2norm_output = first(self.layers).use_cosine_sim, **mlp_kwargs) for _ in range(num_quantizers - 1)])
|
|
154
|
+
|
|
155
|
+
# sharing codebook logic
|
|
156
|
+
|
|
79
157
|
if not shared_codebook:
|
|
80
158
|
return
|
|
81
159
|
|
|
@@ -120,7 +198,31 @@ class ResidualVQ(Module):
|
|
|
120
198
|
mask = indices == -1.
|
|
121
199
|
indices = indices.masked_fill(mask, 0) # have it fetch a dummy code to be masked out later
|
|
122
200
|
|
|
123
|
-
|
|
201
|
+
if not self.implicit_neural_codebook:
|
|
202
|
+
# gather all the codes
|
|
203
|
+
|
|
204
|
+
all_codes = get_at('q [c] d, b n q -> q b n d', self.codebooks, indices)
|
|
205
|
+
|
|
206
|
+
else:
|
|
207
|
+
# else if using implicit neural codebook, codes will need to be derived layer by layer
|
|
208
|
+
|
|
209
|
+
code_transform_mlps = (None, *self.mlps)
|
|
210
|
+
|
|
211
|
+
all_codes = []
|
|
212
|
+
quantized_out = 0.
|
|
213
|
+
|
|
214
|
+
for codes, indices, maybe_transform_mlp in zip(self.codebooks, indices.unbind(dim = -1), code_transform_mlps):
|
|
215
|
+
|
|
216
|
+
if exists(maybe_transform_mlp):
|
|
217
|
+
codes = maybe_transform_mlp(codes, condition = quantized_out)
|
|
218
|
+
layer_codes = get_at('b n [c] d, b n -> b n d', codes, indices)
|
|
219
|
+
else:
|
|
220
|
+
layer_codes = get_at('[c] d, b n -> b n d', codes, indices)
|
|
221
|
+
|
|
222
|
+
all_codes.append(layer_codes)
|
|
223
|
+
quantized_out += layer_codes
|
|
224
|
+
|
|
225
|
+
all_codes = torch.stack(all_codes)
|
|
124
226
|
|
|
125
227
|
# mask out any codes that were dropout-ed
|
|
126
228
|
|
|
@@ -195,9 +297,16 @@ class ResidualVQ(Module):
|
|
|
195
297
|
null_indices = torch.full(null_indices_shape, -1., device = device, dtype = torch.long)
|
|
196
298
|
null_loss = torch.full((1,), 0., device = device, dtype = x.dtype)
|
|
197
299
|
|
|
300
|
+
# setup the mlps for implicit neural codebook
|
|
301
|
+
|
|
302
|
+
maybe_code_transforms = (None,) * len(self.layers)
|
|
303
|
+
|
|
304
|
+
if self.implicit_neural_codebook:
|
|
305
|
+
maybe_code_transforms = (None, *self.mlps)
|
|
306
|
+
|
|
198
307
|
# go through the layers
|
|
199
308
|
|
|
200
|
-
for quantizer_index,
|
|
309
|
+
for quantizer_index, (vq, maybe_mlp) in enumerate(zip(self.layers, maybe_code_transforms)):
|
|
201
310
|
|
|
202
311
|
if should_quantize_dropout and quantizer_index > rand_quantize_dropout_index:
|
|
203
312
|
all_indices.append(null_indices)
|
|
@@ -208,12 +317,20 @@ class ResidualVQ(Module):
|
|
|
208
317
|
if return_loss:
|
|
209
318
|
layer_indices = indices[..., quantizer_index]
|
|
210
319
|
|
|
211
|
-
|
|
320
|
+
# setup the transform code function to be passed into VectorQuantize forward
|
|
321
|
+
|
|
322
|
+
if exists(maybe_mlp):
|
|
323
|
+
maybe_mlp = partial(maybe_mlp, condition = quantized_out)
|
|
324
|
+
|
|
325
|
+
# vector quantize forward
|
|
326
|
+
|
|
327
|
+
quantized, *rest = vq(
|
|
212
328
|
residual,
|
|
213
329
|
mask = mask,
|
|
214
330
|
indices = layer_indices,
|
|
215
331
|
sample_codebook_temp = sample_codebook_temp,
|
|
216
|
-
freeze_codebook = freeze_codebook
|
|
332
|
+
freeze_codebook = freeze_codebook,
|
|
333
|
+
codebook_transform_fn = maybe_mlp
|
|
217
334
|
)
|
|
218
335
|
|
|
219
336
|
residual = residual - quantized.detach()
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from functools import partial, cache
|
|
2
4
|
from collections import namedtuple
|
|
3
5
|
|
|
@@ -59,10 +61,13 @@ def ema_inplace(old, new, decay):
|
|
|
59
61
|
old.mul_(decay).add_(new * (1 - decay))
|
|
60
62
|
|
|
61
63
|
def pack_one(t, pattern):
|
|
62
|
-
|
|
64
|
+
packed, ps = pack([t], pattern)
|
|
65
|
+
|
|
66
|
+
def unpack_one(to_unpack, unpack_pattern = None):
|
|
67
|
+
unpacked, = unpack(to_unpack, ps, default(unpack_pattern, pattern))
|
|
68
|
+
return unpacked
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
return unpack(t, ps, pattern)[0]
|
|
70
|
+
return packed, unpack_one
|
|
66
71
|
|
|
67
72
|
def lens_to_mask(lens, max_length):
|
|
68
73
|
seq = torch.arange(max_length, device = lens.device)
|
|
@@ -240,12 +245,6 @@ def kmeans(
|
|
|
240
245
|
|
|
241
246
|
return means, bins
|
|
242
247
|
|
|
243
|
-
def batched_embedding(indices, embeds):
|
|
244
|
-
batch, dim = indices.shape[1], embeds.shape[-1]
|
|
245
|
-
indices = repeat(indices, 'h b n -> h b n d', d = dim)
|
|
246
|
-
embeds = repeat(embeds, 'h c d -> h b c d', b = batch)
|
|
247
|
-
return embeds.gather(2, indices)
|
|
248
|
-
|
|
249
248
|
# distributed helpers
|
|
250
249
|
|
|
251
250
|
@cache
|
|
@@ -465,7 +464,8 @@ class EuclideanCodebook(Module):
|
|
|
465
464
|
x,
|
|
466
465
|
sample_codebook_temp = None,
|
|
467
466
|
mask = None,
|
|
468
|
-
freeze_codebook = False
|
|
467
|
+
freeze_codebook = False,
|
|
468
|
+
codebook_transform_fn: Callable | None = None
|
|
469
469
|
):
|
|
470
470
|
needs_codebook_dim = x.ndim < 4
|
|
471
471
|
sample_codebook_temp = default(sample_codebook_temp, self.sample_codebook_temp)
|
|
@@ -476,7 +476,7 @@ class EuclideanCodebook(Module):
|
|
|
476
476
|
x = rearrange(x, '... -> 1 ...')
|
|
477
477
|
|
|
478
478
|
dtype = x.dtype
|
|
479
|
-
flatten,
|
|
479
|
+
flatten, unpack_one = pack_one(x, 'h * d')
|
|
480
480
|
|
|
481
481
|
if exists(mask):
|
|
482
482
|
mask = repeat(mask, 'b n -> c (b h n)', c = flatten.shape[0], h = flatten.shape[-2] // (mask.shape[0] * mask.shape[1]))
|
|
@@ -486,24 +486,51 @@ class EuclideanCodebook(Module):
|
|
|
486
486
|
if self.affine_param:
|
|
487
487
|
self.update_affine(flatten, self.embed, mask = mask)
|
|
488
488
|
|
|
489
|
-
|
|
489
|
+
# affine params
|
|
490
490
|
|
|
491
491
|
if self.affine_param:
|
|
492
492
|
codebook_std = self.codebook_variance.clamp(min = 1e-5).sqrt()
|
|
493
493
|
batch_std = self.batch_variance.clamp(min = 1e-5).sqrt()
|
|
494
494
|
embed = (embed - self.codebook_mean) * (batch_std / codebook_std) + self.batch_mean
|
|
495
495
|
|
|
496
|
-
|
|
496
|
+
# get maybe learnable codes
|
|
497
|
+
|
|
498
|
+
embed = self.embed if self.learnable_codebook else self.embed.detach()
|
|
499
|
+
|
|
500
|
+
# handle maybe implicit neural codebook
|
|
501
|
+
# and calculate distance
|
|
502
|
+
|
|
503
|
+
if exists(codebook_transform_fn):
|
|
504
|
+
transformed_embed = codebook_transform_fn(embed)
|
|
505
|
+
transformed_embed = rearrange(transformed_embed, 'h b n c d -> h (b n) c d')
|
|
506
|
+
broadcastable_input = rearrange(flatten, '... d -> ... 1 d')
|
|
507
|
+
|
|
508
|
+
dist = -F.pairwise_distance(broadcastable_input, transformed_embed)
|
|
509
|
+
else:
|
|
510
|
+
dist = -cdist(flatten, embed)
|
|
511
|
+
|
|
512
|
+
# sample or argmax depending on temperature
|
|
497
513
|
|
|
498
514
|
embed_ind, embed_onehot = self.gumbel_sample(dist, dim = -1, temperature = sample_codebook_temp, training = self.training)
|
|
499
515
|
|
|
500
|
-
embed_ind = unpack_one(embed_ind,
|
|
516
|
+
embed_ind = unpack_one(embed_ind, 'h *')
|
|
517
|
+
|
|
518
|
+
if exists(codebook_transform_fn):
|
|
519
|
+
transformed_embed = unpack_one(transformed_embed, 'h * c d')
|
|
501
520
|
|
|
502
521
|
if self.training:
|
|
503
|
-
unpacked_onehot = unpack_one(embed_onehot,
|
|
504
|
-
|
|
522
|
+
unpacked_onehot = unpack_one(embed_onehot, 'h * c')
|
|
523
|
+
|
|
524
|
+
if exists(codebook_transform_fn):
|
|
525
|
+
quantize = einsum('h b n c, h b n c d -> h b n d', unpacked_onehot, transformed_embed)
|
|
526
|
+
else:
|
|
527
|
+
quantize = einsum('h b n c, h c d -> h b n d', unpacked_onehot, embed)
|
|
528
|
+
|
|
505
529
|
else:
|
|
506
|
-
|
|
530
|
+
if exists(codebook_transform_fn):
|
|
531
|
+
quantize = einx.get_at('h b n [c] d, h b n -> h b n d', transformed_embed, embed_ind)
|
|
532
|
+
else:
|
|
533
|
+
quantize = einx.get_at('h [c] d, h b n -> h b n d', embed, embed_ind)
|
|
507
534
|
|
|
508
535
|
if self.training and self.ema_update and not freeze_codebook:
|
|
509
536
|
|
|
@@ -533,7 +560,7 @@ class EuclideanCodebook(Module):
|
|
|
533
560
|
if needs_codebook_dim:
|
|
534
561
|
quantize, embed_ind = map(lambda t: rearrange(t, '1 ... -> ...'), (quantize, embed_ind))
|
|
535
562
|
|
|
536
|
-
dist = unpack_one(dist,
|
|
563
|
+
dist = unpack_one(dist, 'h * d')
|
|
537
564
|
|
|
538
565
|
return quantize, embed_ind, dist
|
|
539
566
|
|
|
@@ -650,7 +677,8 @@ class CosineSimCodebook(Module):
|
|
|
650
677
|
x,
|
|
651
678
|
sample_codebook_temp = None,
|
|
652
679
|
mask = None,
|
|
653
|
-
freeze_codebook = False
|
|
680
|
+
freeze_codebook = False,
|
|
681
|
+
codebook_transform_fn: Callable | None = None
|
|
654
682
|
):
|
|
655
683
|
needs_codebook_dim = x.ndim < 4
|
|
656
684
|
sample_codebook_temp = default(sample_codebook_temp, self.sample_codebook_temp)
|
|
@@ -662,7 +690,7 @@ class CosineSimCodebook(Module):
|
|
|
662
690
|
|
|
663
691
|
dtype = x.dtype
|
|
664
692
|
|
|
665
|
-
flatten,
|
|
693
|
+
flatten, unpack_one = pack_one(x, 'h * d')
|
|
666
694
|
|
|
667
695
|
if exists(mask):
|
|
668
696
|
mask = repeat(mask, 'b n -> c (b h n)', c = flatten.shape[0], h = flatten.shape[-2] // (mask.shape[0] * mask.shape[1]))
|
|
@@ -671,16 +699,37 @@ class CosineSimCodebook(Module):
|
|
|
671
699
|
|
|
672
700
|
embed = self.embed if self.learnable_codebook else self.embed.detach()
|
|
673
701
|
|
|
674
|
-
|
|
702
|
+
# handle maybe implicit neural codebook
|
|
703
|
+
# and compute cosine sim distance
|
|
704
|
+
|
|
705
|
+
if exists(codebook_transform_fn):
|
|
706
|
+
transformed_embed = codebook_transform_fn(embed)
|
|
707
|
+
transformed_embed = rearrange(transformed_embed, 'h b n c d -> h (b n) c d')
|
|
708
|
+
transformed_embed = l2norm(transformed_embed)
|
|
709
|
+
|
|
710
|
+
dist = einsum('h n d, h n c d -> h n c', flatten, transformed_embed)
|
|
711
|
+
else:
|
|
712
|
+
dist = einsum('h n d, h c d -> h n c', flatten, embed)
|
|
675
713
|
|
|
676
714
|
embed_ind, embed_onehot = self.gumbel_sample(dist, dim = -1, temperature = sample_codebook_temp, training = self.training)
|
|
677
|
-
embed_ind = unpack_one(embed_ind,
|
|
715
|
+
embed_ind = unpack_one(embed_ind, 'h *')
|
|
716
|
+
|
|
717
|
+
if exists(codebook_transform_fn):
|
|
718
|
+
transformed_embed = unpack_one(transformed_embed, 'h * c d')
|
|
678
719
|
|
|
679
720
|
if self.training:
|
|
680
|
-
unpacked_onehot = unpack_one(embed_onehot,
|
|
681
|
-
|
|
721
|
+
unpacked_onehot = unpack_one(embed_onehot, 'h * c')
|
|
722
|
+
|
|
723
|
+
if exists(codebook_transform_fn):
|
|
724
|
+
quantize = einsum('h b n c, h b n c d -> h b n d', unpacked_onehot, transformed_embed)
|
|
725
|
+
else:
|
|
726
|
+
quantize = einsum('h b n c, h c d -> h b n d', unpacked_onehot, embed)
|
|
727
|
+
|
|
682
728
|
else:
|
|
683
|
-
|
|
729
|
+
if exists(codebook_transform_fn):
|
|
730
|
+
quantize = einx.get_at('h b n [c] d, h b n -> h b n d', transformed_embed, embed_ind)
|
|
731
|
+
else:
|
|
732
|
+
quantize = einx.get_at('h [c] d, h b n -> h b n d', embed, embed_ind)
|
|
684
733
|
|
|
685
734
|
if self.training and self.ema_update and not freeze_codebook:
|
|
686
735
|
if exists(mask):
|
|
@@ -702,13 +751,13 @@ class CosineSimCodebook(Module):
|
|
|
702
751
|
embed_normalized = self.embed_avg / rearrange(cluster_size, '... -> ... 1')
|
|
703
752
|
embed_normalized = l2norm(embed_normalized)
|
|
704
753
|
|
|
705
|
-
self.embed.data.copy_(
|
|
754
|
+
self.embed.data.copy_(embed_normalized)
|
|
706
755
|
self.expire_codes_(x)
|
|
707
756
|
|
|
708
757
|
if needs_codebook_dim:
|
|
709
758
|
quantize, embed_ind = map(lambda t: rearrange(t, '1 ... -> ...'), (quantize, embed_ind))
|
|
710
759
|
|
|
711
|
-
dist = unpack_one(dist,
|
|
760
|
+
dist = unpack_one(dist, 'h * d')
|
|
712
761
|
return quantize, embed_ind, dist
|
|
713
762
|
|
|
714
763
|
# main class
|
|
@@ -845,6 +894,7 @@ class VectorQuantize(Module):
|
|
|
845
894
|
affine_param_codebook_decay = affine_param_codebook_decay,
|
|
846
895
|
)
|
|
847
896
|
|
|
897
|
+
self.use_cosine_sim = use_cosine_sim
|
|
848
898
|
self._codebook = codebook_class(**codebook_kwargs)
|
|
849
899
|
|
|
850
900
|
self.in_place_codebook_optimizer = in_place_codebook_optimizer(self._codebook.parameters()) if exists(in_place_codebook_optimizer) else None
|
|
@@ -882,7 +932,7 @@ class VectorQuantize(Module):
|
|
|
882
932
|
if not is_multiheaded:
|
|
883
933
|
codes = codebook[indices]
|
|
884
934
|
else:
|
|
885
|
-
indices,
|
|
935
|
+
indices, unpack_one = pack_one(indices, 'b * h')
|
|
886
936
|
indices = rearrange(indices, 'b n h -> b h n')
|
|
887
937
|
|
|
888
938
|
indices = repeat(indices, 'b h n -> b h n d', d = codebook.shape[-1])
|
|
@@ -890,7 +940,7 @@ class VectorQuantize(Module):
|
|
|
890
940
|
|
|
891
941
|
codes = codebook.gather(2, indices)
|
|
892
942
|
codes = rearrange(codes, 'b h n d -> b n (h d)')
|
|
893
|
-
codes = unpack_one(codes,
|
|
943
|
+
codes = unpack_one(codes, 'b * d')
|
|
894
944
|
|
|
895
945
|
if not self.channel_last:
|
|
896
946
|
codes = rearrange(codes, 'b ... d -> b d ...')
|
|
@@ -910,6 +960,7 @@ class VectorQuantize(Module):
|
|
|
910
960
|
sample_codebook_temp = None,
|
|
911
961
|
freeze_codebook = False,
|
|
912
962
|
return_loss_breakdown = False,
|
|
963
|
+
codebook_transform_fn: Callable | None = None
|
|
913
964
|
):
|
|
914
965
|
orig_input = x
|
|
915
966
|
|
|
@@ -962,7 +1013,8 @@ class VectorQuantize(Module):
|
|
|
962
1013
|
codebook_forward_kwargs = dict(
|
|
963
1014
|
sample_codebook_temp = sample_codebook_temp,
|
|
964
1015
|
mask = mask,
|
|
965
|
-
freeze_codebook = freeze_codebook
|
|
1016
|
+
freeze_codebook = freeze_codebook,
|
|
1017
|
+
codebook_transform_fn = codebook_transform_fn
|
|
966
1018
|
)
|
|
967
1019
|
|
|
968
1020
|
# quantize
|
{vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.github/workflows/build.yml
RENAMED
|
File without changes
|
|
File without changes
|
{vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/.github/workflows/test.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/examples/autoencoder_fsq.py
RENAMED
|
File without changes
|
{vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/examples/autoencoder_lfq.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vector_quantize_pytorch-1.15.6 → vector_quantize_pytorch-1.16.2}/tests/test_latent_quantization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|