We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SpearmanCorrCoef has unnecessary explicit dtype check
## 🐛 Bug
If you're running a model with `torch.cuda.amp.autocast` to `bf16`, you may have model outputs in `bf16` and labels in `fp32`, and then run `metric.compute()` outside of the autocast. Everything works completely fine for most (perhaps all other?) metrics, but `SpearmanCorrCoef` has an explicit check that the `dtype` of the `preds` and `target` are the same (https://github.com/Lightning-AI/metrics/blob/70a844f5aa598035eae50f3268563cfab103c62d/src/torchmetrics/functional/regression/spearman.py#L65). I do not think this check is necessary, because torch will automatically promote one of them when they are multiplied together, which is the only operation between the two tensors that happens while computing spearman. I may be missing something, but it would be great to remove this explicit check so that code using this metric does not need to explicitly cast the inputs, or to just handle the casting inside the metric if it is necessary for some reason.

### To Reproduce
```
In [1]: import torch
   ...: from torchmetrics import MeanSquaredError, SpearmanCorrCoef
   ...: 
   ...: preds = torch.rand((100,), dtype=torch.bfloat16)
   ...: target = torch.rand((100,), dtype=torch.float)
   ...: fp32preds = preds.detach().clone().float()
   ...: 
   ...: sp1 = SpearmanCorrCoef()
   ...: sp2 = SpearmanCorrCoef()
   ...: 
   ...: # Spearman update errors
   ...: sp1.update(preds, target)
/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/utilities/prints.py:36: UserWarning: Metric `SpearmanCorrcoef` will save all targets and predictions in the buffer. For large datasets, this may lead to large memory footprint.
  warnings.warn(*args, **kwargs)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-162d7ed78d22> in <cell line: 12>()
     10 
     11 # Spearman update errors
---> 12 sp1.update(preds, target)
     13 sp2.update(fp32preds, target)
     14 print(sp1.compute())

/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/metric.py in wrapped_func(*args, **kwargs)
    265             self._update_called = True
    266             with torch.set_grad_enabled(self._enable_grad):
--> 267                 return update(*args, **kwargs)
    268 
    269         return wrapped_func

/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/regression/spearman.py in update(self, preds, target)
     88             target: Ground truth values
     89         """
---> 90         preds, target = _spearman_corrcoef_update(preds, target)
     91         self.preds.append(preds)
     92         self.target.append(target)

/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/functional/regression/spearman.py in _spearman_corrcoef_update(preds, target)
     62 
     63     if preds.dtype != target.dtype:
---> 64         raise TypeError(
     65             "Expected `preds` and `target` to have the same data type."
     66             f" Got preds: {preds.dtype} and target: {target.dtype}."

TypeError: Expected `preds` and `target` to have the same data type. Got preds: torch.bfloat16 and target: torch.float32.
```

and if you comment out the dtype check
```
In [1]: import torch
   ...: from torchmetrics import MeanSquaredError, SpearmanCorrCoef
   ...: 
   ...: preds = torch.rand((100,), dtype=torch.bfloat16)
   ...: target = torch.rand((100,), dtype=torch.float)
   ...: fp32preds = preds.detach().clone().float()
   ...: 
   ...: sp1 = SpearmanCorrCoef()
   ...: sp2 = SpearmanCorrCoef()
   ...: 
   ...: # Spearman update errors
   ...: sp1.update(preds, target)
   ...: sp2.update(fp32preds, target)
   ...: 
   ...: 
   ...: print(sp1.compute())
   ...: print(sp2.compute())
/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/utilities/prints.py:36: UserWarning: Metric `SpearmanCorrcoef` will save all targets and predictions in the buffer. For large datasets, this may lead to large memory footprint.
  warnings.warn(*args, **kwargs)
tensor(-0.0699)
tensor(-0.0699)
```

#### Code sample
See above

### Expected behavior
Spearman computation works with `preds` and `target` having different `dtype`.

