A while back I wrote about language modeling without neural networks, where I generated Shakespeare with an unbounded n-gram model: no weights, no training, …

409 points•networked•9 days ago•164 comments•

164 comments

jll299 days ago
Yes: you can classify a test file by topic with gzip as follows:

  gzip -9 sports.txt   testfile.txt

  gzip -9 politics.txt testfile.txt

  gzip -9 business.txt testfile.txt
(ass. sports.txt politics.txt and business.txt are text docs pertaining from the sports, politics and business domains, respectively, and have equal size)

The test file belongs to the topic with the smallest size *.gz file.

Witten's group at Waikato uni were perhaps the first to work on this.

Also check out the Hutter prize if you are interested in this.

stingraycharles9 days ago
Back in the day - maybe two decades ago - I implemented language detection like this.

I seeded gzip compressors’ dictionaries with Wikipedia articles in different languages.

I would then try to use said dictionaries on any random text, and the one that was best able to compress it, was the correct language.

Absolutely totally not the best approach, but very fast and super simple to implement.

ape49 days ago
Or maybe make a list of the most used 1000 words in each language. And see which list has the most occurrences.
actionfromafar9 days ago
Sounds like the best approach. :)
LPisGood9 days ago
There are some deep connections between machine learning, compression, and cryptography with information theory as a common thread.

Also, I’ve never seen “ass.” Used to shorten “aside” — I typically use N.B. but perhaps only for important ones.

shoo9 days ago
For anyone wanting an introductory text for information theory & that explores some of these connections & applications, it's worth checking out the late David MacKay's 2003 textbook Information Theory, Inference & Learning Algorithms https://www.inference.org.uk/itila/
matzf9 days ago
The "ass." more likely stands for "assuming".
arrowsmith9 days ago
3Blue1Brown has a good video about this: https://www.youtube.com/watch?v=l6DKRf-fAAM
myrmidon9 days ago
Nitpick: Doing it exactly like this is flawed because you let the compressibility of your references taint the result; what you would prefer is the compressed size of testfile given sports.txt/... as a dictionary without accounting for the compressed size of that, no?

Really interesting approach though.

akoboldfrying8 days ago
You're right, you should subtract off the compressed sizes of the respective reference files before comparing. (This suffices if we assume that later input data does not influence the compression of earlier input data, which is true except for certain unusual conditions like a repeated substring at the end of the reference data that also appears at the beginning of the test data.)
woadwarrior019 days ago
aka Normalized compression distance (NCD). Its close cousin: Normalized Google distance (NGD) is also super interesting!

https://en.wikipedia.org/wiki/Normalized_compression_distanc...

chris_va9 days ago
We used a similar technique for a class project (N decades ago) to test this:

https://en.wikipedia.org/wiki/Baconian_theory_of_Shakespeare...

By looking at mutual information from different authors on the same topic vs same author on different topics. As I recall, it convincingly disproved the hypothesis.

GodelNumbering9 days ago
3blue1brown did a series on this topic: https://www.youtube.com/watch?v=l6DKRf-fAAM https://www.youtube.com/watch?v=GlYgs6v2YfU (i think one more is yet to release)
kevinrineer8 days ago
Wonderful link. Just commenting to add: in the first video, Grant mentioned it would be a trilogy series.
jrflo8 days ago
I keep thinking that surely I missed the 3rd video in the series but no, 2 months later we are still waiting for the conclusion. I'm sure it'll be worth the wait though.
Culonavirus9 days ago
This tracks perfectly with Winrar being more profitable than OpenAI... coincidence? I think not!
wolfi19 days ago
winrar is profitable? sure? well, on the other hand, they sure don't make losses
shezi9 days ago
They are a German GmbH and must publicly state their financials: https://www.northdata.de/win%C2%B7rar%20GmbH,%20Berlin/Amtsg...

Looks pretty profitable to me.

mg9 days ago

    give it a normal text prompt, and it
    continues that prompt by searching
    for the byte sequences that compress
    best.
One moment, how are we supposed to know how well that search was done? There is no way to search a meaningful part of the search space.

So the result only gives us some lower bound of how well gzip works as a "plausibility tester" of a continuation of a text. The space of possible sequences is many orders of magnitude larger than what was searched. So there might be sequences in there that compress much better.

