vector-quantize-pytorch 1.19.4__tar.gz → 1.20.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 (29) hide show
  1. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/PKG-INFO +10 -2
  2. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/README.md +9 -0
  3. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/examples/autoencoder.py +3 -3
  4. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/examples/autoencoder_fsq.py +0 -1
  5. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/examples/autoencoder_lfq.py +0 -2
  6. vector_quantize_pytorch-1.20.0/examples/autoencoder_sim_vq.py +84 -0
  7. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/pyproject.toml +1 -1
  8. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/__init__.py +1 -0
  9. vector_quantize_pytorch-1.20.0/vector_quantize_pytorch/sim_vq.py +124 -0
  10. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/utils.py +2 -0
  11. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/vector_quantize_pytorch.py +34 -29
  12. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/.github/workflows/build.yml +0 -0
  13. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/.github/workflows/python-publish.yml +0 -0
  14. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/.github/workflows/test.yml +0 -0
  15. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/.gitignore +0 -0
  16. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/LICENSE +0 -0
  17. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/images/fsq.png +0 -0
  18. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/images/lfq.png +0 -0
  19. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/images/vq.png +0 -0
  20. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/ruff.toml +0 -0
  21. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/tests/test_latent_quantization.py +0 -0
  22. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/tests/test_readme.py +0 -0
  23. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/finite_scalar_quantization.py +0 -0
  24. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/latent_quantization.py +0 -0
  25. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/lookup_free_quantization.py +0 -0
  26. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/random_projection_quantizer.py +0 -0
  27. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/residual_fsq.py +0 -0
  28. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/residual_lfq.py +0 -0
  29. {vector_quantize_pytorch-1.19.4 → vector_quantize_pytorch-1.20.0}/vector_quantize_pytorch/residual_vq.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: vector-quantize-pytorch
3
- Version: 1.19.4
3
+ Version: 1.20.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
@@ -26,7 +26,6 @@ License: MIT License
26
26
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
27
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
28
  SOFTWARE.
29
- License-File: LICENSE
30
29
  Keywords: artificial intelligence,deep learning,pytorch,quantization
31
30
  Classifier: Development Status :: 4 - Beta
32
31
  Classifier: Intended Audience :: Developers
@@ -758,3 +757,12 @@ assert loss.item() >= 0
758
757
  url = {https://api.semanticscholar.org/CorpusID:273229218}
759
758
  }
