lyte-codes commited on
Commit
355dd97
·
verified ·
1 Parent(s): dee5fa7

Image tokenizer 263701: patch VQ, 1024 codes

Browse files
Files changed (1) hide show
  1. README.md +84 -0
README.md ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - image-tokenizer
5
+ - vector-quantization
6
+ - vq
7
+ library_name: numpy
8
+ ---
9
+
10
+ # Image tokenizer — patch VQ, 1024 codes
11
+
12
+ Turns an image into 1,024 discrete tokens, and back into an approximation of
13
+ the image. Model `263701`.
14
+
15
+ ```python
16
+ from imagetok import PatchVQTokenizer
17
+ from PIL import Image
18
+
19
+ tok = PatchVQTokenizer.load("imagetok_1024.npz")
20
+ ids = tok.encode(Image.open("photo.jpg")) # 1024 ints, each 0..1023
21
+ back = tok.decode(ids) # a PIL image
22
+ ```
23
+
24
+ ## It is lossy, and that is not a bug to be fixed
25
+
26
+ A text tokenizer is exactly invertible — byte-level BPE returns the bytes it was
27
+ given, and anything less is broken. An image tokenizer cannot do that and
28
+ nothing will make it: a photograph is millions of continuous values and a token
29
+ is one integer out of a thousand. The mapping discards information by design.
30
+
31
+ So fidelity is reported as a **quantity**, not a pass mark. There is no pass
32
+ mark, and whether coarse is acceptable depends on what the tokens are for.
33
+
34
+ ## Measured on photographs it never saw
35
+
36
+ | | |
37
+ |---|---|
38
+ | tokens per image | 1,024 (32×32 grid of 8×8 patches, 256×256 input) |
39
+ | bits per token | 10 |
40
+ | size as tokens | 1,280 bytes |
41
+ | size as raw pixels | 196,608 bytes |
42
+ | compression | **154× smaller** |
43
+ | reconstruction | **23.4 dB**, mean absolute error 13.0/255 |
44
+ | codebook used | 970 of 1,024 (95%), usage perplexity 462 |
45
+
46
+ ## What the numbers say about where the loss comes from
47
+
48
+ Quadrupling the codebook from 256 to 1024 buys **0.9 dB** (22.5 → 23.4). Halving
49
+ the patch size buys **2.3 dB** and costs four times the tokens:
50
+
51
+ | patch | tokens/image | reconstruction |
52
+ |---|---|---|
53
+ | 16×16 | 256 | 21.6 dB |
54
+ | 8×8 | 1,024 | 23.9 dB |
55
+ | 4×4 | 4,096 | 26.6 dB |
56
+
57
+ So the loss is dominated by the **patch grid**, not the codebook. An 8×8 patch
58
+ cannot represent an edge crossing it at an angle however many codes exist, which
59
+ is the visible failure — straight edges go blocky while colour and layout
60
+ survive.
61
+
62
+ That also bounds anything built on top: a model that generates these tokens can
63
+ never produce an image better than this tokenizer can reconstruct. If you are
64
+ using this as the front end of a generative or editing model, 23.4 dB is your
65
+ ceiling, and a learned convolutional VQ-VAE at the same token count would raise
66
+ it — the encoder can place information anywhere in the patch instead of matching
67
+ against a fixed dictionary.
68
+
69
+ ## Method
70
+
71
+ k-means over patches drawn from the training corpus, k-means++ seeded so that a
72
+ corpus of mostly-sky does not put every code in the sky. Nearest code wins and
73
+ its index is the token. This is what a VQ-VAE does with a neural encoder in
74
+ front; without one it stays inspectable — every token is a patch you can look
75
+ at, so codebook collapse is visible rather than theoretical.
76
+
77
+ Trained on 272 CC-licensed photographs from Wikimedia Commons, held out 48 for
78
+ the numbers above. A larger and more varied corpus would move these figures;
79
+ they are reported on what was actually used.
80
+
81
+ ## Licence
82
+
83
+ Apache 2.0. `imagetok.py` and `metric.py` are included so the numbers can be
84
+ reproduced rather than taken on trust.