VKВлад КуликовОткрытые лекции
RL для LLM4 / 13

Модуль 4. Градиенты политики: от REINFORCE к PPO

Выберите ответы и нажмите «Проверить». Для чисел подходят точка, запятая и простые дроби. Ответы и черновики сохраняются в этом браузере и общие для RU/EN.

Открытые вопросы и задания с кодом проверяются самостоятельно по авторскому разбору. Код на сайте не запускается.

Проверено: 0 / 8 · Верно: 0

Вопрос P01 · Цена тождества логарифмической производной

один ответ

Тождество ∇θE[f(X)]=E[f(X)∇θlog⁡pθ(X)]\nabla_\theta \mathbb{E}[f(X)] = \mathbb{E}[f(X)\nabla_\theta\log p_\theta(X)] позволяет не дифференцировать ff. Что мы получаем взамен?

Один правильный вариант

Вопрос P02 · Накопленная награда от текущего шага

код-задача

Спецификация: Gt=∑k=tT−1γk−trk+1G_t = \sum_{k=t}^{T-1}\gamma^{k-t} r_{k+1} — награда от текущего шага до конца эпизода. Считать обратным проходом: Gt=rt+1+γGt+1G_t = r_{t+1} + \gamma G_{t+1}, GT=0G_T = 0.

Формат ввода: строка 1 — награды через пробел; строка 2 — γ\gamma. Формат вывода: одна строка — G0,…,GT−1G_0, \ldots, G_{T-1} через пробел (6 знаков).

Стартовый код:

import numpy as np

def reward_to_go(rewards, gamma=1.0):
    # ВАШ КОД ЗДЕСЬ
    raise NotImplementedError

if __name__ == "__main__":
    rewards = [float(x) for x in input().split()]
    gamma = float(input())
    print(" ".join(f"{x:.6f}" for x in reward_to_go(rewards, gamma)))

Открытые тесты:

stdinstdout
1 0 2 3 ⏎ 0.94.807000 4.230000 4.700000 3.000000
1 0 2 3 ⏎ 1.06.000000 5.000000 5.000000 3.000000
0 0 1 ⏎ 0.50.250000 0.500000 1.000000

Вопрос P03 · Что можно вычесть без поправки

один ответ

Из Qπ(s,a)Q^\pi(s,a) вычитают опорный уровень. Какое условие делает эту замену безопасной для ожидаемого градиента?

Один правильный вариант

Вопрос P04 · Масштаб группового центрирования

числовой ответ · допуск ±0.005

Награды группы центрируются по общему среднему: Ai=Ri−RˉA_i = R_i - \bar R, размер группы G=8G = 8, ответы условно независимы.

На какой множитель отличается ожидание получаемой оценки градиента от E[RS]\mathbb{E}[RS]?

Вопрос P05 · RLOO и групповое среднее: коллинеарность и масштаб

код-задача

Спецификация: Aimean=Ri−RˉA_i^{\text{mean}} = R_i - \bar R, где Rˉ\bar R — среднее всей группы; AiLOO=Ri−1G−1∑j≠iRjA_i^{\mathrm{LOO}} = R_i - \frac{1}{G-1}\sum_{j\ne i} R_j. Требуется G≥2G \ge 2.

Формат ввода: строка 1 — размер группы GG; строка 2 — награды через пробел. Формат вывода: строка 1 — преимущества по общему среднему (6 знаков); строка 2 — преимущества RLOO (6 знаков); строка 3 — отношение A0LOO/A0meanA^{\mathrm{LOO}}_0/A^{\text{mean}}_0 (6 знаков) или undefined, если знаменатель равен нулю.

Стартовый код:

import numpy as np

def group_and_loo(rewards):
    """Верните (mean_advantages, loo_advantages)."""
    # ВАШ КОД ЗДЕСЬ
    raise NotImplementedError

if __name__ == "__main__":
    g = int(input())
    rewards = [float(x) for x in input().split()]
    mean_adv, loo_adv = group_and_loo(rewards)
    print(" ".join(f"{x:.6f}" for x in mean_adv))
    print(" ".join(f"{x:.6f}" for x in loo_adv))
    print(f"{loo_adv[0] / mean_adv[0]:.6f}" if abs(mean_adv[0]) > 1e-12 else "undefined")

Открытые тесты:

stdinstdout
4 ⏎ 1 0 1 00.500000 -0.500000 0.500000 -0.500000 ⏎ 0.666667 -0.666667 0.666667 -0.666667 ⏎ 1.333333
3 ⏎ 2 2 20.000000 0.000000 0.000000 ⏎ 0.000000 0.000000 0.000000 ⏎ undefined

Вопрос P06 · Обобщённое оценивание преимущества

код-задача