760
759
  ```
760
+
761
+ ```bibtex
762
+ @inproceedings{Zhu2024AddressingRC,
763
+ title = {Addressing Representation Collapse in Vector Quantized Models with One Linear Layer},
764
+ author = {Yongxin Zhu and Bocheng Li and Yifei Xin and Linli Xu},
765
+ year = {2024},
766
+ url = {https://api.semanticscholar.org/CorpusID:273812459}
767
+ }
768
+ ```
@@ -714,3 +714,12 @@ assert loss.item() >= 0
714
714
  url = {https://api.semanticscholar.org/CorpusID:273229218}
715
715
  }
716
716
  ```
717
+
718
+ ```bibtex
719
+ @inproceedings{Zhu2024AddressingRC,
720
+ title = {Addressing Representation Collapse in Vector Quantized Models with One Linear Layer},
721
+ author = {Yongxin Zhu and Bocheng Li and Yifei Xin and Linli Xu},
722
+ year = {2024},
723
+ url = {https://api.semanticscholar.org/CorpusID:273812459}
724
+ }
725
+ ```
@@ -71,12 +71,12 @@ train_dataset = DataLoader(
71
71
  shuffle=True,
72
72
  )
73
73
 
74
- print("baseline")
75
74
  torch.random.manual_seed(seed)
76
75
 
77
76
  model = SimpleVQAutoEncoder(
78
- codebook_size=num_codes,
79
- rotation_trick=rotation_trick
77
+ codebook_size = num_codes,
78
+ rotation_trick = True,
79
+ straight_through = False
80
80
  ).to(device)
81
81
 
82
82
  opt = torch.optim.AdamW(model.parameters(), lr=lr)
@@ -76,7 +76,6 @@ train_dataset = DataLoader(
76
76
  shuffle=True,
77
77
  )
78
78
 
79
- print("baseline")
80
79
  torch.random.manual_seed(seed)
81
80
  model = SimpleFSQAutoEncoder(levels).to(device)
82
81
  opt = torch.optim.AdamW(model.parameters(), lr=lr)
@@ -87,8 +87,6 @@ train_dataset = DataLoader(
87
87
  shuffle=True,
88
88
  )
89
89
 
90
- print("baseline")
91
-
92
90
  torch.random.manual_seed(seed)
93
91
 
94
92
  model = LFQAutoEncoder(
@@ -0,0 +1,84 @@
1
+ # FashionMnist VQ experiment with various settings.
2
+ # From https://github.com/minyoungg/vqtorch/blob/main/examples/autoencoder.py
3
+
4
+ from tqdm.auto import trange
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ from torchvision import datasets, transforms
9
+ from torch.utils.data import DataLoader
10
+
11
+ from vector_quantize_pytorch import SimVQ, Sequential
12
+
13
+ lr = 3e-4
14
+ train_iter = 10000
15
+ num_codes = 256
16
+ seed = 1234
17
+ rotation_trick = True
18
+ device = "cuda" if torch.cuda.is_available() else "cpu"
19
+
20
+ def SimVQAutoEncoder(**vq_kwargs):
21
+ return Sequential(
22
+ nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1),
23
+ nn.MaxPool2d(kernel_size=2, stride=2),
24
+ nn.GELU(),
25
+ nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1),
26
+ nn.MaxPool2d(kernel_size=2, stride=2),
27
+ SimVQ(dim=32, accept_image_fmap = True, **vq_kwargs),
28
+ nn.Upsample(scale_factor=2, mode="nearest"),
29
+ nn.Conv2d(32, 16, kernel_size=3, stride=1, padding=1),
30
+ nn.GELU(),
31
+ nn.Upsample(scale_factor=2, mode="nearest"),
32
+ nn.Conv2d(16, 1, kernel_size=3, stride=1, padding=1),
33
+ )
34
+
35
+ def train(model, train_loader, train_iterations=1000, alpha=10):
36
+ def iterate_dataset(data_loader):
37
+ data_iter = iter(data_loader)
38
+ while True:
39
+ try:
40
+ x, y = next(data_iter)
41
+ except StopIteration:
42
+ data_iter = iter(data_loader)
43
+ x, y = next(data_iter)
44
+ yield x.to(device), y.to(device)
45
+
46
+ for _ in (pbar := trange(train_iterations)):
47
+ opt.zero_grad()
48
+ x, _ = next(iterate_dataset(train_loader))
49
+
50
+ out, indices, cmt_loss = model(x)
51
+ out = out.clamp(-1., 1.)
52
+
53
+ rec_loss = (out - x).abs().mean()
54
+ (rec_loss + alpha * cmt_loss).backward()
55
+
56
+ opt.step()
57
+
58
+ pbar.set_description(
59
+ f"rec loss: {rec_loss.item():.3f} | "
60
+ + f"cmt loss: {cmt_loss.item():.3f} | "
61
+ + f"active %: {indices.unique().numel() / num_codes * 100:.3f}"
62
+ )
63
+
64
+ transform = transforms.Compose(
65
+ [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]
66
+ )
67
+
68
+ train_dataset = DataLoader(
69
+ datasets.FashionMNIST(
70
+ root="~/data/fashion_mnist", train=True, download=True, transform=transform
71
+ ),
72
+ batch_size=256,
73
+ shuffle=True,
74
+ )
75
+
76
+ torch.random.manual_seed(seed)
77
+
78
+ model = SimVQAutoEncoder(
79
+ codebook_size = num_codes,
80
+ rotation_trick = rotation_trick
81
+ ).to(device)
82
+
83
+ opt = torch.optim.AdamW(model.parameters(), lr=lr)
84
+ train(model, train_dataset, train_iterations=train_iter)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vector-quantize-pytorch"
3
- version = "1.19.4"
3
+ version = "1.20.0"
4
4
  description = "Vector Quantization - Pytorch"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -6,5 +6,6 @@ from vector_quantize_pytorch.lookup_free_quantization import LFQ
6
6
  from vector_quantize_pytorch.residual_lfq import ResidualLFQ, GroupedResidualLFQ
7
7
  from vector_quantize_pytorch.residual_fsq import ResidualFSQ, GroupedResidualFSQ
8
8
  from vector_quantize_pytorch.latent_quantization import LatentQuantize
9
+ from vector_quantize_pytorch.sim_vq import SimVQ
9
10
 
10
11
  from vector_quantize_pytorch.utils import Sequential
