def train(
        self,
        experiences: Union[TDatasetExperience, Iterable[TDatasetExperience]],
        eval_streams: Optional[
            Sequence[Union[TDatasetExperience, Iterable[TDatasetExperience]]]
        ] = None,
        **kwargs
    ):
        """Training loop.

        JointTraining concatenates all the experiences together and
        trains on all of them at the same time (a.k.a. offline training).

        :param experiences: single Experience or sequence.
        :param eval_streams: list of streams for evaluation.
            If None: use training experiences for evaluation.
            Use [] if you do not want to evaluate during training.

        :return: dictionary containing last recorded value for
            each metric name.
        """
        self.is_training = True
        self.model.train()
        self.model.to(self.device)

        if self._is_fitted:
            raise AlreadyTrainedError(
                "JointTraining can be trained only once. "
                "Please call the train method once on the entire stream."
            )

        # Normalize training and eval data.
        experiences_list: Iterable[TDatasetExperience] = (
            _experiences_parameter_as_iterable(experiences)
        )

        if eval_streams is None:
            eval_streams = [experiences_list]

        self._eval_streams = _group_experiences_by_stream(eval_streams)

        self._experiences = list(experiences_list)
        self._before_training(**kwargs)
        for self.experience in self._experiences:
            self._before_training_exp(**kwargs)
            self._train_exp(self.experience, self._eval_streams, **kwargs)
            self._after_training_exp(**kwargs)
            # Joint training only needs a single step because
            # it concatenates all the data at once.
            break
        self._after_training(**kwargs)

        res = self.evaluator.get_last_metrics()
        self._is_fitted = True
        return res
Training loop.

        JointTraining concatenates all the experiences together and
        trains on all of them at the same time (a.k.a. offline training).

        :param experiences: single Experience or sequence.
        :param eval_streams: list of streams for evaluation.
            If None: use training experiences for evaluation.
            Use [] if you do not want to evaluate during training.

        :return: dictionary containing last recorded value for
            each metric name.
        
avalanche/training/supervised/joint_training.py