Amusing that the link to an article on ternary numbers was posted by Mr Triplett. (:
The article is well-written and illustrated. The technique described is used in llama.cpp for running language models like BitNet b1.58 whose weights are stored as ternary types.
> ..in which every single parameter (or weight) of the LLM is ternary {-1, 0, 1}
> significantly more cost-effective in terms of latency, memory, throughput, and energy consumption
The original paper on this technique was published in Feb 2024. (Also linked from the article)
However, since then there have only been a few other models using ternary weights. I get the impression that there are factors not considered in the paper which make it less practical than it seemed.
lioeters
It's impressive how close to optimal this is.
You can beat the efficiency of 5 trits in 8 bits (1.6) with as few as 17 trits in 27 bits (~1.588), but once you account for rounding up to a whole number of bytes for practical reasons, then beating the efficiency requires going to at least 111 trits in 176 bits (~1.586), or perhaps more practically for fast unpacking, 161 trits in 256 bits (~1.59).
At that level, even if you have, say, 27B trits, the more efficient encodings would save something like 38-45MB (theoretical limit ~48MB), likely at the cost of some slowdown.
JoshTriplett
How does this packing/unpacking scheme compare to just using a lookup table?
Diggsey
Despite my ignorance on what would be involved, I like to fantasize that companies like Apple (who own their own chip design and hardware) can put these ternary pack/unpack operations in hardware with a single instruction for each (and also instructions for performing the various matrix convolutions using ternary numbers) so that we can get on-device LLMs.
I suppose with the recent quantized Bonsai models we're already seeing on-device LLMs for phones and the like… But I (again, forgive my ignorance) assume that there is an order of magnitude or more in performance sitting out there if we get custom hardware instructions.
JKCalhoun
One way to beat this in terms of coding efficiency would be to use something like rANS (explanation [1], code [2]).
You would have a more complicated decoder with rANS though, even if you removed the frequency table lookup (because always 1/3) and you'd only produce one output at a time instead of 5 doing this with a lookup table.
It might be possible to use a combination of both techniques with e.g. a 16 bit accumulator, multiplying by 243 to get the value to lookup into bits 23-16 and then bias and shift the incoming 8 bits into the accumulator.
I wonder if NNs could be trained well enough with 1 bit weights (i.e. 0 and 1) with some layers doing addition, while others substraction (i.e. weight sign would be "hardcoded" into the network architecture). Or with zero-less weights (e.g. -1, -0.5, 0.5, 1).
newpavlov
"I'll be calling a "ternary digit" a "trit", like a "binary digit" is called a "bit"."
And missed it by one letter. <jk>
JKCalhoun
Would this imply that the matrices should have dimensions of multiples of 40?
kleton
Would having 16 bits to pack a tuple of ternary numbers have a potential to give even better efficiency?
comments (10)
The article is well-written and illustrated. The technique described is used in llama.cpp for running language models like BitNet b1.58 whose weights are stored as ternary types.
> ..in which every single parameter (or weight) of the LLM is ternary {-1, 0, 1}
> significantly more cost-effective in terms of latency, memory, throughput, and energy consumption
The original paper on this technique was published in Feb 2024. (Also linked from the article)
The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits - https://arxiv.org/abs/2402.17764
However, since then there have only been a few other models using ternary weights. I get the impression that there are factors not considered in the paper which make it less practical than it seemed.
lioeters
You can beat the efficiency of 5 trits in 8 bits (1.6) with as few as 17 trits in 27 bits (~1.588), but once you account for rounding up to a whole number of bytes for practical reasons, then beating the efficiency requires going to at least 111 trits in 176 bits (~1.586), or perhaps more practically for fast unpacking, 161 trits in 256 bits (~1.59).
At that level, even if you have, say, 27B trits, the more efficient encodings would save something like 38-45MB (theoretical limit ~48MB), likely at the cost of some slowdown.
JoshTriplett
Diggsey
I suppose with the recent quantized Bonsai models we're already seeing on-device LLMs for phones and the like… But I (again, forgive my ignorance) assume that there is an order of magnitude or more in performance sitting out there if we get custom hardware instructions.
JKCalhoun
You would have a more complicated decoder with rANS though, even if you removed the frequency table lookup (because always 1/3) and you'd only produce one output at a time instead of 5 doing this with a lookup table.
It might be possible to use a combination of both techniques with e.g. a 16 bit accumulator, multiplying by 243 to get the value to lookup into bits 23-16 and then bias and shift the incoming 8 bits into the accumulator.
[1] https://fgiesen.wordpress.com/2014/02/18/rans-with-static-pr...
[2] https://github.com/rygorous/ryg_rans
ralferoo
jjgreen
newpavlov
And missed it by one letter. <jk>
JKCalhoun
kleton
evrimoztamur