@@ -0,0 +1,124 @@
1
+ from typing import Callable
2
+
3
+ import torch
4
+ from torch import nn
5
+ from torch.nn import Module
6
+ import torch.nn.functional as F
7
+
8
+ from einx import get_at
9
+ from einops import rearrange, pack, unpack
10
+
11
+ from vector_quantize_pytorch.vector_quantize_pytorch import rotate_from_to
12
+
13
+ # helper functions
14
+
15
+ def exists(v):
16
+ return v is not None
17
+
18
+ def identity(t):
19
+ return t
20
+
21
+ def default(v, d):
22
+ return v if exists(v) else d
23
+
24
+ def pack_one(t, pattern):
25
+ packed, packed_shape = pack([t], pattern)
26
+
27
+ def inverse(out, inv_pattern = None):
28
+ inv_pattern = default(inv_pattern, pattern)
29
+ out, = unpack(out, packed_shape, inv_pattern)
30
+ return out
31
+
32
+ return packed, inverse
33
+
34
+ # class
35
+
36
+ class SimVQ(Module):
37
+ def __init__(
38
+ self,
39
+ dim,
40
+ codebook_size,
41
+ init_fn: Callable = identity,
42
+ accept_image_fmap = False,
43
+ rotation_trick = True, # works even better with rotation trick turned on, with no asymmetric commit loss or straight through
44
+ commit_loss_input_to_quantize_weight = 0.25,
45
+ ):
46
+ super().__init__()
47
+ self.accept_image_fmap = accept_image_fmap
48
+
49
+ codebook = torch.randn(codebook_size, dim) * (dim ** -0.5)
50
+ codebook = init_fn(codebook)
51
+
52
+ # the codebook is actually implicit from a linear layer from frozen gaussian or uniform
53
+
54
+ self.codebook_to_codes = nn.Linear(dim, dim, bias = False)
55
+ self.register_buffer('codebook', codebook)
56
+
57
+
58
+ # whether to use rotation trick from Fifty et al.
59
+ # https://arxiv.org/abs/2410.06424
60
+
61
+ self.rotation_trick = rotation_trick
62
+ self.register_buffer('zero', torch.tensor(0.), persistent = False)
63
+
64
+ # commit loss weighting - weighing input to quantize a bit less is crucial for it to work
65
+
66
+ self.commit_loss_input_to_quantize_weight = commit_loss_input_to_quantize_weight
67
+
68
+ def forward(
69
+ self,
70
+ x
71
+ ):
72
+ if self.accept_image_fmap:
73
+ x = rearrange(x, 'b d h w -> b h w d')
74
+ x, inverse_pack = pack_one(x, 'b * d')
75
+
76
+ implicit_codebook = self.codebook_to_codes(self.codebook)
77
+
78
+ with torch.no_grad():
79
+ dist = torch.cdist(x, implicit_codebook)
80
+ indices = dist.argmin(dim = -1)
81
+
82
+ # select codes
83
+
84
+ quantized = get_at('[c] d, b n -> b n d', implicit_codebook, indices)
85
+
86
+ if self.rotation_trick:
87
+ # rotation trick from @cfifty
88
+
89
+ quantized = rotate_from_to(quantized, x)
90
+
91
+ commit_loss = self.zero
92
+ else:
93
+ # commit loss and straight through, as was done in the paper
94
+
95
+ commit_loss = (
96
+ F.mse_loss(x, quantized.detach()) * self.commit_loss_input_to_quantize_weight +
97
+ F.mse_loss(x.detach(), quantized)
98
+ )
99
+
100
+ quantized = (quantized - x).detach() + x
101
+
102
+ if self.accept_image_fmap:
103
+ quantized = inverse_pack(quantized)
104
+ quantized = rearrange(quantized, 'b h w d-> b d h w')
105
+
106
+ indices = inverse_pack(indices, 'b *')
107
+
108
+ return quantized, indices, commit_loss
109
+
110
+ # main
111
+
112
+ if __name__ == '__main__':
113
+
114
+ x = torch.randn(1, 512, 32, 32)
115
+
116
+ sim_vq = SimVQ(
117
+ dim = 512,
118
+ codebook_size = 1024,
119
+ accept_image_fmap = True
120
+ )
121
+
122
+ quantized, indices, commit_loss = sim_vq(x)
123
+
124
+ assert x.shape == quantized.shape
@@ -12,6 +12,7 @@ from vector_quantize_pytorch.lookup_free_quantization import LFQ
12
12
  from vector_quantize_pytorch.residual_lfq import ResidualLFQ, GroupedResidualLFQ
13
13
  from vector_quantize_pytorch.residual_fsq import ResidualFSQ, GroupedResidualFSQ
