vector-quantize-pytorch 1.24.2__tar.gz → 1.25.0__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 (33) hide show
  1. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/PKG-INFO +14 -1
  2. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/README.md +13 -0
  3. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/pyproject.toml +1 -1
  4. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/__init__.py +2 -0
  5. vector_quantize_pytorch-1.25.0/vector_quantize_pytorch/binary_mapper.py +145 -0
  6. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/.github/workflows/build.yml +0 -0
  7. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/.github/workflows/python-publish.yml +0 -0
  8. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/.github/workflows/test.yml +0 -0
  9. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/.gitignore +0 -0
  10. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/LICENSE +0 -0
  11. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/examples/autoencoder.py +0 -0
  12. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/examples/autoencoder_fsq.py +0 -0
  13. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/examples/autoencoder_lfq.py +0 -0
  14. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/examples/autoencoder_sim_vq.py +0 -0
  15. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/images/fsq.png +0 -0
  16. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/images/lfq.png +0 -0
  17. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/images/simvq.png +0 -0
  18. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/images/vq.png +0 -0
  19. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/ruff.toml +0 -0
  20. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/tests/test_latent_quantization.py +0 -0
  21. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/tests/test_lfq.py +0 -0
  22. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/tests/test_readme.py +0 -0
  23. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/finite_scalar_quantization.py +0 -0
  24. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/latent_quantization.py +0 -0
  25. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/lookup_free_quantization.py +0 -0
  26. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/random_projection_quantizer.py +0 -0
  27. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/residual_fsq.py +0 -0
  28. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/residual_lfq.py +0 -0
  29. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/residual_sim_vq.py +0 -0
  30. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/residual_vq.py +0 -0
  31. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/sim_vq.py +0 -0
  32. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/utils.py +0 -0
  33. {vector_quantize_pytorch-1.24.2 → vector_quantize_pytorch-1.25.0}/vector_quantize_pytorch/vector_quantize_pytorch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vector-quantize-pytorch
3
- Version: 1.24.2
3
+ Version: 1.25.0
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
@@ -835,3 +835,16 @@ assert loss.item() >= 0
835
835
  url = {https://arxiv.org/abs/2509.26469},
836
836
  }
