vector-quantize-pytorch 1.22.18__tar.gz → 1.23.4__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.
Files changed (32) hide show
  1. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/PKG-INFO +1 -1
  2. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/pyproject.toml +1 -1
  3. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/tests/test_readme.py +27 -0
  4. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/finite_scalar_quantization.py +4 -1
  5. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/vector_quantize_pytorch.py +64 -19
  6. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/.github/workflows/build.yml +0 -0
  7. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/.github/workflows/python-publish.yml +0 -0
  8. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/.github/workflows/test.yml +0 -0
  9. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/.gitignore +0 -0
  10. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/LICENSE +0 -0
  11. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/README.md +0 -0
  12. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/examples/autoencoder.py +0 -0
  13. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/examples/autoencoder_fsq.py +0 -0
  14. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/examples/autoencoder_lfq.py +0 -0
  15. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/examples/autoencoder_sim_vq.py +0 -0
  16. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/images/fsq.png +0 -0
  17. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/images/lfq.png +0 -0
  18. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/images/simvq.png +0 -0
  19. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/images/vq.png +0 -0
  20. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/ruff.toml +0 -0
  21. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/tests/test_latent_quantization.py +0 -0
  22. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/tests/test_lfq.py +0 -0
  23. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/__init__.py +0 -0
  24. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/latent_quantization.py +0 -0
  25. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/lookup_free_quantization.py +0 -0
  26. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/random_projection_quantizer.py +0 -0
  27. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/residual_fsq.py +0 -0
  28. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/residual_lfq.py +0 -0
  29. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/residual_sim_vq.py +0 -0
  30. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/residual_vq.py +0 -0
  31. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/sim_vq.py +0 -0
  32. {vector_quantize_pytorch-1.22.18 → vector_quantize_pytorch-1.23.4}/vector_quantize_pytorch/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vector-quantize-pytorch
3
- Version: 1.22.18
3
+ Version: 1.23.4
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vector-quantize-pytorch"
3
- version = "1.22.18"
3
+ version = "1.23.4"
4
4
  description = "Vector Quantization - Pytorch"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -434,3 +434,30 @@ def test_vq_custom_ema_update_weighting(
434
434
 
435
435
  assert torch.allclose(codebook_before[did_not_update], codebook_after[did_not_update], atol = 1e-6)
436
436
  assert (codebook_before[did_update] != codebook_after[did_update]).all()
437
+
438
+ def test_accum_ema_update():
439
+ from vector_quantize_pytorch import VectorQuantize
440
+
441
+ vq = VectorQuantize(
442
+ dim = 256,
443
+ use_cosine_sim = True,
444
+ codebook_dim = 128,
445
+ codebook_size = 8, # codebook size
446
+ decay = 0.8, # the exponential moving average decay, lower means the dictionary will change faster
447
+ commitment_weight = 1., # the weight on the commitment loss
448
+ )
449
+
450
+ x = torch.randn(16, 1024, 256)
451
+
452
+ codebook_before = vq.codebook.clone()
453
+
454
+ vq.train()
455
+
456
+ _ = vq(x, accum_ema_update = True)
457
+ _ = vq(x, accum_ema_update = True)
458
+
459
+ assert torch.allclose(codebook_before, vq.codebook, atol = 1e-6)
460
+
461
+ _ = vq(x)
462
+
463
+ assert not torch.allclose(codebook_before, vq.codebook, atol = 1e-6)
@@ -61,7 +61,7 @@ def floor_ste(z):
61
61
  class FSQ(Module):
62
62
  def __init__(
63
63
  self,
64
- levels: list[int],
64
+ levels: list[int] | tuple[int, ...],
65
65
  dim: int | None = None,
66
66
  num_codebooks = 1,
67
67
  keep_num_codebooks_dim: bool | None = None,
@@ -76,6 +76,9 @@ class FSQ(Module):
76
76
  ):
77
77
  super().__init__()
78
78
 
79
+ if isinstance(levels, tuple):
80
+ levels = list(levels)
81
+
79
82
  _levels = tensor(levels, dtype = int32)
80
83
  self.register_buffer('_levels', _levels, persistent = False)
81
84
 
@@ -61,7 +61,22 @@ def log(t, eps = 1e-20):
61
61
  def entropy(prob, eps = 1e-5):
62
62
  return (-prob * log(prob, eps = eps)).sum(dim = -1)
63
63
 
64
+ def accum_grad_(t, grad):
65
+ if exists(t.grad):
66
+ t.grad.add_(grad)
67
+ else:
68
+ t.grad = grad.clone().detach()
69
+
64
70
  def ema_inplace(old, new, decay, weight = None):
71
+
72
+ # if old.grad is populated, add it to new and set it to None
73
+
74
+ if exists(old.grad):
75
+ new.add_(old.grad)
76
+ old.grad = None
77
+
78
+ # take care of custom weighting
79
+
65
80
  weight = default(weight, 1.)
66
81
 
67
82
  if is_tensor(weight):
@@ -71,7 +86,7 @@ def ema_inplace(old, new, decay, weight = None):
71
86
  assert weight.ndim == 2 and weight.shape == old.shape[:2]
72
87
  weight = append_dims_to(weight, old.ndim)
73
88
 
74
- old.lerp_(new, (1. - decay) * weight)
89
+ old.data.lerp_(new, (1. - decay) * weight)
75
90
 
76
91
  def pack_one(t, pattern):
77
92
  packed, ps = pack([t], pattern)
@@ -258,12 +273,14 @@ def efficient_rotation_trick_transform(u, q, e):
258
273
  e = rearrange(e, 'b d -> b 1 d')
259
274
  w = l2norm(u + q, dim = 1).detach()
260
275
 
261
- return (
276
+ out = (
262
277
  e -
263
278
  2 * (e @ rearrange(w, 'b d -> b d 1') @ rearrange(w, 'b d -> b 1 d')) +
264
279
  2 * (e @ rearrange(u, 'b d -> b d 1').detach() @ rearrange(q, 'b d -> b 1 d').detach())
265
280
  )
266
281
 
282
+ return rearrange(out, '... 1 -> ...')
283
+
267
284
  def rotate_to(src, tgt):
268
285
  # rotation trick STE (https://arxiv.org/abs/2410.06424) to get gradients through VQ layer.
269
286
  src, inverse = pack_one(src, '* d')
@@ -276,7 +293,7 @@ def rotate_to(src, tgt):
276
293
  safe_div(src, norm_src),
277
294
  safe_div(tgt, norm_tgt),
278
295
  src
279
- ).squeeze()
296
+ )
280
297
 
