We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`MeanAveragePrecision` update method does not accept `torchvision.datapoints.BoundingBox` arguments
## 🐛 Bug

When the `preds` or `target` arguments to `MeanAveragePrecision.update` method are not of the type `list[dict[str,Tensor]]` a ValueError is raised, but this precludes dictionary values of type `torchvision.datapoints.BoundingBox` which inherit from Tensor.  

The ValueError is raised in the function `torchmetrics.detection.helpers._input_validator`.  I think this could be fixed by changing all the lines like 

`if any(type(target[ivn]) is not Tensor for target in targets):`

to be something like

`if not all(isinstance(target[ivn], Tensor) for target in targets):`

One could also validate that the `BoundingBox.format` is the same as `MeanAveragePrecision.box_format` whenever a BoundingBox class is passed to the update method.

### To Reproduce

```python
from torch import tensor
from torchmetrics.detection import MeanAveragePrecision
from torchvision.datapoints import BoundingBox, BoundingBoxFormat

preds = [
    dict(
        boxes=tensor([[1.0, 2.0, 1.0, 2.0]]),
        scores=tensor([0.1]),
        labels=tensor([0]),
    )
]

bounding_box = BoundingBox(
    data=tensor([[1.0, 2.0, 1.0, 2.0]]),
    format=BoundingBoxFormat.XYXY,
    spatial_size=(100,100)
)
target = [
    dict(
        boxes=bounding_box,
        labels=tensor([0]),
    )
]

metric = MeanAveragePrecision(iou_type='bbox', box_format='xyxy')
metric.update(preds, target)
```

### Expected behavior

`MeanAveragePrecision.update` should accept `torchvision.datapoints.BoundingBox` arguments.

### Environment
python 3.11.4
pytorch 2.0.1
torchmetrics 1.2.0
torchvision 0.15.2