837
837
  ```
838
+
839
+ ```bibtex
840
+ @misc{fleuret2025freetransformer,
841
+ title = {The Free Transformer},
842
+ author = {François Fleuret},
843
+ year = {2025},
844
+ eprint = {2510.17558},
845
+ archivePrefix = {arXiv},
846
+ primaryClass = {cs.LG},
847
+ url = {https://arxiv.org/abs/2510.17558},
848
+ }
849
+ ```
850
+
@@ -791,3 +791,16 @@ assert loss.item() >= 0
791
791
  url = {https://arxiv.org/abs/2509.26469},
792
792
  }
793
793
  ```
794
+
795
+ ```bibtex
796
+ @misc{fleuret2025freetransformer,
797
+ title = {The Free Transformer},
798
+ author = {François Fleuret},
799
+ year = {2025},
800
+ eprint = {2510.17558},
801
+ archivePrefix = {arXiv},
802
+ primaryClass = {cs.LG},
803
+ url = {https://arxiv.org/abs/2510.17558},
804
+ }
805
+ ```
806
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vector-quantize-pytorch"
3
- version = "1.24.2"
3
+ version = "1.25.0"
4
4
  description = "Vector Quantization - Pytorch"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -10,4 +10,6 @@ from vector_quantize_pytorch.latent_quantization import LatentQuantize
10
10
  from vector_quantize_pytorch.sim_vq import SimVQ
11
11
  from vector_quantize_pytorch.residual_sim_vq import ResidualSimVQ
12
12
 
13
+ from vector_quantize_pytorch.binary_mapper import BinaryMapper
14
+
13
15
  from vector_quantize_pytorch.utils import Sequential
@@ -0,0 +1,145 @@
1
+ from __future__ import annotations
2
+
3
+ # proposed in https://arxiv.org/abs/2510.17558 as a more stable alternative to VAE by François Fleuret
4
+
5
+ from math import log
6
+
7
+ import torch
8
+ from torch import nn, tensor, arange
9
+ import torch.nn.functional as F
10
+ from torch.nn import Module
11
+
12
+ from einops import einsum, pack, unpack
13
+
14
+ # constants
15
+
16
+ NAT = log(2)
17
+
18
+ # helper functions
19
+
20
+ def exists(v):
21
+ return v is not None
22
+
23
+ def default(v, d):
24
+ return v if exists(v) else d
25
+
26
+ # tensor helpers
27
+
28
+ def binary_entropy(logits):
29
+ prob = logits.sigmoid()
30
+ not_prob = 1. - prob
31
+ return -(prob * F.logsigmoid(logits) + not_prob * F.logsigmoid(-logits)).sum(dim = -1)
32
+
33
+ def pack_with_inverse(t, pattern):
34
+ packed, ps = pack([t], pattern)
35
+
36
+ def inverse(out, inv_pattern = None):
37
+ inv_pattern = default(inv_pattern, pattern)
38
+ unpacked, = unpack(out, ps, inv_pattern)
39
+ return unpacked
40
+
41
+ return packed, inverse
42
+
43
+ # binary mapper
44
+
45
+ class BinaryMapper(Module):
46
+ def __init__(
47
+ self,
48
+ bits = 1,
49
+ kl_loss_threshold = NAT # 1 bit
50
+ ):
51
+ super().__init__()
52
+
53
+ self.bits = bits
54
+ self.num_codes = 2 ** bits
55
+
56
+ power_two = 2 ** arange(bits)
57
+ codes = (arange(self.num_codes)[:, None].bitwise_and(power_two) != 0).byte().bool()
58
+
59
+ self.register_buffer('power_two', power_two, persistent = False)
60
+ self.register_buffer('codes', codes, persistent = False)
61
+
62
+ # aux loss
63
+
64
+ self.kl_loss_threshold = kl_loss_threshold
65
+ self.register_buffer('zero', tensor(0.), persistent = False)
66
+
67
+ def forward(
68
+ self,
69
+ logits,
70
+ temperature = 1.,
71
+ straight_through = None,
72
+ calc_aux_loss = None,
73
+ return_indices = False
74
+ ):
75
+ straight_through = default(straight_through, self.training)
76
+ calc_aux_loss = default(calc_aux_loss, self.training)
77
+
78
+ assert logits.shape[-1] == self.bits, f'logits must have a last dimension of {self.bits}'
79
+
80
+ # allow for any number of leading dimensions
81
+
82
+ logits, inverse_pack_lead_dims = pack_with_inverse(logits, '* bits')
83
+
84
+ # temperature and prob for sampling
85
+
86
+ prob_for_sample = (logits / temperature).sigmoid()
87
+
88
+ # sampling
89
+
90
+ sampled_bits = (torch.rand_like(logits) <= prob_for_sample).long()
91
+ indices = (self.power_two * sampled_bits).sum(dim = -1)
92
+
93
+ one_hot = F.one_hot(indices, self.num_codes).float()
94
+
95
+ # maybe calculate aux loss
96
+
97
+ aux_kl_loss = self.zero
98
+
99
+ if calc_aux_loss:
100
+ # calculate negative entropy
101
+
102
+ kl_div = self.bits * NAT - binary_entropy(logits)
103
+ aux_kl_loss = F.relu(kl_div - self.kl_loss_threshold).mean()
104
+
105
+ # maybe straight through
106
+
107
+ if straight_through:
108
+ # get the soft G for the gradients and do a straight through
109
+
110
+ soft_G = (
111
+ einsum(F.logsigmoid(logits), self.codes.float(), '... bits, codes bits -> ... codes') +
112
+ einsum(F.logsigmoid(-logits), (~self.codes).float(), '... bits, codes bits -> ... codes')
113
+ ).exp()
114
+
115
+ # straight through
116
+
117
+ one_hot = one_hot + soft_G - soft_G.detach()
118
+
119
+ # inverse pack
120
+
121
+ one_hot = inverse_pack_lead_dims(one_hot)
122
+ indices = inverse_pack_lead_dims(indices, '*')
123
+
124
+ # returning
125
+
126
+ if not return_indices:
127
+ return one_hot, aux_kl_loss
128
+
129
+ # also allow for returning indices, even though it can be derived from sparse output with an argmax
130
+
131
+ return one_hot, indices, aux_kl_loss
132
+
133
+ # allow for quick copy paste
134
+
135
+ if __name__ == '__main__':
136
+
137
+ binary_mapper = BinaryMapper(bits = 8)
138
+
139
+ logits = torch.randn(3, 4, 8)
140
+
141
+ sparse_one_hot, indices, aux_loss = binary_mapper(logits, return_indices = True)
142
+
143
+ assert sparse_one_hot.shape == (3, 4, 2 ** 8)
144
+ assert indices.shape == (3, 4)
145
+ assert aux_loss.numel() == 1