summarize_from_feedback/reward_model.py (42 lines of code) (raw):
import functools
import torch
from summarize_from_feedback import tasks
from summarize_from_feedback.query_response_model import QueryResponseModel, PADDING_TOKEN
from summarize_from_feedback.utils.torch_utils import first_true_indices, gather_one
from summarize_from_feedback.utils.assertions import assert_shape_eq, assert_eq
def _response_indices(response_tokens):
indices = first_true_indices(response_tokens == PADDING_TOKEN) - 1
return torch.max(indices, torch.zeros([1], dtype=indices.dtype, device=response_tokens.device))
def _wrap_reward_model_fn(fn):
@functools.wraps(fn)
def wrapped(outputs_mb, inputs_mb):
rewards = outputs_mb["reward"]["response"][:, :, 1:]
rewards = gather_one(rewards, inputs_mb["last_response_index"], dim=2)
outputs_mb["reward"] = rewards
return fn(outputs_mb, inputs_mb)
return wrapped
class RewardModel(QueryResponseModel):
"""
Represents a reward model, containing a reward head.
Only a single reward is computed for each sequence.
"""
def __init__(self, task_hparams: tasks.TaskHParams = None, init_zero=False, **kwargs):
init_scales = kwargs.pop("init_scales", dict())
if init_zero:
assert "reward" not in init_scales
init_scales["reward"] = 0
super().__init__(logit_head=False, heads=("reward",), init_scales=init_scales, **kwargs)
self.task_hparams = task_hparams
def reward(self, query_tokens, response_tokens, eval_fn=None, eval_inputs=None, **kwargs):
"""
:return: A dict with structure:
reward: [batch, num_responses]
eval_stats: dict of stats returned by eval_fn
"""
last_response_indices = _response_indices(response_tokens).to(self.device)
if self.task_hparams is not None:
assert_eq(query_tokens.size(1), self.task_hparams.query.length)
assert_eq(response_tokens.size(2), self.task_hparams.response.length)
assert query_tokens.size(0) == response_tokens.size(0)
if eval_fn is not None:
eval_fn = _wrap_reward_model_fn(eval_fn)
eval_inputs["last_response_index"] = last_response_indices
result = self._eval(
query_tokens, response_tokens, eval_fn=eval_fn, eval_inputs=eval_inputs, **kwargs
)
result["reward"] = gather_one(
result["reward"]["response"][:, :, 1:], last_response_indices, dim=2
)
assert_shape_eq(result["reward"], (response_tokens.size(0), response_tokens.size(1)))
return result