Trefon.
← Wszystkie notatki 9 min

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.

Jacek Trefon
  • 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]:

TokenT = 1,3T = 1,0T = 0,6
A0,4760,5430,699
B0,2570,2440,184
C0,2040,1810,112
D0,0470,0270,005
E0,0150,0060,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 k najbardziej prawdopodobnych tokenów. Jest toporny: k = 40 to 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. Przy T = 1 i p = 0.9 w 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. Przy min_p = 0.05 i p_max = 0.543 pró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:

  1. Próbkowanie. Odrobina entropii łamie symetrię. Na mojej maszynie do inferencji przejście na --temp 0.6 --top-p 0.95 --min-p 0.05 zatrzymał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).
  2. 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

  1. 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.
  2. 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.
  3. Sprawdzaj kolejność łańcucha, gdy przenosisz ustawienia między silnikami.
  4. 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.

Masz podobny problem?

Opisz swój problem

30-minutowa rozmowa techniczna z inżynierem, który to buduje. Bez działu sprzedaży, bez slajdów.