VKVlad KulikovPublic / lectures
RL for LLM5 / 13

Module 5. Learning from fixed data: imitation, deep Q-methods, and offline RL

Try each exercise first. Expand worked answers or project guidance when needed; their open state is shared between RU/EN.

Download course files (.zip) 382.1 KB

The archive preserves the source folder structure, both languages, and supporting files.

When SFT is literally BC

For each case, decide whether token-level SFT can literally be viewed as behavioral cloning. Identify the state, action, and loss mask.

  1. A prompt and expert answer are given; loss is applied only to response tokens.

  2. Loss is applied to both the user prompt and assistant response.

  3. The external task defines one action as a whole response, but optimization uses token negative log-likelihood.

  4. Several demonstrations exist for each prompt and their likelihoods are all maximized.

Why is “SFT is always identical to BC” too strong without specifying the action unit and mask?

Show answer and solution
  1. Yes, under the token-level abstraction. State st=(x,y<t)s_t=(x,y_{<t}), action at=yta_t=y_t, and the mask is one only on response tokens.

  2. It remains sequence maximum likelihood, but clones a broader process. User tokens are also treated as predicted actions, so it is not simply BC of the assistant policy without a qualification.

  3. Yes, with matched masks and reduction. At the whole-response level the state is xx and the action is yy. The identity −log⁡πθ(y∣x)=−∑tlog⁡πθ(yt∣x,y<t)-\log\pi_\theta(y\mid x)=-\sum_t\log\pi_\theta(y_t\mid x,y_{<t}) makes summed response-token NLL exactly the BC objective for that action, including EOS under the same convention. Backpropagation through the factorization does not change the objective. Averaging each response by its own length changes example weights; a global normalization by a fixed token count only rescales the batch objective.

  4. Yes. Multiple demonstrations define an empirical distribution of expert actions, so maximizing their likelihood remains BC even when the expert is stochastic.

The unqualified slogan hides the unit of action, state construction, and mask—the elements that specify which policy is cloned.

Two state distributions

A policy has 1% error on expert states.

  1. Why does this not imply 1% deployment error?

  2. When may dtπEd_t^{\pi_E} and dtπθd_t^{\pi_\theta} remain close?

  3. Give one recoverable and one irreversible error.

  4. What should be measured in addition to action accuracy on demonstrations?

Show answer and solution
  1. The 1% error is measured under dtπEd_t^{\pi_E}. The learned policy can enter states rare under the expert, where its error rate differs.

  2. The distributions may stay close when errors are rare and recoverable, dynamics are stable, recovery demonstrations are present, or the model generalizes well nearby.

  3. Recoverable: one unnecessary move in a corridor. Irreversible: falling from a cliff or committing an irreversible transaction.

  4. Evaluate closed-loop behavior: expected return, success probability, failure cost, recovery quality, or another metric on trajectories generated by the policy itself.

DAgger, RLHF, and feedback format

Match these protocols:

  1. an expert labels the correct action at a state visited by the current policy;

  2. a human selects the better of two complete responses;

  3. an automatic verifier returns a scalar reward for a complete response.

Which corresponds to Dataset Aggregation (DAgger), preference learning, and RL with verifiable rewards? What structural feature do they share, and why are their objectives not interchangeable?

Show answer and solution
  1. DAgger: the expert supplies a target action for a visited state.

  2. Preference learning: the human supplies a pairwise comparison.

  3. RL with verifiable reward: a program supplies scalar outcome feedback.

All three can gather feedback on current-policy behavior rather than only static demonstrations. Action labels, pairwise preferences, and scalar rewards nevertheless live in different observation spaces and induce different losses and estimators.

Replay memory and a fixed log

Compare standard DQN with experience replay against offline RL.

  1. Why can both be off-policy?

  2. Why does a DQN replay buffer not make the problem offline RL?

  3. What happens if the current DQN policy discovers a useful new state region?

  4. Why is the same coverage error more fundamental with a fixed log?

Show answer and solution
  1. The target policy can differ from the behavior policy that generated transitions.

  2. Standard DQN continues interacting and adding new transitions; its dataset is not fixed for the whole run.

  3. The new region enters replay and can correct previous value estimates with actual outcomes.

  4. In offline RL, an unsupported-action hypothesis cannot be tested. A value error can be selected and bootstrapped without corrective experience.

Target network and reference policy

