Matematyka próbkowania: temperatura, top-p, min-p i dlaczego agenci się zapętlają
Co każdy sampler robi z rozkładem prawdopodobieństwa, policzone na prawdziwych liczbach: temperatura, top-k, top-p, min-p i kary za powtórzenia. Dlaczego kolejność w łańcuchu ma znaczenie, dlaczego kary psują kod i JSON oraz jak ustawienia próbkowania odbijają się na pętlach agentów i szybkości dekodowania.
- deep dive
- próbkowanie
- inferencja
- agenci
Model nie zwraca tekstu. Zwraca wynik dla każdego tokenu w słowniku, czyli logity, a łańcuch samplerów zamienia je w jeden wybór. Większość zgłoszeń w stylu „model jest głupi”, które widzę, to tak naprawdę błędy samplera. Poniżej pokazuję, co robi każdy krok, na prawdziwych liczbach.
Od logitów do prawdopodobieństw
Softmax zamienia logity z w prawdopodobieństwa, a temperatura T najpierw dzieli logity:
p_i = exp(z_i / T) / Σ_j exp(z_j / T)
Weźmy pięć tokenów-kandydatów z logitami [5.0, 4.2, 3.9, 2.0, 0.5]:
| Token | T = 1,3 | T = 1,0 | T = 0,6 |
|---|---|---|---|
| A | 0,476 | 0,543 | 0,699 |
| B | 0,257 | 0,244 | 0,184 |
| C | 0,204 | 0,181 | 0,112 |
| D | 0,047 | 0,027 | 0,005 |
| E | 0,015 | 0,006 | 0,0004 |
Niższa temperatura wyostrza rozkład w stronę najbardziej prawdopodobnego tokenu; wyższa go spłaszcza. Przy T → 0 dostajesz dekodowanie zachłanne: zawsze najbardziej prawdopodobny token, w pełni deterministycznie.
Obcinanie: top-k, top-p, min-p
Temperatura zmienia kształt rozkładu. Samplery obcinające odrzucają jego ogon, żeby token z szansą 1 na 200 nigdy nie mógł zostać wybrany:
- Top-k zostawia
knajbardziej prawdopodobnych tokenów. Jest toporny:k = 40to za dużo, gdy model jest pewny, i za mało, gdy nie jest. - Top-p, czyli nucleus sampling (Holtzman i in., 2020), zostawia najmniejszy zbiór tokenów, których prawdopodobieństwa sumują się do co najmniej
p. PrzyT = 1ip = 0.9w przykładzie zostają A, B i C, które łącznie pokrywają 0,967. - Min-p (Nguyen i in., 2024) zostawia każdy token, którego prawdopodobieństwo wynosi co najmniej
min_p × p_max. Przymin_p = 0.05ip_max = 0.543próg wynosi 0,027, więc znowu przeżywają A, B i C.
Przewaga min-p polega na tym, że próg skaluje się z pewnością modelu. Gdy najbardziej prawdopodobny token ma 0,9, odpada wszystko poniżej 0,045. Gdy model naprawdę nie jest pewny, a najbardziej prawdopodobny token ma 0,2, poprzeczka spada do 0,01 i przeżywa więcej alternatyw. Top-p przesuwa natomiast cięcie według masy, co gorzej sprawdza się przy bardzo płaskich albo bardzo spiczastych rozkładach.
Kolejność ma znaczenie
Samplery działają jako łańcuch, a llama.cpp pozwala ustawić ich kolejność przez --samplers. Kolejność zmienia wynik:
- Najpierw obcinanie, potem temperatura: o zbiorze kandydatów decyduje surowa pewność modelu, a temperatura tylko zmienia kształt tego, co przeżyło.
- Najpierw temperatura, potem obcinanie: wysoka temperatura najpierw spłaszcza rozkład i przepuszcza przez cięcie większą część ogona.
Żadna z tych kolejności nie jest błędna, ale te same ustawienia znaczą co innego w różnych silnikach. Gdy przenosisz konfigurację między silnikami, sprawdzaj łańcuch, nie tylko liczby.
Kary za powtórzenia i dlaczego psują kod
Kara za powtórzenia w stylu CTRL (Keskar i in., 2019) zmniejsza logity tokenów, które pojawiły się już w ostatnim oknie: dodatnie logity są dzielone przez θ, ujemne mnożone. Kary za częstość i za obecność odejmują zamiast tego α × count + β × [count > 0].
Dla prozy to w porządku. Dla kodu i JSON-a to trucizna, bo tam powtórzenia są składnią: nawiasy klamrowe, cudzysłowy, przecinki, wcięcia, te same nazwy kluczy w każdej linii. Jeśli je ukarzesz, dostaniesz zniekształcone wywołania narzędzi i zepsute wcięcia. Dla agentów i kodu trzymam kary za powtórzenia wyłączone, a powtórzeniami zajmuję się gdzie indziej.
Dlaczego agenci się zapętlają
Pętla agenta to układ ze sprzężeniem zwrotnym. Model widzi wynik narzędzia, wybiera akcję i znowu widzi wynik. Jeśli akcja dała ten sam wynik co ostatnio, kontekst jest teraz prawie identyczny jak w poprzednim kroku. Deterministyczny albo prawie deterministyczny sampler wybiera wtedy znowu tę samą akcję. Powtarzanie samo się wzmacnia: każde powtórzenie zwiększa szansę na następne.
Dwie poprawki, na różnych warstwach:
- Próbkowanie. Odrobina entropii łamie symetrię. Na mojej maszynie do inferencji przejście na
--temp 0.6 --top-p 0.95 --min-p 0.05zatrzymało pętle wywołań narzędzi. Podniosło też dekodowanie z 62 do 82 tok/s, bo ustawienia próbkowania zmieniają, ile spekulatywnych tokenów szkicu zostaje przyjętych (ta matematyka jest w notatce o dekodowaniu). - Harness. Wykrywanie powtórzonych wywołań, odmowa dwukrotnego uruchomienia identycznego wywołania i wymuszenie innego planu działają pewniej niż strojenie temperatury. amber-bench ma do tego cały zestaw testów dyscypliny pętli, a notatka o benchmarku pokazuje, jak bardzo modele się w nim różnią.
Zasady, których się trzymam
- Agenci i kod: temperatura około 0,6, top-p i min-p jako bariery ochronne, bez kary za powtórzenia. Pętlami zajmuje się harness.
- Ewaluacje: przy porównywaniu modeli stałe ziarno i niska temperatura, potem powtórzone uruchomienia, żeby zobaczyć rozrzut. Jedno uruchomienie z próbkowaniem to nie pomiar.
- Sprawdzaj kolejność łańcucha, gdy przenosisz ustawienia między silnikami.
- Ograniczaj format, nie treść. Jeśli potrzebujesz poprawnego JSON-a, użyj dekodowania z ograniczeniami, zamiast obniżać temperaturę, aż model przestanie być kreatywny.
Źródła: Holtzman i in., The Curious Case of Neural Text Degeneration (ICLR 2020). Nguyen i in., Turning Up the Heat: Min-p Sampling (2024). Keskar i in., CTRL (2019). Pomiar 62 → 82 tok/s pochodzi z produkcyjnej konfiguracji mojego forka.