Roadmap / Post-Training & Alignment

✓

Reward Model Loss (Bradley-Terry)

easypost-traininglossesrlhf

The problem

People find it easier to say which of two answers is better than to write the perfect answer. A reward model learns from such comparisons: it gives every answer a score, its reward, so that the answer people preferred (the chosen one) gets a higher score than the one they did not (the rejected one). You will write the loss that trains it, its gradient, and a way to measure how often it ranks the pair correctly.

The Bradley-Terry loss

The Bradley-Terry model says that the probability that the chosen answer beats the rejected one depends only on the difference of their rewards:

P(chosen≻rejected)=σ(rc−rr)P(\text{chosen} \succ \text{rejected}) = \sigma(r_c - r_r)

where σ\sigma is the sigmoid, rcr_c the reward of the chosen answer and rrr_r the reward of the rejected one. The loss is the negative log of that probability, averaged over NN pairs:

L=1N∑n−log⁡σ(rc(n)−rr(n))\mathcal{L} = \frac{1}{N} \sum_{n} -\log \sigma\big(r_c^{(n)} - r_r^{(n)}\big)

Example. One pair.

  • rc=2r_c = 2, rr=0.5r_r = 0.5: the difference is d=1.5d = 1.5, σ(1.5)=0.82\sigma(1.5) = 0.82, loss −log⁡0.82=0.20-\log 0.82 = 0.20. Correct ranking: small loss.
  • rc=0.5r_c = 0.5, rr=2r_r = 2: d=−1.5d = -1.5, σ(−1.5)=0.18\sigma(-1.5) = 0.18, loss 1.701.70. Wrong ranking: large loss.
  • rc=102r_c = 102, rr=100.5r_r = 100.5: the same difference as the first case, the same loss 0.200.20. Only the difference counts, never the absolute scale.

Why not compute −log⁡σ(d)-\log \sigma(d) directly? For a very wrong ranking, such as d=−1000d = -1000, σ(d)\sigma(d) rounds to 0 and the log is −∞-\infty. The identity −log⁡σ(d)=log⁡(1+e−d)-\log \sigma(d) = \log(1 + e^{-d}) is computed safely by np.logaddexp(0, -d), which gives 10001000.

The gradient

With d=rc−rrd = r_c - r_r, the derivative of −log⁡σ(d)-\log \sigma(d) with respect to dd is −σ(−d)=−(1−σ(d))-\sigma(-d) = -(1 - \sigma(d)): the more wrong the ranking, the closer to −1-1. So the gradient with respect to rcr_c is that, and for rrr_r it is the opposite, both divided by NN because of the mean.

Example. For the first pair above (d=1.5d = 1.5): −σ(−1.5)=−0.18-\sigma(-1.5) = -0.18 for rcr_c and +0.18+0.18 for rrr_r (with N=1N = 1). Training moves against the gradient, so it raises rcr_c and lowers rrr_r, only a little: the ranking is already right. For the second pair (d=−1.5d = -1.5): −0.82-0.82 and +0.82+0.82, a strong push.

Accuracy

The accuracy is the fraction of pairs where the chosen answer gets the higher reward.

Example. Three pairs with r_chosen = [2, 1, 0] and r_rejected = [1, 2, -1]: the chosen answer wins in pairs 1 and 3, loses in pair 2: accuracy 2/32/3.

What to implement

For arrays r_chosen and r_rejected of shape (N,)(N,):

  • preference_loss(r_chosen, r_rejected): the mean loss, stable for any rewards.
  • preference_grads(r_chosen, r_rejected): the gradients with respect to r_chosen and to r_rejected, as a pair of arrays.
  • preference_accuracy(r_chosen, r_rejected): the accuracy.

Requirements

  • Use np.logaddexp(0, -d) for the loss, so that d=−1000d = -1000 gives 1000 instead of inf.
  • No loops.
solution.py
Python idle

Press Run (⌘/Ctrl + Enter) to test your code.