A DQN target network and an RLHF reference policy may both be frozen copies. For each, state:

  1. what quantity it defines;

  2. whether it enters a Bellman bootstrap;

  3. how and when it is updated;

  4. why implementation similarity does not imply equal mathematical roles.

Show answer and solution

The DQN target network supplies the next-state value in a Bellman target, directly participates in bootstrapping, and is periodically copied or slowly updated.

The RLHF reference policy defines a distributional anchor for a KL penalty or likelihood ratio. It is not an estimate of future return and is usually fixed within a run.

Both may be copies, but one stabilizes a moving value target while the other defines the cost of deviation from reference behavior.

Impossibility without coverage

The log contains only action a0a_0 with reward zero; action a1a_1 is absent.

  1. Construct two environments consistent with the data but with different optimal actions.

  2. Why can no algorithm guarantee the optimal action in both worlds from this log alone?

  3. What additional assumption could make a conclusion possible?

  4. Why does a larger neural network not remove non-identifiability?

Show answer and solution
  1. World A: r(a0)=0r(a_0)=0, r(a1)=+1r(a_1)=+1. World B: r(a0)=0r(a_0)=0, r(a1)=−1r(a_1)=-1.

  2. The datasets are identical, so an algorithm receives the same input and must return the same output. No single action is optimal in both worlds.

  3. Examples include reward smoothness, a known dynamics model, structural relations among actions, a causal model, or new interaction.

  4. More capacity represents more candidate functions; it does not make the observations distinguish between two compatible worlds.

Four offline-RL safeguards

Match each method to its main mechanism:

  • Batch-Constrained deep Q-learning (BCQ);
  • Twin Delayed Deep Deterministic Policy Gradient plus BC (TD3+BC);
  • CQL;
  • IQL.

Mechanisms:

  1. restrict candidates to actions similar to the log;

  2. add a behavior-cloning penalty to the actor update;

  3. lower values over broad candidate actions relative to logged actions;

  4. learn values through dataset actions and extract a policy by weighted BC.

For each method, name one failure mode of excessive conservatism.

Show answer and solution
  • BCQ → 1. Excessive restriction may exclude a rare but valuable improvement.
  • TD3+BC → 2. An overly strong BC term reduces the method to cloning.
  • CQL → 3. Excessive conservatism may systematically undervalue useful actions.
  • IQL → 4. Poor expectile, temperature, or weight clipping may either prevent improvement or concentrate the policy too narrowly.

DT, DPO, and ILQL

For each setting, identify its learned objects and whether Bellman bootstrapping is used.

  1. Decision Transformer;

  2. Direct Preference Optimization (DPO);

  3. Implicit Language Q-Learning (ILQL).

Why can all three use fixed data while not being the same form of offline RL?

Show answer and solution
  • DT: learns a conditional action distribution from history and return-to-go; no explicit Bellman bootstrap.
  • DPO: learns a policy from pairwise preferences relative to a reference policy; no Q-function or Bellman target.
  • ILQL: learns token-level QQ and VV from rewarded trajectories and uses sequential value recursion before advantage-weighted policy extraction.

Fixed data specify access to experience, not a unique objective. Demonstrations, preferences, and rewarded transitions support different counterfactual questions.

Masked BC/SFT loss

Selected-token log-probabilities are

L=(−0.1−0.2−1.0−0.3−0.7−0.4)L= \begin{pmatrix} -0.1 & -0.2 & -1.0\\ -0.3 & -0.7 & -0.4 \end{pmatrix}

with mask

M=(011001).M= \begin{pmatrix} 0 & 1 & 1\\ 0 & 0 & 1 \end{pmatrix}.

Compute the summed negative log-likelihood and its mean over active tokens. Why would dividing by all six matrix entries define a different objective?

Show answer and solution

The active entries are −0.2-0.2, −1.0-1.0, and −0.4-0.4:

∑−LijMij=1.6,Lmean=1.63=0.533333…\sum -L_{ij}M_{ij}=1.6, \qquad \mathcal L_{\mathrm{mean}}=\frac{1.6}{3}=0.533333\ldots

Dividing by all six positions gives 0.2666670.266667 and makes gradient scale depend on how many masked positions are present. The usual token mean divides by active targets.

Tightrope without an asymptotic shortcut

For ε=0.02\varepsilon=0.02 and T=20T=20, compute:

  1. exact JBCJ_{\mathrm{BC}};

  2. exact regret;

  3. the approximation εT(T+1)/2\varepsilon T(T+1)/2;

  4. normalized regret (T−J)/(εT2)(T-J)/(\varepsilon T^2).