14
14
  from vector_quantize_pytorch.latent_quantization import LatentQuantize
15
+ from vector_quantize_pytorch.sim_vq import SimVQ
15
16
 
16
17
  QUANTIZE_KLASSES = (
17
18
  VectorQuantize,
@@ -20,6 +21,7 @@ QUANTIZE_KLASSES = (
20
21
  RandomProjectionQuantizer,
21
22
  FSQ,
22
23
  LFQ,
24
+ SimVQ,
23
25
  ResidualLFQ,
24
26
  GroupedResidualLFQ,
25
27
  ResidualFSQ,
@@ -76,19 +76,6 @@ def lens_to_mask(lens, max_length):
76
76
  seq = torch.arange(max_length, device = lens.device)
77
77
  return seq < lens[:, None]
78
78
 
79
- def efficient_rotation_trick_transform(u, q, e):
80
- """
81
- 4.2 in https://arxiv.org/abs/2410.06424
82
- """
83
- e = rearrange(e, 'b d -> b 1 d')
84
- w = l2norm(u + q, dim = 1).detach()
85
-
86
- return (
87
- e -
88
- 2 * (e @ rearrange(w, 'b d -> b d 1') @ rearrange(w, 'b d -> b 1 d')) +
89
- 2 * (e @ rearrange(u, 'b d -> b d 1').detach() @ rearrange(q, 'b d -> b 1 d').detach())
90
- )
91
-
92
79
  def uniform_init(*shape):
93
80
  t = torch.empty(shape)
94
81
  nn.init.kaiming_uniform_(t)
@@ -248,6 +235,39 @@ def kmeans(
248
235
 
249
236
  return means, bins
250
237
 
238
+ # rotation trick related
239
+
240
+ def efficient_rotation_trick_transform(u, q, e):
241
+ """
242
+ 4.2 in https://arxiv.org/abs/2410.06424
243
+ """
244
+ e = rearrange(e, 'b d -> b 1 d')
245
+ w = l2norm(u + q, dim = 1).detach()
246
+
247
+ return (
248
+ e -
249
+ 2 * (e @ rearrange(w, 'b d -> b d 1') @ rearrange(w, 'b d -> b 1 d')) +
250
+ 2 * (e @ rearrange(u, 'b d -> b d 1').detach() @ rearrange(q, 'b d -> b 1 d').detach())
251
+ )
252
+
253
+ def rotate_from_to(src, tgt):
254
+ # rotation trick STE (https://arxiv.org/abs/2410.06424) to get gradients through VQ layer.
255
+ tgt, inverse = pack_one(tgt, '* d')
256
+ src, _ = pack_one(src, '* d')
257
+
258
+ norm_tgt = tgt.norm(dim = -1, keepdim = True)
259
+ norm_src = src.norm(dim = -1, keepdim = True)
260
+
261
+ rotated_src = efficient_rotation_trick_transform(
262
+ safe_div(tgt, norm_tgt),
263
+ safe_div(src, norm_src),
264
+ tgt
265
+ ).squeeze()
266
+
267
+ rotated = rotated_src * safe_div(norm_src, norm_tgt).detach()
268
+
269
+ return inverse(rotated)
270
+
251
271
  # distributed helpers
252
272
 
253
273
  @cache
@@ -1098,22 +1118,7 @@ class VectorQuantize(Module):
1098
1118
  commit_quantize = maybe_detach(quantize)
1099
1119
 
1100
1120
  if self.rotation_trick:
1101
- # rotation trick STE (https://arxiv.org/abs/2410.06424) to get gradients through VQ layer.
1102
- x, inverse = pack_one(x, '* d')
1103
- quantize, _ = pack_one(quantize, '* d')
1104
-
1105
- norm_x = x.norm(dim = -1, keepdim = True)
1106
- norm_quantize = quantize.norm(dim = -1, keepdim = True)
1107
-
1108
- rot_quantize = efficient_rotation_trick_transform(
1109
- safe_div(x, norm_x),
1110
- safe_div(quantize, norm_quantize),
1111
- x
1112
- ).squeeze()
1113
-
1114
- quantize = rot_quantize * safe_div(norm_quantize, norm_x).detach()
1115
-
1116
- x, quantize = inverse(x), inverse(quantize)
1121
+ quantize = rotate_from_to(quantize, x)
1117
1122
  else:
1118
1123
  # standard STE to get gradients through VQ layer.
1119
1124
  quantize = x + (quantize - x).detach()