RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Eruo Fredoline
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /RLHF, DPO, and PPO
  6. /Ch. 8
RLHF, DPO, and PPO

08. Reward Model Evaluation

Chapter 8 of 24 · 20 min
KEY INSIGHT

A reward model with 60% accuracy on test pairs is barely better than random (50%). But it might still be useful for RL if the errors are systematic and predictable. Conversely, a 70% accurate model with correlated errors might perform worse in RL. Evaluate qualitatively before trusting the numbers.

Evaluating reward models is tricky because you don't have ground-truth preferences—only more noisy approximations. Standard classification metrics (accuracy, F1) don't capture what you care about: whether high-reward responses are actually better than low-reward ones.

Kendall's Tau correlation: Measures rank correlation between predicted rewards and true preferences. A tau of 0.5 means the model correctly orders half of all possible pairs.

from scipy.stats import kendalltau
import numpy as np

def evaluate_reward_model(reward_model, test_pairs):
    """
    test_pairs: list of {"prompt": str, "chosen": str, "rejected": str}
    """
    predicted_rewards_chosen = []
    predicted_rewards_rejected = []
    
    for pair in test_pairs:
        # Tokenize and get rewards
        chosen_reward = reward_model(pair["prompt"], pair["chosen"])
        rejected_reward = reward_model(pair["prompt"], pair["rejected"])
        predicted_rewards_chosen.append(chosen_reward)
        predicted_rewards_rejected.append(rejected_reward)
    
    # Calculate accuracy: how often is chosen > rejected?
    accuracy = np.mean([
        c > r for c, r in zip(predicted_rewards_chosen, predicted_rewards_rejected)
    ])
    
    # Kendall's Tau: rank correlation
    # Create binary labels (1 if chosen > rejected, 0 otherwise)
    # Perfect model would have tau = 1.0
    all_rewards = predicted_rewards_chosen + predicted_rewards_rejected
    labels = [1] * len(predicted_rewards_chosen) + [0] * len(predicted_rewards_rejected)
    tau, p_value = kendalltau(all_rewards, labels)
    
    return {"accuracy": accuracy, "kendall_tau": tau, "p_value": p_value}

Reward model tests for systematic biases:

def test_length_bias(reward_model, base_prompt):
    """Test if reward model prefers longer/shorter responses."""
    short_response = "The answer is 42."
    long_response = "The answer is 42. This is based on deep analysis of the problem. " * 5
    
    short_reward = reward_model(base_prompt, short_response)
    long_reward = reward_model(base_prompt, long_response)
    
    print(f"Short response reward: {short_reward:.3f}")
    print(f"Long response reward: {long_reward:.3f}")
    print(f"Length bias: {'Present' if abs(short_reward - long_reward) > 0.1 else 'Minimal'}")

def test_sybil_attack(reward_model, prompt, good_response, injected_response):
    """Test if reward model is fooled by sybil attacks (flattery, manipulation)."""
    # A good response followed by sycophantic flattery
    sycophant_response = good_response + " You are absolutely right, and your intelligence is remarkable."
    
    good_reward = reward_model(prompt, good_response)
    sycophant_reward = reward_model(prompt, sycophant_response)
    
    print(f"Good response reward: {good_reward:.3f}")
    print(f"Sycophant response reward: {sycophant_reward:.3f}")
    print(f"Sycophancy detected: {'Yes' if sycophant_reward > good_reward else 'No'}")

Human preference prediction: The ultimate test is whether the reward model's preferences match human preferences. Sample responses at the extremes of the reward distribution and have humans evaluate them.

EXERCISE

Take your trained reward model and run the three tests above (length bias, sycophancy, format sensitivity). Document the results quantitatively. For any biases found, propose a data augmentation or regularization strategy to mitigate them. Implement one mitigation and re-run the test to measure improvement.

← Chapter 7
Data Collection
Chapter 9 →
PPO Theory