Why is the approximation already visibly different from the exact value?

Show answer and solution

With q=0.98q=0.98,

J=0.98(1−0.9820)0.02≈16.287209384,J=\frac{0.98(1-0.98^{20})}{0.02}\approx16.287209384, 20−J≈3.712790616.20-J\approx3.712790616.

The first-order approximation is

0.02⋅20⋅212=4.2,\frac{0.02\cdot20\cdot21}{2}=4.2,

and normalized regret is

3.7127906160.02⋅202≈0.464098827.\frac{3.712790616}{0.02\cdot20^2}\approx0.464098827.

Here εT=0.4\varepsilon T=0.4 is not very small, so higher-order terms are visible.

DQN targets and a terminal mask

Given

r=(1,−2,0.5),d=(0,1,0),γ=0.9,r=(1,-2,0.5),\qquad d=(0,1,0),\qquad \gamma=0.9,

and

Qθ−(s′,⋅)=(24100100−13),Q_{\theta^-}(s',\cdot)= \begin{pmatrix} 2 & 4\\ 100 & 100\\ -1 & 3 \end{pmatrix},

compute the three DQN targets. Why does 100 not enter the second target?

Show answer and solution

The maxima are (4,100,3)(4,100,3), hence

y=(1+0.9⋅4,  −2,  0.5+0.9⋅3)=(4.6,−2,3.2).y=(1+0.9\cdot4,\;-2,\;0.5+0.9\cdot3)=(4.6,-2,3.2).

The second transition is terminal, so continuation value is masked out.

DQN versus Double DQN

Let

Qθ(s′,⋅)=(354210),Qθ−(s′,⋅)=(1012−167).Q_\theta(s',\cdot)= \begin{pmatrix} 3&5&4\\ 2&1&0 \end{pmatrix}, \qquad Q_{\theta^-}(s',\cdot)= \begin{pmatrix} 10&1&2\\ -1&6&7 \end{pmatrix}.

Rewards are r=(0,1)r=(0,1), neither transition is terminal, and γ=0.5\gamma=0.5.

  1. Compute standard DQN targets.

  2. Which actions does the online network select?

  3. Compute Double-DQN targets.

  4. How does the example display selection–evaluation separation?

Show answer and solution

Standard DQN uses target-network maxima 1010 and 77:

yDQN=(5,4.5).y_{\mathrm{DQN}}=(5,4.5).

The online network selects actions (1,0)(1,0). The target network values those actions as (1,−1)(1,-1), so

yDouble=(0.5,0.5).y_{\mathrm{Double}}=(0.5,0.5).

The example deliberately makes the rankings disagree: one network selects; the other evaluates.

CQL and the IQL expectile loss

For one state,

Q=(2,0,−1),Q=(2,0,-1),

and logged action 0:

  1. compute the discrete CQL term
log⁡∑aeQ(a)−Q(0);\log\sum_a e^{Q(a)}-Q(0);
  1. for IQL residuals u=(−2,1,3)u=(-2,1,3) and τ=0.8\tau=0.8, compute
∣τ−1{u<0}∣u2\left|\tau-\mathbf 1\{u<0\}\right|u^2

componentwise and on average;

  1. explain why positive residuals receive more weight for τ>1/2\tau>1/2.
Show answer and solution
log⁡(e2+e0+e−1)−2≈0.169846020.\log(e^2+e^0+e^{-1})-2\approx0.169846020.

At τ=0.8\tau=0.8, negative residuals have weight 0.20.2 and positive residuals weight 0.80.8:

L=(0.8,0.8,7.2),Lˉ=2.933333…L=(0.8,0.8,7.2), \qquad \bar L=2.933333\ldots

The asymmetric weighting moves VV toward an upper expectile of values represented in the data.

Return-to-go and the DT condition

For rewards

r=(1,0,−2,4),r=(1,0,-2,4),
  1. compute undiscounted return-to-go;

  2. starting from desired return 5, update the target after each reward;

  3. with Gttarget=5G_t^{\mathrm{target}}=5, rt=1r_t=1, and γ=0.5\gamma=0.5, compute the next discounted target;

  4. explain why a large desired return does not guarantee a large realized return.

Show answer and solution
G=(3,2,2,4).G=(3,2,2,4).

Starting from 5, the undiscounted target sequence is

5→4→4→6→2.5\to4\to4\to6\to2.

For γ=0.5\gamma=0.5,

Gt+1target=5−10.5=8.G_{t+1}^{\mathrm{target}}=\frac{5-1}{0.5}=8.

The target is an input condition. If the dataset does not support that return, the model extrapolates; the condition does not alter environment dynamics or guarantee the outcome.

Masked negative log-likelihood

Implement:

Python
import numpy as np

def masked_bc_nll(
    selected_log_probs: np.ndarray,
    mask: np.ndarray,
    reduction: str = "mean",
) -> float:
    """Return the mean or sum of -log pi over active entries."""
    ...

Shapes must match; the mask must contain only zero and one; an empty active mask raises ValueError; reduction accepts only "mean" or "sum".

Open checks:

Python
logprobs = np.array([[-0.1, -0.2, -1.0], [-0.3, -0.7, -0.4]])
mask = np.array([[0, 1, 1], [0, 0, 1]])
assert abs(masked_bc_nll(logprobs, mask, reduction="sum") - 1.6) < 1e-12
assert abs(masked_bc_nll(logprobs, mask) - 1.6 / 3) < 1e-12
Show answer and solution
Python
import numpy as np

def masked_bc_nll(
    selected_log_probs: np.ndarray,
    mask: np.ndarray,
    reduction: str = "mean",
) -> float:
    lp = np.asarray(selected_log_probs, dtype=np.float64)
    m = np.asarray(mask)
    if lp.shape != m.shape:
        raise ValueError("shapes must match")
    if np.any((m != 0) & (m != 1)):
        raise ValueError("mask must be binary")
    active_count = int(m.sum())
    if active_count == 0:
        raise ValueError("empty active mask")
    total = float(np.where(m.astype(bool), -lp, 0.0).sum())
    if reduction == "sum":
        return total
    if reduction == "mean":
        return total / active_count
    raise ValueError("reduction must be 'mean' or 'sum'")

Exact tightrope return

Implement:

Python
def tightrope_return(epsilon: float, horizon: int) -> float:
    ...

def tightrope_regret(epsilon: float, horizon: int) -> float:
    ...

Handle ε=0\varepsilon=0, T=0T=0, and invalid inputs.

Open checks:

Python
assert tightrope_return(0.0, 20) == 20.0
assert tightrope_regret(0.0, 20) == 0.0
Show answer and solution
Python
def tightrope_return(epsilon: float, horizon: int) -> float:
    if not 0.0 <= epsilon <= 1.0 or horizon < 0:
        raise ValueError
    if horizon == 0:
        return 0.0
    if epsilon == 0.0:
        return float(horizon)
    q = 1.0 - epsilon
    return q * (1.0 - q ** horizon) / epsilon

def tightrope_regret(epsilon: float, horizon: int) -> float:
    return float(horizon) - tightrope_return(epsilon, horizon)

DQN and Double DQN

Implement vectorized functions:

Python
import numpy as np

def dqn_targets(rewards, terminated, next_q_target, gamma=0.99):
    ...

def double_dqn_targets(rewards, terminated, next_q_online, next_q_target, gamma=0.99):
    ...

Q arrays have shape [B, A]; terminal transitions do not bootstrap.

Open checks:

Python
result = dqn_targets(
    np.array([1.0, -2.0, 0.5]),
    np.array([0, 1, 0]),
    np.array([[2.0, 4.0], [100.0, 100.0], [-1.0, 3.0]]),
    gamma=0.9,
)
np.testing.assert_allclose(result, [4.6, -2.0, 3.2])
Show answer and solution
Python
import numpy as np

def dqn_targets(rewards, terminated, next_q_target, gamma=0.99):
    r = np.asarray(rewards, dtype=float)
    term = np.asarray(terminated, dtype=bool)
    q = np.asarray(next_q_target, dtype=float)
    return r + gamma * (~term) * q.max(axis=1)

def double_dqn_targets(rewards, terminated, next_q_online, next_q_target, gamma=0.99):
    r = np.asarray(rewards, dtype=float)
    term = np.asarray(terminated, dtype=bool)
    online = np.asarray(next_q_online, dtype=float)
    target = np.asarray(next_q_target, dtype=float)
    actions = online.argmax(axis=1)
    selected = target[np.arange(len(r)), actions]
    return r + gamma * (~term) * selected

Production code should additionally validate shapes and γ\gamma; the reference module does so.

A minimal pessimistic choice rule

For empirical reward means μ^a\hat\mu_a and counts nan_a, implement the teaching lower-confidence score

μ^a−cna.\hat\mu_a-\frac{c}{\sqrt{n_a}}.

Actions with na=0n_a=0 receive −∞-\infty. Explain why this illustrates coverage but is not a universal offline-RL algorithm.

Signature:

Python
def pessimistic_values(
    empirical_means: np.ndarray,
    counts: np.ndarray,
    *,
    radius_scale: float = 1.0,
) -> np.ndarray:
    ...

Open checks:

Python
values = pessimistic_values(np.array([0.8, 0.5]), np.array([4, 0]))
assert abs(values[0] - 0.3) < 1e-12
assert values[1] == -np.inf
wide = pessimistic_values(np.array([0.8]), np.array([1]))
assert wide[0] < 0.3
Show answer and solution
Python
import numpy as np

def pessimistic_values(
    empirical_means: np.ndarray,
    counts: np.ndarray,
    *,
    radius_scale: float = 1.0,
) -> np.ndarray:
    means = np.asarray(empirical_means, dtype=np.float64)
    n = np.asarray(counts, dtype=np.float64)
    if means.shape != n.shape or np.any(n < 0) or not np.isfinite(radius_scale) or radius_scale < 0:
        raise ValueError("invalid shapes, counts, or radius_scale")
    out = np.full_like(means, -np.inf)
    seen = n > 0
    out[seen] = means[seen] - radius_scale / np.sqrt(n[seen])
    return out

This ignores sequential dynamics, representation error, systematic collection bias, and statistically calibrated confidence bounds. It illustrates support, not a general algorithm.

CQL, expectiles, and IQL weights

Implement:

Python
def cql_penalty(q_values, data_actions):
    ...

def expectile_loss(residuals, tau):
    ...

def iql_weights(advantages, beta, max_weight=100.0):
    ...

cql_penalty must use stable log-sum-exp and IQL weights must be clipped above.

Open checks:

Python
q = np.array([2.0, 0.0, -1.0])
assert abs(cql_penalty(q, 0) - (np.log(np.exp(q).sum()) - 2.0)) < 1e-9
assert cql_penalty(q, 0) > 0.0
assert abs(cql_penalty(q, 0) - 0.1698460) < 1e-6
Show answer and solution
Python
import numpy as np

def _logsumexp(x, axis=-1):
    x = np.asarray(x, dtype=float)
    m = np.max(x, axis=axis, keepdims=True)
    return np.squeeze(m + np.log(np.exp(x - m).sum(axis=axis, keepdims=True)), axis=axis)

def cql_penalty(q_values, data_actions):
    q = np.asarray(q_values, dtype=float)
    if q.ndim == 1:
        q = q[None, :]
    a = np.asarray(data_actions, dtype=int)
    if a.ndim == 0:
        a = np.full(q.shape[0], int(a))
    return float(np.mean(_logsumexp(q) - q[np.arange(q.shape[0]), a]))

def expectile_loss(residuals, tau):
    u = np.asarray(residuals, dtype=float)
    if not 0 < tau < 1:
        raise ValueError
    return np.abs(tau - (u < 0)) * u ** 2

def iql_weights(advantages, beta, max_weight=100.0):
    a = np.asarray(advantages, dtype=float)
    return np.minimum(np.exp(np.minimum(beta * a, np.log(max_weight))), max_weight)

Return-to-go and target update

Implement:

Python
def return_to_go(rewards, gamma=1.0):
    ...

def update_target_return(current_target, reward, gamma=1.0):
    ...

The second function uses (Gt−rt)/γ(G_t-r_t)/\gamma and must reject γ=0\gamma=0.

Open checks:

Python
np.testing.assert_allclose(return_to_go([1.0, 0.0, -2.0, 4.0]), [3.0, 2.0, 2.0, 4.0])
Show answer and solution
Python
import numpy as np

def return_to_go(rewards, gamma=1.0):
    r = np.asarray(rewards, dtype=float)
    out = np.empty_like(r)
    running = 0.0
    for t in range(len(r) - 1, -1, -1):
        running = r[t] + gamma * running
        out[t] = running
    return out

def update_target_return(current_target, reward, gamma=1.0):
    if not 0.0 < gamma <= 1.0:
        raise ValueError("gamma must be in (0, 1]")
    return (float(current_target) - float(reward)) / gamma