Repository: continualai/avalanche
Issue: Benchmark with a task label per pattern fails on strategy.train() call

I am trying to train a `Naive` strategy on a fake benchmark where task labels are provided for each pattern. It seems that there is a call to `task_label` instead of `task_labels` which cause the code to fail (since `task_label` is not defined for this kind of benchmark). The error is raised on a `isinstance` check which makes it kind of hard to debug.

This is the code and the traceback:
```python
tr_ds = [AvalancheTensorDataset(torch.randn(10, 7, 3), torch.randint(0, 3, (10,)),
                                dataset_type=AvalancheDatasetType.CLASSIFICATION,
                                task_labels=torch.randint(0, 5, (10,)).tolist()) for i in range(3)]
ts_ds = [AvalancheTensorDataset(torch.randn(10, 7, 3), torch.randint(0, 3, (10,)),
                                dataset_type=AvalancheDatasetType.CLASSIFICATION,
                                task_labels=torch.randint(0, 5, (10,)).tolist()) for i in range(3)]
scenario = create_multi_dataset_generic_benchmark(train_datasets=tr_ds, test_datasets=ts_ds)
model = SimpleMLP(input_size=3, num_classes=2)
cl_strategy = Naive(model, SGD(model.parameters(), lr=0.001, momentum=0.9),
        CrossEntropyLoss(), train_mb_size=500, train_epochs=1, eval_mb_size=100,
        device='cpu', evaluator=None)
for i, experience in enumerate(scenario.train_stream):
    cl_strategy.train(experience)

Traceback (most recent call last):
  File "test.py", line 163, in <module>
    main(args)
  File "test.py", line 137, in main
    res = cl_strategy.train(experience)
  File "/home/acossu/avalanche/avalanche/training/strategies/base_strategy.py", line 221, in train
    if isinstance(experiences, Experience):
  File "/home/acossu/miniconda3/envs/avalanche-dev-env/lib/python3.8/typing.py", line 1017, in __instancecheck__
    if all(hasattr(instance, attr) and
  File "/home/acossu/miniconda3/envs/avalanche-dev-env/lib/python3.8/typing.py", line 1017, in <genexpr>
    if all(hasattr(instance, attr) and
  File "/home/acossu/avalanche/avalanche/benchmarks/scenarios/generic_cl_scenario.py", line 607, in task_label
    raise ValueError('The task_label property can only be accessed '
ValueError: The task_label property can only be accessed when the experience contains a single task label
```

Changed files:
avalanche/evaluation/metrics/confusion_matrix.py, avalanche/training/strategies/base_strategy.py, avalanche/evaluation/metrics/accuracy.py, tests/test_avalanche_dataset.py

diff --git a/avalanche/evaluation/metrics/accuracy.py b/avalanche/evaluation/metrics/accuracy.py
index c9163713..d62dfc05 100644
--- a/avalanche/evaluation/metrics/accuracy.py
+++ b/avalanche/evaluation/metrics/accuracy.py
@@ -9,7 +9,7 @@
 # Website: www.continualai.org                                                 #
 ################################################################################
 
-from typing import TYPE_CHECKING, List
+from typing import List
 
 import torch
 from torch import Tensor
diff --git a/avalanche/evaluation/metrics/confusion_matrix.py b/avalanche/evaluation/metrics/confusion_matrix.py
index a0da2eba..009cee00 100644
--- a/avalanche/evaluation/metrics/confusion_matrix.py
+++ b/avalanche/evaluation/metrics/confusion_matrix.py
@@ -246,7 +246,8 @@ class StreamConfusionMatrix(PluginMetric[Tensor]):
                  normalize: Literal['true', 'pred', 'all'] = None,
                  save_image: bool = True,
                  image_creator: Callable[[Tensor, Sequence], Image] =
-                 default_cm_image_creator, absolute_class_order: bool = False):
+                 default_cm_image_creator,
+                 absolute_class_order: bool = False):
         """
         Creates an instance of the Stream Confusion Matrix metric.
 
diff --git a/avalanche/training/strategies/base_strategy.py b/avalanche/training/strategies/base_strategy.py
index 0c65d7c1..a9e6afe6 100644
--- a/avalanche/training/strategies/base_strategy.py
+++ b/avalanche/training/strategies/base_strategy.py
@@ -218,12 +218,12 @@ class BaseStrategy:
         self.model.to(self.device)
 
         # Normalize training and eval data.
-        if isinstance(experiences, Experience):
+        if not isinstance(experiences, Sequence):
             experiences = [experiences]
         if eval_streams is None:
             eval_streams = [experiences]
         for i, exp in enumerate(eval_streams):
-            if isinstance(exp, Experience):
+            if not isinstance(exp, Sequence):
                 eval_streams[i] = [exp]
 
         self.before_training(**kwargs)
@@ -322,7 +322,7 @@ class BaseStrategy:
         self.is_training = False
         self.model.eval()
 
-        if isinstance(exp_list, Experience):
+        if not isinstance(exp_list, Sequence):
             exp_list = [exp_list]
 
         self.before_eval(**kwargs)
diff --git a/tests/test_avalanche_dataset.py b/tests/test_avalanche_dataset.py
index f5896b9e..90ed96e6 100644
--- a/tests/test_avalanche_dataset.py
+++ b/tests/test_avalanche_dataset.py
@@ -1,7 +1,11 @@
 import unittest
 
 from os.path import expanduser
-
+from avalanche.models import SimpleMLP
+from torch.optim import SGD
+from torch.nn import CrossEntropyLoss
+from avalanche.training.strategies import Naive
+from avalanche.benchmarks.generators import dataset_benchmark
 import PIL
 import torch
 from PIL import ImageChops
@@ -310,6 +314,29 @@ class AvalancheDatasetTests(unittest.TestCase):
         with self.assertRaises(KeyError):
             subset_task11 = dataset.task_set[11]
 
+    def test_avalanche_tensor_dataset_task_labels_train(self):
+        tr_ds = [AvalancheTensorDataset(
+            torch.randn(10, 4),
+            torch.randint(0, 3, (10,)),
+            dataset_type=AvalancheDatasetType.CLASSIFICATION,
+            task_labels=torch.randint(0, 5, (10,)).tolist()) for i in range(3)]
+        ts_ds = [AvalancheTensorDataset(
+            torch.randn(10, 4), torch.randint(0, 3, (10,)),
+            dataset_type=AvalancheDatasetType.CLASSIFICATION,
+            task_labels=torch.randint(0, 5, (10,)).tolist()) for i in range(3)]
+        scenario = dataset_benchmark(train_datasets=tr_ds, test_datasets=ts_ds)
+        model = SimpleMLP(input_size=4, num_classes=3)
+        cl_strategy = Naive(model, SGD(model.parameters(), lr=0.001,
+                                       momentum=0.9),
+                            CrossEntropyLoss(), train_mb_size=5,
+                            train_epochs=1, eval_mb_size=5,
+                            device='cpu', evaluator=None)
+        exp = []
+        for i, experience in enumerate(scenario.train_stream):
+            exp.append(i)
+            cl_strategy.train(experience)
+        self.assertEqual(len(exp), 3)
+
     def test_avalanche_dataset_task_labels_inheritance(self):
         dataset_mnist = MNIST(root=expanduser("~") + "/.avalanche/data/mnist/",
                               download=True)