Repository: automl/auto-sklearn

Issue:
Cross Validation: Able to fit() but unable to refit()
Was able to fit the model successfully with cross validation. However, when refitting, an unexpected error occurred. Shouldn't there be no issue since both fit and refit calls fit() in base.py and I have passed in the same parameters for both fit() and refit().

Ran the following code:
```python
automl = autosklearn.classification.AutoSklearnClassifier(
        tmp_folder='/tmp/autosklearn_cv_tmp',
        output_folder='/tmp/autosklearn_cv_out',
        delete_tmp_folder_after_terminate=False,
        resampling_strategy='cv',
        resampling_strategy_arguments={'folds': 10})

automl.fit(X_train.copy(), y_train.copy(), dataset_name='Emotion')

automl.refit(X_train.copy(), y_train.copy())

```

The relevant part of the stack trace:
```
/home/cs/anaconda3/lib/python3.6/site-packages/autosklearn/estimators.py in refit(self, X, y)
     48 
     49         """
---> 50         return self._automl.refit(X, y)
     51 
     52     def fit_ensemble(self, y, task=None, metric=None, precision='32',

/home/cs/anaconda3/lib/python3.6/site-packages/autosklearn/estimators.py in refit(self, X, y)
     48 
     49         """
---> 50         return self._automl.refit(X, y)
     51 
     52     def fit_ensemble(self, y, task=None, metric=None, precision='32',

/home/cs/anaconda3/lib/python3.6/site-packages/autosklearn/automl.py in refit(self, X, y)
    495                         with warnings.catch_warnings():
    496                             warnings.showwarning = send_warnings_to_log
--> 497                             model.fit(X.copy(), y.copy())
    498                         break
    499                     except ValueError as e:

/home/cs/anaconda3/lib/python3.6/site-packages/autosklearn/pipeline/base.py in fit(self, X, y, fit_params)
     86             a classification algorithm first.
     87         """
---> 88         X, fit_params = self.fit_transformer(X, y, fit_params=fit_params)
     89         self.fit_estimator(X, y, **fit_params)
     90         return self

/home/cs/anaconda3/lib/python3.6/site-packages/autosklearn/pipeline/classification.py in fit_transformer(self, X, y, fit_params)
     82 
     83     def fit_transformer(self, X, y, fit_params=None):
---> 84         self.num_targets = 1 if len(y.shape) == 1 else y.shape[1]
     85 
     86         if fit_params is None:

AttributeError: 'list' object has no attribute 'shape'

```



Discussion:
Thanks a lot for reporting this. I'm working on this issue, but it may take some time until the fix is in Auto-sklearn. An easy hotfix is that you cast `X` and `y` yourself prior to calling `refit(X, y)`.
Late but thank you for the recommendation!

Resolving patch:
diff --git a/autosklearn/automl.py b/autosklearn/automl.py
--- a/autosklearn/automl.py
+++ b/autosklearn/automl.py
@@ -1,12 +1,10 @@
 # -*- encoding: utf-8 -*-
-from collections import defaultdict
 import io
 import json
 import os
 import unittest.mock
 import warnings
 
-
 from ConfigSpace.read_and_write import pcs
 import numpy as np
 import numpy.ma as ma
@@ -15,6 +13,9 @@
 from smac.tae.execute_ta_run import StatusType
 from smac.stats.stats import Stats
 from sklearn.externals import joblib
+import sklearn.utils
+import scipy.sparse
+from sklearn.metrics.classification import type_of_target
 
 from autosklearn.constants import *
 from autosklearn.metrics import Scorer
@@ -27,6 +28,8 @@
 from autosklearn.ensemble_builder import EnsembleBuilder
 from autosklearn.smbo import AutoMLSMBO
 from autosklearn.util.hash import hash_array_or_matrix
+from autosklearn.metrics import f1_macro, accuracy, r2
+from autosklearn.constants import *
 
 
 def _model_predict(self, X, batch_size, identifier):