281
298
  rotated = rotated_tgt * safe_div(norm_tgt, norm_src).detach()
282
299
 
@@ -511,7 +528,8 @@ class EuclideanCodebook(Module):
511
528
  mask = None,
512
529
  freeze_codebook = False,
513
530
  codebook_transform_fn: Callable | None = None,
514
- ema_update_weight: Tensor | Callable | None = None
531
+ ema_update_weight: Tensor | Callable | None = None,
532
+ accum_ema_update = False
515
533
  ):
516
534
  needs_codebook_dim = x.ndim < 4
517
535
  sample_codebook_temp = default(sample_codebook_temp, self.sample_codebook_temp)
@@ -603,12 +621,16 @@ class EuclideanCodebook(Module):
603
621
  if callable(ema_update_weight):
604
622
  ema_update_weight = ema_update_weight(embed_sum, cluster_size)
605
623
 
606
- ema_inplace(self.cluster_size.data, cluster_size, self.decay, ema_update_weight)
607
- ema_inplace(self.embed_avg.data, embed_sum, self.decay, ema_update_weight)
624
+ if accum_ema_update:
625
+ accum_grad_(self.cluster_size, cluster_size)
626
+ accum_grad_(self.embed_avg, embed_sum)
627
+ else:
628
+ ema_inplace(self.cluster_size, cluster_size, self.decay, ema_update_weight)
629
+ ema_inplace(self.embed_avg, embed_sum, self.decay, ema_update_weight)
608
630
 
609
- if not self.manual_ema_update:
610
- self.update_ema()
611
- self.expire_codes_(x)
631
+ if not self.manual_ema_update:
632
+ self.update_ema()
633
+ self.expire_codes_(x)
612
634
 
613
635
  if needs_codebook_dim:
614
636
  quantize, embed_ind = map(lambda t: rearrange(t, '1 ... -> ...'), (quantize, embed_ind))
@@ -743,7 +765,8 @@ class CosineSimCodebook(Module):
743
765
  mask = None,
744
766
  freeze_codebook = False,
745
767
  codebook_transform_fn: Callable | None = None,
746
- ema_update_weight: Tensor | None = None
768
+ ema_update_weight: Tensor | None = None,
769
+ accum_ema_update = False
747
770
  ):
748
771
  needs_codebook_dim = x.ndim < 4
749
772
  sample_codebook_temp = default(sample_codebook_temp, self.sample_codebook_temp)
