טמפרטורה, top-p והדטרמיניזם שאין לכם
Temperature מחלקת את ה-logits לפני ה-softmax — וזה מפרק את רעיון ״חוגת היצירתיות״. וגם: אותה קריאה greedy, פעמיים, שתי תשובות.
בעמוד הזה
הנה אותה בקשה שנשלחה לאותו מודל חמש פעמים. אותם משקלים, אותו prompt, אותה מכונה, אותו 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, ברוב התיעוד הוא מתואר כחוגת יצירתיות, והתיאור הזה שגוי באופן שהפרק הזה יכול להדגים במקום רק לטעון.
זה גם הפרק שבו שלוש הבטחות מוקדמות נפרעות. פרק 4 הגדיר את ה-logit ואף פעם לא ממש השתמש בו. תיבת הנקודה הצפה של פרק 2 הסתיימה בהוראה — זכרו את זה כשפרק 17 ישאל למה אותו prompt, מודל ו-seed יכולים לייצר tokens שונים. ותיבת mixture-of-experts של פרק 9 הבטיחה קטלוג של ארבע סיבות לאי-דטרמיניזם. שלושתן מגיעות בהמשך.
השורה האחת שכל הפרק נשען עליה
קישור למקטע: השורה האחת שכל הפרק נשען עליהפרק 4 הציג את ה-logit כציון ממשי לא מנורמל, אחד לכל מחלקה. פרק 8 גרם למודל שפה לייצר אחד כזה לכל ערך באוצר המילים. ה-softmax הופך את הווקטור להסתברויות:
Temperature נכנסת כאן — השם שאול מהפיזיקה הסטטיסטית, שבה אותו פרמטר שולט בכמה בחדות התפלגות בולצמן מתרכזת במצבי האנרגיה הנמוכה שלה1 — ו-היא מחלקת את ה-logits לפני האקספוננט:
המיקום הזה הוא כל המנגנון, ושווה לראות בשתי שורות אלגברה למה הוא לא יכול היה להיות בשום מקום אחר. נניח שניסיתם להחיל temperature על ההסתברויות במקום זאת — להכפיל אותן ב- ולנרמל מחדש. הייתם מקבלים
הקבוע מתבטל. כפל הסתברויות לא עושה שום דבר בכלל; ההתפלגות חוזרת ללא שינוי. ל-temperature יש השפעה רק משום שהיא פועלת על האקספוננט, שם חלוקה ב- לפני העלאה בחזקה שקולה להעלאת כל הסתברות בחזקת — עיצוב לא-ליניארי מחדש שמשנה את היחסים בין הערכים, ולא את הסקאלה המשותפת שלהם.
מהמיקום הזה, שני הגבולות נובעים בלי עוד עבודה. כאשר ה-logit הגדול ביותר בורח מהשאר ו- קורסת אל ה-token היחיד שקיבל את הציון הגבוה ביותר: greedy decoding. כאשר גדל, כל נע לעבר אפס, כל אקספוננט נע לעבר 1, וההתפלגות משתטחת לעבר אחידה על פני כל אוצר המילים. בדיוק ב- הנוסחה מחלקת באפס, ולכן כל מימוש מטפל בזה כמקרה מיוחד של המקסימום האריתמטי — כולל הווידג׳ט למטה, שעובר ל-argmax ב-.
אזהרה אחת, כי התנגשות השמות גורמת לבלבול אמיתי. יש דבר שני, לא קשור, שנקרא temperature בלמידת מכונה: temperature scaling, שיטת כיול שמתאימה ערך אחד על סט ולידציה כדי שהביטחון של מסווג יתאים לדיוק שלו.2 אותה נוסחה, אין קשר ל-generation. כשמאמרים אומרים ״temperature״ הם לעיתים מתכוונים לזה; הפרק הזה אף פעם לא.
הנה ההתפלגות הזאת, עם החשבון מול העיניים. ה-logits קבועים וסבירים, כך שאפשר לבדוק את המספרים בטקסט מול מה שאתם רואים:
Temperature היא לא חוגת יצירתיות
קישור למקטע: Temperature היא לא חוגת יצירתיותהמספר ␣banana הוא כל הטיעון בקטן: העלאת ה-temperature לא יכולה לתת למודל רעיון שלא היה לו. ה-logits כבר חושבו, הדירוג כבר קבוע, ו-temperature משמרת אותו בדיוק — שום כמות של חום לעולם לא תעביר token שקיבל ציון נמוך מעל token שקיבל ציון גבוה. כל מה שהיא עושה הוא לחלק מחדש מסה במורד הדירוג שהמודל עצמו ייצר. Temperature גבוהה לא הופכת מודל ליותר יצירתי; היא מגדילה את הסיכוי שהוא יפלוט את ה-tokens שהוא עצמו דירג כגרועים.
באוצר מילים אמיתי זה מפסיק להיות קוריוז והופך לסיבה שבגללה פלט ב-temperature גבוהה אינו שמיש. נמדד על Qwen/Qwen2.5-0.5B-Instruct, מעבר קדימה אחד, ה-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++ כאפשרויות חיות למילה שאחרי A:. הזבל בבלוק הפתיחה הוא התוצאה הישירה, וזה לא באג במודל או בספרייה — זה מה שהבקשה ביקשה.
הטווח השימושי צר ותלוי במשימה ולא בטעם. בשאלה עובדתית התשובה היא 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 עבור המודל הזה במשימה הזאת, והעצה הכנה היא למצוא אותה במדידה על המשימה שלכם, לא בהעתקת מספר מפוסט בבלוג.
למה הטקסט הסביר ביותר הוא טקסט גרוע
קישור למקטע: למה הטקסט הסביר ביותר הוא טקסט גרועיש שאלה מובנת שמסתתרת מתחת לכל זה: אם למודל יש התפלגות הסתברות ו-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 כבר הופיעו קודם באותו פלט. זו ניוון טקסט נוירוני, כפי שנקרא והוסבר בידי Holtzman ואחרים במאמר שהציג את top-p.3 המודל לא שבור; מקסום הסתברות רצף הוא פשוט יעד שגוי לטקסט פתוח. כתיבה אנושית אינה רצף המילים הסביר ביותר — יש בה הפתעה, הסתברות ה-token שלה נודדת, יורדת ומתאוששת — בעוד שהמסלול בעל ההסתברות המרבית הוא נקודת שבת, שברגע שנכנסים אליה אין לה סיבה לצאת.
זו הסיבה ש-sampling קיים בכלל. וזה גם, וזה החלק שבדרך כלל נשמט, לא חוק אוניברסלי. פרק 12 מדד 24 מתוך 24 תשובות נכונות בבעיות מילוליות דו-שלביות עם greedy decoding רגיל, ו-sampling ב-temperature 0.8 הוריד את זה ל-81 %; self-consistency אז הוציא פי שישה tokens כדי לטפס חזרה למקום שבו greedy כבר היה. שני הדברים נכונים בו-זמנית:
Generation פתוח. אין המשך נכון יחיד, ולכן ההמשך הסביר ביותר הוא מלכודת — הוא לולאתי, ו-87.6 % ממנו מועתק מעצמו. בצעו sample.
משימות עם תשובה נכונה אחת. יש המשך נכון יחיד, ולכן משיכה של כל דבר אחר היא משיכת שגיאה. ה-100 % של פרק 12 הפכו ל-81 % בדיוק מהסיבה הזאת. אל תבצעו sample.
רוב ה-production prompts הם מהסוג השני ומוגדרים כמו הראשון, כי ה-temperature נשארה על מה שקוד הדוגמה השתמש בו.
שתי דרכי חיתוך, ורק אחת מהן מסתגלת
קישור למקטע: שתי דרכי חיתוך, ורק אחת מהן מסתגלת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 % |
קבוע אחד, שני כישלונות בכיוונים הפוכים. ב-prompt העובדתי, מכניס 39 tokens שביחד שווים 3.6 % — הוא נותן לזבל לעבור, כולל מועמד של תשע אלפיות האחוז, כי הכלל סופר מקומות ולא ראיות. ב-prompt הסיפורי, אותו זורק 21 % מהמסה שהמודל באמת הקצה, כי הגרעין האמיתי שם הוא ברוחב 467 tokens.
Top-p גורם למספר אחד בדיוק לעשות את שני התפקידים. קבעו והוא משאיר token אחד ב-prompt הראשון ו-467 בשני, כי הוא שואל שאלה על ההתפלגות במקום לכפות עליה ספירה. ראו את ההסתגלות הזאת ישירות — אותו חיתוך, ארבע temperatures:
הווידג׳ט הזה גם מיישב תפיסה שגויה שראוי לקרוא לה בשם, כי היא עולה לאנשים כסף אמיתי. בהתפלגות בטוחה, top_p = 0.9 הוא לא ״קצת גיוון״. הוא greedy. ב-temperature 1 ה-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)המקורי, ממאמר CTRL.7 הוא מחלק במקום לחסר, עם טיפול בסימן משום שחלוקת logit שלילי הייתה מגדילה אותו. לכן העוצמה שלו תלויה בגודל ה-logit, כלומר אותו פוגע אחרת בנקודות שונות באותו משפט.
אותו המשך מנוון מקודם, כאשר כל אחד מהם מופעל. ״צעדים ששונו״ סופר כמה מתוך 120 צעדי ה-generation בחרו token שונה מזה שהמודל ללא קנס היה בוחר. הריצה כאן היא 120 צעדים לעומת 140 בבלוק שלמעלה, ולכן קו הבסיס ללא קנס הוא 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 וחתך את החזרתיות ברבע — הלולאה הוחזקה יחד בידי קומץ tokens. Frequency ב-0.5 שינה פי ארבעה יותר החלטות עם השפעה גדולה בהרבה, כי מכפיל הספירה ממשיך לגדול בזמן שקבוע ה-presence לא. וקנס CTRL בערך המועתק בהרחבה 1.2 כתב מחדש 35 מתוך 120 החלטות, וזה לא דחיפה קלה; זה מודל אחר.
המספר האחרון הזה מכין את הכישלון שאף אחד לא מזהיר מפניו.
מה קנסות עושים לטקסט שאמור לחזור על עצמו
קישור למקטע: מה קנסות עושים לטקסט שאמור לחזור על עצמוקוד חוזר על עצמו. טבלאות חוזרות על עצמן. רשימות חוזרות על עצמן. פלט מובנה חוזר על עצמו מעצם ההגדרה — זה מה שמבנה הוא. קנס לא יכול להבדיל בין מודל שנתקע בלולאה לבין מודל שפולט נכון את השורה הרביעית בטבלה, כי בשני המקרים זה נראה כמו token שמופיע שוב.
אותן שלוש משימות, נוצרו בשלוש דרכים:
| משימה | כלום | frequency 0.5 | repetition 1.2 |
|---|---|---|---|
| טבלת markdown, 6 שורות | 0 / 56 צעדים ששונו | 0 / 56 | 2 / 62 |
| פונקציית Python | 0 / 93 | 0 / 93 | 10 / 110 |
| רשימת bullets, 1 עד 12 | 0 / 50 | 0 / 50 | 0 / 50 |
קנס frequency ב-0.5 התברר כלא מזיק בכל השלוש, וזו תוצאה שימושית ומפתיעה מעט, והיא אומרת משהו מדויק: מאחר ששום החלטה לא השתנתה, ה-tokens המבניים כנראה ניצחו במיקומים שלהם ביותר ממה שהקנס חיסר, גם אחרי שהופיעו חמש ושש פעמים. קנס CTRL, ש-מחלק במקום זאת, כן מזיז אותם, והנה מה שהוא ייצר:
repetition 1.2, markdown table:
| n | 2^n |
| --- | --- |
| 0 | 1 |
| 1 | 2 |
| 2 | 4 |היישור מתפרק: כמות הריווח בתוך כל תא משתנה משורה לשורה, כי רצף הרווחים לפני הקו האנכי הסוגר הוא בדיוק סוג החזרתיות שהקנס נועד לשבור. קוסמטי, וזה עלה בשישה 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, ריפד את הפלט בהערות מומצאות כדי להוציא את התקציב שלו על tokens שלא שימשו, ואז נכנס ל-range בעל שלושה ארגומנטים עם stride. ההערה אומרת incrementing by 2 each time, וזה שגוי עבור סכום ריבועים מ-1 עד . Repetition penalty ייצר קוד שגוי מ-prompt שנענה נכון בלעדיו.
הכלל שנובע מכך קצר: קנסות מיועדים לפרוזה פתוחה, והם צריכים להיות כבויים עבור קוד, פלט מובנה, נתונים טבלאיים וכל דבר עם schema. פרק 18 עוסק בדיוק בקטגוריה השנייה הזאת.
סדר היישום, ולמה הוא משנה את התשובה
קישור למקטע: סדר היישום, ולמה הוא משנה את התשובהכל מימוש אמיתי מפעיל את אלה ברצף מסוים אחד:
penalties → temperature → top-k → top-p → sample
זה לא ניהול חשבונות שרירותי, והחלפה בין שני שלבים מייצרת התפלגויות שונות באמת. שתי מדידות, שתיהן על ה-prompt העובדתי.
חיתוך לפני או אחרי ה-temperature. הגרעין מחושב על כל התפלגות שניתנת לו, ו-temperature משנה את ההתפלגות הזאת באופן קיצוני:
| top-p 0.9 אחרי temperature | top-p 0.9 לפני temperature | |
|---|---|---|
| token אחד | token אחד | |
| 353 tokens | token אחד | |
| 32,966 tokens | token אחד |
ב- אותה הגדרה נומינלית מניבה קבוצת מועמדים של 32,966 או של 1, רק כתלות בשאלה איזה שלב רץ קודם. אם אי פעם תהיתם למה העלאת ה-temperature ״לא עושה כלום״ אצל ספק אחד ומשמידה את הפלט אצל אחר עם אותם שני מספרים, הטבלה הזאת היא תשובה סבירה.
ענישה לפני או אחרי ה-temperature. חיסור קנס ואז חלוקה ב- נותנים קנס אפקטיבי של ; חלוקה קודם ואז חיסור נותנים . עם presence penalty של 1.0 שמוחל על ה-token המוביל:
| temperature | מענישים, ואז מחממים | מחממים, ואז מענישים |
|---|---|---|
| 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, בסדר שלמעלה.
שש-עשרה שורות, וכל מה שבפרק הזה נמצא בהן. זה אותו חישוב שהווידג׳ט מבצע, על וקטור 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 הופך בשקט לחיתוך מעט הדוק יותר מכל מימוש אחר.
זה אחד המקומות הבודדים במחצית השנייה של הקורס שבהם Python היא השפה הנכונה, והסיבה מבנית ולא סגנונית: כל שורה למעלה צריכה את וקטור ה-logits המלא בידיים שלכם, וב-HTTP API הווקטור הזה לא קיים. אתם יכולים לשלוח temperature ו-top_p לספק; אתם לא יכולים לממש אותם, ואתם לא יכולים לראות מה הם עשו.
אין API אוניברסלי ל-sampling
קישור למקטע: אין API אוניברסלי ל-samplingכל ספק מקבל תת-קבוצה אחרת של הבקרות האלה, עם טווחים שונים, ומתעלם מהשאר בשקט. זו לא תלונה מופשטת. כל יישום שמציע בחירת מודל צריך לכתוב את ההבדלים איפשהו, והקובץ שבו הוא עושה זאת הוא מפה של אי-התאימות. הנה מה שקטלוג אחד כזה מצהיר עבור פרמטר יחיד על פני תשעת מקורות הטקסט שהוא תומך בהם:
| טווח temperature מוצהר | מקורות |
|---|---|
| 0 עד 1 | Anthropic, Google, Meta, Cerebras, PaLM |
| 0 עד 1.5 | Mistral |
| 0 עד 2 | OpenAI, DeepSeek, xAI |
המילה זהה; הסקאלה לא. ״temperature של 1״ היא ההתפלגות הלא-משונה אצל אחד והחום המרבי המותר אצל אחר, וחצי מהקטלוג לא יכול לבטא את הערך שהחצי השני מתייחס אליו כנייטרלי-פלוס-קצת. שאר הכפתורים לא אחידים באותה מידה: הרשומות של OpenAI, DeepSeek ו-xAI מקבלות presence ו-frequency penalties וללא topK; הרשומות של Google, Meta, Cerebras ו-PaLM מקבלות topK וללא קנסות; Anthropic מקבלת topK, topP ו-stop sequences וללא קנסות; ו-בדיוק אחד מתוך התשעה — Mistral — מקבל seed. שליחת פרמטר שספק לא מממש בדרך כלל לא מייצרת שגיאה בכלל: הבקשה מצליחה, הכפתור לא עושה כלום, ואתם מסיקים שלהגדרה אין השפעה.
ושימו לב מה קובץ כזה הוא: טענה על API של מישהו אחר, שנכתבה ביום מסוים, ושום דבר לא מאמת אחר כך. קטלוג שאומר 0 עד 1 עבור ספק שכעת מקבל 0 עד 2 יגביל כל בקשה בשקט.
עוד שתי בקרות שייכות לאותה משפחה. logprobs, כשהיא מוצעת, מחזירה את log-probabilities של ה-token שנבחר ולעיתים את כמה החלופות העליונות — החלון היחיד שאתם מקבלים אל ההתפלגות שעליה הפרק הזה מדבר, והבסיס לכל heuristics של ביטחון שנבנים על מודל סגור. ו-maximum tokens יחד עם stop sequences מסיימים generation ללא שום התייחסות להסתברות: תקרה קשיחה והתאמת מחרוזת. שניהם צפים כ-finish_reason מ-פרק 14, שבו length אומר שהתשובה שלכם נחתכה באמצע משפט בגלל תקציב, לא הסתיימה בידי המודל.
ה-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 שהמודל שלכם מייצר אינו אובייקט מתמטי; הוא פלט של מיליארדי חיבורים בנקודה צפה, ולחיבורים האלה יש סדר.
פרק 2 השאיר את הניסוי הזה מוכן. אותם מיליון מספרי float32, נסכמים בקיבוצים שונים:
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 מפצל reduction על פני יותר או פחות יחידות מקביליות, הוא עושה בדיוק את זה. ושרת מפצל לפי מספר הבקשות שהוא משרת.
הנה ההשפעה הזאת על המודל עצמו. אותו prompt, אותו מעבר קדימה, ההבדל היחיד הוא כמה בקשות אחרות במקרה היו ב-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כשהוא רץ לבד, המודל דטרמיניסטי לחלוטין — עשרים מעברים, זהים עד הביט. הכניסו את אותו prompt ל-batch עם בקשות לא קשורות ו-97 % מה-logits שלו משתנים. שום דבר בבקשה שלכם לא השתנה. בקשה של מישהו אחר הגיעה.
עכשיו החלק הכנה, כי בדרך כלל מספרים את זה כאילו זה סוף הסיפור. שינוי של משנה את הפלט רק אם שני tokens מועמדים היו במרחק כזה זה מזה. על פני 717 צעדי generation ב-12 prompts, הפער הקטן ביותר בין שני ה-logits העליונים היה — פי מאה מההפרעה — ו-שום צעד לא היה קרוב מספיק כדי להתהפך. לכן במודל הזה, ב-float32, על לפטופ, 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 ביטים של mantissa, ולכן ליד גודל logit של 16 הערכים שניתנים לייצוג נמצאים במרחק 0.125 — 16.0, ואז 16.125, ואז 16.25 — ועיגול יכול להזיז logit עד 0.0625. בינתיים 4.7 % מצעדי ה-generation שנמדדו למעלה היו בעלי פער בין שני העליונים מתחת ל-0.1. זה כל ההבדל בין שני הניסויים: ב-float32 ההפרעה הייתה קטנה פי מאה מההחלטה הקרובה ביותר, וב-bfloat16 היא באותו גודל. Production inference רץ ב-16-bit, על חומרה עם kernels מאוחדים וסדרי reduction שאף אחד לא מבטיח לשמור. האם ״הרעש המספרי זניח״ היא שאלה על דיוק וחומרה, לא על המודל.
אז אלה ארבע הסיבות, מקוטלגות כפי שפרק 9 הבטיח:
חיבור בנקודה צפה אינו אסוציאטיבי
קישור למקטע: חיבור בנקודה צפה אינו אסוציאטיביהתיבה של פרק 2. סדר הסכימה משנה את הערך שלה, ולכן כל שינוי באופן שבו reduction מפוצל משנה את ה-logits. זה המצע; שלושת האחרים הם דרכים לשנות את הסדר.
Dynamic batching מקבץ את הבקשה שלכם עם בקשות של זרים
קישור למקטע: Dynamic batching מקבץ את הבקשה שלכם עם בקשות של זריםContinuous batching, מ-פרק 13, הוא הסיבה ש-inference זול — והוא אומר שצורת המטריצות שה-tokens שלכם עוברים דרכן תלויה בתעבורה. נמדד למעלה: 147,321 logits זזו כי גודל ה-batch השתנה.
Mixture-of-experts routing תלוי ב-batch
קישור למקטע: Mixture-of-experts routing תלוי ב-batchהתיבה של פרק 9 כבר אמרה זאת. ה-router עושה בחירה בדידה לכל token בכל שכבה, בכפוף למגבלות קיבולת לכל expert שמחושבות על פני ה-batch. token שהיה הולך ל-expert 7 לבד הולך ל-expert 12 בחברה. זה לא הבדל עיגול; זו קבוצת משקלים אחרת.
המודל שמאחורי השם משתנה
קישור למקטע: המודל שמאחורי השם משתנהמחרוזת גרסה כמו -latest היא מצביע, ומצביעים מופנים מחדש. ספקים גם מעדכנים את שכבת ההגשה תחת מזהה גרסה קבוע. אף אחד מהם לא מוכרז ברזולוציה שתאפשר לכם לקשר אותו לשינוי בפלט שלכם.
פרמטר seed של OpenAI כן בעניין הזה באופן היחיד שבו הוא יכול להיות: הוא נשלח לצד שדה system_fingerprint שמזהה את תצורת ה-backend, והתיעוד מציין שדטרמיניזם הוא best-effort וש-fingerprint שהשתנה אומר שהתוצאות עשויות להיות שונות. קראו את זה כפי שזה — ספק שאומר לכם שהוא שולט בכל ארבע הסיבות שלמעלה, שאתם לא שולטים באף אחת מהן, ושהדבר היחיד שהוא יכול להציע הוא לומר לכם בדיעבד שמשהו זז.
לאן ממשיכים מכאן
קישור למקטע: לאן ממשיכים מכאןכל מה שהיה כאן עסק בכפתור ובהשלכות שלו. צעד אחד אחורה חושף את הבעיה הקשה יותר: האובייקט שכיווננו הוא התפלגות הסתברות, ולהתפלגויות הסתברות אין ממשק.
ל-function call יש אחד. לשורת מסד נתונים יש אחד. ל-handler של POST שמצפה לגוף JSON עם שלושה שדות חובה יש אחד, והוא ידחה כל דבר אחר. בין המודל לבין כל רכיב אחר במערכת שלכם יושב חוזה שצד אחד לא יכול להבטיח לגביו: המודל יפיק משהו, שנמשך מהתפלגות שעיצבתם אבל לא קיבעתם, והקוד בצד השני צריך ערך מסוג ידוע או שהוא זורק שגיאה.
הגשר בין שני העולמות האלה נבנה מהחומר של הפרק הזה ולא מ-parsing וניסיונות חוזרים. אם token ישבור את המבנה הנדרש, לא עושים לו sample ומקווים — קובעים את ה-logit שלו ל- לפני שה-softmax בכלל רואה אותו. Constrained decoding הוא mask מעל אותו וקטור שבילינו את הפרק הזה בעיצובו מחדש, והוא הופך את ״אנא ענה ב-JSON״ מבקשה להבטחה.
פרק 18 הוא החוזה הזה: tool calling, JSON Schema, פלטים מובנים, ומה נדרש כדי להפוך מערכת דטרמיניסטית לבטוחה לבנייה מעל מערכת הסתברותית.
מקורות ושיטה
קישור למקטע: מקורות ושיטהכל המדידות בפרק הזה מגיעות מ-Qwen/Qwen2.5-0.5B-Instruct על CPU, ב-float32 אלא אם צוין אחרת, כאשר ה-sampling ממומש כפי שנכתב בסעיף האופציונלי ולא מואצל לספרייה. זה מודל קטן, והערכים הספציפיים הם שלו; המנגנונים אינם. המאמר של Von Platen, How to generate text with different decoding methods (Hugging Face, 2020), הוא המאמר שהטקסט הזה נמדד מולו והוא עדיין המבוא הקצר הטוב ביותר לאותו חומר. עבור סעיף הדטרמיניזם: הערות השחזוריות של PyTorch מתארות מה seed כן ולא מקבע במכונה אחת, התיעוד של OpenAI על seed ו-system_fingerprint מתאר מה ספק יכול ולא יכול להבטיח, והדיון של Thinking Machines מ-2025 על kernels שאינם תלויי batch הוא ההסבר הציבורי הברור ביותר לכך שתיקון הבעיה ברמת שרת ה-inference אפשרי אך אינו חינמי.
הפניות
קישור למקטע: הפניות-
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 מתאים ערך יחיד על סט ולידציה כדי שהביטחון של המודל יתאים לדיוק שלו; זו שיטת כיול בדיעבד שמוחלת על פלטי מסווג. Temperature sampling היא בקרת runtime על האופן שבו 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). המאמר שהפיץ את 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 המקורי — זה שמחלק. ↩