Настройки сэмплирования
Сэмплирование — последний дюйм инференса: модель оценивает каждый токен словаря, а ваши настройки решают, как это распределение становится одним токеном. Ручки взаимодействуют, поэтому порядок операций важнее любого отдельного значения.
Конвейер, по порядку
Большинство движков применяет сэмплеры примерно в такой последовательности:
- Логиты — сырые оценки, по одной на токен словаря (50k–150k записей).
- Штрафы за повторы — недавно виденные токены получают занижение логитов.
- Температура — логиты делятся на T, заостряя или уплощая всё.
- top_k — жёсткая крышка: выживают только k лучших токенов.
- top_p — ядро: наименьший верхний набор, покрывающий p массы вероятностей.
- min_p — относительный пол: отбрасывает токены ниже min_p × P(топ-токена).
- Сэмпл — выбрать один токен из оставшихся, дописать, повторить.
Фильтр, применённый рано, меняет то, что видит каждый последующий. Помните об этом при наслаивании.
Температура
Температура T делит логиты до softmax. Ниже T — заостряет распределение к топ-токену; выше T — уплощает к равномерному. Конкретно: логиты [5.0, 3.0, 1.0] по трём токенам.
| T | P(топ) | P(второй) | P(третий) |
|---|---|---|---|
| 0.5 | 98.1% | 1.8% | 0.03% |
| 1.0 | 86.7% | 11.7% | 1.6% |
| 1.5 | 75.0% | 19.8% | 5.2% |
При T → 0 это схлопывается в жадный режим: всегда argmax, полностью детерминированно.
Используйте температуру 0 (или 0.000001 там, где движок запрещает 0) для извлечения, классификации и всего, что хотите воспроизводить от запуска к запуску. Чату подходит 0.6–0.8; творческое письмо терпит 0.9–1.2.
top_k: жёсткая крышка
Оставить только k токенов с наивысшей вероятностью и сэмплировать среди них. top_k 40 делает токен 41 и ниже невозможными, что бы ни было.
Это грубый инструмент. k=40 просторно после «The capital of France is» и абсурдно расточительно на позициях редких токенов, где важны лишь два кандидата. Обычный дефолт: 40. Отключайте (0 или -1, зависит от движка), когда используете min_p.
top_p: ядро
Сортировать по вероятности, оставить наименьший набор, чья накопленная вероятность достигает p, ренормировать, сэмплировать.
Разбор: вероятности [0.867, 0.117, 0.016] с top_p 0.9. Верхний токен один покрывает 0.867 < 0.9; добавление второго достигает 0.984 ≥ 0.9. Вы сэмплируете из двух токенов, ренормированных в [0.88, 0.12].
Набор кандидатов сжимается автоматически, когда модель уверена, и растёт, когда не уверена. Типичный диапазон: 0.9–0.95.
min_p: локальный фаворит
Держать только токены, чья вероятность не меньше min_p × P(топ-токена). Пол относителен к масштабу:
- Модель уверена на 99% → пол = 0.05 × 0.99 ≈ 0.05: выживают только реальные претенденты.
- Топ-токен на 30% → пол = 0.05 × 0.30 = 0.015: разнообразие выживает.
Это убивает классические провалы top_k/top_p — перепрореживание уверенного распределения, недопрореживание плоского — и min_p безопасно сочетается с высокой температурой. Рецепт «творчески, но связно»: temp 1.0–1.5, min_p 0.05–0.1. Обычная локальная настройка: min_p 0.05 с выключенными top_k и top_p.
repeat_penalty (семейство llama.cpp)
До применения температуры логиты токенов, встречавшихся в недавнем контексте, делятся на штраф. Значения ниже 1.0 наоборот усиливают повторы. Разумный диапазон: 1.0–1.1.
Побочные эффекты реальны, потому что код и данные повторяют токены намеренно:
- Идентификаторы легитимно повторяются:
countвнутриcounter.count. - Ключи JSON и закрывающие скобки повторяются в каждом объекте массива.
- Штраф 1.2+ ломает код и JSON (потерянные скобки, «исправленные» кавычки) задолго до того, как починит прозаические циклы.
Современным instruct-моделям редко нужно больше 1.05. Для кода и структурированного вывода 1.0 — законный выбор.
frequency и presence penalties (стиль API)
OpenAI-совместимые API открывают frequency_penalty (растёт с каждым повтором) и presence_penalty (плоский штраф за любой уже виденный токен) там, где llama.cpp использует repeat_penalty. Та же цель, другая математика. Не каждый локальный движок поддерживает оба — проверьте, что реализует ваш, прежде чем наслаивать их друг на друга: параметры движка.
Сэмплируйте себя в угол
temp 0.1 + top_k 10 + top_p 0.5 + min_p 0.2 + repeat_penalty 1.3, применённые вместе, могут замаскировать каждый токен-кандидат. Симптомы: предупреждения NaN logprob, пустые генерации, аборты «sampling returned zero candidates».
Это не сломанная модель — это пустой набор кандидатов. Ослабьте стек, по одной ручке за раз. Полный триаж: диагностика.
Пресеты, которые работают
| Задача | temp | top_p | min_p | repeat_penalty |
|---|---|---|---|---|
| Чат (общий) | 0.7 | 0.90–0.95 | 0.05 | 1.0–1.05 |
| Генерация кода | 0.1–0.2 | 0.9 | — | 1.0 |
| Извлечение / классификация | 0 (жадно) | — | — | 1.0 |
| Творческое письмо | 0.9–1.0 | 0.95 | 0.05–0.1 | 1.05–1.1 |
| Перевод | 0.2–0.4 | 0.9 | — | 1.0 |
Строка чата как флаги llama.cpp:
llama-server -m model.gguf --temp 0.7 --top-p 0.95 --min-p 0.05 --repeat-penalty 1.05
Меняйте по одному за раз
Относитесь к пресетам как к отправным точкам, а не законам. Если вы двигаете температуру и top_p вместе и вывод улучшается, вы не узнали, какая ручка сыграла роль.
- Зафиксируйте тестовый набор: 5–10 промптов, задевающих то, что вам важно.
- Сохраняйте выводы по конфигурациям; сравнивайте их бок о бок.
- Меняйте ровно одну ручку за прогон.
- Сохраните победителя как именованный пресет — каждый движок и UI их хранят.
Как эти ручки ложатся на флаги движка и поля API: параметры движка.
Связанные разделы: параметры движка · промптинг · структурированный вывод · диагностика