Skip to content

Commit ac2dd99

Browse files
[DOC] Adds documentation to the abstract evaluator (#160)
* DOC_153 * Changes from Ravin * [FIX] improve clarity of msg in commit
1 parent 8447e91 commit ac2dd99

File tree

2 files changed

+346
-3
lines changed

2 files changed

+346
-3
lines changed

autoPyTorch/evaluation/abstract_evaluator.py

Lines changed: 221 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,81 @@ def send_warnings_to_log(message, category, filename, lineno,
262262

263263

264264
class AbstractEvaluator(object):
265+
"""
266+
This method defines the interface that pipeline evaluators should follow, when
267+
interacting with SMAC through ExecuteTaFuncWithQueue.
268+
269+
An evaluator is an object that:
270+
+ constructs a pipeline (i.e. a classification or regression estimator) for a given
271+
pipeline_config and run settings (budget, seed)
272+
+ Fits and trains this pipeline (TrainEvaluator) or tests a given
273+
configuration (TestEvaluator)
274+
275+
The provided configuration determines the type of pipeline created. For more
276+
details, please read the get_pipeline() method.
277+
278+
Attributes:
279+
backend (Backend):
280+
An object that allows interaction with the disk storage. In particular, allows to
281+
access the train and test datasets
282+
queue (Queue):
283+
Each worker available will instantiate an evaluator, and after completion,
284+
it will append the result to a multiprocessing queue
285+
metric (autoPyTorchMetric):
286+
A scorer object that is able to evaluate how good a pipeline was fit. It
287+
is a wrapper on top of the actual score method (a wrapper on top of
288+
scikit-learn accuracy for example) that formats the predictions accordingly.
289+
budget: (float):
290+
The amount of epochs/time a configuration is allowed to run.
291+
budget_type (str):
292+
The budget type. Currently, only epoch and time are allowed.
293+
pipeline_config (Optional[Dict[str, Any]]):
294+
Defines the content of the pipeline being evaluated. For example, it
295+
contains pipeline specific settings like logging name, or whether or not
296+
to use tensorboard.
297+
configuration (Union[int, str, Configuration]):
298+
Determines the pipeline to be constructed. A dummy estimator is created for
299+
integer configurations, a traditional machine learning pipeline is created
300+
for string based configuration, and NAS is performed when a configuration
301+
object is passed.
302+
seed (int):
303+
A integer that allows for reproducibility of results
304+
output_y_hat_optimization (bool):
305+
Whether this worker should output the target predictions, so that they are
306+
stored on disk. Fundamentally, the resampling strategy might shuffle the
307+
Y_train targets, so we store the split in order to re-use them for ensemble
308+
selection.
309+
num_run (Optional[int]):
310+
An identifier of the current configuration being fit. This number is unique per
311+
configuration.
312+
include (Optional[Dict[str, Any]]):
313+
An optional dictionary to include components of the pipeline steps.
314+
exclude (Optional[Dict[str, Any]]):
315+
An optional dictionary to exclude components of the pipeline steps.
316+
disable_file_output (Union[bool, List[str]]):
317+
By default, the model, it's predictions and other metadata is stored on disk
318+
for each finished configuration. This argument allows the user to skip
319+
saving certain file type, for example the model, from being written to disk.
320+
init_params (Optional[Dict[str, Any]]):
321+
Optional argument that is passed to each pipeline step. It is the equivalent of
322+
kwargs for the pipeline steps.
323+
logger_port (Optional[int]):
324+
Logging is performed using a socket-server scheme to be robust against many
325+
parallel entities that want to write to the same file. This integer states the
326+
socket port for the communication channel.
327+
If None is provided, the logging.handlers.DEFAULT_TCP_LOGGING_PORT is used.
328+
all_supported_metrics (bool):
329+
Whether all supported metrics should be calculated for every configuration.
330+
search_space_updates (Optional[HyperparameterSearchSpaceUpdates]):
331+
An object used to fine tune the hyperparameter search space of the pipeline
332+
"""
265333
def __init__(self, backend: Backend,
266334
queue: Queue,
267335
metric: autoPyTorchMetric,
268336
budget: float,
337+
configuration: Union[int, str, Configuration],
269338
budget_type: str = None,
270339
pipeline_config: Optional[Dict[str, Any]] = None,
271-
configuration: Optional[Configuration] = None,
272340
seed: int = 1,
273341
output_y_hat_optimization: bool = True,
274342
num_run: Optional[int] = None,
@@ -408,6 +476,23 @@ def __init__(self, backend: Backend,
408476
self.logger.debug("Search space updates :{}".format(self.search_space_updates))
409477

410478
def _get_pipeline(self) -> BaseEstimator:
479+
"""
480+
Implements a pipeline object based on the self.configuration attribute.
481+
int: A dummy classifier/dummy regressor is created. This estimator serves
482+
as a baseline model to ignore all models that perform worst than this
483+
fixed estimator. Also, in the worst case scenario, this is the final
484+
estimator created (for instance, in case not enough memory was allocated).
485+
str: A pipeline with traditional classifiers like random forest, SVM, etc is created,
486+
as the configuration will contain an estimator name defining the configuration
487+
to use, for example 'RandomForest'
488+
Configuration: A pipeline object matching this configuration is created. This
489+
is the case of neural architecture search, where different backbones
490+
and head can be passed in the form of a configuration object.
491+
492+
Returns
493+
pipeline (BaseEstimator):
494+
A scikit-learn compliant pipeline which is not yet fit to the data.
495+
"""
411496
assert self.pipeline_class is not None, "Can't return pipeline, pipeline_class not initialised"
412497
if isinstance(self.configuration, int):
413498
pipeline = self.pipeline_class(config=self.configuration,
@@ -436,6 +521,15 @@ def _loss(self, y_true: np.ndarray, y_hat: np.ndarray) -> Dict[str, float]:
436521
The calculate_loss internally translate a score function to
437522
a minimization problem
438523
524+
Args:
525+
y_true (np.ndarray):
526+
The expect labels given by the original dataset
527+
y_hat (np.ndarray):
528+
The prediction of the current pipeline being fit
529+
Returns:
530+
(Dict[str, float]):
531+
A dictionary with metric_name -> metric_loss, for every
532+
supported metric
439533
"""
440534

441535
if isinstance(self.configuration, int):
@@ -461,7 +555,39 @@ def finish_up(self, loss: Dict[str, float], train_loss: Dict[str, float],
461555
* saving the files for the ensembles_statistics
462556
* generate output for SMAC
463557
We use it as the signal handler so we can recycle the code for the
464-
normal usecase and when the runsolver kills us here :)"""
558+
normal usecase and when the runsolver kills us here :)
559+
560+
Args:
561+
loss (Dict[str, float]):
562+
The optimization loss, calculated on the validation set. This will
563+
be the cost used in SMAC
564+
train_loss (Dict[str, float]):
565+
The train loss, calculated on the train set
566+
opt_pred (np.ndarray):
567+
The predictions on the validation set. This validation set is created
568+
from the resampling strategy
569+
valid_pred (Optional[np.ndarray]):
570+
Predictions on a user provided validation set
571+
test_pred (Optional[np.ndarray]):
572+
Predictions on a user provided test set
573+
additional_run_info (Optional[Dict]):
574+
A dictionary with additional run information, like duration or
575+
the crash error msg, if any.
576+
file_output (bool):
577+
Whether or not this pipeline should output information to disk
578+
status (StatusType)
579+
The status of the run, following SMAC StatusType syntax.
580+
581+
Returns:
582+
duration (float):
583+
The elapsed time of the training of this evaluator
584+
loss (float):
585+
The optimization loss of this run
586+
seed (int):
587+
The seed used while fitting the pipeline
588+
additional_info (Dict):
589+
Additional run information, like train/test loss
590+
"""
465591

466592
self.duration = time.time() - self.starttime
467593

@@ -508,6 +634,25 @@ def calculate_auxiliary_losses(
508634
Y_valid_pred: np.ndarray,
509635
Y_test_pred: np.ndarray,
510636
) -> Tuple[Optional[float], Optional[float]]:
637+
"""
638+
A helper function to calculate the performance estimate of the
639+
current pipeline in the user provided validation/test set.
640+
641+
Args:
642+
Y_valid_pred (np.ndarray):
643+
predictions on a validation set provided by the user,
644+
matching self.y_valid
645+
Y_test_pred (np.ndarray):
646+
predictions on a test set provided by the user,
647+
matching self.y_test
648+
Returns:
649+
validation_loss (Optional[float]):
650+
The validation loss under the optimization metric
651+
stored in self.metric
652+
test_loss (Optional[float]]):
653+
The test loss under the optimization metric
654+
stored in self.metric
655+
"""
511656

512657
validation_loss: Optional[float] = None
513658

@@ -530,6 +675,31 @@ def file_output(
530675
Y_valid_pred: np.ndarray,
531676
Y_test_pred: np.ndarray
532677
) -> Tuple[Optional[float], Dict]:
678+
"""
679+
This method decides what file outputs are written to disk.
680+
681+
It is also the interface to the backed save_numrun_to_dir
682+
which stores all the pipeline related information to a single
683+
directory for easy identification of the current run.
684+
685+
Args:
686+
Y_optimization_pred (np.ndarray):
687+
The pipeline predictions on the validation set internally created
688+
from self.y_train
689+
Y_valid_pred (np.ndarray):
690+
The pipeline predictions on the user provided validation set,
691+
which should match self.y_valid
692+
Y_test_pred (np.ndarray):
693+
The pipeline predictions on the user provided test set,
694+
which should match self.y_test
695+
Returns:
696+
loss (Optional[float]):
697+
A loss in case the run failed to store files to
698+
disk
699+
error_dict (Dict):
700+
A dictionary with an error that explains why a run
701+
was not successfully stored to disk.
702+
"""
533703
# Abort if self.Y_optimization is None
534704
# self.Y_optimization can be None if we use partial-cv, then,
535705
# obviously no output should be saved.
@@ -624,6 +794,23 @@ def file_output(
624794

625795
def _predict_proba(self, X: np.ndarray, pipeline: BaseEstimator,
626796
Y_train: Optional[np.ndarray] = None) -> np.ndarray:
797+
"""
798+
A wrapper function to handle the prediction of classification tasks.
799+
It also makes sure that the predictions has the same dimensionality
800+
as the expected labels
801+
802+
Args:
803+
X (np.ndarray):
804+
A set of features to feed to the pipeline
805+
pipeline (BaseEstimator):
806+
A model that will take the features X return a prediction y
807+
This pipeline must be a classification estimator that supports
808+
the predict_proba method.
809+
Y_train (Optional[np.ndarray]):
810+
Returns:
811+
(np.ndarray):
812+
The predictions of pipeline for the given features X
813+
"""
627814
@no_type_check
628815
def send_warnings_to_log(message, category, filename, lineno,
629816
file=None, line=None):
@@ -640,6 +827,24 @@ def send_warnings_to_log(message, category, filename, lineno,
640827

641828
def _predict_regression(self, X: np.ndarray, pipeline: BaseEstimator,
642829
Y_train: Optional[np.ndarray] = None) -> np.ndarray:
830+
"""
831+
A wrapper function to handle the prediction of regression tasks.
832+
It is a wrapper to provide the same interface to _predict_proba
833+
834+
Regression predictions expects an unraveled dimensionality.
835+
To comply with scikit-learn VotingRegressor requirement, if the estimator
836+
predicts a (N,) shaped array, it is converted to (N, 1)
837+
838+
Args:
839+
X (np.ndarray):
840+
A set of features to feed to the pipeline
841+
pipeline (BaseEstimator):
842+
A model that will take the features X return a prediction y
843+
Y_train (Optional[np.ndarray]):
844+
Returns:
845+
(np.ndarray):
846+
The predictions of pipeline for the given features X
847+
"""
643848
@no_type_check
644849
def send_warnings_to_log(message, category, filename, lineno,
645850
file=None, line=None):
@@ -658,6 +863,20 @@ def send_warnings_to_log(message, category, filename, lineno,
658863

659864
def _ensure_prediction_array_sizes(self, prediction: np.ndarray,
660865
Y_train: np.ndarray) -> np.ndarray:
866+
"""
867+
This method formats a prediction to match the dimensionality of the provided
868+
labels (Y_train). This should be used exclusively for classification tasks
869+
870+
Args:
871+
prediction (np.ndarray):
872+
The un-formatted predictions of a pipeline
873+
Y_train (np.ndarray):
874+
The labels from the dataset to give an intuition of the expected
875+
predictions dimensionality
876+
Returns:
877+
(np.ndarray):
878+
The formatted prediction
879+
"""
661880
assert self.datamanager.num_classes is not None, "Called function on wrong task"
662881
num_classes: int = self.datamanager.num_classes
663882

0 commit comments

Comments
 (0)