Спецификация: эпизод завершается терминально на последнем шаге. δt=rt+γVt+1−Vt\delta_t = r_t + \gamma V_{t+1} - V_t, где VT=0V_{T} = 0; A^t=δt+γλA^t+1\widehat A_t = \delta_t + \gamma\lambda \widehat A_{t+1}, A^T=0\widehat A_T = 0. Цель критика: V^t=Vt+A^t\widehat V_t = V_t + \widehat A_t.

Формат ввода: строка 1 — награды; строка 2 — оценки ценности VtV_t; строка 3 — γ\gamma и λ\lambda. Формат вывода: строка 1 — A^t\widehat A_t через пробел (6 знаков); строка 2 — цели критика (6 знаков).

Стартовый код:

import numpy as np

def gae(rewards, values, gamma, lam):
    """Верните (advantages, value_targets)."""
    # ВАШ КОД ЗДЕСЬ
    raise NotImplementedError

if __name__ == "__main__":
    rewards = [float(x) for x in input().split()]
    values = [float(x) for x in input().split()]
    gamma, lam = (float(x) for x in input().split())
    adv, targets = gae(rewards, values, gamma, lam)
    print(" ".join(f"{x:.6f}" for x in adv))
    print(" ".join(f"{x:.6f}" for x in targets))

Открытые тесты:

stdinstdout
0 0 1 ⏎ 0.4 0.5 0.6 ⏎ 1.0 0.50.250000 0.300000 0.400000 ⏎ 0.650000 0.800000 1.000000
0 0 1 ⏎ 0.4 0.5 0.6 ⏎ 1.0 0.00.100000 0.100000 0.400000 ⏎ 0.500000 0.600000 1.000000

Вопрос P07 · Бутстрэп на границе эпизода

один ответ

Пакет собирали с лимитом длины, и часть эпизодов оборвалась по этому лимиту, а часть закончилась настоящим терминалом. Что происходит с оценкой преимущества, если обе группы обработать одинаково — как терминальные?

Один правильный вариант

Вопрос P08 · Когда плато клиппирования активно

несколько ответов

Для каких сочетаний знака преимущества и изменения отношения клиппированная ветвь действительно ограничивает цель? Отметьте все верные.

Отметьте все верные варианты

Вопрос P09 · Диагностика PPO: снаружи интервала и активный клип

код-задача

Спецификация: для каждого примера даны отношение rir_i и преимущество A^i\widehat A_i. Вычислите три показателя при заданном ε\varepsilon:

  1. доля ri∉[1−ε,1+ε]r_i \notin [1-\varepsilon, 1+\varepsilon];
  2. доля примеров, где пессимистическая ветвь строго меньше неклиппированной, то есть min⁡(riA^i, clip⁡(ri)A^i)<riA^i\min(r_i\widehat A_i,\ \operatorname{clip}(r_i)\widehat A_i) < r_i\widehat A_i;
  3. неотрицательная выборочная оценка D^=1N∑i[(ri−1)−log⁡ri]\widehat D = \frac1N\sum_i[(r_i-1) - \log r_i].

Формат ввода: строка 1 — число примеров NN и ε\varepsilon; далее NN строк ratio advantage. Формат вывода: три строки — показатели 1, 2 и 3 (6 знаков).

Стартовый код:

import numpy as np

def ppo_diagnostics(ratio, advantage, clip_epsilon):
    """Верните (outside_fraction, active_clip_fraction, approx_kl)."""
    # ВАШ КОД ЗДЕСЬ
    raise NotImplementedError

if __name__ == "__main__":
    n, eps = input().split()
    rows = [tuple(float(x) for x in input().split()) for _ in range(int(n))]
    r = np.array([row[0] for row in rows])
    a = np.array([row[1] for row in rows])
    for value in ppo_diagnostics(r, a, float(eps)):
        print(f"{value:.6f}")

Открытые тесты:

stdinstdout
5 0.2 ⏎ 0.75 1.0 ⏎ 1.00 1.0 ⏎ 1.30 1.0 ⏎ 1.10 -1.0 ⏎ 0.85 -1.00.400000 ⏎ 0.200000 ⏎ 0.018505

Вопрос P10 · Неотрицательная выборочная оценка KL

числовой ответ · допуск ±0.001

Отношения вероятностей на трёх примерах: r=(0.8, 1.0, 1.25)r = (0.8,\ 1.0,\ 1.25).

Чему равна оценка D^=13∑i[(ri−1)−log⁡ri]\widehat D = \frac13\sum_i[(r_i - 1) - \log r_i]?

Вопрос P11 · RLOO и GRPO: общая идея и различия

один ответ

RLOO и GRPO генерируют несколько ответов на один запрос и строят относительный сигнал. Что различает их в каноническом виде?

Один правильный вариант

Вопрос P12 · Что не решает один вес на все токены

один ответ

Преимущество ответа A(y)A(y) размножено по всем токенам и умножено на маску. Что эта конструкция делает корректно, а что нет?

Один правильный вариант