Repository: Lightning-AI/torchmetrics

Issue:
`learned_perceptual_image_patch_similarity` function needs to synchronize device and dtype between net and input images
## 🐛 Bug

When I try to use `preds` and `target` on `torch.device('cuda:0')` to calculate with function `learned_perceptual_image_patch_similarity` from `torchmetrics.functional.image`,  the function will throw exception. 

Maybe there are some other functions with internal `torch.nn.Module` instances in `torchmetrics.functional` will proceed like this.

### To Reproduce

```python
import torch
from torchmetrics.functional.image import learned_perceptual_image_patch_similarity

result = torch.rand(1, 3, 50, 50, device='cuda:0', dtype=torch.float64)
target = torch.rand(1, 3, 50, 50, device='cuda:0', dtype=torch.float64)
learned_perceptual_image_patch_similarity(result, target, normalize=True)
```

### Expected behavior

Change

https://github.com/Lightning-AI/torchmetrics/blob/bcf7867020f5893258d0fedba7aaa16aee6505ca/src/torchmetrics/functional/image/lpips.py#L430

To 

```python
    loss, total = _lpips_update(img1, img2, net.to(device=img1.device, dtype=img1.dtype), normalize) 
```

### Environment

|Name|Version|Build|Channel|
|:-:|:-:|:-:|:-:|
|_anaconda_depends|2023.07|py311_0|https://repo.anaconda.com/pkgs/main|
|conda|23.9.0|py311haa95532_0|https://repo.anaconda.com/pkgs/main|
|python|3.10.13|he1021f5_0|defaults|
|pytorch|2.1.0|py3.10_cuda12.1_cudnn8_0|pytorch|
|pytorch-cuda|12.1|hde6ce7c_5|pytorch|
|pytorch-mutex|1.0|cuda|pytorch|
|torchaudio|2.1.0|pypi_0|pypi|
|torchmetrics|1.2.0|pyhd8ed1ab_0|conda-forge|
|torchvision| 0.16.0|pypi_0|pypi|



Discussion:

Resolving patch:
diff --git a/src/torchmetrics/functional/image/lpips.py b/src/torchmetrics/functional/image/lpips.py
--- a/src/torchmetrics/functional/image/lpips.py
+++ b/src/torchmetrics/functional/image/lpips.py
@@ -426,6 +426,6 @@ def learned_perceptual_image_patch_similarity(
         tensor(0.1008, grad_fn=<DivBackward0>)
 
     """
-    net = _NoTrainLpips(net=net_type)
+    net = _NoTrainLpips(net=net_type).to(device=img1.device, dtype=img1.dtype)
     loss, total = _lpips_update(img1, img2, net, normalize)
     return _lpips_compute(loss.sum(), total, reduction)


Test patch:
diff --git a/tests/unittests/image/test_lpips.py b/tests/unittests/image/test_lpips.py
--- a/tests/unittests/image/test_lpips.py
+++ b/tests/unittests/image/test_lpips.py
@@ -18,6 +18,7 @@
 import torch
 from lpips import LPIPS as LPIPS_reference  # noqa: N811
 from torch import Tensor
+from torchmetrics.functional.image.lpips import learned_perceptual_image_patch_similarity
 from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity
 from torchmetrics.utilities.imports import _LPIPS_AVAILABLE
 
@@ -68,6 +69,16 @@ def test_lpips(self, net_type, ddp):
             metric_args={"net_type": net_type},
         )
 
+    def test_lpips_functional(self):
+        """Test functional implementation of metric."""
+        self.run_functional_metric_test(
+            preds=_inputs.img1,
+            target=_inputs.img2,
+            metric_functional=learned_perceptual_image_patch_similarity,
+            reference_metric=partial(_compare_fn, net_type="alex"),
+            metric_args={"net_type": "alex"},
+        )
+
     def test_lpips_differentiability(self):
         """Test the differentiability of the metric, according to its `is_differentiable` attribute."""
         self.run_differentiability_test(