--- 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/detection/helpers.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 Dict, Literal, Sequence, Tuple, Union
15 
16 from torch import Tensor
17 
18 
19 def _input_validator(
20     preds: Sequence[Dict[str, Tensor]],
21     targets: Sequence[Dict[str, Tensor]],
22     iou_type: Union[Literal["bbox", "segm"], Tuple[Literal["bbox", "segm"]]] = "bbox",
23     ignore_score: bool = False,
24 ) -> None:
25     """Ensure the correct input format of `preds` and `targets`."""
26     if isinstance(iou_type, str):
27         iou_type = (iou_type,)
28 
29     name_map = {"bbox": "boxes", "segm": "masks"}
30     if any(tp not in name_map for tp in iou_type):
31         raise Exception(f"IOU type {iou_type} is not supported")
32     item_val_name = [name_map[tp] for tp in iou_type]
33 
34     if not isinstance(preds, Sequence):
35         raise ValueError(f"Expected argument `preds` to be of type Sequence, but got {preds}")
36     if not isinstance(targets, Sequence):
37         raise ValueError(f"Expected argument `target` to be of type Sequence, but got {targets}")
38     if len(preds) != len(targets):
39         raise ValueError(
40             f"Expected argument `preds` and `target` to have the same length, but got {len(preds)} and {len(targets)}"
41         )
42 
43     for k in [*item_val_name, "labels"] + (["scores"] if not ignore_score else []):
44         if any(k not in p for p in preds):
45             raise ValueError(f"Expected all dicts in `preds` to contain the `{k}` key")
46 
47     for k in [*item_val_name, "labels"]:
48         if any(k not in p for p in targets):
49             raise ValueError(f"Expected all dicts in `target` to contain the `{k}` key")
50 
51     for ivn in item_val_name:
52         if any(type(pred[ivn]) is not Tensor for pred in preds):
53             raise ValueError(f"Expected all {ivn} in `preds` to be of type Tensor")
54     if not ignore_score and any(type(pred["scores"]) is not Tensor for pred in preds):
55         raise ValueError("Expected all scores in `preds` to be of type Tensor")
56     if any(type(pred["labels"]) is not Tensor for pred in preds):
57         raise ValueError("Expected all labels in `preds` to be of type Tensor")
58     for ivn in item_val_name:
59         if any(type(target[ivn]) is not Tensor for target in targets):
60             raise ValueError(f"Expected all {ivn} in `target` to be of type Tensor")
61     if any(type(target["labels"]) is not Tensor for target in targets):
62         raise ValueError("Expected all labels in `target` to be of type Tensor")
63 
64     for i, item in enumerate(targets):
65         for ivn in item_val_name:
66             if item[ivn].size(0) != item["labels"].size(0):
67                 raise ValueError(
68                     f"Input '{ivn}' and labels of sample {i} in targets have a"
69                     f" different length (expected {item[ivn].size(0)} labels, got {item['labels'].size(0)})"
70                 )
71     if ignore_score:
72         return
73     for i, item in enumerate(preds):
74         for ivn in item_val_name:
75             if not (item[ivn].size(0) == item["labels"].size(0) == item["scores"].size(0)):
76                 raise ValueError(
77                     f"Input '{ivn}', labels and scores of sample {i} in predictions have a"
78                     f" different length (expected {item[ivn].size(0)} labels and scores,"
79                     f" got {item['labels'].size(0)} labels and {item['scores'].size(0)})"
80                 )
81 
82 
83 def _fix_empty_tensors(boxes: Tensor) -> Tensor:
84     """Empty tensors can cause problems in DDP mode, this methods corrects them."""
85     if boxes.numel() == 0 and boxes.ndim == 1:
86         return boxes.unsqueeze(0)
87     return boxes
88 
89 
90 def _validate_iou_type_arg(iou_type: Union[Literal["bbox", "segm"], Tuple[str]] = "bbox") -> Tuple[str]:
91     allowed_iou_types = ("segm", "bbox")
92     if isinstance(iou_type, str):
93         iou_type = (iou_type,)
94     if any(tp not in allowed_iou_types for tp in iou_type):
95         raise ValueError(
96             f"Expected argument `iou_type` to be one of {allowed_iou_types} or a list of, but got {iou_type}"
97         )
98     return iou_type
99
```
--- 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/detection/helpers.py b/src/torchmetrics/detection/helpers.py
--- a/src/torchmetrics/detection/helpers.py
+++ b/src/torchmetrics/detection/helpers.py
@@ -49,16 +49,16 @@
             raise ValueError(f"Expected all dicts in `target` to contain the `{k}` key")
 
     for ivn in item_val_name:
-        if any(type(pred[ivn]) is not Tensor for pred in preds):
+        if not all(isinstance(pred[ivn], Tensor) for pred in preds):
             raise ValueError(f"Expected all {ivn} in `preds` to be of type Tensor")
-    if not ignore_score and any(type(pred["scores"]) is not Tensor for pred in preds):
+    if not ignore_score and not all(isinstance(pred["scores"], Tensor) for pred in preds):
         raise ValueError("Expected all scores in `preds` to be of type Tensor")
-    if any(type(pred["labels"]) is not Tensor for pred in preds):
+    if not all(isinstance(pred["labels"], Tensor) for pred in preds):
         raise ValueError("Expected all labels in `preds` to be of type Tensor")
     for ivn in item_val_name:
-        if any(type(target[ivn]) is not Tensor for target in targets):
+        if not all(isinstance(target[ivn], Tensor) for target in targets):
             raise ValueError(f"Expected all {ivn} in `target` to be of type Tensor")
-    if any(type(target["labels"]) is not Tensor for target in targets):
+    if not all(isinstance(target["labels"], Tensor) for target in targets):
         raise ValueError("Expected all labels in `target` to be of type Tensor")
 
     for i, item in enumerate(targets):
@@ -88,6 +88,7 @@
 
 
 def _validate_iou_type_arg(iou_type: Union[Literal["bbox", "segm"], Tuple[str]] = "bbox") -> Tuple[str]:
+    """Validate that iou type argument is correct."""
     allowed_iou_types = ("segm", "bbox")
     if isinstance(iou_type, str):
         iou_type = (iou_type,)

{"golden_diff": "diff --git a/src/torchmetrics/detection/helpers.py b/src/torchmetrics/detection/helpers.py\n--- a/src/torchmetrics/detection/helpers.py\n+++ b/src/torchmetrics/detection/helpers.py\n@@ -49,16 +49,16 @@\n             raise ValueError(f\"Expected all dicts in `target` to contain the `{k}` key\")\n \n     for ivn in item_val_name:\n-        if any(type(pred[ivn]) is not Tensor for pred in preds):\n+        if not all(isinstance(pred[ivn], Tensor) for pred in preds):\n             raise ValueError(f\"Expected all {ivn} in `preds` to be of type Tensor\")\n-    if not ignore_score and any(type(pred[\"scores\"]) is not Tensor for pred in preds):\n+    if not ignore_score and not all(isinstance(pred[\"scores\"], Tensor) for pred in preds):\n         raise ValueError(\"Expected all scores in `preds` to be of type Tensor\")\n-    if any(type(pred[\"labels\"]) is not Tensor for pred in preds):\n+    if not all(isinstance(pred[\"labels\"], Tensor) for pred in preds):\n         raise ValueError(\"Expected all labels in `preds` to be of type Tensor\")\n     for ivn in item_val_name:\n-        if any(type(target[ivn]) is not Tensor for target in targets):\n+        if not all(isinstance(target[ivn], Tensor) for target in targets):\n             raise ValueError(f\"Expected all {ivn} in `target` to be of type Tensor\")\n-    if any(type(target[\"labels\"]) is not Tensor for target in targets):\n+    if not all(isinstance(target[\"labels\"], Tensor) for target in targets):\n         raise ValueError(\"Expected all labels in `target` to be of type Tensor\")\n \n     for i, item in enumerate(targets):\n@@ -88,6 +88,7 @@\n \n \n def _validate_iou_type_arg(iou_type: Union[Literal[\"bbox\", \"segm\"], Tuple[str]] = \"bbox\") -> Tuple[str]:\n+    \"\"\"Validate that iou type argument is correct.\"\"\"\n     allowed_iou_types = (\"segm\", \"bbox\")\n     if isinstance(iou_type, str):\n         iou_type = (iou_type,)\n", "issue": "`MeanAveragePrecision` update method does not accept `torchvision.datapoints.BoundingBox` arguments\n## \ud83d\udc1b Bug\r\n\r\nWhen the `preds` or `target` arguments to `MeanAveragePrecision.update` method are not of the type `list[dict[str,Tensor]]` a ValueError is raised, but this precludes dictionary values of type `torchvision.datapoints.BoundingBox` which inherit from Tensor.  \r\n\r\nThe ValueError is raised in the function `torchmetrics.detection.helpers._input_validator`.  I think this could be fixed by changing all the lines like \r\n\r\n`if any(type(target[ivn]) is not Tensor for target in targets):`\r\n\r\nto be something like\r\n\r\n`if not all(isinstance(target[ivn], Tensor) for target in targets):`\r\n\r\nOne could also validate that the `BoundingBox.format` is the same as `MeanAveragePrecision.box_format` whenever a BoundingBox class is passed to the update method.\r\n\r\n### To Reproduce\r\n\r\n```python\r\nfrom torch import tensor\r\nfrom torchmetrics.detection import MeanAveragePrecision\r\nfrom torchvision.datapoints import BoundingBox, BoundingBoxFormat\r\n\r\npreds = [\r\n    dict(\r\n        boxes=tensor([[1.0, 2.0, 1.0, 2.0]]),\r\n        scores=tensor([0.1]),\r\n        labels=tensor([0]),\r\n    )\r\n]\r\n\r\nbounding_box = BoundingBox(\r\n    data=tensor([[1.0, 2.0, 1.0, 2.0]]),\r\n    format=BoundingBoxFormat.XYXY,\r\n    spatial_size=(100,100)\r\n)\r\ntarget = [\r\n    dict(\r\n        boxes=bounding_box,\r\n        labels=tensor([0]),\r\n    )\r\n]\r\n\r\nmetric = MeanAveragePrecision(iou_type='bbox', box_format='xyxy')\r\nmetric.update(preds, target)\r\n```\r\n\r\n### Expected behavior\r\n\r\n`MeanAveragePrecision.update` should accept `torchvision.datapoints.BoundingBox` arguments.\r\n\r\n### Environment\r\npython 3.11.4\r\npytorch 2.0.1\r\ntorchmetrics 1.2.0\r\ntorchvision 0.15.2\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 Dict, Literal, Sequence, Tuple, Union\n\nfrom torch import Tensor\n\n\ndef _input_validator(\n    preds: Sequence[Dict[str, Tensor]],\n    targets: Sequence[Dict[str, Tensor]],\n    iou_type: Union[Literal[\"bbox\", \"segm\"], Tuple[Literal[\"bbox\", \"segm\"]]] = \"bbox\",\n    ignore_score: bool = False,\n) -> None:\n    \"\"\"Ensure the correct input format of `preds` and `targets`.\"\"\"\n    if isinstance(iou_type, str):\n        iou_type = (iou_type,)\n\n    name_map = {\"bbox\": \"boxes\", \"segm\": \"masks\"}\n    if any(tp not in name_map for tp in iou_type):\n        raise Exception(f\"IOU type {iou_type} is not supported\")\n    item_val_name = [name_map[tp] for tp in iou_type]\n\n    if not isinstance(preds, Sequence):\n        raise ValueError(f\"Expected argument `preds` to be of type Sequence, but got {preds}\")\n    if not isinstance(targets, Sequence):\n        raise ValueError(f\"Expected argument `target` to be of type Sequence, but got {targets}\")\n    if len(preds) != len(targets):\n        raise ValueError(\n            f\"Expected argument `preds` and `target` to have the same length, but got {len(preds)} and {len(targets)}\"\n        )\n\n    for k in [*item_val_name, \"labels\"] + ([\"scores\"] if not ignore_score else []):\n        if any(k not in p for p in preds):\n            raise ValueError(f\"Expected all dicts in `preds` to contain the `{k}` key\")\n\n    for k in [*item_val_name, \"labels\"]:\n        if any(k not in p for p in targets):\n            raise ValueError(f\"Expected all dicts in `target` to contain the `{k}` key\")\n\n    for ivn in item_val_name:\n        if any(type(pred[ivn]) is not Tensor for pred in preds):\n            raise ValueError(f\"Expected all {ivn} in `preds` to be of type Tensor\")\n    if not ignore_score and any(type(pred[\"scores\"]) is not Tensor for pred in preds):\n        raise ValueError(\"Expected all scores in `preds` to be of type Tensor\")\n    if any(type(pred[\"labels\"]) is not Tensor for pred in preds):\n        raise ValueError(\"Expected all labels in `preds` to be of type Tensor\")\n    for ivn in item_val_name:\n        if any(type(target[ivn]) is not Tensor for target in targets):\n            raise ValueError(f\"Expected all {ivn} in `target` to be of type Tensor\")\n    if any(type(target[\"labels\"]) is not Tensor for target in targets):\n        raise ValueError(\"Expected all labels in `target` to be of type Tensor\")\n\n    for i, item in enumerate(targets):\n        for ivn in item_val_name:\n            if item[ivn].size(0) != item[\"labels\"].size(0):\n                raise ValueError(\n                    f\"Input '{ivn}' and labels of sample {i} in targets have a\"\n                    f\" different length (expected {item[ivn].size(0)} labels, got {item['labels'].size(0)})\"\n                )\n    if ignore_score:\n        return\n    for i, item in enumerate(preds):\n        for ivn in item_val_name:\n            if not (item[ivn].size(0) == item[\"labels\"].size(0) == item[\"scores\"].size(0)):\n                raise ValueError(\n                    f\"Input '{ivn}', labels and scores of sample {i} in predictions have a\"\n                    f\" different length (expected {item[ivn].size(0)} labels and scores,\"\n                    f\" got {item['labels'].size(0)} labels and {item['scores'].size(0)})\"\n                )\n\n\ndef _fix_empty_tensors(boxes: Tensor) -> Tensor:\n    \"\"\"Empty tensors can cause problems in DDP mode, this methods corrects them.\"\"\"\n    if boxes.numel() == 0 and boxes.ndim == 1:\n        return boxes.unsqueeze(0)\n    return boxes\n\n\ndef _validate_iou_type_arg(iou_type: Union[Literal[\"bbox\", \"segm\"], Tuple[str]] = \"bbox\") -> Tuple[str]:\n    allowed_iou_types = (\"segm\", \"bbox\")\n    if isinstance(iou_type, str):\n        iou_type = (iou_type,)\n    if any(tp not in allowed_iou_types for tp in iou_type):\n        raise ValueError(\n            f\"Expected argument `iou_type` to be one of {allowed_iou_types} or a list of, but got {iou_type}\"\n        )\n    return iou_type\n", "path": "src/torchmetrics/detection/helpers.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 Dict, Literal, Sequence, Tuple, Union\n\nfrom torch import Tensor\n\n\ndef _input_validator(\n    preds: Sequence[Dict[str, Tensor]],\n    targets: Sequence[Dict[str, Tensor]],\n    iou_type: Union[Literal[\"bbox\", \"segm\"], Tuple[Literal[\"bbox\", \"segm\"]]] = \"bbox\",\n    ignore_score: bool = False,\n) -> None:\n    \"\"\"Ensure the correct input format of `preds` and `targets`.\"\"\"\n    if isinstance(iou_type, str):\n        iou_type = (iou_type,)\n\n    name_map = {\"bbox\": \"boxes\", \"segm\": \"masks\"}\n    if any(tp not in name_map for tp in iou_type):\n        raise Exception(f\"IOU type {iou_type} is not supported\")\n    item_val_name = [name_map[tp] for tp in iou_type]\n\n    if not isinstance(preds, Sequence):\n        raise ValueError(f\"Expected argument `preds` to be of type Sequence, but got {preds}\")\n    if not isinstance(targets, Sequence):\n        raise ValueError(f\"Expected argument `target` to be of type Sequence, but got {targets}\")\n    if len(preds) != len(targets):\n        raise ValueError(\n            f\"Expected argument `preds` and `target` to have the same length, but got {len(preds)} and {len(targets)}\"\n        )\n\n    for k in [*item_val_name, \"labels\"] + ([\"scores\"] if not ignore_score else []):\n        if any(k not in p for p in preds):\n            raise ValueError(f\"Expected all dicts in `preds` to contain the `{k}` key\")\n\n    for k in [*item_val_name, \"labels\"]:\n        if any(k not in p for p in targets):\n            raise ValueError(f\"Expected all dicts in `target` to contain the `{k}` key\")\n\n    for ivn in item_val_name:\n        if not all(isinstance(pred[ivn], Tensor) for pred in preds):\n            raise ValueError(f\"Expected all {ivn} in `preds` to be of type Tensor\")\n    if not ignore_score and not all(isinstance(pred[\"scores\"], Tensor) for pred in preds):\n        raise ValueError(\"Expected all scores in `preds` to be of type Tensor\")\n    if not all(isinstance(pred[\"labels\"], Tensor) for pred in preds):\n        raise ValueError(\"Expected all labels in `preds` to be of type Tensor\")\n    for ivn in item_val_name:\n        if not all(isinstance(target[ivn], Tensor) for target in targets):\n            raise ValueError(f\"Expected all {ivn} in `target` to be of type Tensor\")\n    if not all(isinstance(target[\"labels\"], Tensor) for target in targets):\n        raise ValueError(\"Expected all labels in `target` to be of type Tensor\")\n\n    for i, item in enumerate(targets):\n        for ivn in item_val_name:\n            if item[ivn].size(0) != item[\"labels\"].size(0):\n                raise ValueError(\n                    f\"Input '{ivn}' and labels of sample {i} in targets have a\"\n                    f\" different length (expected {item[ivn].size(0)} labels, got {item['labels'].size(0)})\"\n                )\n    if ignore_score:\n        return\n    for i, item in enumerate(preds):\n        for ivn in item_val_name:\n            if not (item[ivn].size(0) == item[\"labels\"].size(0) == item[\"scores\"].size(0)):\n                raise ValueError(\n                    f\"Input '{ivn}', labels and scores of sample {i} in predictions have a\"\n                    f\" different length (expected {item[ivn].size(0)} labels and scores,\"\n                    f\" got {item['labels'].size(0)} labels and {item['scores'].size(0)})\"\n                )\n\n\ndef _fix_empty_tensors(boxes: Tensor) -> Tensor:\n    \"\"\"Empty tensors can cause problems in DDP mode, this methods corrects them.\"\"\"\n    if boxes.numel() == 0 and boxes.ndim == 1:\n        return boxes.unsqueeze(0)\n    return boxes\n\n\ndef _validate_iou_type_arg(iou_type: Union[Literal[\"bbox\", \"segm\"], Tuple[str]] = \"bbox\") -> Tuple[str]:\n    \"\"\"Validate that iou type argument is correct.\"\"\"\n    allowed_iou_types = (\"segm\", \"bbox\")\n    if isinstance(iou_type, str):\n        iou_type = (iou_type,)\n    if any(tp not in allowed_iou_types for tp in iou_type):\n        raise ValueError(\n            f\"Expected argument `iou_type` to be one of {allowed_iou_types} or a list of, but got {iou_type}\"\n        )\n    return iou_type\n", "path": "src/torchmetrics/detection/helpers.py"}]}