@@ -819,12 +842,17 @@ class CosineSimCodebook(Module):
819
842
  if callable(ema_update_weight):
820
843
  ema_update_weight = ema_update_weight(embed_sum, bins)
821
844
 
822
- ema_inplace(self.cluster_size.data, bins, self.decay, ema_update_weight)
823
- ema_inplace(self.embed_avg.data, embed_sum, self.decay, ema_update_weight)
845
+ if accum_ema_update:
846
+ accum_grad_(self.cluster_size, bins)
847
+ accum_grad_(self.embed_avg, embed_sum)
848
+ else:
849
+
850
+ ema_inplace(self.cluster_size, bins, self.decay, ema_update_weight)
851
+ ema_inplace(self.embed_avg, embed_sum, self.decay, ema_update_weight)
824
852
 
825
- if not self.manual_ema_update:
826
- self.update_ema()
827
- self.expire_codes_(x)
853
+ if not self.manual_ema_update:
854
+ self.update_ema()
855
+ self.expire_codes_(x)
828
856
 
829
857
  if needs_codebook_dim:
830
858
  quantize, embed_ind = map(lambda t: rearrange(t, '1 ... -> ...'), (quantize, embed_ind))
@@ -870,7 +898,7 @@ class VectorQuantize(Module):
870
898
  stochastic_sample_codes = False,
871
899
  sample_codebook_temp = 1.,
872
900
  straight_through = False,
873
- rotation_trick = True, # Propagate grads through VQ layer w/ rotation trick: https://arxiv.org/abs/2410.06424 by @cfifty
901
+ rotation_trick = None, # Propagate grads through VQ layer w/ rotation trick: https://arxiv.org/abs/2410.06424 by @cfifty
874
902
  sync_codebook = None,
875
903
  sync_affine_param = False,
876
904
  ema_update = True,
@@ -885,6 +913,8 @@ class VectorQuantize(Module):
885
913
  return_zeros_for_masked_padding = True
886
914
  ):
887
915
  super().__init__()
916
+ rotation_trick = default(rotation_trick, dim > 1) # only use rotation trick if feature dimension greater than 1
917
+
888
918
  self.dim = dim
889
919
  self.heads = heads
890
920
  self.separate_codebook_per_head = separate_codebook_per_head
@@ -1037,6 +1067,19 @@ class VectorQuantize(Module):
1037
1067
  if not exists(self.in_place_codebook_optimizer):
1038
1068
  return
1039
1069
 
1070
+ # handle ddp, thanks to @gdoras
1071
+
1072
+ if self._codebook.use_ddp:
1073
+
1074
+ for param in self._codebook.parameters():
1075
+ if not exists(param.grad):
1076
+ continue
1077
+
1078
+ distributed.all_reduce(param.grad)
1079
+ param.grad /= distributed.get_world_size()
1080
+
1081
+ # optimizer step
1082
+
1040
1083
  self.in_place_codebook_optimizer.step()
1041
1084
  self.in_place_codebook_optimizer.zero_grad()
1042
1085
 
@@ -1062,7 +1105,8 @@ class VectorQuantize(Module):
1062
1105
  freeze_codebook = None,
1063
1106
  return_loss_breakdown = False,
1064
1107
  codebook_transform_fn: Callable | None = None,
1065
- ema_update_weight: Tensor | None = None
1108
+ ema_update_weight: Tensor | None = None,
1109
+ accum_ema_update = False
1066
1110
  ):
1067
1111
  orig_input, input_requires_grad = x, x.requires_grad
1068
1112
 
@@ -1119,7 +1163,8 @@ class VectorQuantize(Module):
1119
1163
  mask = mask,
1120
1164
  freeze_codebook = freeze_codebook,
1121
1165
  codebook_transform_fn = codebook_transform_fn,
1122
- ema_update_weight = ema_update_weight
1166
+ ema_update_weight = ema_update_weight,
1167
+ accum_ema_update = accum_ema_update
1123
1168
  )
1124
1169
 
1125
1170
  # quantize
@@ -1222,7 +1267,7 @@ class VectorQuantize(Module):
1222
1267
  # calculate codebook diversity loss (negative of entropy) if needed
1223
1268
 
1224
1269
  if self.has_codebook_diversity_loss:
1225
- prob = (-distances * self.codebook_diversity_temperature).softmax(dim = -1)
1270
+ prob = (distances * self.codebook_diversity_temperature).softmax(dim = -1)
1226
1271
  avg_prob = reduce(prob, '... n l -> n l', 'mean')
1227
1272
  codebook_diversity_loss = -entropy(avg_prob).mean()
1228
1273