Модуль 3. Бандиты, исследование и одношаговые решения
Сначала попробуйте решить упражнение. Ответы, подробные решения и проектные ориентиры раскрываются отдельно и сохраняют своё состояние при переключении RU/EN.
Скачать файлы курса (.zip) 382,1 КБАрхив содержит файлы на обоих языках и вспомогательные материалы с сохранением структуры каталогов.
Бандит или последовательная задача
Для каждого случая выберите наиболее точную модель: обычный бандит, контекстный бандит или марковский процесс принятия решений (Markov decision process, MDP).
-
Сервис на каждом независимом запросе выбирает одну из трёх моделей; известны признаки запроса, после ответа приходит скалярная оценка, а выбор не влияет на будущие запросы.
-
Агент открывает страницы сайта, извлекает сведения и решает, какую ссылку открыть дальше.
-
Для одинаковой аудитории поочерёдно показываются два неизменных баннера; регистрируется только клик по показанному баннеру.
-
Диалоговая система выбирает реплику, после которой пользователь отвечает и меняет ход разговора.
Для каждого ответа укажите одно предположение, нарушение которого изменило бы выбранную модель.
Показать ответ и решение
-
Контекстный бандит. Признаки запроса влияют на выбор модели, но ответ не меняет следующий запрос. Модель перестанет быть достаточной, если обслуживание пользователя влияет на его дальнейшие запросы или удержание.
-
Марковский процесс принятия решений (
Markov decision process, MDP). Открытая страница меняет доступные ссылки и сведения, то есть действие создаёт следующее состояние. -
Обычный бандит. Контекст считается одинаковым, награда наблюдается только для показанного баннера. Если аудитория или привлекательность баннеров меняются со временем, появляется нестационарность или контекст.
-
MDP либо частично наблюдаемая последовательная задача. Реплика меняет будущий диалог. Бандитная модель была бы допустима только при оценке одной законченной реплики без продолжения.
Главный тест: зависит ли ценность действия от управляемого будущего состояния? Если да, одного раунда недостаточно.
Что измеряет регрет
Выберите три корректных утверждения.
-
Псевдорегрет конкретной траектории можно вычислить без знания истинных средних наград.
-
Разложение показывает, что неоптимальное действие с малым разрывом может выбираться чаще без большой мгновенной цены.
-
Сублинейный регрет означает .
-
Логарифмический регрет гарантирует, что алгоритм превосходит все другие алгоритмы на каждом конечном горизонте.
-
Реализованная накопленная награда случайна даже при фиксированной последовательности действий, если награды шумные.
Показать ответ и решение
Корректны 2, 3 и 5.
-
Неверно: для псевдорегрета нужны истинные средние или их знание симулятором. В реальном неизвестном бандите они недоступны напрямую.
-
Верно: каждый выбор действия стоит ; малый разрыв означает небольшую цену одного ошибочного выбора.
-
Верно: это определение сублинейного роста.
-
Неверно: асимптотический порядок не задаёт универсальный рейтинг на конечном горизонте; важны константы и экземпляр.
-
Верно: при случайных наградах одна и та же последовательность действий может давать разные суммы.
Постоянное ε и оптимистичная инициализация
Выберите два наиболее точных утверждения.
-
При постоянном ε-жадная стратегия продолжает с положительной частотой выбирать неоптимальные действия.
-
Оптимистичная инициализация гарантирует логарифмический регрет в любой нестационарной среде.
-
Постоянный размер шага может быть полезен при дрейфе наград, потому что уменьшает вес старых наблюдений.
-
Чистая жадность всегда имеет линейный регрет на каждом запуске.
-
Убывающее автоматически даёт оптимальный регрет независимо от скорости убывания.
Показать ответ и решение
Корректны 1 и 3.
При постоянном случайная ветвь не исчезает, поэтому неоптимальные действия продолжают выбираться. Постоянный размер шага экспоненциально уменьшает вклад старых наблюдений и может отслеживать дрейф.
Оптимистичная инициализация не является универсальной гарантией, чистая жадность не обязана провалиться на каждом конкретном запуске, а слишком быстро убывающее может прекратить исследование до обнаружения лучшего действия.
Область действия классической гарантии
Метод верхней доверительной границы (upper confidence bound, UCB) применяется к стационарному бандиту; UCB1 — его классический вариант.
Выберите три условия или оговорки, необходимые для корректного чтения гарантии UCB1.
-
Награды ограничены, в стандартной теореме — интервалом .
-
Средние наград не меняются со временем.
-
Логарифмическая оценка не зависит от разрывов .
-
Конечный регрет может быть заметным, если два действия почти одинаковы.
-
Любой численный показатель неопределённости нейросети является доверительной границей UCB.
-
Множество действий может произвольно меняться по ходу обучения, а классическое доказательство UCB1 остаётся без изменений.
Показать ответ и решение
Метод верхней доверительной границы (upper confidence bound, UCB) и его классический вариант UCB1 требуют читать теорему вместе с предположениями. Корректны 1, 2 и 4.
- Классический UCB1 использует концентрацию для наград в .
- Средние должны оставаться стационарными.
- Оценка зависит от : почти равные действия различить трудно, поэтому конечный регрет может быть велик.
Пункт 3 неверен именно из-за зависимости от разрывов. Пункт 5 смешивает теоретическую доверительную границу с произвольным показателем неопределённости. Пункт 6 меняет саму постановку: при меняющемся множестве действий классическое доказательство нельзя переносить без новой проверки.
Что делает сэмплирование Томпсона
Для бернуллиевского действия задано априорное распределение . После 8 успехов и 2 неудач выберите три корректных утверждения.
-
Апостериорное распределение равно .
-
Алгоритм выбирает действие с максимальным апостериорным средним без случайности.
-
На каждом раунде сэмплируется одно правдоподобное среднее для каждого действия.
-
Слабо изученное действие может быть выбрано из-за широкого апостериорного распределения.
-
Дата публикации идеи в 1933 году сама доказывает современную логарифмическую гарантию.
Показать ответ и решение
Корректны 1, 3 и 4.
С априорным восемь успехов и две неудачи дают
Алгоритм сэмплирует правдоподобное среднее каждого действия и выбирает максимальный сэмпл. Поэтому широкое распределение малоизученного действия иногда приводит к его выбору. Это не жадность по апостериорному среднему. Историческая дата идеи не заменяет отдельный анализ регрета.
LLM как контекстный бандит
Выберите три корректных утверждения.
-
Если запрос считается контекстом, полный ответ — одним действием, а после скалярной награды эпизод заканчивается, внешняя постановка является контекстным бандитом.
-
Из одношаговой абстракции с наградой за полный ответ следует, что токены перестают быть последовательными действиями.
-
Для многоходового агента с инструментами обычно нужно состояние, содержащее последствия предыдущих действий.
-
Выбор между несколькими моделями для независимых запросов может быть контекстным бандитом.
-
Любая процедура Best-of-N автоматически является многоруким бандитом.
Показать ответ и решение
Корректны 1, 3 и 4.
Внешняя постановка с наградой за полный ответ является контекстным бандитом, если после награды раунд заканчивается. Внутри ответа остаётся токеновая последовательность. Многоходовый агент меняет состояние инструментов и диалога, поэтому требует последовательной модели. Выбор маршрута или модели для независимых запросов — естественный контекстный бандит.
Best-of-N с фиксированной политикой — повторное сэмплирование и отбор, а не автоматически многорукий бандит.
Перекрытие при оценивании по журналу
Оценивание с обратной вероятностью выбора (inverse propensity scoring, IPS) используется для новой политики по журналу поведенческой политики . Его самонормированная версия — self-normalized inverse propensity scoring (SNIPS), а оцениватель, объединяющий модель награды и веса вероятностей, — оценивателем с двойной устойчивостью (doubly robust estimator, DR).
Выберите три корректных утверждения.
-
Для всех пар с требуется .
-
Малые вероятности поведения могут создавать большие веса и высокую дисперсию.
-
Если вероятности поведения не были сохранены, их всегда можно точно восстановить из выбранных действий.
-
SNIPS-оценка в общем случае имеет смещение.
-
DR создаёт наблюдаемую награду для действия, которое никогда не выбиралось и не моделировалось.
Показать ответ и решение
Оценивание с обратной вероятностью выбора (inverse propensity scoring, IPS), его самонормированная версия self-normalized inverse propensity scoring (SNIPS) и оцениватель с двойной устойчивостью (doubly robust estimator, DR) требуют явного учёта того, как журнал был собран. Корректны 1, 2 и 4.
IPS может оценить целевое действие только там, где поведенческая политика давала ему положительную вероятность. Вес резко растёт при малой , увеличивая дисперсию. SNIPS уменьшает чувствительность к общему масштабу весов, но в общем случае вносит смещение.
По одному выбранному действию невозможно точно восстановить вероятность, с которой политика случайно выбрала его. DR тоже не создаёт фактическую контрфактическую награду без перекрытия; вне области покрытия остаётся экстраполяция модели.
Температура, Best-of-N и энтропия
В пункте 6 используется групповая относительная оптимизация политики (group relative policy optimization, GRPO). Выберите четыре корректных утверждения.
-
Повышение температуры чистого softmax при фиксированных логитах делает распределение более плоским.
-
Температурная генерация фиксированной LLM сама по себе обновляет политику по награде.
-
Для независимых кандидатов с одной вероятностью успеха формула задаёт вероятность наличия хотя бы одного успеха в пуле.
-
Комбинаторный оцениватель pass@ по кандидатам и успехам равен .
-
Снижение энтропии всегда означает ухудшение политики.
-
Если все награды в группе GRPO одинаковы, после вычитания группового среднего относительный сигнал равен нулю.
Показать ответ и решение
Корректны 1, 3, 4 и 6.
Температура меняет форму фиксированного softmax-распределения, но не обновляет параметры по награде. Формула покрытия требует независимости и одинаковой вероятности успеха при фиксированном запросе. Идеальный выбор нужен лишь для отождествления покрытия с точностью возвращённого ответа; наличие успеха в пуле само по себе этого не гарантирует. Комбинаторная формула оценивает pass@ по конечной выборке. Снижение энтропии может быть нормальным следствием уверенного улучшения; оно становится проблемой только в определённом динамическом контексте. Одинаковые групповые награды дают нулевые центрированные преимущества.
Инкрементальное среднее
Действие выбиралось 4 раза. Его текущая оценка равна . Пятая награда равна .
-
Вычислите инкрементально.
-
Найдите сумму первых четырёх наград, совместимую с .
-
Проверьте результат прямым средним по пяти наблюдениям.
Показать ответ и решение
Инкрементальное обновление:
Сумма первых четырёх наград:
Прямая проверка:
Разложение регрета
Средние трёх действий равны
За раундов ожидаемые числа выборов равны
-
Найдите и разрывы .
-
Вычислите ожидаемый регрет.
-
Как изменится регрет, если 10 выборов второго действия заменить 10 выборами третьего?
Показать ответ и решение
Лучшее среднее:
Разрывы:
Регрет:
Если десять выборов второго действия заменить десятью выборами третьего, регрет уменьшится на
то есть станет равен .
Один индекс UCB1
На раунде два действия имеют оценки и числа выборов:
Для индекса
вычислите и с точностью до и укажите выбранное действие. Объясните, почему действие с меньшим средним может победить.
Показать ответ и решение
При :
Выбирается действие 2. Его среднее меньше, но оно исследовано в четыре раза слабее, поэтому бонус неопределённости значительно больше.
Этот выбор не утверждает, что действие 2 действительно лучше; он утверждает, что при текущих данных оптимистичная правдоподобная оценка для него выше.
Апостериорное бета-распределение
Для двух бернуллиевских действий используется априорное распределение .
- действие 1: 12 успехов и 8 неудач;
- действие 2: 3 успеха и 1 неудача.
-
Запишите оба апостериорных распределения.
-
Вычислите их средние.
-
Какое действие имеет большее апостериорное среднее?
-
Почему сэмплирование Томпсона всё же может выбрать другое действие?
Показать ответ и решение
Для действия 1:
Среднее:
Для действия 2:
Большее апостериорное среднее у действия 2. Но его распределение основано только на четырёх наблюдениях и шире. На отдельном раунде сэмпл из может оказаться выше сэмпла из , поэтому Томпсон иногда выберет действие 1.
IPS, SNIPS и DR на трёх строках
Журнал содержит:
| 1 | 1 | 0.50 | 1.00 | 0.60 | 0.70 |
| 2 | 0 | 0.25 | 0.50 | 0.30 | 0.40 |
| 3 | 1 | 0.80 | 0.40 | 0.70 | 0.65 |
-
Вычислите веса .
-
Вычислите .
-
Вычислите .
-
Вычислите DR-оценку.
-
Укажите, какая строка сильнее всего влияет на дисперсию IPS и почему.
Показать ответ и решение
Веса:
IPS:
SNIPS:
Построчные DR-слагаемые:
Следовательно,
Строки 1 и 2 имеют одинаково большие веса 2 и сильнее влияют на дисперсию, чем строка 3. В общем случае особенно опасна строка с наименьшей вероятностью поведения при ненулевой вероятности целевой политики.
Энтропийная политика, Best-of-N и pass@k
Оценки двух действий равны , температура .
-
Вычислите оптимальную энтропийно-регуляризованную политику .
-
Если вероятность успеха одного независимого кандидата , найдите вероятность хотя бы одного успеха при .
-
Найдите минимальное , обеспечивающее вероятность не менее .
-
Для , , вычислите оцениватель pass@ по конечной выборке.
-
Объясните, почему ответы из пунктов 2 и 4 описывают разные статистические объекты.
Показать ответ и решение
При и :
Best-of-5:
Для 90%:
поэтому минимальное целое .
Конечновыборочный pass@3:
Число предполагает истинную вероятность и независимые новые генерации. Число вычислено из конечного набора из десяти уже полученных кандидатов с двумя успехами.
Псевдорегрет по действиям
Реализуйте функцию:
import numpy as np
def pseudo_regret_curve(means: np.ndarray, actions: np.ndarray) -> np.ndarray:
"""Вернуть накопленный псевдорегрет после каждого действия."""
...Требования:
means— одномерный массив средних;actions— одномерный массив целых индексов;- неверный индекс вызывает
ValueError; - результат имеет тип
floatи ту же длину, чтоactions.
Проверка:
means = np.array([0.2, 0.5, 0.7])
actions = np.array([0, 2, 1])
# ожидается [0.5, 0.5, 0.7]Открытые проверки:
np.testing.assert_allclose(
pseudo_regret_curve([0.2, 0.5, 0.7], [0, 2, 1]),
[0.5, 0.5, 0.7],
)Показать ответ и решение
import numpy as np
def pseudo_regret_curve(means: np.ndarray, actions: np.ndarray) -> np.ndarray:
means = np.asarray(means, dtype=float)
actions = np.asarray(actions, dtype=int)
if means.ndim != 1 or means.size < 2:
raise ValueError("means must be one-dimensional")
if actions.ndim != 1:
raise ValueError("actions must be one-dimensional")
if np.any((actions < 0) | (actions >= means.size)):
raise ValueError("invalid action index")
gaps = means.max() - means[actions]
return np.cumsum(gaps, dtype=float)Проверка:
result = pseudo_regret_curve(
np.array([0.2, 0.5, 0.7]),
np.array([0, 2, 1]),
)
assert np.allclose(result, [0.5, 0.5, 0.7])Псевдорегрет не убывает, потому что каждое приращение неотрицательно.
ε-жадный бернуллиевский бандит
Реализуйте:
import numpy as np
def run_epsilon_greedy(
probabilities: np.ndarray,
horizon: int,
epsilon: float,
seed: int,
) -> tuple[np.ndarray, np.ndarray]:
"""Вернуть массивы действий и наград."""
...Правила:
- награда выбранного действия —
rng.random() < probabilities[action]; - при жадной ничьей выбирайте случайно среди максимумов;
- оценка обновляется выборочным средним;
- используйте
np.random.default_rng(seed); - на каждом раунде сначала решается вопрос исследования, затем генерируется награда.
Сравните , и на одном наборе вероятностей минимум по 100 независимым запускам. Постройте таблицу среднего псевдорегрета: вывод по одному начальному значению генератора случайных чисел недостаточен.
Открытые проверки:
actions, rewards = run_epsilon_greedy([0.1, 0.4, 0.6], 40, 0.1, 17)
assert actions.shape == (40,)
assert rewards.shape == (40,)
assert np.all((rewards == 0.0) | (rewards == 1.0))Показать ответ и решение
import numpy as np
def run_epsilon_greedy(probabilities, horizon, epsilon, seed):
p = np.asarray(probabilities, dtype=float)
if p.ndim != 1 or p.size < 2 or np.any((p < 0) | (p > 1)):
raise ValueError("invalid probabilities")
if horizon <= 0 or not 0 <= epsilon <= 1:
raise ValueError("invalid horizon or epsilon")
rng = np.random.default_rng(seed)
q = np.zeros(p.size)
n = np.zeros(p.size, dtype=int)
actions = np.empty(horizon, dtype=int)
rewards = np.empty(horizon, dtype=float)
for t in range(horizon):
if rng.random() < epsilon:
action = int(rng.integers(p.size))
else:
best = np.flatnonzero(np.isclose(q, q.max()))
action = int(rng.choice(best))
reward = float(rng.random() < p[action])
q[action] += (reward - q[action]) / (n[action] + 1)
n[action] += 1
actions[t] = action
rewards[t] = reward
return actions, rewardsДля сравнения значений ε нужно усреднять результаты по множеству независимых начальных значений генератора случайных чисел. Один удачный или неудачный запуск жадной стратегии не показывает её ожидаемого поведения.
UCB1
Реализуйте UCB1 для наград в :
import numpy as np
def run_ucb1(
probabilities: np.ndarray,
horizon: int,
seed: int,
) -> tuple[np.ndarray, np.ndarray]:
...Условия:
-
первые раундов выберите действия
0, 1, ..., K-1; -
затем используйте ;
-
обновляйте среднее инкрементально;
-
верните действия и награды.
Проверьте, что каждое действие выбрано хотя бы один раз и что накопленный псевдорегрет не убывает.
Открытые проверки:
actions, rewards = run_ucb1([0.1, 0.4, 0.6], 3, 5)
assert np.array_equal(actions, [0, 1, 2])
assert rewards.shape == (3,)Показать ответ и решение
import numpy as np
def run_ucb1(probabilities, horizon, seed):
p = np.asarray(probabilities, dtype=float)
if p.ndim != 1 or p.size < 2 or np.any((p < 0) | (p > 1)):
raise ValueError("invalid probabilities")
if horizon <= 0:
raise ValueError("horizon must be positive")
rng = np.random.default_rng(seed)
k = p.size
q = np.zeros(k)
n = np.zeros(k, dtype=int)
actions = np.empty(horizon, dtype=int)
rewards = np.empty(horizon, dtype=float)
for t in range(horizon):
if t < k:
action = t
else:
index = q + np.sqrt(2 * np.log(t + 1) / n)
best = np.flatnonzero(np.isclose(index, index.max()))
action = int(rng.choice(best))
reward = float(rng.random() < p[action])
q[action] += (reward - q[action]) / (n[action] + 1)
n[action] += 1
actions[t] = action
rewards[t] = reward
return actions, rewardsПроверки:
means = np.array([0.1, 0.4, 0.6])
actions, rewards = run_ucb1(means, 100, 23)
assert np.array_equal(actions[:3], [0, 1, 2])
regret = np.cumsum(means.max() - means[actions])
assert np.all(np.diff(regret) >= -1e-12)Сэмплирование Томпсона
Реализуйте сэмплирование Томпсона с бета-бернуллиевской моделью награды:
import numpy as np
def run_thompson(
probabilities: np.ndarray,
horizon: int,
seed: int,
prior_alpha: float = 1.0,
prior_beta: float = 1.0,
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""Вернуть действия, награды и итоговые alpha/beta."""
...После каждого успеха увеличивайте alpha[action], после неудачи — beta[action]. Сравните с UCB1 на нескольких экземплярах, включая случай с близкими средними. В отчёте отделите наблюдение вашего эксперимента от общей гарантии.
Открытые проверки:
actions, rewards, alpha, beta = run_thompson(
[0.1, 0.4, 0.6], 10, 23
)
assert actions.shape == rewards.shape == (10,)
assert alpha.shape == beta.shape == (3,)
assert np.isclose((alpha + beta).sum(), 16.0)Показать ответ и решение
import numpy as np
def run_thompson(
probabilities,
horizon,
seed,
prior_alpha=1.0,
prior_beta=1.0,
):
p = np.asarray(probabilities, dtype=float)
if p.ndim != 1 or p.size < 2 or np.any((p < 0) | (p > 1)):
raise ValueError("invalid probabilities")
if horizon <= 0 or prior_alpha <= 0 or prior_beta <= 0:
raise ValueError("invalid parameters")
rng = np.random.default_rng(seed)
alpha = np.full(p.size, float(prior_alpha))
beta = np.full(p.size, float(prior_beta))
actions = np.empty(horizon, dtype=int)
rewards = np.empty(horizon, dtype=float)
for t in range(horizon):
samples = rng.beta(alpha, beta)
action = int(np.argmax(samples))
reward = float(rng.random() < p[action])
alpha[action] += reward
beta[action] += 1.0 - reward
actions[t] = action
rewards[t] = reward
return actions, rewards, alpha, betaВ отчёте следует писать, например: «на 200 независимых запусках данного бернуллиевского стенда сэмплирование Томпсона дало меньший средний псевдорегрет к ». Формулировка «сэмплирование Томпсона всегда лучше UCB» из такого опыта не следует.
IPS, SNIPS и двойная устойчивость
Реализуйте три функции:
def ips_value(rewards, behavior_probs, target_probs) -> float:
...
def snips_value(rewards, behavior_probs, target_probs) -> float:
...
def doubly_robust_value(
rewards,
behavior_probs,
target_probs,
predictions_logged,
predictions_target,
) -> float:
...predictions_target[i] уже содержит . Выдавайте ValueError, если вероятность поведения неположительна. Добавьте эксперимент, где одна вероятность уменьшается от до , и покажите, как меняется IPS-вес.
Открытые проверки:
actual = ips_value(
[1.0, 0.0, 1.0],
[0.5, 0.25, 0.5],
[1.0, 0.0, 0.5],
)
assert np.isclose(actual, 1.0)Показать ответ и решение
import numpy as np
def _arrays(rewards, behavior_probs, target_probs):
r = np.asarray(rewards, dtype=float)
p = np.asarray(behavior_probs, dtype=float)
q = np.asarray(target_probs, dtype=float)
if r.ndim != 1 or p.shape != r.shape or q.shape != r.shape or r.size == 0:
raise ValueError("equal non-empty vectors required")
if np.any(p <= 0) or np.any(p > 1) or np.any((q < 0) | (q > 1)):
raise ValueError("invalid probabilities")
return r, p, q
def ips_value(rewards, behavior_probs, target_probs):
r, p, q = _arrays(rewards, behavior_probs, target_probs)
return float(np.mean(q * r / p))
def snips_value(rewards, behavior_probs, target_probs):
r, p, q = _arrays(rewards, behavior_probs, target_probs)
w = q / p
if w.sum() <= 0:
raise ValueError("zero total target weight")
return float(np.dot(w, r) / w.sum())
def doubly_robust_value(
rewards,
behavior_probs,
target_probs,
predictions_logged,
predictions_target,
):
r, p, q = _arrays(rewards, behavior_probs, target_probs)
logged = np.asarray(predictions_logged, dtype=float)
target = np.asarray(predictions_target, dtype=float)
if logged.shape != r.shape or target.shape != r.shape:
raise ValueError("prediction shapes must match")
return float(np.mean(target + q / p * (r - logged)))Если , то при вес равен 1, а при — уже 50. Одно наблюдение с таким весом способно доминировать в оценке; это и есть практическая цена слабого перекрытия.
Энтропия, Best-of-N и pass@k
Реализуйте:
import numpy as np
def stable_softmax(logits, temperature=1.0) -> np.ndarray:
...
def categorical_entropy(probabilities) -> float:
...
def best_of_n_success(p: float, n: int) -> float:
...
def pass_at_k(n: int, c: int, k: int) -> float:
...Требования:
- softmax устойчив к большим логитам;
- энтропия измеряется в натах и использует соглашение ;
- Best-of-N использует устойчивые
log1p/expm1для малых и больших ; - pass@ реализуется как либо эквивалентное устойчивое произведение;
- недопустимые вызывают
ValueError.
Проверьте, что для фиксированных логитов энтропия возрастает при температурах , и , но не делайте из этого вывода о качестве или истинности ответа.
Открытые проверки:
p = stable_softmax([1000.0, 1001.0])
assert np.isclose(p.sum(), 1.0)
assert np.all(p > 0.0)Показать ответ и решение
from math import comb
import numpy as np
def stable_softmax(logits, temperature=1.0):
z = np.asarray(logits, dtype=float)
if z.ndim != 1 or z.size == 0 or not np.all(np.isfinite(z)):
raise ValueError("invalid logits")
if temperature <= 0 or not np.isfinite(temperature):
raise ValueError("temperature must be positive")
scaled = z / temperature
weights = np.exp(scaled - scaled.max())
return weights / weights.sum()
def categorical_entropy(probabilities):
p = np.asarray(probabilities, dtype=float)
if p.ndim != 1 or np.any(p < 0) or not np.isclose(p.sum(), 1):
raise ValueError("invalid probability vector")
positive = p[p > 0]
return float(-np.dot(positive, np.log(positive)))
def best_of_n_success(p, n):
if not 0 <= p <= 1 or n < 1:
raise ValueError("invalid p or n")
if p == 1:
return 1.0
return float(-np.expm1(n * np.log1p(-p)))
def pass_at_k(n, c, k):
if n <= 0 or c < 0 or c > n or k <= 0 or k > n:
raise ValueError("invalid n, c, k")
if n - c < k:
return 1.0
return float(1 - comb(n - c, k) / comb(n, k))Проверка энтропии:
logits = np.array([0.0, 1.0, 2.0])
entropies = [
categorical_entropy(stable_softmax(logits, temperature=t))
for t in (0.5, 1.0, 2.0)
]
assert entropies[0] < entropies[1] < entropies[2]Это свойство чистого softmax при фиксированных логитах. Оно не утверждает, что более высокая температура улучшает качество, калибровку или истинность ответа.