summarize_from_feedback/utils/torch_utils.py (36 lines of code) (raw):

import numpy as np import torch import torch.nn.functional as F def to_numpy(x): if isinstance(x, torch.Tensor): return x.cpu().detach().numpy() if isinstance(x, np.ndarray): return x if isinstance(x, float): return np.array(x) raise ValueError(f"Unexpected type {type(x)}") def tensors_to_device(data, device): if data is None: return None elif isinstance(data, torch.Tensor): return data.to(device) elif isinstance(data, dict): return {k: tensors_to_device(v, device) for k, v in data.items()} else: raise ValueError(f"Unsupported type: {type(data)}") def nans(shape, dtype, device): return torch.ones(shape, dtype=dtype, device=device) * float("nan") def first_true_indices(bools, dtype=torch.long): """ Takes an N-dimensional bool tensor and returns an (N-1)-dimensional tensor of integers giving the position of the first True in each "row". Returns the length of the rows (bools.size(-1)) if no element is True in a given row. """ row_len = bools.size(-1) zero_or_index = row_len * (~bools).type(dtype) + torch.arange( row_len, dtype=dtype, device=bools.device ) return torch.min(zero_or_index, dim=-1).values def gather_one(x, indices, *, dim): """ Gather with only one element along the gathered dimension """ return torch.gather(x, dim=dim, index=indices.unsqueeze(dim)).squeeze(dim) def label_logprobs(*, logits, labels): """cross-entropy for arbitrary shapes""" assert logits.shape[:-1] == labels.shape, f"{logits.shape}[:-1] != {labels.shape}" flat_logits = logits.contiguous().view([-1, logits.size(-1)]) flat_labels = labels.contiguous().view([-1]) flat_logprobs = -F.cross_entropy(input=flat_logits, target=flat_labels, reduction="none") return flat_logprobs.view(labels.shape)