### Environment
Checked that it is an issue on `0.10.1`, and the check still exists on master (linked above)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/torchmetrics/functional/regression/spearman.py`
Content:
```
1 # Copyright The PyTorch Lightning team.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from typing import Tuple
15 
16 import torch
17 from torch import Tensor
18 
19 from torchmetrics.utilities.checks import _check_same_shape
20 
21 
22 def _find_repeats(data: Tensor) -> Tensor:
23     """find and return values which have repeats i.e. the same value are more than once in the tensor."""
24     temp = data.detach().clone()
25     temp = temp.sort()[0]
26 
27     change = torch.cat([torch.tensor([True], device=temp.device), temp[1:] != temp[:-1]])
28     unique = temp[change]
29     change_idx = torch.cat([torch.nonzero(change), torch.tensor([[temp.numel()]], device=temp.device)]).flatten()
30     freq = change_idx[1:] - change_idx[:-1]
31     atleast2 = freq > 1
32     return unique[atleast2]
33 
34 
35 def _rank_data(data: Tensor) -> Tensor:
36     """Calculate the rank for each element of a tensor.
37 
38     The rank refers to the indices of an element in the corresponding sorted tensor (starting from 1).
39     Duplicates of the same value will be assigned the mean of their rank.
40 
41     Adopted from `Rank of element tensor`_
42     """
43     n = data.numel()
44     rank = torch.empty_like(data)
45     idx = data.argsort()
46     rank[idx[:n]] = torch.arange(1, n + 1, dtype=data.dtype, device=data.device)
47 
48     repeats = _find_repeats(data)
49     for r in repeats:
50         condition = data == r
51         rank[condition] = rank[condition].mean()
52     return rank
53 
54 
55 def _spearman_corrcoef_update(preds: Tensor, target: Tensor, num_outputs: int) -> Tuple[Tensor, Tensor]:
56     """Updates and returns variables required to compute Spearman Correlation Coefficient.
57 
58     Checks for same shape and type of input tensors.
59 
60     Args:
61         preds: Predicted tensor
62         target: Ground truth tensor
63     """
64 
65     if preds.dtype != target.dtype:
66         raise TypeError(
67             "Expected `preds` and `target` to have the same data type."
68             f" Got preds: {preds.dtype} and target: {target.dtype}."
69         )
70     _check_same_shape(preds, target)
71     if preds.ndim > 2 or target.ndim > 2:
72         raise ValueError(
73             f"Expected both predictions and target to be either 1- or 2-dimensional tensors,"
74             f" but got {target.ndim} and {preds.ndim}."
75         )
76     if (num_outputs == 1 and preds.ndim != 1) or (num_outputs > 1 and num_outputs != preds.shape[-1]):
77         raise ValueError(
78             f"Expected argument `num_outputs` to match the second dimension of input, but got {num_outputs}"
79             f" and {preds.ndim}."
80         )
81 
82     return preds, target
83 
84 
85 def _spearman_corrcoef_compute(preds: Tensor, target: Tensor, eps: float = 1e-6) -> Tensor:
86     """Computes Spearman Correlation Coefficient.
87 
88     Args:
89         preds: Predicted tensor
90         target: Ground truth tensor
91         eps: Avoids ``ZeroDivisionError``.
92 
93     Example:
94         >>> target = torch.tensor([3, -0.5, 2, 7])
95         >>> preds = torch.tensor([2.5, 0.0, 2, 8])
96         >>> preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1)
97         >>> _spearman_corrcoef_compute(preds, target)
98         tensor(1.0000)
99     """
100     if preds.ndim == 1:
101         preds = _rank_data(preds)
102         target = _rank_data(target)
103     else:
104         preds = torch.stack([_rank_data(p) for p in preds.T]).T
105         target = torch.stack([_rank_data(t) for t in target.T]).T
106 
107     preds_diff = preds - preds.mean(0)
108     target_diff = target - target.mean(0)
109 
110     cov = (preds_diff * target_diff).mean(0)
111     preds_std = torch.sqrt((preds_diff * preds_diff).mean(0))
112     target_std = torch.sqrt((target_diff * target_diff).mean(0))
113 
114     corrcoef = cov / (preds_std * target_std + eps)
115     return torch.clamp(corrcoef, -1.0, 1.0)
116 
117 
118 def spearman_corrcoef(preds: Tensor, target: Tensor) -> Tensor:
119     r"""Computes `spearmans rank correlation coefficient`_:
120 
121     .. math:
122         r_s = = \frac{cov(rg_x, rg_y)}{\sigma_{rg_x} * \sigma_{rg_y}}
123 
124     where :math:`rg_x` and :math:`rg_y` are the rank associated to the variables x and y. Spearmans correlations
125     coefficient corresponds to the standard pearsons correlation coefficient calculated on the rank variables.
126 
127     Args:
128         preds: estimated scores
129         target: ground truth scores
130 
131     Example (single output regression):
132         >>> from torchmetrics.functional import spearman_corrcoef
133         >>> target = torch.tensor([3, -0.5, 2, 7])
134         >>> preds = torch.tensor([2.5, 0.0, 2, 8])
135         >>> spearman_corrcoef(preds, target)
136         tensor(1.0000)
137 
138     Example (multi output regression):
139         >>> from torchmetrics.functional import spearman_corrcoef
140         >>> target = torch.tensor([[3, -0.5], [2, 7]])
141         >>> preds = torch.tensor([[2.5, 0.0], [2, 8]])
142         >>> spearman_corrcoef(preds, target)
143         tensor([1.0000, 1.0000])
144     """
145     preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1 if preds.ndim == 1 else preds.shape[-1])
146     return _spearman_corrcoef_compute(preds, target)
147
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/torchmetrics/functional/regression/spearman.py b/src/torchmetrics/functional/regression/spearman.py
--- a/src/torchmetrics/functional/regression/spearman.py
+++ b/src/torchmetrics/functional/regression/spearman.py
@@ -62,10 +62,9 @@
         target: Ground truth tensor
     """
 
-    if preds.dtype != target.dtype:
+    if not (preds.is_floating_point() and target.is_floating_point()):
         raise TypeError(
-            "Expected `preds` and `target` to have the same data type."
-            f" Got preds: {preds.dtype} and target: {target.dtype}."
+            "Expected `preds` and `target` both to be floating point tensors, but got {pred.dtype} and {target.dtype}"
         )
     _check_same_shape(preds, target)
     if preds.ndim > 2 or target.ndim > 2:

{"golden_diff": "diff --git a/src/torchmetrics/functional/regression/spearman.py b/src/torchmetrics/functional/regression/spearman.py\n--- a/src/torchmetrics/functional/regression/spearman.py\n+++ b/src/torchmetrics/functional/regression/spearman.py\n@@ -62,10 +62,9 @@\n         target: Ground truth tensor\n     \"\"\"\n \n-    if preds.dtype != target.dtype:\n+    if not (preds.is_floating_point() and target.is_floating_point()):\n         raise TypeError(\n-            \"Expected `preds` and `target` to have the same data type.\"\n-            f\" Got preds: {preds.dtype} and target: {target.dtype}.\"\n+            \"Expected `preds` and `target` both to be floating point tensors, but got {pred.dtype} and {target.dtype}\"\n         )\n     _check_same_shape(preds, target)\n     if preds.ndim > 2 or target.ndim > 2:\n", "issue": "SpearmanCorrCoef has unnecessary explicit dtype check\n## \ud83d\udc1b Bug\r\nIf you're running a model with `torch.cuda.amp.autocast` to `bf16`, you may have model outputs in `bf16` and labels in `fp32`, and then run `metric.compute()` outside of the autocast. Everything works completely fine for most (perhaps all other?) metrics, but `SpearmanCorrCoef` has an explicit check that the `dtype` of the `preds` and `target` are the same (https://github.com/Lightning-AI/metrics/blob/70a844f5aa598035eae50f3268563cfab103c62d/src/torchmetrics/functional/regression/spearman.py#L65). I do not think this check is necessary, because torch will automatically promote one of them when they are multiplied together, which is the only operation between the two tensors that happens while computing spearman. I may be missing something, but it would be great to remove this explicit check so that code using this metric does not need to explicitly cast the inputs, or to just handle the casting inside the metric if it is necessary for some reason.\r\n\r\n### To Reproduce\r\n```\r\nIn [1]: import torch\r\n   ...: from torchmetrics import MeanSquaredError, SpearmanCorrCoef\r\n   ...: \r\n   ...: preds = torch.rand((100,), dtype=torch.bfloat16)\r\n   ...: target = torch.rand((100,), dtype=torch.float)\r\n   ...: fp32preds = preds.detach().clone().float()\r\n   ...: \r\n   ...: sp1 = SpearmanCorrCoef()\r\n   ...: sp2 = SpearmanCorrCoef()\r\n   ...: \r\n   ...: # Spearman update errors\r\n   ...: sp1.update(preds, target)\r\n/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/utilities/prints.py:36: UserWarning: Metric `SpearmanCorrcoef` will save all targets and predictions in the buffer. For large datasets, this may lead to large memory footprint.\r\n  warnings.warn(*args, **kwargs)\r\n---------------------------------------------------------------------------\r\nTypeError                                 Traceback (most recent call last)\r\n<ipython-input-1-162d7ed78d22> in <cell line: 12>()\r\n     10 \r\n     11 # Spearman update errors\r\n---> 12 sp1.update(preds, target)\r\n     13 sp2.update(fp32preds, target)\r\n     14 print(sp1.compute())\r\n\r\n/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/metric.py in wrapped_func(*args, **kwargs)\r\n    265             self._update_called = True\r\n    266             with torch.set_grad_enabled(self._enable_grad):\r\n--> 267                 return update(*args, **kwargs)\r\n    268 \r\n    269         return wrapped_func\r\n\r\n/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/regression/spearman.py in update(self, preds, target)\r\n     88             target: Ground truth values\r\n     89         \"\"\"\r\n---> 90         preds, target = _spearman_corrcoef_update(preds, target)\r\n     91         self.preds.append(preds)\r\n     92         self.target.append(target)\r\n\r\n/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/functional/regression/spearman.py in _spearman_corrcoef_update(preds, target)\r\n     62 \r\n     63     if preds.dtype != target.dtype:\r\n---> 64         raise TypeError(\r\n     65             \"Expected `preds` and `target` to have the same data type.\"\r\n     66             f\" Got preds: {preds.dtype} and target: {target.dtype}.\"\r\n\r\nTypeError: Expected `preds` and `target` to have the same data type. Got preds: torch.bfloat16 and target: torch.float32.\r\n```\r\n\r\nand if you comment out the dtype check\r\n```\r\nIn [1]: import torch\r\n   ...: from torchmetrics import MeanSquaredError, SpearmanCorrCoef\r\n   ...: \r\n   ...: preds = torch.rand((100,), dtype=torch.bfloat16)\r\n   ...: target = torch.rand((100,), dtype=torch.float)\r\n   ...: fp32preds = preds.detach().clone().float()\r\n   ...: \r\n   ...: sp1 = SpearmanCorrCoef()\r\n   ...: sp2 = SpearmanCorrCoef()\r\n   ...: \r\n   ...: # Spearman update errors\r\n   ...: sp1.update(preds, target)\r\n   ...: sp2.update(fp32preds, target)\r\n   ...: \r\n   ...: \r\n   ...: print(sp1.compute())\r\n   ...: print(sp2.compute())\r\n/workdisk/danielking/composer_venv/lib/python3.9/site-packages/torchmetrics/utilities/prints.py:36: UserWarning: Metric `SpearmanCorrcoef` will save all targets and predictions in the buffer. For large datasets, this may lead to large memory footprint.\r\n  warnings.warn(*args, **kwargs)\r\ntensor(-0.0699)\r\ntensor(-0.0699)\r\n```\r\n\r\n#### Code sample\r\nSee above\r\n\r\n### Expected behavior\r\nSpearman computation works with `preds` and `target` having different `dtype`.\r\n\r\n### Environment\r\nChecked that it is an issue on `0.10.1`, and the check still exists on master (linked above)\r\n\r\n\n", "before_files": [{"content": "# Copyright The PyTorch Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nfrom typing import Tuple\n\nimport torch\nfrom torch import Tensor\n\nfrom torchmetrics.utilities.checks import _check_same_shape\n\n\ndef _find_repeats(data: Tensor) -> Tensor:\n    \"\"\"find and return values which have repeats i.e. the same value are more than once in the tensor.\"\"\"\n    temp = data.detach().clone()\n    temp = temp.sort()[0]\n\n    change = torch.cat([torch.tensor([True], device=temp.device), temp[1:] != temp[:-1]])\n    unique = temp[change]\n    change_idx = torch.cat([torch.nonzero(change), torch.tensor([[temp.numel()]], device=temp.device)]).flatten()\n    freq = change_idx[1:] - change_idx[:-1]\n    atleast2 = freq > 1\n    return unique[atleast2]\n\n\ndef _rank_data(data: Tensor) -> Tensor:\n    \"\"\"Calculate the rank for each element of a tensor.\n\n    The rank refers to the indices of an element in the corresponding sorted tensor (starting from 1).\n    Duplicates of the same value will be assigned the mean of their rank.\n\n    Adopted from `Rank of element tensor`_\n    \"\"\"\n    n = data.numel()\n    rank = torch.empty_like(data)\n    idx = data.argsort()\n    rank[idx[:n]] = torch.arange(1, n + 1, dtype=data.dtype, device=data.device)\n\n    repeats = _find_repeats(data)\n    for r in repeats:\n        condition = data == r\n        rank[condition] = rank[condition].mean()\n    return rank\n\n\ndef _spearman_corrcoef_update(preds: Tensor, target: Tensor, num_outputs: int) -> Tuple[Tensor, Tensor]:\n    \"\"\"Updates and returns variables required to compute Spearman Correlation Coefficient.\n\n    Checks for same shape and type of input tensors.\n\n    Args:\n        preds: Predicted tensor\n        target: Ground truth tensor\n    \"\"\"\n\n    if preds.dtype != target.dtype:\n        raise TypeError(\n            \"Expected `preds` and `target` to have the same data type.\"\n            f\" Got preds: {preds.dtype} and target: {target.dtype}.\"\n        )\n    _check_same_shape(preds, target)\n    if preds.ndim > 2 or target.ndim > 2:\n        raise ValueError(\n            f\"Expected both predictions and target to be either 1- or 2-dimensional tensors,\"\n            f\" but got {target.ndim} and {preds.ndim}.\"\n        )\n    if (num_outputs == 1 and preds.ndim != 1) or (num_outputs > 1 and num_outputs != preds.shape[-1]):\n        raise ValueError(\n            f\"Expected argument `num_outputs` to match the second dimension of input, but got {num_outputs}\"\n            f\" and {preds.ndim}.\"\n        )\n\n    return preds, target\n\n\ndef _spearman_corrcoef_compute(preds: Tensor, target: Tensor, eps: float = 1e-6) -> Tensor:\n    \"\"\"Computes Spearman Correlation Coefficient.\n\n    Args:\n        preds: Predicted tensor\n        target: Ground truth tensor\n        eps: Avoids ``ZeroDivisionError``.\n\n    Example:\n        >>> target = torch.tensor([3, -0.5, 2, 7])\n        >>> preds = torch.tensor([2.5, 0.0, 2, 8])\n        >>> preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1)\n        >>> _spearman_corrcoef_compute(preds, target)\n        tensor(1.0000)\n    \"\"\"\n    if preds.ndim == 1:\n        preds = _rank_data(preds)\n        target = _rank_data(target)\n    else:\n        preds = torch.stack([_rank_data(p) for p in preds.T]).T\n        target = torch.stack([_rank_data(t) for t in target.T]).T\n\n    preds_diff = preds - preds.mean(0)\n    target_diff = target - target.mean(0)\n\n    cov = (preds_diff * target_diff).mean(0)\n    preds_std = torch.sqrt((preds_diff * preds_diff).mean(0))\n    target_std = torch.sqrt((target_diff * target_diff).mean(0))\n\n    corrcoef = cov / (preds_std * target_std + eps)\n    return torch.clamp(corrcoef, -1.0, 1.0)\n\n\ndef spearman_corrcoef(preds: Tensor, target: Tensor) -> Tensor:\n    r\"\"\"Computes `spearmans rank correlation coefficient`_:\n\n    .. math:\n        r_s = = \\frac{cov(rg_x, rg_y)}{\\sigma_{rg_x} * \\sigma_{rg_y}}\n\n    where :math:`rg_x` and :math:`rg_y` are the rank associated to the variables x and y. Spearmans correlations\n    coefficient corresponds to the standard pearsons correlation coefficient calculated on the rank variables.\n\n    Args:\n        preds: estimated scores\n        target: ground truth scores\n\n    Example (single output regression):\n        >>> from torchmetrics.functional import spearman_corrcoef\n        >>> target = torch.tensor([3, -0.5, 2, 7])\n        >>> preds = torch.tensor([2.5, 0.0, 2, 8])\n        >>> spearman_corrcoef(preds, target)\n        tensor(1.0000)\n\n    Example (multi output regression):\n        >>> from torchmetrics.functional import spearman_corrcoef\n        >>> target = torch.tensor([[3, -0.5], [2, 7]])\n        >>> preds = torch.tensor([[2.5, 0.0], [2, 8]])\n        >>> spearman_corrcoef(preds, target)\n        tensor([1.0000, 1.0000])\n    \"\"\"\n    preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1 if preds.ndim == 1 else preds.shape[-1])\n    return _spearman_corrcoef_compute(preds, target)\n", "path": "src/torchmetrics/functional/regression/spearman.py"}], "after_files": [{"content": "# Copyright The PyTorch Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nfrom typing import Tuple\n\nimport torch\nfrom torch import Tensor\n\nfrom torchmetrics.utilities.checks import _check_same_shape\n\n\ndef _find_repeats(data: Tensor) -> Tensor:\n    \"\"\"find and return values which have repeats i.e. the same value are more than once in the tensor.\"\"\"\n    temp = data.detach().clone()\n    temp = temp.sort()[0]\n\n    change = torch.cat([torch.tensor([True], device=temp.device), temp[1:] != temp[:-1]])\n    unique = temp[change]\n    change_idx = torch.cat([torch.nonzero(change), torch.tensor([[temp.numel()]], device=temp.device)]).flatten()\n    freq = change_idx[1:] - change_idx[:-1]\n    atleast2 = freq > 1\n    return unique[atleast2]\n\n\ndef _rank_data(data: Tensor) -> Tensor:\n    \"\"\"Calculate the rank for each element of a tensor.\n\n    The rank refers to the indices of an element in the corresponding sorted tensor (starting from 1).\n    Duplicates of the same value will be assigned the mean of their rank.\n\n    Adopted from `Rank of element tensor`_\n    \"\"\"\n    n = data.numel()\n    rank = torch.empty_like(data)\n    idx = data.argsort()\n    rank[idx[:n]] = torch.arange(1, n + 1, dtype=data.dtype, device=data.device)\n\n    repeats = _find_repeats(data)\n    for r in repeats:\n        condition = data == r\n        rank[condition] = rank[condition].mean()\n    return rank\n\n\ndef _spearman_corrcoef_update(preds: Tensor, target: Tensor, num_outputs: int) -> Tuple[Tensor, Tensor]:\n    \"\"\"Updates and returns variables required to compute Spearman Correlation Coefficient.\n\n    Checks for same shape and type of input tensors.\n\n    Args:\n        preds: Predicted tensor\n        target: Ground truth tensor\n    \"\"\"\n\n    if not (preds.is_floating_point() and target.is_floating_point()):\n        raise TypeError(\n            \"Expected `preds` and `target` both to be floating point tensors, but got {pred.dtype} and {target.dtype}\"\n        )\n    _check_same_shape(preds, target)\n    if preds.ndim > 2 or target.ndim > 2:\n        raise ValueError(\n            f\"Expected both predictions and target to be either 1- or 2-dimensional tensors,\"\n            f\" but got {target.ndim} and {preds.ndim}.\"\n        )\n    if (num_outputs == 1 and preds.ndim != 1) or (num_outputs > 1 and num_outputs != preds.shape[-1]):\n        raise ValueError(\n            f\"Expected argument `num_outputs` to match the second dimension of input, but got {num_outputs}\"\n            f\" and {preds.ndim}.\"\n        )\n\n    return preds, target\n\n\ndef _spearman_corrcoef_compute(preds: Tensor, target: Tensor, eps: float = 1e-6) -> Tensor:\n    \"\"\"Computes Spearman Correlation Coefficient.\n\n    Args:\n        preds: Predicted tensor\n        target: Ground truth tensor\n        eps: Avoids ``ZeroDivisionError``.\n\n    Example:\n        >>> target = torch.tensor([3, -0.5, 2, 7])\n        >>> preds = torch.tensor([2.5, 0.0, 2, 8])\n        >>> preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1)\n        >>> _spearman_corrcoef_compute(preds, target)\n        tensor(1.0000)\n    \"\"\"\n    if preds.ndim == 1:\n        preds = _rank_data(preds)\n        target = _rank_data(target)\n    else:\n        preds = torch.stack([_rank_data(p) for p in preds.T]).T\n        target = torch.stack([_rank_data(t) for t in target.T]).T\n\n    preds_diff = preds - preds.mean(0)\n    target_diff = target - target.mean(0)\n\n    cov = (preds_diff * target_diff).mean(0)\n    preds_std = torch.sqrt((preds_diff * preds_diff).mean(0))\n    target_std = torch.sqrt((target_diff * target_diff).mean(0))\n\n    corrcoef = cov / (preds_std * target_std + eps)\n    return torch.clamp(corrcoef, -1.0, 1.0)\n\n\ndef spearman_corrcoef(preds: Tensor, target: Tensor) -> Tensor:\n    r\"\"\"Computes `spearmans rank correlation coefficient`_:\n\n    .. math:\n        r_s = = \\frac{cov(rg_x, rg_y)}{\\sigma_{rg_x} * \\sigma_{rg_y}}\n\n    where :math:`rg_x` and :math:`rg_y` are the rank associated to the variables x and y. Spearmans correlations\n    coefficient corresponds to the standard pearsons correlation coefficient calculated on the rank variables.\n\n    Args:\n        preds: estimated scores\n        target: ground truth scores\n\n    Example (single output regression):\n        >>> from torchmetrics.functional import spearman_corrcoef\n        >>> target = torch.tensor([3, -0.5, 2, 7])\n        >>> preds = torch.tensor([2.5, 0.0, 2, 8])\n        >>> spearman_corrcoef(preds, target)\n        tensor(1.0000)\n\n    Example (multi output regression):\n        >>> from torchmetrics.functional import spearman_corrcoef\n        >>> target = torch.tensor([[3, -0.5], [2, 7]])\n        >>> preds = torch.tensor([[2.5, 0.0], [2, 8]])\n        >>> spearman_corrcoef(preds, target)\n        tensor([1.0000, 1.0000])\n    \"\"\"\n    preds, target = _spearman_corrcoef_update(preds, target, num_outputs=1 if preds.ndim == 1 else preds.shape[-1])\n    return _spearman_corrcoef_compute(preds, target)\n", "path": "src/torchmetrics/functional/regression/spearman.py"}]}