Source code for rlightning.policy.utils.utils

# Copied from RLinf/RLinf (Apache-2.0):
# https://github.com/RLinf/RLinf
# Original path: rlightning/policy/utils/utils.py
# See THIRD_PARTY_NOTICES.md for details.

from typing import Optional

import torch


[docs] def huber_loss(error: torch.Tensor, delta: float) -> torch.Tensor: return torch.where(error.abs() < delta, 0.5 * error**2, delta * (error.abs() - 0.5 * delta))
[docs] def preprocess_loss_inputs( logprobs: torch.Tensor, old_logprobs: torch.Tensor, advantages: torch.Tensor, logprob_type: Optional[str] = None, single_action_dim: Optional[int] = None, loss_mask: Optional[torch.Tensor] = None, loss_mask_sum: Optional[torch.Tensor] = None, values: Optional[torch.Tensor] = None, prev_values: Optional[torch.Tensor] = None, returns: Optional[torch.Tensor] = None, reward_type: Optional[str] = None, **kwargs, ) -> dict: if reward_type == "chunk_level": advantages = advantages.flatten() if loss_mask is not None: loss_mask = loss_mask.flatten() if loss_mask_sum is not None: loss_mask_sum = loss_mask_sum.flatten() if values is not None: values = values.flatten() if prev_values is not None: prev_values = prev_values.flatten() if returns is not None: returns = returns.flatten() bsz = logprobs.shape[0] if logprob_type == "token_level": # logprobs, old_logprobs: [bsz, num_action_chunks, action_dim] -> [bsz, num_action_chunks, action_dim] logprobs = logprobs.reshape(bsz, -1, single_action_dim) old_logprobs = old_logprobs.reshape(bsz, -1, single_action_dim) advantages = advantages.unsqueeze(-1) if loss_mask is not None: loss_mask = loss_mask.unsqueeze(-1) if loss_mask_sum is not None: loss_mask_sum = loss_mask_sum.unsqueeze(-1) elif logprob_type == "action_level": # logprobs, old_logprobs: [bsz, num_action_chunks, action_dim] -> [bsz, num_action_chunks] logprobs = logprobs.reshape(bsz, -1, single_action_dim).sum(dim=-1) old_logprobs = old_logprobs.reshape(bsz, -1, single_action_dim).sum(dim=-1) elif logprob_type == "chunk_level": # logprobs, old_logprobs: [bsz, num_action_chunks, action_dim] -> [bsz] logprobs = logprobs.reshape(bsz, -1, single_action_dim).sum(dim=[1, 2]) old_logprobs = old_logprobs.reshape(bsz, -1, single_action_dim).sum(dim=[1, 2]) target_shape = logprobs.shape advantages = expand_to_target_dim(advantages, target_shape) loss_mask = expand_to_target_dim(loss_mask, target_shape) loss_mask_sum = expand_to_target_dim(loss_mask_sum, target_shape) values = expand_to_target_dim(values, target_shape) prev_values = expand_to_target_dim(prev_values, target_shape) returns = expand_to_target_dim(returns, target_shape) kwargs.update( { "logprobs": logprobs, "old_logprobs": old_logprobs, "advantages": advantages, "loss_mask": loss_mask, "loss_mask_sum": loss_mask_sum, "values": values, "prev_values": prev_values, "returns": returns, } ) return kwargs
[docs] def postprocess_loss_metric(metrics_data: dict) -> dict: for k, v in metrics_data.items(): if isinstance(v, torch.Tensor): metrics_data[k] = v.detach().item() elif isinstance(v, (float, int)): metrics_data[k] = v return metrics_data
[docs] def expand_to_target_dim(tensor, target_shape): if tensor is None: return None if tensor.shape != target_shape: while len(tensor.shape) < len(target_shape): tensor = tensor.unsqueeze(-1) return tensor
[docs] def append_to_dict(data, new_data): for key, val in new_data.items(): if key not in data: data[key] = [] data[key].append(val) data[key].append(val)
[docs] def masked_mean(values: torch.Tensor, mask: torch.Tensor, axis=None): """Compute mean of tensor with a masked values.""" if mask is None: return values.mean(axis=axis) elif (~mask).all(): return (values * mask).sum(axis=axis) else: return (values * mask).sum(axis=axis) / mask.sum(axis=axis)
[docs] def masked_sum(values: torch.Tensor, mask: torch.Tensor, axis=None): """Compute mean of tensor with a masked values.""" return (values * mask).sum(axis=axis)
[docs] def seq_mean_token_sum(values: torch.Tensor, mask: torch.Tensor, dim: int = -1): seq_losses = torch.sum(values * mask, dim=-1) # token-sum loss = torch.mean(seq_losses) # seq-mean return loss
[docs] def seq_mean_token_mean(values: torch.Tensor, mask: torch.Tensor, dim: int = -1): seq_losses = torch.sum(values * mask, dim=-1) / torch.sum(mask, dim=-1) # token-mean loss = torch.mean(seq_losses) # seq-mean return loss
[docs] def masked_mean_ratio(values: torch.Tensor, mask: torch.Tensor, loss_mask_ratio: torch.Tensor): # for embodied tasks return (values / loss_mask_ratio * mask).mean()