@@ -808,3 +811,120 @@ def _create_search_space(self, tmp_dir, backend, datamanager,
 
     def configuration_space_created_hook(self, datamanager, configuration_space):
         return configuration_space
+
+
+class AutoMLClassifier(AutoML):
+    def __init__(self, *args, **kwargs):
+        self._classes = []
+        self._n_classes = []
+        self._n_outputs = 0
+
+        super().__init__(*args, **kwargs)
+
+    def fit(self, X, y,
+            task=MULTICLASS_CLASSIFICATION,
+            metric=None,
+            feat_type=None,
+            dataset_name=None):
+        X = sklearn.utils.check_array(X, accept_sparse="csr",
+                                      force_all_finite=False)
+        y = sklearn.utils.check_array(y, ensure_2d=False)
+
+        if scipy.sparse.issparse(X):
+            X.sort_indices()
+
+        y_task = type_of_target(y)
+        task_mapping = {'multilabel-indicator': MULTILABEL_CLASSIFICATION,
+                        'multiclass': MULTICLASS_CLASSIFICATION,
+                        'binary': BINARY_CLASSIFICATION}
+
+        task = task_mapping.get(y_task)
+        if task is None:
+            raise ValueError('Cannot work on data of type %s' % y_task)
+
+        if metric is None:
+            if task == MULTILABEL_CLASSIFICATION:
+                metric = f1_macro
+            else:
+                metric = accuracy
+
+        y = self._process_target_classes(y)
+
+        return super().fit(X, y, task, metric, feat_type, dataset_name)
+
+    def fit_ensemble(self, y, task=None, metric=None, precision='32',
+                     dataset_name=None, ensemble_nbest=None,
+                     ensemble_size=None):
+        self._process_target_classes(y)
+        return super().fit_ensemble(y, task, metric, precision,
+                                    dataset_name,
+                                    ensemble_nbest, ensemble_size)
+
+    def _process_target_classes(self, y):
+        y = np.atleast_1d(y)
+        if y.ndim == 2 and y.shape[1] == 1:
+            warnings.warn("A column-vector y was passed when a 1d array was"
+                          " expected. Please change the shape of y to "
+                          "(n_samples,), for example using ravel().",
+                          sklearn.utils.DataConversionWarning, stacklevel=2)
+
+        if y.ndim == 1:
+            # reshape is necessary to preserve the data contiguity against vs
+            # [:, np.newaxis] that does not.
+            y = np.reshape(y, (-1, 1))
+
+        self._n_outputs = y.shape[1]
+
+        y = np.copy(y)
+
+        self._classes = []
+        self._n_classes = []
+
+        for k in range(self._n_outputs):
+            classes_k, y[:, k] = np.unique(y[:, k], return_inverse=True)
+            self._classes.append(classes_k)
+            self._n_classes.append(classes_k.shape[0])
+
+        self._n_classes = np.array(self._n_classes, dtype=np.int)
+
+        if y.shape[1] == 1:
+            y = y.flatten()
+
+        return y
+
+    def predict(self, X, batch_size=None, n_jobs=1):
+        predicted_probabilities = super().predict(
+            X, batch_size=batch_size, n_jobs=n_jobs
+        )
+
+        if self._n_outputs == 1:
+            predicted_indexes = np.argmax(predicted_probabilities, axis=1)
+            predicted_classes = self._classes[0].take(predicted_indexes)
+
+            return predicted_classes
+        else:
+            predicted_indices = (predicted_probabilities > 0.5).astype(int)
+            n_samples = predicted_probabilities.shape[0]
+            predicted_classes = np.zeros((n_samples, self._n_outputs))
+
+            for k in range(self._n_outputs):
+                output_predicted_indexes = predicted_indices[:, k].reshape(-1)
+                predicted_classes[:, k] = self._classes[k].take(
+                    output_predicted_indexes)
+
+            return predicted_classes
+
+    def predict_proba(self, X, batch_size=None, n_jobs=1):
+        return super().predict(X, batch_size=batch_size, n_jobs=n_jobs)
+
+
+class AutoMLRegressor(AutoML):
+    def fit(self, X, y,
+            task=MULTICLASS_CLASSIFICATION,
+            metric=None,
+            feat_type=None,
+            dataset_name=None):
+        if metric is None:
+            metric = r2
+        return super().fit(X=X, y=y, task=REGRESSION, metric=metric,
+                           feat_type=feat_type, dataset_name=dataset_name)
diff --git a/autosklearn/estimators.py b/autosklearn/estimators.py
--- a/autosklearn/estimators.py
+++ b/autosklearn/estimators.py
@@ -1,105 +1,11 @@
 # -*- encoding: utf-8 -*-
-
-import numpy as np
-import warnings
-
-from sklearn.metrics.classification import type_of_target
 from sklearn.base import BaseEstimator
-import sklearn.utils
-import scipy.sparse
 
-import autosklearn.automl
-from autosklearn.metrics import f1_macro, accuracy, r2
-from autosklearn.constants import *
+from autosklearn.automl import AutoMLClassifier, AutoMLRegressor
 from autosklearn.util.backend import create
 
 
-class AutoMLDecorator(object):
-
-    def __init__(self, automl):
-        self._automl = automl
-
-    def fit(self, *args, **kwargs):
-        self._automl.fit(*args, **kwargs)
-
-    def refit(self, X, y):
-        """Refit all models found with fit to new data.
-
-        Necessary when using cross-validation. During training, auto-sklearn
-        fits each model k times on the dataset, but does not keep any trained
-        model and can therefore not be used to predict for new data points.
-        This methods fits all models found during a call to fit on the data
-        given. This method may also be used together with holdout to avoid
-        only using 66% of the training data to fit the final model.
-
-        Parameters
-        ----------
-
-        X : array-like or sparse matrix of shape = [n_samples, n_features]
-            The training input samples.
-
-        y : array-like, shape = [n_samples] or [n_samples, n_outputs]
-            The targets.
-
-        Returns
-        -------
-
-        self
-
-        """
-        return self._automl.refit(X, y)
-
-    def fit_ensemble(self, y, task=None, metric=None, precision='32',
-                     dataset_name=None, ensemble_nbest=None,
-                     ensemble_size=None):
-
-        return self._automl.fit_ensemble(y, task, metric, precision,
-                                         dataset_name, ensemble_nbest,
-                                         ensemble_size)
-
-    def predict(self, X, batch_size=None, n_jobs=1):
-        return self._automl.predict(X, batch_size=batch_size, n_jobs=n_jobs)
-
-    def score(self, X, y):
-        return self._automl.score(X, y)
-
-    def show_models(self):
-        """Return a representation of the final ensemble found by auto-sklearn.
-
-        Returns
-        -------
-        str
-
-        """
-        return self._automl.show_models()
-
-    def get_models_with_weights(self):
-        """Return a list of the final ensemble found by auto-sklearn.
-
-        Returns
-        -------
-        [(weight_1, model_1), ..., (weight_n, model_n)]
-
-        """
-        return self._automl.get_models_with_weights()
-
-    @property
-    def cv_results_(self):
-        return self._automl.cv_results_
-
-    @property
-    def trajectory_(self):
-        return self._automl.trajectory_
-
-    @property
-    def fANOVA_input_(self):
-        return self._automl.fANOVA_input_
-
-    def sprint_statistics(self):
-        return self._automl.sprint_statistics()
-
-
-class AutoSklearnEstimator(AutoMLDecorator, BaseEstimator):
+class AutoSklearnEstimator(BaseEstimator):
 
     def __init__(self,
                  time_left_for_this_task=3600,
@@ -130,7 +36,6 @@ def __init__(self,
             models. By increasing this value, *auto-sklearn* has a higher
             chance of finding better models.
 
-
         per_run_time_limit : int, optional (default=360)
             Time limit for a single call to the machine learning model.
             Model fitting will be terminated if the machine learning
@@ -268,9 +173,11 @@ def __init__(self,
         self.shared_mode = shared_mode
         self.disable_evaluator_output = disable_evaluator_output
         self.configuration_mode = configuration_mode
-        super(AutoSklearnEstimator, self).__init__(None)
 
-    def build_automl(self):
+        self._automl = None
+        super().__init__()
+
+    def build_automl(self, cls):
         if self.shared_mode:
             self.delete_output_folder_after_terminate = False
             self.delete_tmp_folder_after_terminate = False
@@ -285,7 +192,7 @@ def build_automl(self):
                          output_directory=self.output_folder,
                          delete_tmp_folder_after_terminate=self.delete_tmp_folder_after_terminate,
                          delete_output_folder_after_terminate=self.delete_output_folder_after_terminate)
-        automl = autosklearn.automl.AutoML(
+        automl = cls(
             backend=backend,
             time_left_for_this_task=self.time_left_for_this_task,
             per_run_time_limit=self.per_run_time_limit,
@@ -313,7 +220,7 @@ def build_automl(self):
 
     def fit(self, *args, **kwargs):
         self._automl = self.build_automl()
-        super(AutoSklearnEstimator, self).fit(*args, **kwargs)
+        self._automl.fit(*args, **kwargs)
 
     def fit_ensemble(self, y, task=None, metric=None, precision='32',
                      dataset_name=None, ensemble_nbest=None,
@@ -364,6 +271,74 @@ def fit_ensemble(self, y, task=None, metric=None, precision='32',
                                          dataset_name, ensemble_nbest,
                                          ensemble_size)
 
+    def refit(self, X, y):
+        """Refit all models found with fit to new data.
+
+        Necessary when using cross-validation. During training, auto-sklearn
+        fits each model k times on the dataset, but does not keep any trained
+        model and can therefore not be used to predict for new data points.
+        This methods fits all models found during a call to fit on the data
+        given. This method may also be used together with holdout to avoid
+        only using 66% of the training data to fit the final model.
+
+        Parameters
+        ----------
+
+        X : array-like or sparse matrix of shape = [n_samples, n_features]
+            The training input samples.
+
+        y : array-like, shape = [n_samples] or [n_samples, n_outputs]
+            The targets.
+
+        Returns
+        -------
+
+        self
+
+        """
+        return self._automl.refit(X, y)
+
+    def predict(self, X, batch_size=None, n_jobs=1):
+        return self._automl.predict(X, batch_size=batch_size, n_jobs=n_jobs)
+
+    def score(self, X, y):
+        return self._automl.score(X, y)
+
+    def show_models(self):
+        """Return a representation of the final ensemble found by auto-sklearn.
+
+        Returns
+        -------
+        str
+
+        """
+        return self._automl.show_models()
+
+    def get_models_with_weights(self):
+        """Return a list of the final ensemble found by auto-sklearn.
+
+        Returns
+        -------
+        [(weight_1, model_1), ..., (weight_n, model_n)]
+
+        """
+        return self._automl.get_models_with_weights()
+
+    @property
+    def cv_results_(self):
+        return self._automl.cv_results_
+
+    @property
+    def trajectory_(self):
+        return self._automl.trajectory_
+
+    @property
+    def fANOVA_input_(self):
+        return self._automl.fANOVA_input_
+
+    def sprint_statistics(self):
+        return self._automl.sprint_statistics()
+
 
 class AutoSklearnClassifier(AutoSklearnEstimator):
     """
@@ -372,8 +347,7 @@ class AutoSklearnClassifier(AutoSklearnEstimator):
     """
 
     def build_automl(self):
-        automl = super(AutoSklearnClassifier, self).build_automl()
-        return AutoMLClassifier(automl)
+        return super().build_automl(AutoMLClassifier)
 
     def fit(self, X, y,
             metric=None,
@@ -412,9 +386,8 @@ def fit(self, X, y,
         self
 
         """
-        return super(AutoSklearnClassifier, self).fit(X=X, y=y, metric=metric,
-                                                      feat_type=feat_type,
-                                                      dataset_name=dataset_name)
+        return super().fit(X=X, y=y, metric=metric, feat_type=feat_type,
+                           dataset_name=dataset_name)
 
     def predict(self, X, batch_size=None, n_jobs=1):
         """Predict classes for X.
@@ -429,8 +402,7 @@ def predict(self, X, batch_size=None, n_jobs=1):
             The predicted classes.
 
         """
-        return super(AutoSklearnClassifier, self).predict(
-            X, batch_size=batch_size, n_jobs=n_jobs)
+        return super().predict(X, batch_size=batch_size, n_jobs=n_jobs)
 
     def predict_proba(self, X, batch_size=None, n_jobs=1):
 
@@ -457,8 +429,7 @@ class AutoSklearnRegressor(AutoSklearnEstimator):
     """
 
     def build_automl(self):
-        automl = super(AutoSklearnRegressor, self).build_automl()
-        return AutoMLRegressor(automl)
+        return super().build_automl(AutoMLRegressor)
 
     def fit(self, X, y,
             metric=None,
@@ -496,9 +467,8 @@ def fit(self, X, y,
         """
         # Fit is supposed to be idempotent!
         # But not if we use share_mode.
-        return super(AutoSklearnRegressor, self).fit(X=X, y=y, metric=metric,
-                                                     feat_type=feat_type,
-                                                     dataset_name=dataset_name)
+        return super().fit(X=X, y=y, metric=metric, feat_type=feat_type,
+                           dataset_name=dataset_name)
 
     def predict(self, X, batch_size=None, n_jobs=1):
         """Predict regression target for X.
@@ -513,121 +483,4 @@ def predict(self, X, batch_size=None, n_jobs=1):
             The predicted values.
 
         """
-        return super(AutoSklearnRegressor, self).predict(
-            X, batch_size=batch_size, n_jobs=n_jobs)
-
-
-class AutoMLClassifier(AutoMLDecorator):
-
-    def __init__(self, automl):
-        self._classes = []
-        self._n_classes = []
-        self._n_outputs = 0
-
-        super(AutoMLClassifier, self).__init__(automl)
-
-    def fit(self, X, y,
-            metric=None,
-            loss=None,
-            feat_type=None,
-            dataset_name=None):
-        X = sklearn.utils.check_array(X, accept_sparse="csr",
-                                      force_all_finite=False)
-        y = sklearn.utils.check_array(y, ensure_2d=False)
-
-        if scipy.sparse.issparse(X):
-            X.sort_indices()
-
-        y_task = type_of_target(y)
-        task_mapping = {'multilabel-indicator': MULTILABEL_CLASSIFICATION,
-                        'multiclass': MULTICLASS_CLASSIFICATION,
-                        'binary': BINARY_CLASSIFICATION}
-
-        task = task_mapping.get(y_task)
-        if task is None:
-            raise ValueError('Cannot work on data of type %s' % y_task)
-
-        if metric is None:
-            if task == MULTILABEL_CLASSIFICATION:
-                metric = f1_macro
-            else:
-                metric = accuracy
-
-        y = self._process_target_classes(y)
-
-        return self._automl.fit(X, y, task, metric, feat_type, dataset_name)
-
-    def fit_ensemble(self, y, task=None, metric=None, precision='32',
-                     dataset_name=None, ensemble_nbest=None,
-                     ensemble_size=None):
-        self._process_target_classes(y)
-        return self._automl.fit_ensemble(y, task, metric, precision, dataset_name,
-                                         ensemble_nbest, ensemble_size)
-
-    def _process_target_classes(self, y):
-        y = np.atleast_1d(y)
-        if y.ndim == 2 and y.shape[1] == 1:
-            warnings.warn("A column-vector y was passed when a 1d array was"
-                          " expected. Please change the shape of y to "
-                          "(n_samples,), for example using ravel().",
-                          sklearn.utils.DataConversionWarning, stacklevel=2)
-
-        if y.ndim == 1:
-            # reshape is necessary to preserve the data contiguity against vs
-            # [:, np.newaxis] that does not.
-            y = np.reshape(y, (-1, 1))
-
-        self._n_outputs = y.shape[1]
-
-        y = np.copy(y)
-
-        self._classes = []
-        self._n_classes = []
-
-        for k in range(self._n_outputs):
-            classes_k, y[:, k] = np.unique(y[:, k], return_inverse=True)
-            self._classes.append(classes_k)
-            self._n_classes.append(classes_k.shape[0])
-
-        self._n_classes = np.array(self._n_classes, dtype=np.int)
-
-        if y.shape[1] == 1:
-            y = y.flatten()
-
-        return y
-
-    def predict(self, X, batch_size=None, n_jobs=1):
-        predicted_probabilities = self._automl.predict(
-            X, batch_size=batch_size, n_jobs=n_jobs)
-
-        if self._n_outputs == 1:
-            predicted_indexes = np.argmax(predicted_probabilities, axis=1)
-            predicted_classes = self._classes[0].take(predicted_indexes)
-
-            return predicted_classes
-        else:
-            predicted_indices = (predicted_probabilities > 0.5).astype(int)
-            n_samples = predicted_probabilities.shape[0]
-            predicted_classes = np.zeros((n_samples, self._n_outputs))
-
-            for k in range(self._n_outputs):
-                output_predicted_indexes = predicted_indices[:, k].reshape(-1)
-                predicted_classes[:, k] = self._classes[k].take(output_predicted_indexes)
-
-            return predicted_classes
-
-    def predict_proba(self, X, batch_size=None, n_jobs=1):
-        return self._automl.predict(X, batch_size=batch_size, n_jobs=n_jobs)
-
-
-class AutoMLRegressor(AutoMLDecorator):
-
-    def fit(self, X, y,
-            metric=None,
-            feat_type=None,
-            dataset_name=None,
-            ):
-        if metric is None:
-            metric = r2
-        return self._automl.fit(X=X, y=y, task=REGRESSION, metric=metric,
-                                feat_type=feat_type, dataset_name=dataset_name)
+        return super().predict(X, batch_size=batch_size, n_jobs=n_jobs)
diff --git a/example/example_metrics.py b/example/example_metrics.py
--- a/example/example_metrics.py
+++ b/example/example_metrics.py
@@ -45,7 +45,7 @@ def main():
     predictions = cls.predict(X_test)
     print("Accuracy score {:g} using {:s}".
           format(sklearn.metrics.accuracy_score(y_test, predictions),
-                 cls._automl._automl._metric.name))
+                 cls._automl._metric.name))
 
     # Second example: Use own accuracy metric
     print("#"*80)
@@ -63,7 +63,7 @@ def main():
     predictions = cls.predict(X_test)
     print("Accuracy score {:g} using {:s}".
           format(sklearn.metrics.accuracy_score(y_test, predictions),
-                 cls._automl._automl._metric.name))
+                 cls._automl._metric.name))
 
     # Third example: Use own accuracy metric with additional argument
     print("#"*80)
@@ -82,7 +82,7 @@ def main():
     predictions = cls.predict(X_test)
     print("Accuracy score {:g} using {:s}".
           format(sklearn.metrics.accuracy_score(y_test, predictions),
-                 cls._automl._automl._metric.name))
+                 cls._automl._metric.name))
 
 
 if __name__ == "__main__":


Test patch:
diff --git a/test/test_automl/test_estimators.py b/test/test_automl/test_estimators.py
--- a/test/test_automl/test_estimators.py
+++ b/test/test_automl/test_estimators.py
@@ -1,4 +1,3 @@
-import collections
 import os
 import pickle
 import sys
@@ -14,7 +13,7 @@
 from autosklearn.classification import AutoSklearnClassifier
 from autosklearn.regression import AutoSklearnRegressor
 from autosklearn.metrics import accuracy, f1_macro, mean_squared_error
-from autosklearn.estimators import AutoMLClassifier
+from autosklearn.automl import AutoMLClassifier, AutoML
 from autosklearn.util.backend import Backend, BackendContext
 from autosklearn.constants import *
 sys.path.append(os.path.dirname(__file__))
@@ -155,9 +154,9 @@ def test_fit_pSMAC(self):
         self.assertEqual(len(os.listdir(os.path.join(output, '.auto-sklearn',
                                                      'ensembles'))), 1)
         self.assertGreaterEqual(score, 0.90)
-        self.assertEqual(automl._automl._automl._task, MULTICLASS_CLASSIFICATION)
+        self.assertEqual(automl._automl._task, MULTICLASS_CLASSIFICATION)
 
-        models = automl._automl._automl.models_
+        models = automl._automl.models_
         classifier_types = [type(c) for c in models.values()]
         self.assertIn(ArrayReturningDummyPredictor, classifier_types)
 
@@ -193,18 +192,21 @@ def test_cv_results(self):
 
         
 class AutoMLClassifierTest(Base, unittest.TestCase):
-
-    def test_multiclass_prediction(self):
+    @unittest.mock.patch('autosklearn.automl.AutoML.predict')
+    def test_multiclass_prediction(self, predict_mock):
         classes = [['a', 'b', 'c']]
         predicted_probabilities = [[0, 0, 0.99], [0, 0.99, 0], [0.99, 0, 0],
                                    [0, 0.99, 0], [0, 0, 0.99]]
         predicted_indexes = [2, 1, 0, 1, 2]
         expected_result = ['c', 'b', 'a', 'b', 'c']
 
-        automl_mock = unittest.mock.Mock()
-        automl_mock.predict.return_value = np.array(predicted_probabilities)
+        predict_mock.return_value = np.array(predicted_probabilities)
 
-        classifier = AutoMLClassifier(automl_mock)
+        classifier = AutoMLClassifier(
+            time_left_for_this_task=1,
+            per_run_time_limit=1,
+            backend=None,
+        )
         classifier._classes = [np.array(classes)]
         classifier._n_outputs = 1
         classifier._n_classes = np.array([3])
@@ -213,7 +215,8 @@ def test_multiclass_prediction(self):
 
         np.testing.assert_array_equal(expected_result, actual_result)
 
-    def test_multilabel_prediction(self):
+    @unittest.mock.patch('autosklearn.automl.AutoML.predict')
+    def test_multilabel_prediction(self, predict_mock):
         classes = [[1, 2], [13, 17]]
         predicted_probabilities = [[0.99, 0],
                                    [0.99, 0],
@@ -223,10 +226,13 @@ def test_multilabel_prediction(self):
         predicted_indexes = np.array([[1, 0], [1, 0], [0, 1], [1, 1], [1, 1]])
         expected_result = np.array([[2, 13], [2, 13], [1, 17], [2, 17], [2, 17]])
 
-        automl_mock = unittest.mock.Mock()
-        automl_mock.predict.return_value = np.array(predicted_probabilities)
+        predict_mock.return_value = np.array(predicted_probabilities)
 
-        classifier = AutoMLClassifier(automl_mock)
+        classifier = AutoMLClassifier(
+            time_left_for_this_task=1,
+            per_run_time_limit=1,
+            backend=None,
+        )
         classifier._classes = list(map(np.array, classes))
         classifier._n_outputs = 2
         classifier._n_classes = np.array([3, 2])
@@ -315,6 +321,25 @@ def test_binary(self):
         score = accuracy(Y_test, predictions)
         self.assertGreaterEqual(score, 0.9)
 
+    @unittest.mock.patch.object(AutoML, 'fit')
+    @unittest.mock.patch.object(AutoML, 'refit')
+    @unittest.mock.patch.object(AutoML, 'fit_ensemble')
+    def test_conversion_of_list_to_np(self, fit_ensemble, refit, fit):
+        automl = AutoSklearnClassifier()
+        X = [[1], [2], [3]]
+        y = [1, 2, 3]
+        automl.fit(X, y)
+        self.assertEqual(fit.call_count, 1)
+        self.assertIsInstance(fit.call_args[0][0], np.ndarray)
+        self.assertIsInstance(fit.call_args[0][1], np.ndarray)
+        automl.refit(X, y)
+        self.assertEqual(refit.call_count, 1)
+        self.assertIsInstance(refit.call_args[0][0], np.ndarray)
+        self.assertIsInstance(refit.call_args[0][1], np.ndarray)
+        automl.fit_ensemble(y)
+        self.assertEqual(fit_ensemble.call_count, 1)
+        self.assertIsInstance(fit_ensemble.call_args[0][0], np.ndarray)
+
 
 class AutoMLRegressorTest(Base, unittest.TestCase):
     def test_regression(self):
@@ -332,4 +357,23 @@ def test_regression(self):
         self.assertEqual(predictions.shape, (356,))
         score = mean_squared_error(Y_test, predictions)
         # On average np.sqrt(30) away from the target -> ~5.5 on average
-        self.assertGreaterEqual(score, -30)
\ No newline at end of file
+        self.assertGreaterEqual(score, -30)
+
+    @unittest.mock.patch.object(AutoML, 'fit')
+    @unittest.mock.patch.object(AutoML, 'refit')
+    @unittest.mock.patch.object(AutoML, 'fit_ensemble')
+    def test_conversion_of_list_to_np(self, fit_ensemble, refit, fit):
+        automl = AutoSklearnRegressor()
+        X = [[1], [2], [3]]
+        y = [1, 2, 3]
+        automl.fit(X, y)
+        self.assertEqual(fit.call_count, 1)
+        self.assertIsInstance(fit.call_args[0][0], np.ndarray)
+        self.assertIsInstance(fit.call_args[0][1], np.ndarray)
+        automl.refit(X, y)
+        self.assertEqual(refit.call_count, 1)
+        self.assertIsInstance(refit.call_args[0][0], np.ndarray)
+        self.assertIsInstance(refit.call_args[0][1], np.ndarray)
+        automl.fit_ensemble(y)
+        self.assertEqual(fit_ensemble.call_count, 1)
+        self.assertIsInstance(fit_ensemble.call_args[0][0], np.ndarray)
\ No newline at end of file