Repository: Lightning-AI/torchmetrics

Issue:
classwisewrapper doesn't support prefix
## 🐛 Bug
Hi, good afternoon.

I have defined `ClasswiseWrapper` inside a `MetricCollection` which looks like this

```python
train_metrics = MetricCollection({
                # weighted acc
                "WA": Accuracy(num_classes=num_classes, threshold=0.5, average=avg),
                # unweight acc
                "UA": Accuracy(num_classes=num_classes, threshold=0.5, average="micro"),
                "Precision": Precision(num_classes=num_classes, threshold=0.5, average=avg),
                "Recall": Recall(num_classes=num_classes, threshold=0.5, average=avg),
                "UAR": Recall(num_classes=num_classes, threshold=0.5, average="micro"),
                # weighted F1
                "WF1": F1Score(num_classes=num_classes, threshold=0.5, average=avg),
                # unweight F1
                "UF1": F1Score(num_classes=num_classes, threshold=0.5, average="micro"),
                "MAE": MeanAbsoluteError(),
                "Corr": Corr(compute_on_step=False),
                "acc": ClasswiseWrapper(Accuracy(num_classes=num_classes, average=None), labels),
                "r": ClasswiseWrapper(Precision(num_classes=num_classes, average=None), labels),
                "p": ClasswiseWrapper(Recall(num_classes=num_classes, average=None), labels),
                "f1": ClasswiseWrapper(F1Score(num_classes=num_classes, average=None), labels),
            }, prefix="train/epoch/")
```
But it seems that when I call
```
metrics = train_metrics.compute()
```
although I can get other metrics with prefix all right (e.g. `train/epoch/UF1`),classwisewrapper doesn't take prefix into account, and I get `acc_label1` `acc_label2` etc.

### Expected behavior

I think once classwisewrapper is inside a `MetricCollection` it should have something like `train/epoch/acc_label1`.

### Environment

- PyTorch Version (e.g., 1.0): 1.8.2
- OS (e.g., Linux): Linux
- How you installed PyTorch (`conda`, `pip`, source): conda
- Python version: 3.7.11
- Any other relevant information: torch metrics install from lastest master (0.8.0.dev0)

### Additional context

Thank you for this awesome project!!


Discussion:
@cnut1648 thanks for reporting this. I take a look at it today (should be a simple fix). Great to know that the wrapper is useful to some users :]

Resolving patch:
diff --git a/torchmetrics/collections.py b/torchmetrics/collections.py
--- a/torchmetrics/collections.py
+++ b/torchmetrics/collections.py
@@ -131,7 +131,9 @@ def forward(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
         Positional arguments (args) will be passed to every metric in the collection, while keyword arguments (kwargs)
         will be filtered based on the signature of the individual metric.
         """
-        return _flatten_dict({k: m(*args, **m._filter_kwargs(**kwargs)) for k, m in self.items()})
+        res = {k: m(*args, **m._filter_kwargs(**kwargs)) for k, m in self.items(keep_base=True)}
+        res = _flatten_dict(res)
+        return {self._set_name(k): v for k, v in res.items()}
 
     def update(self, *args: Any, **kwargs: Any) -> None:
         """Iteratively call update for each metric.
@@ -219,8 +221,9 @@ def compute(self) -> Dict[str, Any]:
                     mi = getattr(self, cg[i])
                     for state in m0._defaults:
                         setattr(mi, state, getattr(m0, state))
-        res = {k: m.compute() for k, m in self.items()}
-        return _flatten_dict(res)
+        res = {k: m.compute() for k, m in self.items(keep_base=True)}
+        res = _flatten_dict(res)
+        return {self._set_name(k): v for k, v in res.items()}
 
     def reset(self) -> None:
         """Iteratively call reset for each metric."""


Test patch:
diff --git a/tests/wrappers/test_classwise.py b/tests/wrappers/test_classwise.py
--- a/tests/wrappers/test_classwise.py
+++ b/tests/wrappers/test_classwise.py
@@ -38,20 +38,32 @@ def test_output_with_labels():
         assert f"accuracy_{lab}" in val
 
 
-def test_using_metriccollection():
+@pytest.mark.parametrize("prefix", [None, "pre_"])
+@pytest.mark.parametrize("postfix", [None, "_post"])
+def test_using_metriccollection(prefix, postfix):
     """Test wrapper in combination with metric collection."""
     labels = ["horse", "fish", "cat"]
     metric = MetricCollection(
         {
             "accuracy": ClasswiseWrapper(Accuracy(num_classes=3, average=None), labels=labels),
             "recall": ClasswiseWrapper(Recall(num_classes=3, average=None), labels=labels),
-        }
+        },
+        prefix=prefix,
+        postfix=postfix,
     )
     preds = torch.randn(10, 3).softmax(dim=-1)
     target = torch.randint(3, (10,))
     val = metric(preds, target)
     assert isinstance(val, dict)
     assert len(val) == 6
+
+    def _get_correct_name(base):
+        name = base if prefix is None else prefix + base
+        name = name if postfix is None else name + postfix
+        return name
+
     for lab in labels:
-        assert f"accuracy_{lab}" in val
-        assert f"recall_{lab}" in val
+        name = _get_correct_name(f"accuracy_{lab}")
+        assert name in val
+        name = _get_correct_name(f"recall_{lab}")
+        assert name in val