Shortcuts

Source code for torcheval.metrics.functional.regression.r2_score

# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

# pyre-ignore-all-errors[16]: Undefined attribute of metric states.

from typing import Tuple

import torch


[docs]@torch.inference_mode() def r2_score( input: torch.Tensor, target: torch.Tensor, *, multioutput: str = "uniform_average", num_regressors: int = 0, ) -> torch.Tensor: """ Compute R-squared score, which is the proportion of variance in the dependent variable that can be explained by the independent variable. Its class version is ``torcheval.metrics.R2Score``. Args: input: Tensor of predicted values with shape of (n_sample, n_output). target: Tensor of ground truth values with shape of (n_sample, n_output). multioutput (Optional): - ``'uniform_average'`` [default]: Return scores of all outputs are averaged with uniform weight. - ``'raw_values'``: Return a full set of scores. - ``variance_weighted``: Return scores of all outputs are averaged with weighted by the variances of each individual output. num_regressors (Optional): Number of independent variables used, applied to adjusted R-squared score. Defaults to zero (standard R-squared score). Raises: ValueError: - If value of multioutput does not exist in (``raw_values``, ``uniform_average``, ``variance_weighted``). - If value of num_regressors is not an ``integer`` in the range of [0, n_samples - 1]. Examples:: >>> import torch >>> from torcheval.metrics.functional import r2_score >>> input = torch.tensor([0, 2, 1, 3]) >>> target = torch.tensor([0, 1, 2, 3]) >>> r2_score(input, target) tensor(0.6) >>> input = torch.tensor([[0, 2], [1, 6]]) >>> target = torch.tensor([[0, 1], [2, 5]]) >>> r2_score(input, target) tensor(0.6250) >>> input = torch.tensor([[0, 2], [1, 6]]) >>> target = torch.tensor([[0, 1], [2, 5]]) >>> r2_score(input, target, multioutput="raw_values") tensor([0.5000, 0.7500]) >>> input = torch.tensor([[0, 2], [1, 6]]) >>> target = torch.tensor([[0, 1], [2, 5]]) >>> r2_score(input, target, multioutput="variance_weighted") tensor(0.7000) >>> input = torch.tensor([1.2, 2.5, 3.6, 4.5, 6]) >>> target = torch.tensor([1, 2, 3, 4, 5]) >>> r2_score(input, target, multioutput="raw_values", num_regressors=2) tensor(0.6200) """ _r2_score_param_check(multioutput, num_regressors) sum_squared_obs, sum_obs, sum_squared_residual, num_obs = _r2_score_update( input, target ) return _r2_score_compute( sum_squared_obs, sum_obs, sum_squared_residual, num_obs, multioutput, num_regressors, )
def _r2_score_update( input: torch.Tensor, target: torch.Tensor, ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: _r2_score_update_input_check(input, target) return _update(input, target) @torch.jit.script def _update( input: torch.Tensor, target: torch.Tensor, ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: sum_squared_obs = torch.sum(torch.square(target), dim=0) sum_obs = torch.sum(target, dim=0) sum_squared_residual = torch.sum(torch.square(target - input), dim=0) num_obs = torch.tensor(target.size(0)) return sum_squared_obs, sum_obs, sum_squared_residual, num_obs def _r2_score_compute( sum_squared_obs: torch.Tensor, sum_obs: torch.Tensor, rss: torch.Tensor, num_obs: torch.Tensor, multioutput: str, num_regressors: int, ) -> torch.Tensor: if num_obs < 2: raise ValueError( "There is no enough data for computing. Needs at least two samples to calculate r2 score." ) if num_regressors >= num_obs - 1: raise ValueError( "The `num_regressors` must be smaller than n_samples - 1, " f"got num_regressors={num_regressors}, n_samples={num_obs}.", ) return _compute( sum_squared_obs, sum_obs, rss, num_obs, multioutput, num_regressors, ) @torch.jit.script def _compute( sum_squared_obs: torch.Tensor, sum_obs: torch.Tensor, rss: torch.Tensor, num_obs: torch.Tensor, multioutput: str, num_regressors: int, ) -> torch.Tensor: tss = sum_squared_obs - torch.square(sum_obs) / num_obs # Calculate R2 score when multioutput is equal to raw_values. r_squared = 1 - (rss / tss) if multioutput == "uniform_average": r_squared = torch.mean(r_squared) elif multioutput == "variance_weighted": r_squared = torch.sum(r_squared * tss / torch.sum(tss)) # If num_regressors is not equal to 0, adjusted R2 applies. if num_regressors != 0: r_squared = 1 - (1 - r_squared) * (num_obs - 1) / (num_obs - num_regressors - 1) return r_squared def _r2_score_param_check( multioutput: str, num_regressors: int, ) -> None: if multioutput not in ("raw_values", "uniform_average", "variance_weighted"): raise ValueError( "The `multioutput` must be either `raw_values` or `uniform_average` or `variance_weighted`, " f"got multioutput={multioutput}." ) if not isinstance(num_regressors, int) or num_regressors < 0: raise ValueError( "The `num_regressors` must an integer larger or equal to zero, " f"got num_regressors={num_regressors}." ) def _r2_score_update_input_check( input: torch.Tensor, target: torch.Tensor, ) -> None: if input.ndim >= 3 or target.ndim >= 3: raise ValueError( "The dimension `input` and `target` should be 1D or 2D, " f"got shapes {input.shape} and {target.shape}." ) if input.size() != target.size(): raise ValueError( "The `input` and `target` should have the same size, " f"got shapes {input.shape} and {target.shape}." )

Docs

Access comprehensive developer documentation for PyTorch

View Docs

Tutorials

Get in-depth tutorials for beginners and advanced developers

View Tutorials

Resources

Find development resources and get your questions answered

View Resources