Lossless compression of English messages using GPT-2
textsynth.org
textsynth.org
A natural question I've pondered from time to time is whether Fabrice is really a time traveler from a more advanced civilization in the future, sent back in time to show us, mere mortals, what humankind will be capable of in the future.
If this sounds far-fetched, consider that he has created FFMPEG, QEMU, LibBF, SoftFP, BPG, TinyEMU, a software implementation of 4G/LTE, a PC emulator in Javascript, the TCC compiler, TinyGL, LZEXE, and a tiny program for computing the biggest known prime number.
And that's just a partial list of his successful projects, which now of course also include software for lossless compression with Transformer neural networks.
Any of these projects, on its own, would be considered a notable achievement for an ordinary human being.
Source: https://bellard.org
--
Copied and edited some text from my post a year ago: https://news.ycombinator.com/item?id=19591308 -- I never cease to be amazed by the guy.
Bellards contributions are a packaged tool (as opposed to PoC code) and demo webpage, and the idea of using CJK characters rather than outputting binary data (in todays world of JSON, binary data has fallen out of fashion).
Assuming the decompressor already has GPT2 weights is analogous to assuming it has a massive fixed dictionary of English words and phrases and doing code substitution — it’s likely the pragmatic answer in some scenario, but it’s not a fair basis for comparison. Real-world compressors use dictionary coders, but they build the dictionary specifically for the data when it’s compressed and then count that dictionary in the compressed size. For competitions like the Hutter Compression Prize (1GB of English Wikipedia) the reported size includes the complete binary of the decompressor program too.
GPT2 model weights require over 5GB of storage, so you’d need a corpus orders of magnitude larger for it to be even close to competitive by that standard. And it appears it would lose anyway — the OP claims ~15% ratio even with “cheating”, and the current Hutter Prize winner for 1GB of enwiki is ~11% without “cheating”.
I am, in fact, currently involved in research that uses GPT-2 for format-transforming encryption and we follow the exact same recipe but in reverse. Encrypt a message, then "decompress" the random bits into English text using GPT-2. Assuming the receiver has the same GPT-2 state (model parameters and prompt) then they will reproduce the same random bits by arithmetic compression, which can then be decrypted with the shared key.
[root@archlinux mail]# pwd
/mail
[root@archlinux mail]# du -skh .
68G .
And this is a tiny personal mailserver. There's loads of applications where a 5GB penalty* is well below the amount of text you're looking at (wikipedia springs to mind since they're in the same kind of size range for text.)However, I agree with you on the real-world uselessness of a GPT-based compression algorithm.
Large static dictionaries exploit a loophole that would make comparisons meaningless if carried to the extreme — you could trivially include the entire benchmark corpus in the decompressor itself and claim your compressed file size is 0 bytes. That’s why the Hutter Prize rules are what they are.
If you can bring the complete benchmark corpus (or substantial subsets of it) “into the wilderness”, the benchmark isn’t worth running. It’s not a compressor, it’s a database with stable keys. A Library of Congress LCCN code uniquely identifies the complete text of any published book, but it doesn’t contain a compressed copy of that book.
The simple way to achieve that is to have an encoding dictionary of words, but then add to the end of the dictionary "sh", etc., and then add to the end of that "a", "b", "c", etc. When tokenizing words, prefer to use a whole word, but if you can't do that, split to syllables, and failing that, individual letters. That has the benefit that any ascii string can go through the system.
So yes, there are ways to work around this but it seems like the simplest explanation for why unusual words break the encoder.
Otherwise it's a good idea and it works, but it's super slow, only working for English text, and the system requirements are huge. I like it.
This is useful for applications that limit the number of characters, e.g. Twitter.
I wonder if Chinese is even more info dense, as it does not have the syllabic hiragana/katakana characters ?
However it's worth noting that Chinese characters are analogous to entire words in English, and are composed of components much like English characters are composed of letters.
For example "thanks" is spelled "t h a n k s"
"謝" is made up of "言 身 寸"
(Of course, the components in Chinese have less correlation to their pronunciation, but the main point I'm making here is that there is a LOT of overlap in the common components used to assemble the entire Chinese lexicon.)
It is really not a fair comparison to compare languages in terms of their number of characters needed to represent something.
Better measures would be the fastest time (in seconds) needed to use speech to convey a concept intelligibly to an average native speaker, or the square centimeters of paper needed to convey an idea given the same level of eyesight.
Maybe someone remembers better than me.
^ It was something like Go or Tetris where they were tracking every single move.
If you're counting by "number of characters" you might as well use the entire Unicode range including all the Emoji if you are going to mix up Chinese+Japanese+Korean, which nobody would already never do.
Also, "number of characters" is a bit meaningless in the sense that human-intelligible Chinese is already far more compact than human-intelligible English in number of characters, and that's only because each character inherently carries more information, and not because the language itself is a compressed representation of ideas. Chinese characters are also made up of a standard set of components that are reused throughout the lexicon and assembled into different ways to make different characters, so it isn't "fair" to count a Chinese character on the same footing as an English character. A Chinese character is loosely more analogous to an entire word in English, and the components inside Chinese characters are kind of analogous to English letters (except they are arranged two-dimensionally and are most of the time not related to a character's pronunciation).
A more interesting study would be compressing English text into shorter strings that use English characters only.
I've implemented this approach in my aitextgen package (https://github.com/minimaxir/aitextgen/blob/master/aitextgen...) to encode massive input datasets as a uint16 Numpy array; when gzipped on disk, it's about 1/10th of the original data set size.
However, the technique in this submission gets about compression to 1/10 w/o the gzipping. Hmm.
(Side note: aren't these codepoints very expensive to encode in UTF-8? It seems there must be a lower-valued range more suited to it)
Check the 'How does it look?' section.
> each compressed character holds 15 data bits by using the CJK and the Hangul Syllables unicode ranges.
In UTF-8 these characters take 3 bytes each. Which makes it less space efficient than base64 (60% overhead vs 33% overhead).
The CJK/Hangul scheme has more information per character but I'm not sure where that matters.
So I'm just wondering why you would use something more obscure, less space efficient, and not ascii compatible.
EDIT: Ohhh, I know, and because twitter cares about characters. So you can use this to put essays into tweets.
The author might as well have included the rest of the Unicode range including Arabic, Emoji, and math symbols.
Typed in 你好吗 and decompressed it. The decompression was an entertaining read.
Try swapping a few characters in the compressed string before decompressing and get a totally unrelated, but somewhat plausible, sentence. -->
䔹䧹焫놉勏㦿顱㦽膑裚躈葊
Swapping last two: 䔹䧹焫놉勏㦿顱㦽膑裚葊躈 -->
Try swapping a few characters in the compressed string before decompressing and get a totally unrelated, but somewhat applied tlh
Swapping first two: 䧹䔹焫놉勏㦿顱㦽膑裚躈葊 -->
Sexy Shania Twain acting as a sprite for sexy Hogan's Alley demo dude
my site
my favorite animal's name is camelid 2 my favorite artist is david maile my favorite movie's are
Pretty wild!for i in range(20): print ''.join(unichr(random.randrange(20000, 25000)) for x in range(4))
to generate some random text; one string like 劓惂儶宓 turns up this bizarre output:
> Honeybees ( Apis mellifera ) are splendidly beautiful little creatures. They have shapely abdomens, amphistales and pedipalps, round chests, and square backs … all of them beautifully highly marketable. Exactly what has caused the popularity of bees I do not quite know; just what they do is a mystery to me. I beg to differ. The
A fun game to play is to see how many characters a name takes: it’s an indication of your importance to the Internet.
In answer to the why Chinese, it seems to me to be easier to read and more compact to display than hexlified bytes.
Can the same effect be achieved by looking at actual probability of the next word from a large corpus of existing text (a-la markov chains)?
The theory being that GPT2 should have a distribution closely matching "reality" and thus minimizing the output size?
The impact of bias in training data is interesting in general here. What's the impact on Wikipedia's article biases? That's probably one of the main corpuses used.
This won't win, but it seems he cares and has some talent :)