Repository: Lightning-AI/torchmetrics

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




Discussion:
Hi! thanks for your contribution!, great first issue!

Resolving patch:
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 @@ def _input_validator(
             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 _fix_empty_tensors(boxes: Tensor) -> Tensor:
 
 
 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,)


Test patch: