summarize_from_feedback/models/sample_fns.py (39 lines of code) (raw):
from dataclasses import dataclass
from typing import Callable
import torch
Logits = torch.FloatTensor
@dataclass
class Sample:
logits: Logits
tokens: torch.LongTensor
Sampler = Callable[[Logits], Sample]
def standard(temperature: float = 1.0) -> Sampler:
def sample(logits: Logits) -> Sample:
logits = logits / (temperature + 1e-7)
# There was a regression in torch that made categorical only work with fp32.
# We can track the issue on github and remove this once it makes it into a
# pytorch release or nightly:
#
# https://github.com/pytorch/pytorch/issues/29211
#
logits_fp32 = logits.float()
return Sample(
logits=logits, tokens=torch.distributions.Categorical(logits=logits_fp32).sample()
)
return sample
def argmax() -> Sampler:
def sample(logits: Logits) -> Sample:
return Sample(logits=logits, tokens=torch.argmax(logits, dim=-1))
return sample
def nucleus_sampler(top_p: float = 0.9, temperature=1.0) -> Sampler:
"""
Return a sampler that decides diversity via nucleus sampling.
p=0.9 means that the top 90% of likelihood-weighted options are considered. p=0.0 is
equivalent to argmax, p=1.0 has no effect.
When a logit is on the boundary of being included or not being included, default
to including it.
"""
if top_p == 0.0:
return argmax()
if top_p == 1.0:
return standard(temperature=temperature)
def sample(logits: Logits) -> Sample:
"""
Remove logits that do not represent the top_p proportion of likelihoods.
When a logit is on the boundary of being included or not being included, default
to including it.
"""
logits = logits.clone()
sorted_logits, sorted_indices = torch.sort(logits, descending=True, dim=-1)
cumulative_probs = torch.cumsum(torch.nn.functional.softmax(sorted_logits, dim=-1), dim=-1)
# Remove tokens with cumulative probability above the threshold.
sorted_indices_to_remove = cumulative_probs > top_p
# Shift the indices to the right to keep also the first token above the threshold.
sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
sorted_indices_to_remove[..., 0] = 0
indices_to_remove = torch.zeros_like(logits, dtype=torch.bool).scatter_(
dim=-1, index=sorted_indices, src=sorted_indices_to_remove
)
logits[indices_to_remove] = -float("Inf")
return standard(temperature=temperature)(logits)
return sample