The text mentions beamsearch, but I don't see a discussion about how well beamsearch performs in finding the global optima when it comes to gzip compressibility of a text?

shoo9 days ago
That's a fair question. Suppose we have a way to find a byte sequence x that globally minimises len(gzip(context + prompt + x)) over all sequences x of length n. Here + denotes string concatenation.

It's unclear if this is very useful.

The reason it may not be very useful is that one of Deflate's ingredients is a pass that replaces repeated substrings with backreferences to the earlier occurrence in the plaintext input stream.

E.g. suppose we want to find an n=200 byte sequence x that minimises len(gzip(context+prompt+x)).

If there exists any 200 byte sequence y such that prompt+y is a substring of context, then Deflate can encode prompt+y as a backreference to that earlier sequence - it needs to store a match-length & a distance-length, encoded using its Huffman trees. This candidate solution y may not be a global minima to our stated objective function, but if not, it's probably going to be a very good near-optimal approximate solution.

Taking a step back, repeating huge chunks of the input context produces something that's great for minimising compressed output size but doesn't seem particularly helpful as a generative model.

edit:

Yep, I tried it out by running an experiment. Searching for the prompt in the context & then copying the following text as the solution produces solutions that are much better, in the sense of minimising the compressed output length, than beam search, while also being unhelpful as a generative tool.

With the same example as the blog post:

  context: first 30,000 bytes of tinyshakespeare.txt
  prompt: 'MENENIUS:\n'
Let x denote a solution, x is a string of length 200.

Let L(x) denote len(gzip(context+prompt+x)), our objective function

Let's call the proposed search method of searching for the prompt in the input rfind (after python's str.rfind).

Then we have

   search method      soln               soln length   feasible?     objective value      search time (wall clock, s)
   -------------      ----               -----------   ---------     ---------------      ---------------------------
   emptystring        ""                          0          no              13,023                     0.04s
   gzipt beam search  see blog post             200         yes              13,051                    11.93s
   rfind              see below                 200         yes              13,026                     0.04s

So 'rfind' is finding a solution that does a better job of minimising the objective function -- it only takes 3 bytes more to encode than the infeasible emptystring solution, and costs 25 fewer bytes than the solution found by the beam search implemented by gzipt per the blog post.

Here's the solution 'generated' by rfind copying and pasting from the input context, starting from the rightmost occurrence of "MENENIUS:"

   MENENIUS:
   O, true-bred!
   
   First Senator:
   Your company to the Capitol; where, I know,
   Our greatest friends attend us.
   
   TITUS:
   
   COMINIUS:
   Noble Marcius!
   
   First Senator:
   
   MARCIUS:
   Nay, let them follow:
   The Volsces 

Here's the code for 'rfind' - our complete 'generative algorithm':

    def find_candidate_solution_from_context(context, prompt, length):
        n = len(context)
        i = context.rfind(prompt, 0, n-length)
        if i < 0:
            return b''
        i += len(prompt)
        return context[i:i+length]

Can hook it into gzipt.py by adding this line after out is defined, but before the beam search begins

    out += find_candidate_solution_from_context(corpus_window, prompt, length)
StilesCrisis9 days ago
Read to the end: they aren't actually looking for the best-compressing output, because this quickly devolves into aaaaaaaaaaa. They keep a sliding window over a small portion of recent text and use that.

Basically I think the entire premise falls apart due to that choice--they forced an interesting-looking outcome by adjusting the algorithm until gzip started picking random slabs of letters instead of ever-larger repeating runs.

Ohentis8 days ago
I had actually thought of doing this, but didn't for this exact reason. I knew I would have to fudge things to make it anything interesting.
im_down_w_otp9 days ago
Meh. That’s nothing compared to the amount of curation and tuning the LLMs are coerced with.
elendilm9 days ago
Good article.

Compression is a property of language.

A seemingly simple sentence like "I had lunch" has enormous amount of information compressed inside it.

The word lunch is a compressed form of "having food at noon" while "noon" in turn is a compressed form of "Sun's position against Earth's rotation" and so on and so forth.

Every sentence has layers of compressed sentences. How many layers one chooses to decompress is up to the person.

Read the full thread on Hacker News →

Related stories