run(training_set, trainer, [filename], [force]) -> model

    Runs the bootstrapped training of a strong classifier using the given training data and a strong classifier trainer.
    The training set need to contain extracted features already, as this function will need the features several times.

    **Parameters:**

    ``training_set`` : :py:class:`TrainingSet`
      The training set containing pre-extracted feature files

    ``trainer`` : :py:class:`bob.learn.boosting.Boosting`
      A strong boosting trainer to use for selecting the weak classifiers and their weights for each round.

    ``filename`` : str
      A filename, where to write the resulting strong classifier to.
      This filename is also used as a base to compute filenames of intermediate files, which store results of each of the bootstrapping steps.

    ``force`` : bool
      If set to ``False`` (the default), the bootstrapping will continue the round, where it has been stopped during the last run (reading the current stage from respective files).
      If set to ``True``, the training will start from the beginning.

    **Returns:**

    ``model`` : :py:class:`bob.learn.boosting.BoostedMachine`
      The resulting strong classifier, a weighted combination of weak classifiers.

def run(self, training_set, trainer, filename = "bootstrapped_model.hdf5", force = False):
    """run(training_set, trainer, [filename], [force]) -> model

    Runs the bootstrapped training of a strong classifier using the given training data and a strong classifier trainer.
    The training set need to contain extracted features already, as this function will need the features several times.

    **Parameters:**

    ``training_set`` : :py:class:`TrainingSet`
      The training set containing pre-extracted feature files

    ``trainer`` : :py:class:`bob.learn.boosting.Boosting`
      A strong boosting trainer to use for selecting the weak classifiers and their weights for each round.

    ``filename`` : str
      A filename, where to write the resulting strong classifier to.
      This filename is also used as a base to compute filenames of intermediate files, which store results of each of the bootstrapping steps.

    ``force`` : bool
      If set to ``False`` (the default), the bootstrapping will continue the round, where it has been stopped during the last run (reading the current stage from respective files).
      If set to ``True``, the training will start from the beginning.

    **Returns:**

    ``model`` : :py:class:`bob.learn.boosting.BoostedMachine`
      The resulting strong classifier, a weighted combination of weak classifiers.
    """

    feature_extractor = training_set.feature_extractor()

    training_data = None
    training_labels = None
    model = None

    positive_indices, negative_indices = set(), set()

    for b in range(self.m_number_of_rounds):
      # check if old results are present
      temp_file = "%s_round_%d.hdf5" % (os.path.splitext(filename)[0], b+1)
      if os.path.exists(temp_file) and not force:
        logger.info("Loading already computed stage %d from %s.", b+1, temp_file)
        model, positives, negatives = self._load(bob.io.base.HDF5File(temp_file))
        positive_indices |= positives
        negative_indices |= negatives

      else:
        if positive_indices or negative_indices:
          # load data from previous rounds
          logger.info("Getting training data of previous rounds")
          training_data, training_labels = training_set.sample(positive_indices = positive_indices, negative_indices = negative_indices)
          positive_indices, negative_indices = set(), set()

        # get data for current round
        logger.info("Getting new data for bootstrapping round %d", b+1)
        new_data, new_labels = training_set.sample(model, self.m_number_of_positive_examples_per_round, self.m_number_of_negative_examples_per_round)
        if training_data is None:
          training_data = new_data
        else:
          training_data = numpy.append(training_data, new_data, axis=0)
        if training_labels is None:
          training_labels = new_labels
        else:
          training_labels = numpy.append(training_labels, new_labels, axis=0)

        logger.info("Starting training with %d examples", training_data.shape[0])
        model = trainer.train(training_data, training_labels, self.m_number_of_weak_learners_per_round[b], model)

        # write model and extractor to temporary file to be able to catch up later
        logger.info("Saving results for stage %d to file %s", b+1, temp_file)
        self._save(bob.io.base.HDF5File(temp_file, 'w'), model, training_set.positive_indices, training_set.negative_indices)

      feature_extractor.model_indices = model.indices

    # finally, return the trained model
    return model