Odchudzanie modelu to sport bez mety — zawsze znajdzie się ktoś, kto urwie jeszcze jeden bit. Najpierw było szesnaście bitów na wagę i pliki, przy których dysk kwiczał. Potem przyszła kwantyzacja po treningu i zeszliśmy na osiem, na cztery, gdzieś na dnie forum ktoś odpalał dwa. Za każdym razem wracało to samo pytanie — „a da się jeszcze niżej?" — i za każdym razem ktoś mądrzejszy odpowiadał, że przy dwóch bitach model zaczyna gadać jak po trzech piwach. No i w tym całym schodzeniu w dół pada w końcu pytanie, które brzmi jak żart: a gdyby tak jeden bit? Gdyby waga mogła być tylko włączona albo wyłączona?
Okazuje się, że to nie żart. W lutym 2024 grupa z Microsoft Research położyła na arXiv pracę o wdzięcznym tytule „The Era of 1-bit LLMs" i pokazała coś, co na pierwszy rzut oka wygląda na herezję: model, w którym każda waga przyjmuje jedną z trzech wartości — minus jeden, zero albo plus jeden — a mimo to od pewnego rozmiaru dorównuje pełnoprecyzyjnej LLaMie.1 Nazwali go BitNet b1.58. I zanim złapiesz się na tym „1.58 bita" jak na literówce — spokojnie, to nie literówka. To rozłóżmy na części.
Skąd te 1,58 bita — czyli dlaczego nie okrągła jedynka
Najpierw sama nazwa, bo ona zdradza cały pomysł. Skoro waga może być tylko jedną z trzech
rzeczy — -1, 0 albo +1 — to ile informacji trzeba, żeby taki stan zapisać? Logarytm
przy podstawie dwa z trzech. A log2(3) to jakieś 1,58.1 Stąd b1.58: nie dlatego,
że ktoś w pamięci trzyma ułamki bitów, tylko dlatego, że tyle wynosi teoretyczny koszt
informacyjny wyboru jednego z trzech wariantów.
I tu pierwsza pułapka, w którą łatwo wdepnąć: 1,58 bita to nie jest dosłowna liczba bitów, jaką waga zajmuje na dysku. To granica informacyjna, nie format zapisu. W praktycznych implementacjach — kiedy ktoś pakuje taki model do GGUF-a — wartość ternarna i tak ląduje zwykle na dwóch bitach plus trochę struktury dookoła. Więc jak zobaczysz „1.58-bit" na karcie modelu, czytaj to jako „trzy stany na wagę", a nie jako obietnicę, że plik jest fizycznie pięciokrotnie mniejszy niż czterobitowy. To dwa różne piętra: ile musisz zapamiętać, a jak akurat to zapakowałeś.
Dlaczego akurat ternarne, a nie czyste zero-jeden? Bo to zero pośrodku robi robotę. Waga
równa zeru to po ludzku „to połączenie mnie nie obchodzi" — model dostaje wbudowaną możliwość
wycięcia neuronu z równania. Oryginalny BitNet, wcześniejsza praca tej samej ekipy z 2023
roku, jechał na czystych wagach binarnych, tylko -1 i +1.2 Dorzucenie zera to
właśnie ten skok od BitNetu do BitNetu b1.58 — z pozoru drobny, a robi całą różnicę w jakości.
„Trenowany od zera" — i czemu to nie jest zwykła kwantyzacja
Teraz sedno, bo tu większość ludzi przy pierwszym czytaniu odruchowo myśli
o złym torze. Kiedy słyszysz „model na trzech wartościach", w głowie zapala się „aha, czyli
kolejna kwantyzacja" — bierzemy gotową, wytrenowaną w FP16 sieć i po fakcie zaokrąglamy jej
wagi. Tak działa GGUF-owe Q4_K_M, tak działają GPTQ czy AWQ — rozgryzaliśmy te potreningowe
sztuczki tutaj. Model istnieje najpierw w pełnej precyzji, a dopiero
potem go ściskasz i modlisz się, że nie zgłupieje.
BitNet b1.58 działa dokładnie odwrotnie. Nikt tu niczego nie kwantyzuje po fakcie. Model jest trenowany od zera z wagami zamkniętymi w tych trzech wartościach — sieć od pierwszego kroku uczy się żyć w ternarnym świecie i sama układa sobie wagi tak, żeby jej to nie przeszkadzało.1 To fundamentalna różnica: taki model nigdy nie istniał w FP16. Nie ma oryginału, z którego zszedłeś w dół i coś po drodze zgubiłeś. Ternarność nie jest stratą nałożoną na koniec — jest warunkiem brzegowym od startu.
| Kwantyzacja po treningu (PTQ) | BitNet b1.58 | |
|---|---|---|
| Kiedy niska precyzja | po treningu, na gotowej sieci | od pierwszego kroku treningu |
| Czy istnieje wersja FP16 | tak, to oryginał | nie, nigdy nie istniała |
| Wagi | ściśnięte np. do 4 bitów | ternarne {-1, 0, +1} |
| Aktywacje | różnie | 8-bitowe (schemat W1.58A8) |
| Typowe ryzyko | jakość spada przy mocnym cięciu | luka jakości znika dopiero od pewnego rozmiaru |
Skąd model wie, na którą z trzech wartości zaokrąglić daną wagę podczas treningu? Robi to
funkcja o ładnej nazwie absmean. Cała macierz wag jest najpierw skalowana przez swoją
średnią wartość bezwzględną, a potem każda liczba idzie do najbliższej całkowitej ze zbioru
{-1, 0, +1}.3 Proste jak konstrukcja cepa i o to chodzi — im mniej fikuśne, tym
lepiej się liczy.
Mnożenie? Jakie mnożenie
Tu wchodzi część, dla której cały ten cyrk się opłaca. Serce każdego LLM-a to mnożenie
macierzy — miliardy mnożeń liczby przez liczbę, i to właśnie one zżerają prąd i czas. A teraz
policz na palcach, co się dzieje, kiedy jeden z czynników może być tylko -1, 0 albo +1.
Mnożenie przez +1? To po prostu dodaj tę drugą liczbę. Przez -1? Odejmij. Przez 0?
Pomiń, nic nie rób.
I nagle znika mnożenie. Zostają same dodawania i odejmowania — a te są dla krzemu dużo tańsze. Praca podaje twardą liczbę: dla samej operacji mnożenia macierzy to około 71 razy mniej energii na chipie 7nm w porównaniu z odpowiednikiem w FP16.3 Nie o kilka procent — o rząd wielkości i to z hakiem. To nie jest „lepsza kompresja", to zmiana tego, jaką operację w ogóle wykonuje procesor.
Dla ciebie, człowieka z jedną kartą pod biurkiem, znaczenie jest dwustronne. Z jednej strony mniej pamięci i mniej prądu na token to marzenie każdego, kto liczył, ile VRAM-u zeżre KV-cache przy długim kontekście. Z drugiej — mnożenie zamienione na dodawanie najlepiej opłaca się na sprzęcie, który to rozumie. Autorzy wprost sugerują, że era 1-bitowych modeli woła o nowy, dedykowany krzem projektowany pod ternarną arytmetykę.3 Dzisiejsze GPU są zbudowane pod mnożenie zmiennoprzecinkowe — więc pełnię tej obietnicy zobaczymy dopiero, gdy hardware nadgoni pomysł.
Haczyk: to działa dopiero od pewnego rozmiaru
Zanim pobiegniesz ogłaszać koniec FP16, jedna trzeźwa uwaga — i to taka, którą sami autorzy kładą na stół, bez chowania pod dywan. Ta cudowna „jakość jak w pełnej precyzji" nie pojawia się na małych modelach. Przy 700M czy 1,3B parametrów między BitNetem b1.58 a pełną LLaMą wciąż widać zauważalną lukę — ternarny model gada wyraźnie gorzej.3
Magia zaczyna się gdzieś od 3 miliardów parametrów w górę. Dopiero od tego progu BitNet b1.58 dogania pełnoprecyzyjną LLaMę zarówno pod względem perplexity (miary tego, jak model „dziwi się" tekstowi), jak i na zadaniach końcowych.3 Model 3,9B potrafi już przebić 3B LLaMę — i to przy mniejszym zużyciu pamięci oraz niższej latencji.3 Reszta liczb z pracy jest w tym samym duchu: redukcja pamięci 2,6–3,55×, przyspieszenie generacji 1,23–4,1× (rośnie z rozmiarem), a dla modelu 70B przepustowość wyższa 8,9× przy jedenastokrotnie większym batchu.3
Stąd bierze się najciekawszy wniosek pracy — nowe „prawo skalowania". Autorzy pokazują, że 13-miliardowy BitNet b1.58 potrafi być bardziej efektywny — pamięciowo, energetycznie i czasowo — niż zwykły model 3B w FP16.3 Innymi słowy: przestań patrzeć na samą liczbę parametrów. Przy ternarnych wagach większy model może być lżejszy w użyciu od mniejszego pełnoprecyzyjnego. To wywraca do góry nogami intuicję, którą wszyscy nosimy — że więcej parametrów zawsze znaczy cięższy plik.
Zrób to sam — Microsoft wypuścił konkretny model
To nie zostało teorią na papierze. Microsoft wydał gotowy, produkcyjny model:
microsoft/bitnet-b1.58-2B-4T — około 2 miliardów parametrów, wytrenowany na 4 bilionach
tokenów, na licencji MIT.4 Pod maską to transformer z warstwami BitLinear (to w nich
siedzą te ternarne wagi), z RoPE, z aktywacją squared ReLU w FFN, normalizacją subln i bez
biasów.4 Schemat, który już znasz z tego wpisu: W1.58A8 — wagi 1,58-bitowe, aktywacje
ośmiobitowe.
I teraz najważniejsza pułapka praktyczna, bo tu połowa ludzi się nabiera. Jeśli odpalisz
ten model przez zwykłą bibliotekę transformers z Hugging Face — nie zobaczysz żadnych
oszczędności. Karta modelu mówi to wprost: efektywność pamięci i energii ujawnia się
wyłącznie z dedykowaną implementacją.4 transformers policzy ci ten model jak każdy
inny, gęsto i drogo — bo nie umie skorzystać z tego, że mnożenia są zbędne. To trochę jak
kupić samochód na prąd i tankować go benzyną z kanistra.
Tą dedykowaną implementacją jest bitnet.cpp — framework inferencyjny z repozytorium
microsoft/BitNet na GitHubie.5 I tu druga pułapka, tym razem dla porządkowych: to
nie jest część ggml-org, mimo że stoi na llama.cpp i pachnie tym samym ekosystemem.
To osobny projekt utrzymywany przez Microsoft, opisany we własnej pracy na arXiv.6
Dostarcza dedykowane kernele — I2_S na x86 i ARM, TL1 na ARM, TL2 na x86 — i to one
robią tę robotę z zamianą mnożeń na dodawania.5
git clone --recursive https://github.com/microsoft/BitNet.git
cd BitNet
# dokładne kroki (setup_env.py, wybór kernela, pobranie GGUF-a)
# są w README repozytorium — trzymaj się ich, bo się zmieniają
Liczby z bitnet.cpp są równie soczyste jak z papieru: na ARM-owym CPU przyspieszenia
1,37–5,07× i redukcja energii 55–70%, na x86 przyspieszenia 2,37–6,17× i redukcja energii
72–82%.5 Wisienka na torcie: framework pozwala uruchomić model klasy 100B na pojedynczym
CPU z prędkością rzędu 5–7 tokenów na sekundę.5 Sto miliardów parametrów. Na procesorze.
Bez karty. Przeczytaj to zdanie jeszcze raz i przypomnij sobie, ile kosztuje GPU zdolne
udźwignąć taki model po staremu.
Cała droga lokalnego LLM-owca to jedno długie schodzenie po drabinie precyzji. Szesnaście bitów, osiem, cztery — i za każdym razem ktoś na forum wróżył, że niżej już się nie da, że na dole tej drabiny model rozpłynie się w bełkocie. BitNet b1.58 nie tyle zszedł o kolejny szczebel, co zauważył, że drabina od początku stała nie tam. Zamiast ściskać gotowe liczby coraz mocniej — nauczył sieć od urodzenia myśleć trzema stanami i wyrzucił mnożenie za burtę.
Czy to już koniec ery zmiennoprzecinkowej? Nie dziś — dopóki krzem pod biurkiem woli mnożyć
niż dodawać, pełnia tej obietnicy leży zapakowana i czeka na sprzęt, który ją rozpakuje. Ale
kierunek jest wytyczony, model do ściągnięcia leży na Hugging Face, a bitnet.cpp już liczy.
Czasem nie zmieniasz odpowiedzi na stare pytanie — zmieniasz pytanie. Nie „ile bitów damy
radę utrzymać", tylko „po co nam w ogóle mnożenie".
Ma, Wang, Ma i in., The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits, arXiv:2402.17764, arxiv.org/abs/2402.17764 — tytuł, autorzy, data zgłoszenia (27 lutego 2024), definicja wag ternarnych
{-1, 0, +1},log2(3) ≈ 1,58 bitai trening od zera. ↩︎ ↩︎ ↩︎Wang i in., BitNet: Scaling 1-bit Transformers for Large Language Models, arXiv:2310.11453, arxiv.org/abs/2310.11453 — poprzednik b1.58 z wagami binarnymi
{-1, +1}. ↩︎The Era of 1-bit LLMs — pełny tekst, arxiv.org/html/2402.17764v1 — funkcja
absmean, próg ~3B dla dopasowania do FP16, luka na 700M/1.3B, model 3.9B kontra 3B LLaMA, liczby dot. pamięci/latencji/przepustowości, ~71× mniej energii na matmul (7nm), nowe prawo skalowania i wniosek o dedykowanym sprzęcie. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎Karta modelu
microsoft/bitnet-b1.58-2B-4T, huggingface.co/microsoft/bitnet-b1.58-2B-4T — 2B parametrów, 4T tokenów, schemat W1.58A8, warstwy BitLinear, RoPE, squared ReLU, subln, brak biasów, licencja MIT oraz zastrzeżenie o braku zysków wydajności przeztransformers. ↩︎ ↩︎ ↩︎microsoft/BitNet— oficjalne repozytoriumbitnet.cpp, github.com/microsoft/BitNet — kerneleI2_S/TL1/TL2, zamiana mnożeń na dodawania/odejmowania, przyspieszenia i redukcja energii na ARM/x86, uruchomienie modelu 100B na pojedynczym CPU (~5–7 tok/s). ↩︎ ↩︎ ↩︎ ↩︎Wang i in., Bitnet.cpp: Efficient Edge Inference for Ternary LLMs, arXiv:2502.11880, arxiv.org/pdf/2502.11880 — osobna praca opisująca framework inferencyjny dla modeli ternarnych. ↩︎