Temperature, Top-p και ο ντετερμινισμός που δεν έχετε
Το temperature διαιρεί τα logits πριν από το softmax — και έτσι καταρρίπτει την ιδέα του «ρυθμιστή δημιουργικότητας».
Σε αυτή τη σελίδα
Εδώ είναι το ίδιο αίτημα σταλμένο στο ίδιο μοντέλο πέντε φορές. Ίδια βάρη, ίδιο prompt, ίδιο μηχάνημα, ίδιο random seed. Το μόνο που αλλάζει είναι ένας αριθμός.
prompt: "Q: What is the capital of France?\nA:"
T = 0.0 " Paris\nWhat is the question and does the answer answer it? The
question is: What is the capital of France?..."
T = 0.7 " Paris\nWhat is the question: Which city is the capital of
France?..."
T = 1.0 " Paris\nWhat is a good geographical qualifier for describing
Paris concerning its location?\nA: Near the Mediterranean Sea..."
T = 1.5 " Paris\nWhat clue from premise allows we to conclude that Godwin
was &, He chose Healing Crimson Colour No:white flour Pure..."
T = 2.0 "安全感金华.ITEMT]]];\naims assume parental.st-importe.valtermination
Screens قطر_Zeroหมายเลข-zA ('$ספטמבר..."Τίποτα δεν χάλασε. Κάθε token στην τελευταία γραμμή αντλήθηκε απολύτως έγκυρα από την ίδια την κατανομή πιθανοτήτων του μοντέλου πάνω στο λεξιλόγιό του των 151.936 εγγραφών. Ο αριθμός που άλλαξε ονομάζεται temperature, στα περισσότερα documentation περιγράφεται ως ρυθμιστής δημιουργικότητας, και αυτή η περιγραφή είναι λάθος με τρόπο που αυτό το κεφάλαιο μπορεί να δείξει αντί απλώς να ισχυριστεί.
Αυτό είναι επίσης το κεφάλαιο όπου εκπληρώνονται τρεις προηγούμενες υποσχέσεις. Το Κεφάλαιο 4 όρισε το logit και ποτέ δεν το αξιοποίησε πραγματικά. Το κουτί του Κεφαλαίου 2 για την κινητή υποδιαστολή τελείωνε με μια οδηγία — θυμηθείτε το αυτό όταν το Κεφάλαιο 17 ρωτήσει γιατί το ίδιο prompt, μοντέλο και seed μπορούν να παράγουν διαφορετικά tokens. Και το κουτί του Κεφαλαίου 9 για mixture-of-experts υποσχέθηκε έναν κατάλογο τεσσάρων αιτιών μη ντετερμινισμού. Και οι τρεις φτάνουν παρακάτω.
Η μία γραμμή από την οποία κρέμεται όλο το κεφάλαιο
Σύνδεσμος στην ενότητα: Η μία γραμμή από την οποία κρέμεται όλο το κεφάλαιοΤο Κεφάλαιο 4 εισήγαγε το logit ως μια μη κανονικοποιημένη πραγματική βαθμολογία, μία ανά κλάση. Το Κεφάλαιο 8 έκανε ένα γλωσσικό μοντέλο να παράγει μία ανά εγγραφή λεξιλογίου. Το softmax μετατρέπει αυτό το διάνυσμα σε πιθανότητες:
Το temperature μπαίνει εδώ — το όνομα είναι δανεισμένο από τη στατιστική φυσική, όπου η ίδια παράμετρος ελέγχει πόσο έντονα μια κατανομή Boltzmann συγκεντρώνεται στις καταστάσεις χαμηλής ενέργειάς της1 — και διαιρεί τα logits πριν από το εκθετικό:
Αυτή η θέση είναι ολόκληρος ο μηχανισμός, και αξίζει δύο γραμμές άλγεβρας για να δείτε γιατί δεν θα μπορούσε να είναι πουθενά αλλού. Ας υποθέσουμε ότι προσπαθούσατε να εφαρμόσετε temperature στις πιθανότητες αντί γι’ αυτό — να τις κλιμακώσετε κατά και να τις κανονικοποιήσετε ξανά. Θα παίρνατε
Η σταθερά ακυρώνεται. Η κλιμάκωση των πιθανοτήτων δεν κάνει απολύτως τίποτα· η κατανομή επιστρέφει αμετάβλητη. Το temperature έχει επίδραση μόνο επειδή δρα στον εκθέτη, όπου η διαίρεση με πριν από την εκθετικοποίηση ισοδυναμεί με την ύψωση κάθε πιθανότητας στη δύναμη — έναν μη γραμμικό μετασχηματισμό που αλλάζει τους λόγους μεταξύ των εγγραφών αντί για την κοινή τους κλίμακα.
Από αυτή τη θέση, και τα δύο όρια προκύπτουν χωρίς άλλη δουλειά. Καθώς το , το μεγαλύτερο logit απομακρύνεται από τα υπόλοιπα και το καταρρέει στο μοναδικό token με την υψηλότερη βαθμολογία: greedy decoding. Καθώς το μεγαλώνει, κάθε κατευθύνεται προς το μηδέν, κάθε εκθετικό κατευθύνεται προς το 1, και η κατανομή επιπεδώνεται προς την ομοιόμορφη πάνω σε ολόκληρο το λεξιλόγιο. Ακριβώς στο ο τύπος διαιρεί με μηδέν, οπότε κάθε υλοποίηση το αντιμετωπίζει ειδικά ως αριθμητικό μέγιστο — συμπεριλαμβανομένου του widget παρακάτω, που αλλάζει σε argmax στο .
Μία προειδοποίηση, επειδή η σύγκρουση ονομάτων προκαλεί πραγματική σύγχυση. Υπάρχει ένα δεύτερο, άσχετο πράγμα που ονομάζεται temperature στη μηχανική μάθηση: temperature scaling, μια μέθοδος βαθμονόμησης που προσαρμόζει μία τιμή σε ένα σύνολο επικύρωσης ώστε η βεβαιότητα ενός ταξινομητή να ταιριάζει με την ακρίβειά του.2 Ίδιος τύπος, καμία σχέση με generation. Όταν papers λένε «temperature», συχνά εννοούν αυτό· αυτό το κεφάλαιο ποτέ.
Εδώ είναι αυτή η κατανομή, με την αριθμητική μπροστά σας. Τα logits είναι σταθερά και εύλογα, άρα οι αριθμοί στο κείμενο παρακάτω μπορούν να ελεγχθούν με όσα βλέπετε:
Το temperature δεν είναι ρυθμιστής δημιουργικότητας
Σύνδεσμος στην ενότητα: Το temperature δεν είναι ρυθμιστής δημιουργικότηταςΟ αριθμός ␣banana είναι όλο το επιχείρημα σε μικρογραφία: η αύξηση του temperature δεν μπορεί να δώσει σε ένα μοντέλο μια ιδέα που δεν είχε. Τα logits έχουν ήδη υπολογιστεί, η κατάταξη έχει ήδη καθοριστεί, και το temperature τη διατηρεί ακριβώς — καμία ποσότητα θερμότητας δεν μετακινεί ποτέ ένα χαμηλότερα βαθμολογημένο token πάνω από ένα υψηλότερα βαθμολογημένο. Το μόνο που κάνει είναι να αναδιανέμει μάζα προς τα κάτω στην κατάταξη που παρήγαγε το ίδιο το μοντέλο. Υψηλό temperature δεν κάνει ένα μοντέλο πιο εφευρετικό· το κάνει πιο πιθανό να εκπέμψει τα tokens που βαθμολόγησε ως κακά.
Σε ένα πραγματικό λεξιλόγιο αυτό παύει να είναι περιέργεια και γίνεται ο λόγος που το output υψηλού temperature είναι άχρηστο. Μετρημένο στο Qwen/Qwen2.5-0.5B-Instruct, ένα forward pass, το prompt παραπάνω, μετρώντας πόσα tokens χρειάζονται για να συσσωρευτεί ένα δεδομένο μερίδιο της μάζας πιθανότητας:
| temperature | πιθανότητα top-1 | εντροπία | tokens που κρατούν 80 % | 90 % | 95 % | 99 % |
|---|---|---|---|---|---|---|
| 0.5 | 99,98 % | 0,00 nats | 1 | 1 | 1 | 1 |
| 0.7 | 99,65 % | 0,03 nats | 1 | 1 | 1 | 1 |
| 1.0 | 96,01 % | 0,30 nats | 1 | 1 | 1 | 14 |
| 1.2 | 88,20 % | 0,88 nats | 1 | 2 | 13 | 252 |
| 1.5 | 62,83 % | 3,07 nats | 29 | 353 | 2.672 | 26.787 |
| 2.0 | 16,62 % | 8,19 nats | 13.516 | 32.966 | 55.231 | 101.205 |
Διαβάστε την τελευταία γραμμή αργά. Στο , σε μια ερώτηση με ακριβώς μία σωστή απάντηση, 32.966 διαφορετικά tokens μοιράζονται το κορυφαίο 90 % της μάζας πιθανότητας. Αυτό δεν είναι ένας ευρύτερος δημιουργικός χώρος. Είναι ένα μοντέλο στο οποίο η αριθμητική είπε να αντιμετωπίζει ένα κορεατικό μόριο και ένα C++ identifier ως ζωντανές επιλογές για τη λέξη μετά το A:. Τα σκουπίδια στο αρχικό block είναι η άμεση συνέπεια, και δεν είναι bug στο μοντέλο ή στη βιβλιοθήκη — είναι αυτό που ζητούσε το αίτημα.
Το χρήσιμο εύρος είναι στενό και εξαρτάται από την εργασία, όχι από το γούστο. Σε μια factual ερώτηση η απάντηση είναι ένα token και οποιαδήποτε θερμότητα πάνω από περίπου 1,2 εισάγει λάθος χωρίς λόγο. Σε μια ανοιχτού τύπου εργασία υπάρχουν πράγματι περισσότερες από μία καλές συνέχειες, και λίγη θερμότητα αγοράζει ποικιλία που παραμένει ρέουσα:
"Write a two-sentence story about a lighthouse."
T = 0.0 "The lighthouse stood tall and proud, its beacon illuminating the
night sky above. A lone sailor, his eyes fixed on the distant
horizon..."
T = 0.7 "In the quiet, stormy waters of the sea, a lighthouse stood
sentinel over the horizon, its golden dome casting a warm glow
on the fog-shrouded streets below..."
T = 1.0 "In the quiet night, a lone lighthouse stood sentinel over the
sea, its shining beacon a beacon of hope and solace for sailors
and fishermen across the vast and endless ocean..."
T = 1.3 "In the gentle sunlight, now reflecting upon the opening of Jack's
lighthouse, Jim Trahan, a small-time individual difficult to
define in paperwork, wondered about a career where simplicity
reigns..."Στο 1,3 το μοντέλο έχει επινοήσει ένα κύριο όνομα και μια πρόταση που δεν αναλύεται συντακτικά. Η ζώνη ανάμεσα στο «πανομοιότυπο κάθε φορά» και στο «ασυνάρτητο» είναι περίπου 0,6 έως 1,1 για αυτό το μοντέλο σε αυτή την εργασία, και η ειλικρινής συμβουλή είναι να τη βρείτε με μετρήσεις στη δική σας εργασία, όχι αντιγράφοντας έναν αριθμό από ένα blog post.
Γιατί το πιο πιθανό κείμενο είναι κακό κείμενο
Σύνδεσμος στην ενότητα: Γιατί το πιο πιθανό κείμενο είναι κακό κείμενοΥπάρχει μια προφανής ερώτηση που κρύβεται κάτω από όλα αυτά: αν το μοντέλο έχει μια κατανομή πιθανοτήτων και ένα token είναι το πιο πιθανό, γιατί να μην το παίρνουμε πάντα; Το greedy decoding είναι δωρεάν, αναπαραγώγιμο και δεν χρειάζεται παραμέτρους.
Επειδή το αποτέλεσμα είναι αυτό:
prompt: "In a shocking finding, scientists discovered a herd of unicorns
living in a remote valley."
greedy: " The unicorns were so rare that they were not even recognized by
the local people. The unicorns were so rare that they were not
even recognized by the local people. The unicorns were so rare
that they were not even recognized by the local people. ..."
repeated 4-grams: 87.6 %Οκτώ προτάσεις, μία πρόταση. Σχεδόν εννέα στα δέκα παράθυρα τεσσάρων tokens είχαν ήδη εμφανιστεί νωρίτερα στο ίδιο output. Αυτό είναι neural text degeneration, όπως ονομάστηκε και εξηγήθηκε από τους Holtzman et al. στο paper που εισήγαγε το top-p.3 Το μοντέλο δεν είναι χαλασμένο· η μεγιστοποίηση της πιθανότητας ακολουθίας είναι απλώς λάθος στόχος για ανοιχτού τύπου κείμενο. Η ανθρώπινη γραφή δεν είναι η πιο πιθανή ακολουθία λέξεων — κουβαλά έκπληξη, με την πιθανότητα ανά token να περιπλανιέται, να βουτά και να ανακάμπτει — ενώ η διαδρομή μέγιστης πιθανότητας είναι ένα σταθερό σημείο που, μόλις μπει κανείς σε αυτό, δεν έχει κανέναν λόγο να φύγει.
Γι’ αυτό υπάρχει εξαρχής το sampling. Είναι επίσης, και αυτό είναι το κομμάτι που παραλείπεται, όχι ένας καθολικός νόμος. Το Κεφάλαιο 12 μέτρησε 24 στα 24 σωστά σε προβλήματα λέξεων δύο βημάτων με απλό greedy decoding, και το sampling σε temperature 0,8 το έριξε στο 81 %· η self-consistency έπειτα ξόδεψε έξι φορές τα tokens για να ξανασκαρφαλώσει εκεί όπου το greedy ήδη βρισκόταν. Και τα δύο γεγονότα ισχύουν ταυτόχρονα:
Open-ended generation. Δεν υπάρχει μία μοναδική σωστή συνέχεια, άρα η πιο πιθανή είναι παγίδα — κάνει loop, και το 87,6 % της είναι αντιγραμμένο από τον εαυτό της. Κάντε sample.
Εργασίες με μία σωστή απάντηση. Υπάρχει μία μοναδική σωστή συνέχεια, άρα το να τραβήξετε οτιδήποτε άλλο είναι να τραβήξετε λάθος. Το 100 % του Κεφαλαίου 12 έγινε 81 % ακριβώς γι’ αυτόν τον λόγο. Μην κάνετε sample.
Τα περισσότερα production prompts είναι του δεύτερου είδους και ρυθμίζονται σαν το πρώτο, επειδή το temperature έμεινε σε ό,τι χρησιμοποιούσε το example code.
Δύο τρόποι κοπής, και μόνο ο ένας προσαρμόζεται
Σύνδεσμος στην ενότητα: Δύο τρόποι κοπής, και μόνο ο ένας προσαρμόζεταιΤο sampling από την πλήρη κατανομή δεν είναι αυτό που κάνει στην πράξη κανείς, επειδή η ουρά είναι τεράστια και γεμάτη ανοησίες. Κάτι πρέπει να κοπεί. Υπάρχουν δύο κλασικές απαντήσεις και διαφέρουν σε ένα σημείο που αποφασίζει τα πάντα.
Top-k κρατά έναν σταθερό αριθμό υποψηφίων. Ταξινομήστε κατά πιθανότητα, κρατήστε τα πρώτα , απορρίψτε τα υπόλοιπα, κανονικοποιήστε ξανά.4 Top-p, που λέγεται και nucleus sampling, κρατά μια σταθερή ποσότητα μάζας: πάρτε tokens σε φθίνουσα σειρά μέχρι η σωρευτική τους πιθανότητα να φτάσει το , και σταματήστε.3 Τυπικά, ο πυρήνας είναι το μικρότερο σύνολο με
Η διαφορά ακούγεται επιφανειακή και δεν είναι, επειδή τα δύο prompts που στέλνετε στο ίδιο λεπτό έχουν εντελώς διαφορετικά σχήματα κατανομής. Και τα δύο παρακάτω είναι το ίδιο μοντέλο σε temperature 1:
Q: What is the capital of France?\nA: | Once upon a time, | |
|---|---|---|
| πιθανότητα top-1 | 96,01 % | 25,39 % |
| tokens που κρατούν 90 % της μάζας | 1 | 467 |
| top-k = 40 κρατά | 99,61 % της μάζας | 78,87 % της μάζας |
| μάζα στις θέσεις 2 έως 40 | 3,61 % | 53,48 % |
| token στη θέση 40 | ␣Av, 0,0093 % | ␣Dr, 0,128 % |
Ένα σταθερό , δύο αποτυχίες προς αντίθετες κατευθύνσεις. Στο factual prompt, το επιτρέπει 39 tokens που όλα μαζί αξίζουν 3,6 % — αφήνει σκουπίδια να περάσουν, συμπεριλαμβανομένου ενός υποψηφίου στα εννέα χιλιοστά του τοις εκατό, επειδή ο κανόνας μετρά θέσεις και όχι αποδείξεις. Στο story prompt, το ίδιο πετάει 21 % της μάζας που το μοντέλο όντως ανέθεσε, επειδή ο πραγματικός πυρήνας εκεί έχει πλάτος 467 tokens.
Το top-p κάνει ακριβώς έναν αριθμό να κάνει και τις δύο δουλειές. Ορίστε και κρατά 1 token στο πρώτο prompt και 467 στο δεύτερο, επειδή κάνει μια ερώτηση για την κατανομή αντί να επιβάλλει έναν αριθμό πάνω της. Δείτε αυτή την προσαρμογή άμεσα — ίδια κοπή, τέσσερα temperatures:
Αυτό το widget κλείνει επίσης μια παρανόηση που αξίζει να ονομαστεί, επειδή κοστίζει σε ανθρώπους πραγματικά χρήματα. Σε μια βέβαιη κατανομή, το top_p = 0.9 δεν είναι «λίγη ποικιλία». Είναι greedy. Σε temperature 1, το leading token εδώ κρατά 96,90 %, που είναι ήδη πάνω από 0,9, άρα ο πυρήνας έχει πλάτος ένα token και τίποτα άλλο δεν μπορεί ποτέ να τραβηχτεί. Ομάδες θέτουν το top_p στο 0,9 πιστεύοντας ότι χαλάρωσαν κάτι και μετά αναρωτιούνται γιατί κάθε απάντηση είναι πανομοιότυπη.
Βάλτε top-k αντί γι’ αυτό και η αντίθετη αποτυχία είναι εξίσου ορατή:
Οι ποινές, με τους τύπους, επειδή η σύγχυσή τους είναι ενδημική
Σύνδεσμος στην ενότητα: Οι ποινές, με τους τύπους, επειδή η σύγχυσή τους είναι ενδημικήΤρεις διαφορετικοί μηχανισμοί κυκλοφορούν με παρόμοια ονόματα, κάνουν διαφορετικά πράγματα, και η διαφορά είναι μετρήσιμη. Έστω ο αριθμός φορών που το token έχει ήδη εμφανιστεί.
Presence penalty
Σύνδεσμος στην ενότητα: Presence penaltyΑφαιρεί μια σταθερά από κάθε token που έχει εμφανιστεί έστω μία φορά. Το να εμφανιστεί μία φορά και το να εμφανιστεί σαράντα φορές τιμωρούνται πανομοιότυπα. Είναι διακόπτης, όχι ρυθμιστής.
Frequency penalty
Σύνδεσμος στην ενότητα: Frequency penaltyΑφαιρεί αναλογικά με την καταμέτρηση. Ένα token που χρησιμοποιήθηκε τέσσερις φορές τιμωρείται τέσσερις φορές πιο δυνατά από ένα token που χρησιμοποιήθηκε μία φορά, και η πίεση συσσωρεύεται όσο μεγαλώνει το κείμενο.
Repetition penalty (CTRL)
Σύνδεσμος στην ενότητα: Repetition penalty (CTRL)Η αρχική, από το paper CTRL.7 Διαιρεί αντί να αφαιρεί, με την περίπτωση προσήμου απαραίτητη επειδή η διαίρεση ενός αρνητικού logit θα το έκανε μεγαλύτερο. Η ισχύς της επομένως εξαρτάται από το μέγεθος του logit, πράγμα που σημαίνει ότι το ίδιο χτυπά διαφορετικά σε διαφορετικά σημεία της ίδιας πρότασης.
Η ίδια degenerate συνέχεια από πριν, με καθεμία εφαρμοσμένη. Το «βήματα που άλλαξαν» μετρά πόσα από τα 120 generation steps επέλεξαν διαφορετικό token από αυτό που θα είχε επιλέξει το μη τιμωρημένο μοντέλο. Η εκτέλεση είναι 120 βήματα εδώ έναντι 140 στο block παραπάνω, γι’ αυτό το unpenalised baseline γράφει 85,5 % αντί για 87,6 %:
| ρύθμιση | επαναλαμβανόμενα 4-grams | βήματα που άλλαξαν |
|---|---|---|
| τίποτα | 85,5 % | 0 / 120 |
| presence 0.5 | 65,0 % | 3 / 120 |
| presence 1.0 | 3,4 % | 11 / 120 |
| frequency 0.5 | 6,0 % | 12 / 120 |
| frequency 1.0 | 0,0 % | 20 / 120 |
| repetition 1.2 (CTRL) | 0,0 % | 35 / 120 |
Τρία πράγματα προκύπτουν. Το presence στο 0,5 άλλαξε τρεις αποφάσεις από 120 και έκοψε την επανάληψη κατά ένα τέταρτο — το loop κρατιόταν από μια χούφτα tokens. Το frequency στο 0,5 άλλαξε τέσσερις φορές περισσότερες αποφάσεις με πολύ μεγαλύτερο αποτέλεσμα, επειδή ο πολλαπλασιαστής καταμέτρησης συνεχίζει να μεγαλώνει ενώ η σταθερά presence όχι. Και το CTRL penalty στην ευρέως αντιγραμμένη τιμή 1,2 ξαναέγραψε 35 από 120 αποφάσεις, πράγμα που δεν είναι σπρώξιμο· είναι διαφορετικό μοντέλο.
Αυτός ο τελευταίος αριθμός στήνει την αποτυχία για την οποία κανείς δεν προειδοποιεί.
Τι κάνουν οι ποινές σε κείμενο που υποτίθεται ότι επαναλαμβάνεται
Σύνδεσμος στην ενότητα: Τι κάνουν οι ποινές σε κείμενο που υποτίθεται ότι επαναλαμβάνεταιΟ κώδικας επαναλαμβάνει. Οι πίνακες επαναλαμβάνουν. Οι λίστες επαναλαμβάνουν. Το structured output επαναλαμβάνει εξ ορισμού — αυτό είναι η δομή. Μια ποινή δεν μπορεί να ξεχωρίσει ένα μοντέλο κολλημένο σε loop από ένα μοντέλο που σωστά εκπέμπει την τέταρτη γραμμή ενός πίνακα, επειδή και τα δύο μοιάζουν με ένα token που εμφανίζεται ξανά.
Οι ίδιες τρεις εργασίες, παραγόμενες με τρεις τρόπους:
| εργασία | τίποτα | frequency 0.5 | repetition 1.2 |
|---|---|---|---|
| markdown table, 6 rows | 0 / 56 steps altered | 0 / 56 | 2 / 62 |
| Python function | 0 / 93 | 0 / 93 | 10 / 110 |
| bulleted list, 1 to 12 | 0 / 50 | 0 / 50 | 0 / 50 |
Το frequency penalty στο 0,5 αποδείχθηκε ακίνδυνο και στις τρεις, που είναι χρήσιμο και ελαφρώς απρόσμενο αποτέλεσμα, και λέει κάτι ακριβές: αφού δεν άλλαξε καμία απόφαση, τα structural tokens πρέπει να κέρδιζαν τις θέσεις τους με περισσότερο από όσο αφαιρούσε η ποινή, ακόμα και αφού εμφανίστηκαν πέντε και έξι φορές. Το CTRL penalty, που διαιρεί αντί γι’ αυτό, όντως τα εκτοπίζει, και εδώ είναι τι παρήγαγε:
repetition 1.2, markdown table:
| n | 2^n |
| --- | --- |
| 0 | 1 |
| 1 | 2 |
| 2 | 4 |Η στοίχιση διαλύεται: η ποσότητα padding μέσα σε κάθε κελί αλλάζει από γραμμή σε γραμμή, επειδή η ακολουθία κενών πριν από το closing pipe είναι ακριβώς το είδος επανάληψης που υπάρχει για να σπάει η ποινή. Κοσμητικό, και κόστισε έξι επιπλέον tokens. Η περίπτωση Python δεν είναι κοσμητική:
nothing / frequency 0.5:
total = 0
for i in range(1, n + 1):
total += i ** 2
return total
repetition 1.2:
# Initialize total_sum with 0
total_sum = 0
# Loop through numbers from 1 to n, incrementing by 2 each time
for i in range(1, n + 1,Η ποινή έσπρωξε το μοντέλο μακριά από το total — ήδη χρησιμοποιημένο στο docstring — προς το total_sum, γέμισε το output με επινοημένα σχόλια για να ξοδέψει τον προϋπολογισμό του σε αχρησιμοποίητα tokens, και μετά μπήκε σε ένα τριών ορισμάτων range με stride. Το σχόλιο λέει incrementing by 2 each time, που είναι λάθος για άθροισμα τετραγώνων από 1 έως . Ένα repetition penalty παρήγαγε λανθασμένο κώδικα από ένα prompt που είχε απαντηθεί σωστά χωρίς αυτό.
Ο κανόνας που ακολουθεί είναι σύντομος: οι ποινές είναι για open-ended prose, και πρέπει να είναι απενεργοποιημένες για κώδικα, structured output, tabular data και οτιδήποτε έχει schema. Το Κεφάλαιο 18 αφορά ακριβώς αυτή τη δεύτερη κατηγορία.
Η σειρά εφαρμογής, και γιατί αλλάζει την απάντηση
Σύνδεσμος στην ενότητα: Η σειρά εφαρμογής, και γιατί αλλάζει την απάντησηΚάθε πραγματική υλοποίηση τα εφαρμόζει με μία συγκεκριμένη σειρά:
penalties → temperature → top-k → top-p → sample
Αυτό δεν είναι αυθαίρετη τήρηση βιβλίων, και η ανταλλαγή δύο σταδίων παράγει πραγματικά διαφορετικές κατανομές. Δύο μετρήσεις, και οι δύο στο factual prompt.
Κοπή πριν ή μετά το temperature. Ο πυρήνας υπολογίζεται πάνω σε όποια κατανομή του δοθεί, και το temperature αλλάζει ριζικά αυτή την κατανομή:
| top-p 0.9 μετά το temperature | top-p 0.9 πριν από το temperature | |
|---|---|---|
| 1 token | 1 token | |
| 353 tokens | 1 token | |
| 32.966 tokens | 1 token |
Στο η ίδια ονομαστική ρύθμιση δίνει σύνολο υποψηφίων 32.966 ή 1, ανάλογα αποκλειστικά με το ποιο στάδιο τρέχει πρώτο. Αν αναρωτηθήκατε ποτέ γιατί η αύξηση του temperature «δεν κάνει τίποτα» σε έναν provider και καταστρέφει το output σε άλλον με τους ίδιους δύο αριθμούς, αυτός ο πίνακας είναι μια πιθανή απάντηση.
Ποινή πριν ή μετά το temperature. Η αφαίρεση μιας ποινής και μετά η διαίρεση με δίνει αποτελεσματική ποινή · η διαίρεση πρώτα και μετά η αφαίρεση δίνει . Με presence penalty 1,0 εφαρμοσμένο στο leading token:
| temperature | ποινή, μετά temper | temper, μετά ποινή |
|---|---|---|
| 0.5 | 99,858 % | 99,948 % |
| 1.0 | 89,839 % | 89,839 % |
| 2.0 | 10,783 % | 6,830 % |
Πανομοιότυπα στο , όπως πρέπει. Διαφορά παράγοντα 1,58 στο . Το «presence penalty 1.0» δεν είναι καλά ορισμένη ποσότητα ποινής εκτός αν ξέρετε επίσης πού εφαρμόζεται το temperature, και κανένα API δεν το τεκμηριώνει αυτό.
Εμφάνιση λεπτομερειών
Προαιρετικό: ολόκληρο το pipeline, με τη σειρά παραπάνω.
Δεκαέξι γραμμές, και όλα σε αυτό το κεφάλαιο βρίσκονται μέσα τους. Είναι ο ίδιος υπολογισμός που εκτελεί το widget, πάνω σε ένα πραγματικό διάνυσμα logit αντί για δέκα σταθερούς αριθμούς.
def sample(logits, counts, presence=0.0, frequency=0.0,
temperature=1.0, top_k=0, top_p=1.0, generator=None):
z = logits.clone()
idx = torch.tensor(list(counts)) # 1. penalties
if len(idx):
z[idx] -= presence
z[idx] -= frequency * torch.tensor([float(c) for c in counts.values()])
if temperature <= 0: # 2. temperature
return int(z.argmax()) # T=0 is argmax
p = torch.softmax(z / temperature, -1)
p, order = p.sort(descending=True)
if top_k: # 3. top-k
p[top_k:] = 0
p = p * ((p.cumsum(0) - p) < top_p) # 4. top-p
p = p / p.sum() # 5. renormalise
return int(order[torch.multinomial(p, 1, generator=generator)])Το cumsum(0) - p στη γραμμή top-p είναι η σωρευτική μάζα εξαιρώντας το τρέχον token, και αυτό κάνει τον πυρήνα να περιλαμβάνει το token που περνά το κατώφλι αντί να σταματά ακριβώς πριν από αυτό. Αν το χάσετε κατά ένα, το top_p = 0.9 γίνεται σιωπηλά μια λίγο πιο στενή κοπή από κάθε άλλη υλοποίηση.
Αυτό είναι ένα από τα λίγα σημεία στο δεύτερο μισό του course όπου η Python είναι η σωστή γλώσσα, και ο λόγος είναι δομικός, όχι στιλιστικός: κάθε γραμμή παραπάνω χρειάζεται ολόκληρο το διάνυσμα των logits στα χέρια σας, και μέσω HTTP API αυτό το διάνυσμα δεν υπάρχει. Μπορείτε να στείλετε temperature και top_p σε έναν provider· δεν μπορείτε να τα υλοποιήσετε, και δεν μπορείτε να δείτε τι έκαναν.
Δεν υπάρχει καθολικό sampling API
Σύνδεσμος στην ενότητα: Δεν υπάρχει καθολικό sampling APIΚάθε provider παίρνει διαφορετικό υποσύνολο αυτών των controls, με διαφορετικά εύρη, και αγνοεί τα υπόλοιπα σιωπηλά. Αυτό δεν είναι αφηρημένο παράπονο. Κάθε εφαρμογή που προσφέρει επιλογή μοντέλου πρέπει να γράψει κάπου τις διαφορές, και το αρχείο όπου το κάνει είναι χάρτης της ασυμβατότητας. Εδώ είναι τι δηλώνει ένας τέτοιος κατάλογος για μία παράμετρο στις εννέα πηγές κειμένου που υποστηρίζει:
| δηλωμένο εύρος temperature | πηγές |
|---|---|
| 0 έως 1 | Anthropic, Google, Meta, Cerebras, PaLM |
| 0 έως 1.5 | Mistral |
| 0 έως 2 | OpenAI, DeepSeek, xAI |
Η λέξη είναι ίδια· η κλίμακα όχι. Ένα «temperature of 1» είναι η μη τροποποιημένη κατανομή σε έναν και η μέγιστη επιτρεπτή θερμότητα σε άλλον, και ο μισός κατάλογος δεν μπορεί να εκφράσει την τιμή που ο άλλος μισός αντιμετωπίζει ως ουδέτερο-συν-λίγο. Τα υπόλοιπα knobs είναι εξίσου άνισα: οι εγγραφές OpenAI, DeepSeek και xAI παίρνουν presence και frequency penalties και κανένα topK· οι εγγραφές Google, Meta, Cerebras και PaLM παίρνουν topK και καθόλου penalties· η Anthropic παίρνει topK, topP και stop sequences και καθόλου penalties· και ακριβώς μία από τις εννέα — η Mistral — παίρνει seed. Το να στείλετε μια παράμετρο που ένας provider δεν υλοποιεί γενικά δεν παράγει κανένα error: το αίτημα πετυχαίνει, το knob δεν κάνει τίποτα, και συμπεραίνετε ότι η ρύθμιση δεν έχει επίδραση.
Και προσέξτε τι είναι ένα τέτοιο αρχείο: ένας ισχυρισμός για το API κάποιου άλλου, γραμμένος μια συγκεκριμένη ημέρα, που τίποτα δεν τον επαληθεύει μετά. Ένας κατάλογος που λέει 0 έως 1 για έναν provider που πλέον δέχεται 0 έως 2 θα κάνει σιωπηλά cap σε κάθε αίτημα.
Δύο ακόμα controls ανήκουν στην ίδια οικογένεια. Το logprobs, όπου προσφέρεται, επιστρέφει τις log-probabilities του επιλεγμένου token και συχνά τις κορυφαίες λίγες εναλλακτικές — το μόνο παράθυρο που έχετε προς την κατανομή για την οποία μιλά αυτό το κεφάλαιο, και τη βάση κάθε heuristic εμπιστοσύνης που χτίζεται πάνω σε κλειστό μοντέλο. Και τα maximum tokens συν stop sequences τελειώνουν το generation χωρίς καμία αναφορά στην πιθανότητα: ένα σκληρό cap και ένα string match. Και τα δύο εμφανίζονται ως το finish_reason από το Κεφάλαιο 14, όπου το length σημαίνει ότι η απάντησή σας κόπηκε στη μέση της πρότασης από budget, όχι ότι ολοκληρώθηκε από το μοντέλο.
Το seed, και ο ντετερμινισμός που δεν έχετε
Σύνδεσμος στην ενότητα: Το seed, και ο ντετερμινισμός που δεν έχετεΟρίστε ένα seed και το sampling γίνεται αναπαραγώγιμο. Αυτό το κομμάτι είναι πραγματικό, και είναι εύκολο να επαληθευτεί:
seed = 1234 " Paris\nWhat is a good geographical qualifier for describing
Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 1234 " Paris\nWhat is a good geographical qualifier for describing
Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 7 " Paris is the capital of France. The appellation of Paris is
\"Île de Paris\"."
seed = 7 " Paris is the capital of France. The appellation of Paris is
\"Île de Paris\"."Πανομοιότυπο σε επίπεδο bytes μέσα σε ένα seed, διαφορετικό μεταξύ seeds, ακριβώς όπως διαφημίζεται. Άρα αυτό που διορθώνει το seed είναι η τυχαία κλήρωση στην τελευταία γραμμή εκείνης της συνάρτησης sample — ποιο token επιλέγεται δεδομένης μιας κατανομής.
Αυτό που δεν διορθώνει είναι η κατανομή. Και εκεί βρίσκεται το πρόβλημα, επειδή το διάνυσμα logits που παράγει το μοντέλο σας δεν είναι μαθηματικό αντικείμενο· είναι το output δισεκατομμυρίων προσθέσεων κινητής υποδιαστολής, και αυτές έχουν σειρά.
Το Κεφάλαιο 2 άφησε αυτό το πείραμα έτοιμο. Τα ίδια ένα εκατομμύριο float32 numbers, αθροισμένα σε διαφορετικές ομαδοποιήσεις:
sequential 998.564270020 error vs float64: 6.393e-03
pairwise (numpy) 998.570556641 error vs float64: 1.061e-04
in 4 chunks 998.570495605 error vs float64: 1.672e-04
in 8 chunks 998.570556641 error vs float64: 1.061e-04
in 16 chunks 998.570678711 error vs float64: 1.594e-05
sequential == pairwise? False
4 chunks == 8 chunks? FalseΚοιτάξτε την τελευταία γραμμή. Ο αριθμός των chunks αλλάζει την απάντηση. Αυτό δεν είναι περιέργεια για το numpy· είναι ο μηχανισμός, επειδή όταν ένας inference server χωρίζει ένα reduction σε περισσότερες ή λιγότερες παράλληλες μονάδες, κάνει ακριβώς αυτό. Και ένας server χωρίζει ανάλογα με το πόσα αιτήματα εξυπηρετεί.
Εδώ είναι αυτή η επίδραση πάνω στο ίδιο το μοντέλο. Το ίδιο prompt, το ίδιο forward pass, με μόνη διαφορά πόσα άλλα αιτήματα έτυχε να βρίσκονται στο batch:
20 identical forward passes, batch of 1: 20 / 20 bit-for-bit identical
the same prompt inside a batch of 2: 147,321 of 151,936 logits differ
the same prompt inside a batch of 4: 146,515 of 151,936 logits differ
the same prompt inside a batch of 8: 146,515 of 151,936 logits differ
the same prompt inside a batch of 16: 147,321 of 151,936 logits differ
largest change to any logit: 2.5e-05Όταν τρέχει μόνο του, το μοντέλο είναι τέλεια ντετερμινιστικό — είκοσι περάσματα, πανομοιότυπα μέχρι το bit. Βάλτε το ίδιο prompt σε ένα batch με άσχετα αιτήματα και 97 % των logits του αλλάζουν. Τίποτα στο αίτημά σας δεν άλλαξε. Έφτασε το αίτημα κάποιου άλλου.
Τώρα το ειλικρινές κομμάτι, επειδή συνήθως αυτό λέγεται σαν να ήταν το τέλος της ιστορίας. Μια αλλαγή μεταβάλλει το output μόνο αν δύο υποψήφια tokens ήταν τόσο κοντά μεταξύ τους. Σε 717 generation steps σε δώδεκα prompts, το μικρότερο χάσμα μεταξύ των δύο κορυφαίων logits ήταν — εκατό φορές μεγαλύτερο από τη διαταραχή — και κανένα βήμα δεν ήταν αρκετά κοντά ώστε να αναστραφεί. Άρα σε αυτό το μοντέλο, σε float32, σε laptop, το batching μετακίνησε κάθε logit και δεν άλλαξε κανένα token.
Αυτό είναι περιγραφή ευνοϊκών συνθηκών, όχι καθησυχασμός, και μία αλλαγή σε αυτές τις συνθήκες αρκεί:
same weights, same prompts, greedy decoding, no seed involved
float32 vs bfloat16: 6 of 8 answers diverge
first divergence at step 23, on average
float32: "...it is scattered and dispersed into different colors,
including blue. The blue light is scattered more than other
colors, so it appears to come from the sky."
bfloat16: "...it is scattered and scattered, causing the colors of the
sun to be scattered and scattered, creating the appearance
of a blue color."Έξι από οκτώ απαντήσεις αποκλίνουν, και μία από αυτές υποβαθμίζεται σοβαρά. Ο πίνακας του Κεφαλαίου 2 λέει γιατί: το bfloat16 κρατά 7 bits mantissa, άρα κοντά σε μέγεθος logit 16 οι αναπαραστάσιμες τιμές απέχουν 0,125 — 16,0, μετά 16,125, μετά 16,25 — και η στρογγυλοποίηση μπορεί να μετακινήσει ένα logit έως και 0,0625. Εν τω μεταξύ, το 4,7 % των generation steps που μετρήθηκαν παραπάνω είχαν top-two gap κάτω από 0,1. Αυτή είναι όλη η διαφορά ανάμεσα στα δύο πειράματα: στο float32 η διαταραχή ήταν εκατό φορές μικρότερη από την πιο κοντινή απόφαση, και στο bfloat16 έχει το ίδιο μέγεθος. Το production inference τρέχει σε 16-bit, σε hardware με fused kernels και reduction orders που κανείς δεν υπόσχεται να κρατήσει. Το αν «ο αριθμητικός θόρυβος είναι αμελητέος» είναι ερώτηση για precision και hardware, όχι για το μοντέλο.
Άρα, οι τέσσερις αιτίες, καταλογογραφημένες όπως υποσχέθηκε το Κεφάλαιο 9:
Η πρόσθεση κινητής υποδιαστολής δεν είναι προσεταιριστική
Σύνδεσμος στην ενότητα: Η πρόσθεση κινητής υποδιαστολής δεν είναι προσεταιριστικήΤο κουτί του Κεφαλαίου 2. Η σειρά ενός αθροίσματος αλλάζει την τιμή του, άρα κάθε αλλαγή στον τρόπο με τον οποίο χωρίζεται ένα reduction αλλάζει τα logits. Αυτό είναι το υπόστρωμα· οι άλλες τρεις είναι τρόποι αλλαγής της σειράς.
Το dynamic batching ομαδοποιεί το αίτημά σας με αγνώστων
Σύνδεσμος στην ενότητα: Το dynamic batching ομαδοποιεί το αίτημά σας με αγνώστωνΤο continuous batching, από το Κεφάλαιο 13, είναι ο λόγος που το inference είναι οικονομικά βιώσιμο — και σημαίνει ότι το σχήμα των μητρών μέσα από τις οποίες περνούν τα tokens σας εξαρτάται από την κίνηση. Μετρημένο παραπάνω: 147.321 logits μετακινήθηκαν επειδή άλλαξε το batch size.
Το mixture-of-experts routing εξαρτάται από το batch
Σύνδεσμος στην ενότητα: Το mixture-of-experts routing εξαρτάται από το batchΤο κουτί του Κεφαλαίου 9 το είχε ήδη πει. Ο router κάνει μια διακριτή επιλογή ανά token ανά layer, υπό τους περιορισμούς χωρητικότητας ανά expert που υπολογίζονται πάνω στο batch. Ένα token που μόνο του θα πήγαινε στον expert 7 πηγαίνει στον expert 12 με παρέα. Αυτό δεν είναι διαφορά στρογγυλοποίησης· είναι διαφορετικό σύνολο βαρών.
Το μοντέλο πίσω από το όνομα αλλάζει
Σύνδεσμος στην ενότητα: Το μοντέλο πίσω από το όνομα αλλάζειΈνα version string όπως -latest είναι pointer, και οι pointers ανακατευθύνονται. Οι providers ενημερώνουν επίσης το serving stack κάτω από σταθερό version identifier. Κανένα από τα δύο δεν ανακοινώνεται με την ανάλυση που θα σας επέτρεπε να το συσχετίσετε με την αλλαγή του δικού σας output.
Η παράμετρος seed της OpenAI είναι ειλικρινής γι’ αυτό με τον μόνο τρόπο που μπορεί: έρχεται μαζί με ένα πεδίο system_fingerprint που ταυτοποιεί τη backend configuration, και το documentation δηλώνει ότι ο ντετερμινισμός είναι best-effort και ότι ένα αλλαγμένο fingerprint σημαίνει πως τα αποτελέσματα μπορεί να διαφέρουν. Διαβάστε το ως αυτό που είναι — ένας provider που σας λέει ότι ελέγχει και τις τέσσερις αιτίες παραπάνω, ότι εσείς δεν ελέγχετε καμία, και ότι το ένα πράγμα που μπορεί να προσφέρει είναι να σας πει εκ των υστέρων ότι κάτι μετακινήθηκε.
Πού πηγαίνει αυτό μετά
Σύνδεσμος στην ενότητα: Πού πηγαίνει αυτό μετάΌλα εδώ αφορούσαν ένα knob και τις συνέπειές του. Κάντε ένα βήμα πίσω και εμφανίζεται το δυσκολότερο πρόβλημα: το αντικείμενο που ρυθμίζαμε είναι μια κατανομή πιθανοτήτων, και οι κατανομές πιθανοτήτων δεν έχουν interface.
Ένα function call έχει. Μια γραμμή βάσης δεδομένων έχει. Ένας handler POST που περιμένει JSON body με τρία απαιτούμενα πεδία έχει, και θα απορρίψει οτιδήποτε άλλο. Ανάμεσα στο μοντέλο και κάθε άλλο component στο σύστημά σας βρίσκεται ένα contract για το οποίο η μία πλευρά δεν μπορεί να δώσει υποσχέσεις: το μοντέλο θα παράγει κάτι, τραβηγμένο από μια κατανομή που έχετε διαμορφώσει αλλά όχι σταθεροποιήσει, και ο κώδικας στην άλλη πλευρά χρειάζεται μια τιμή γνωστού τύπου ή αποτυγχάνει.
Η γέφυρα ανάμεσα σε αυτούς τους δύο κόσμους χτίζεται από το υλικό αυτού του κεφαλαίου, όχι από parsing και retries. Αν ένα token θα έσπαγε την απαιτούμενη δομή, δεν το κάνετε sample ελπίζοντας — θέτετε το logit του σε πριν το δει ποτέ το softmax. Το constrained decoding είναι μια μάσκα πάνω στο ίδιο διάνυσμα που περάσαμε αυτό το κεφάλαιο αναδιαμορφώνοντας, και μετατρέπει το «παρακαλώ απαντήστε σε JSON» από αίτημα σε εγγύηση.
Το Κεφάλαιο 18 είναι αυτό το contract: tool calling, JSON Schema, structured outputs, και τι χρειάζεται για να κάνετε ένα ντετερμινιστικό σύστημα ασφαλές να χτιστεί πάνω σε ένα πιθανοκρατικό.
Πηγές και μέθοδος
Σύνδεσμος στην ενότητα: Πηγές και μέθοδοςΌλες οι μετρήσεις σε αυτό το κεφάλαιο προέρχονται από Qwen/Qwen2.5-0.5B-Instruct σε CPU, float32 εκτός αν αναφέρεται αλλιώς, με το sampling υλοποιημένο όπως γράφεται στην προαιρετική ενότητα αντί να ανατίθεται σε βιβλιοθήκη. Είναι ένα μικρό μοντέλο, και οι συγκεκριμένες τιμές είναι δικές του· οι μηχανισμοί δεν είναι. Το How to generate text with different decoding methods του Von Platen (Hugging Face, 2020) είναι το άρθρο απέναντι στο οποίο μετριέται αυτό εδώ και παραμένει η καλύτερη σύντομη εισαγωγή στο ίδιο υλικό. Για την ενότητα determinism: οι σημειώσεις αναπαραγωγιμότητας του PyTorch περιγράφουν τι διορθώνει και τι δεν διορθώνει ένα seed σε ένα μηχάνημα, το documentation της OpenAI για seed και system_fingerprint περιγράφει τι μπορεί και τι δεν μπορεί να υποσχεθεί ένας provider, και η συζήτηση του 2025 από την Thinking Machines για batch-invariant kernels είναι η καθαρότερη δημόσια εξήγηση του γιατί η διόρθωση αυτού στο επίπεδο inference-server είναι δυνατή αλλά όχι δωρεάν.
Παραπομπές
Σύνδεσμος στην ενότητα: Παραπομπές-
Ackley, D. H., Hinton, G. E. and Sejnowski, T. J. A Learning Algorithm for Boltzmann Machines. Cognitive Science 9(1), pp. 147–169 (1985), όπου το temperature σε ένα softmax προέρχεται από τη στατιστική φυσική. Hinton, G., Vinyals, O. and Dean, J., Distilling the Knowledge in a Neural Network, arXiv:1503.02531 (2015), ενότητα 2, είναι όπου η ίδια παράμετρος επανεμφανίζεται στο σύγχρονο deep learning — ως τρόπος έκθεσης της πλήρους κατανομής ενός teacher, που είναι τα soft labels του Κεφαλαίου 13 και όχι το sampling αυτού του κεφαλαίου. ↩
-
Guo, C., Pleiss, G., Sun, Y. and Weinberger, K. Q. On Calibration of Modern Neural Networks. arXiv:1706.04599 (2017). Μην το συγχέετε με το temperature σε αυτό το κεφάλαιο. Το temperature scaling προσαρμόζει μία μοναδική τιμή σε ένα validation set ώστε η βεβαιότητα του μοντέλου να ταιριάζει με την ακρίβειά του· είναι μια post-hoc μέθοδος calibration που εφαρμόζεται στα outputs ενός ταξινομητή. Το temperature sampling είναι runtime control πάνω στο πώς ένας generator τραβά tokens. Ίδιος τύπος, διαφορετικός σκοπός, και καμία κοινή τιμή. ↩
-
Holtzman, A., Buys, J., Du, L., Forbes, M. and Choi, Y. The Curious Case of Neural Text Degeneration. arXiv:1904.09751 (2019). Εισάγει το nucleus sampling και τη μέτρηση ότι το decoding που βασίζεται στη μεγιστοποίηση παράγει κείμενο του οποίου το προφίλ πιθανότητας δεν μοιάζει καθόλου με ανθρώπινο κείμενο. ↩ ↩2
-
Fan, A., Lewis, M. and Dauphin, Y. Hierarchical Neural Story Generation. arXiv:1805.04833 (2018). Το paper που έκανε δημοφιλές το top-k sampling. ↩
-
Nguyen, M. et al. Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs. arXiv:2407.01082 (2024). ↩
-
Meister, C., Pimentel, T., Wiher, G. and Cotterell, R. Locally Typical Sampling. arXiv:2202.00666 (2022). ↩
-
Keskar, N. S., McCann, B., Varshney, L. R., Xiong, C. and Socher, R. CTRL: A Conditional Transformer Language Model for Controllable Generation. arXiv:1909.05858 (2019). Η ενότητα 4.1 είναι το αρχικό repetition penalty — αυτό που διαιρεί. ↩