code: def start_greedy_ensemble_search(automated_run, session, path):
      """Starts an automated ensemble search using greedy forward model selection.
  
      The steps for this search are adapted from "Ensemble Selection from Libraries of Models" by
      Caruana.
  
      1. Start with the empty ensemble
  
      2. Add to the ensemble the model in the library that maximizes the ensemmble's
      performance on the error metric.
  
      3. Repeat step 2 for a fixed number of iterations or until all models have been used.
  
      Args:
          automated_run (xcessiv.models.AutomatedRun): Automated run object
  
          session: Valid SQLAlchemy session
  
          path (str, unicode): Path to project folder
      """
      module = functions.import_string_code_as_module(
          automated_run.source
      )
      assert (
          module.metric_to_optimize
          in automated_run.base_learner_origin.metric_generators
      )
  
      best_ensemble = (
          []
      )  # List containing IDs of best performing ensemble for the last round
  
      secondary_learner = (
          automated_run.base_learner_origin.return_estimator()
      )
      secondary_learner.set_params(
          **module.secondary_learner_hyperparameters
      )
  
      for i in range(module.max_num_base_learners):
          best_score = -float(
              "inf"
          )  # Best metric for this round (not in total!)
          current_ensemble = best_ensemble[
              :
          ]  # Shallow copy of best ensemble
          for base_learner in (
              session.query(models.BaseLearner)
              .filter_by(job_status="finished")
              .all()
          ):
              if (
                  base_learner in current_ensemble
              ):  # Don't append when learner is already in
                  continue
              current_ensemble.append(base_learner)
  
              # Check if our "best ensemble" already exists
              existing_ensemble = (
                  session.query(models.StackedEnsemble)
                  .filter_by(
                      base_learner_origin_id=automated_run.base_learner_origin.id,
                      secondary_learner_hyperparameters=secondary_learner.get_params(),
                      base_learner_ids=sorted(
                          [bl.id for bl in current_ensemble]
                      ),
                  )
                  .first()
              )
  
              if (
                  existing_ensemble
                  and existing_ensemble.job_status == "finished"
              ):
                  score = existing_ensemble.individual_score[
                      module.metric_to_optimize
                  ]
  
              elif (
                  existing_ensemble
                  and existing_ensemble.job_status != "finished"
              ):
                  eval_stacked_ensemble(
                      existing_ensemble, session, path
                  )
                  score = existing_ensemble.individual_score[
                      module.metric_to_optimize
                  ]
  
              else:
                  stacked_ensemble = models.StackedEnsemble(
                      secondary_learner_hyperparameters=secondary_learner.get_params(),
                      base_learners=current_ensemble,
                      base_learner_origin=automated_run.base_learner_origin,
                      job_status="started",
                  )
                  session.add(stacked_ensemble)
                  session.commit()
                  eval_stacked_ensemble(stacked_ensemble, session, path)
                  score = stacked_ensemble.individual_score[
                      module.metric_to_optimize
                  ]
  
              score = -score if module.invert_metric else score
  
              if best_score < score:
                  best_score = score
                  best_ensemble = current_ensemble[:]
  
              current_ensemble.pop()
  
file_path: xcessiv/xcessiv/automatedruns.py
imports: from __future__ import absolute_import, print_function, division, unicode_literals
  from rq import get_current_job
  from xcessiv import functions
  from xcessiv import models
  from xcessiv import constants
  import numpy
  import os
  import sys
  import traceback
  from six import iteritems
  import numbers
  from bayes_opt import BayesianOptimization
label_desc: Use image node_id 5 for calling a global function with example usage: start_greedy_ensemble_search(automated_run, session, path) without return types