Repository: keras-team/autokeras

Issue:
overflow encountered in exp on bayesian.py line 89
<!---
**If you are reporting a bug:**
*  Verify that your issue is not being currently addressed by other issues or pull requests.
*  Please note that Auto-Keras is only compatible with **Python 3.6**.
*  Tag the issue with the `bug report` tag.
-->

### Bug Description
When running image_classifier. If we use a big MAX_MODEL_NUM (1000). https://github.com/jhfjhfj1/autokeras/blob/master/autokeras/bayesian.py#L89 would throw an overflow warning. Which causes a FileNotFound Error to be raised.

Here is the stack trace:

```
  File "/home/tsunglin/autokeras/autokeras/image_classifier.py", line 229, in fit
    run_searcher_once(train_data, test_data, self.path, int(time_remain))
  File "/home/tsunglin/autokeras/autokeras/image_classifier.py", line 42, in run_searcher_once
    searcher.search(train_data, test_data, timeout)
  File "/home/tsunglin/autokeras/autokeras/search.py", line 189, in search
    new_graph, new_father_id = self.maximize_acq(timeout)
  File "/home/tsunglin/autokeras/autokeras/search.py", line 268, in maximize_acq
    nm_graph = self.load_model_by_id(father_id)
  File "/home/tsunglin/autokeras/autokeras/search.py", line 109, in load_model_by_id
    return pickle_from_file(os.path.join(self.path, str(model_id) + '.h5'))
  File "/home/tsunglin/autokeras/autokeras/utils.py", line 190, in pickle_from_file
    return pickle.load(open(path, 'rb'))
FileNotFoundError: [Errno 2] No such file or directory: 'tests/resources/temp/None.h5'
```

### Reproducing Steps
Steps to reproduce the behavior:
  * Step 1: open test_image_classifier
  * Step 2: change Constant.MAX_MODEL_NUM to 1000 in test_save_continue function.
  * Step 3: run the unit test and you'll see the exception.

### Expected Behavior
Without error

### Setup Details
Include the details about the versions of:
 - OS type and version: Ubuntu 16.04
 - Python: 3.6
 - autokeras: commit f78681805241bd017d75c9c24844e82a051dae9a
 - scikit-learn: 0.19.1
 - numpy:1.14.5
 - keras: 2.2.2
 - scipy: 
 - tensorflow: 1.8.0
 - pytorch: 0.4.0

### Additional context




Discussion:

Resolving patch:
diff --git a/autokeras/bayesian.py b/autokeras/bayesian.py
--- a/autokeras/bayesian.py
+++ b/autokeras/bayesian.py
@@ -270,6 +270,9 @@ def optimize_acq(self, model_ids, descriptors, timeout):
 
         if remaining_time < 0:
             raise TimeoutError
+        # Did not found a not duplicated architecture
+        if father_id is None:
+            return None, None
         nm_graph = self.searcher.load_model_by_id(father_id)
         for args in target_graph.operation_history:
             getattr(nm_graph, args[0])(*list(args[1:]))
diff --git a/autokeras/image_supervised.py b/autokeras/image_supervised.py
--- a/autokeras/image_supervised.py
+++ b/autokeras/image_supervised.py
@@ -185,7 +185,6 @@ def fit(self, x_train=None, y_train=None, time_limit=None):
             y_train: A numpy.ndarray instance containing the label of the training data.
             time_limit: The time limit for the search in seconds.
         """
-        start_time = time.time()
         if y_train is None:
             y_train = []
         if x_train is None:
@@ -232,17 +231,23 @@ def fit(self, x_train=None, y_train=None, time_limit=None):
         if time_limit is None:
             time_limit = 24 * 60 * 60
 
-        time_elapsed = time.time() - start_time
-        time_remain = time_limit - time_elapsed
-        while time_remain > 0:
-            run_searcher_once(train_data, test_data, self.path, int(time_remain))
-            if len(self.load_searcher().history) >= Constant.MAX_MODEL_NUM:
-                break
-            time_elapsed = time.time() - start_time
-            time_remain = time_limit - time_elapsed
-        # if no search executed during the time_limit, then raise an error
-        if not len(self.load_searcher().history):
-            raise TimeoutError
+        start_time = time.time()
+        time_remain = time_limit
+        try:
+            while time_remain > 0:
+                run_searcher_once(train_data, test_data, self.path, int(time_remain))
+                if len(self.load_searcher().history) >= Constant.MAX_MODEL_NUM:
+                    break
+                time_elapsed = time.time() - start_time
+                time_remain = time_limit - time_elapsed
+            # if no search executed during the time_limit, then raise an error
+            if time_remain <= 0:
+                raise TimeoutError
+        except TimeoutError:
+            if len(self.load_searcher().history) == 0:
+                raise TimeoutError("Search Time too short. No model was found during the search time.")
+            elif self.verbose:
+                print('Time is out.')
 
     @abstractmethod
     def get_n_output_node(self):
diff --git a/autokeras/search.py b/autokeras/search.py
--- a/autokeras/search.py
+++ b/autokeras/search.py
@@ -173,6 +173,9 @@ def search(self, train_data, test_data, timeout=60 * 60 * 24):
                 new_graph, new_father_id = self.bo.optimize_acq(self.search_tree.adj_list.keys(),
                                                                 self.descriptors,
                                                                 timeout)
+                # Did not found a new architecture
+                if new_father_id is None:
+                    return
                 new_model_id = self.model_count
                 self.model_count += 1
                 self.training_queue.append((new_graph, new_father_id, new_model_id))
@@ -187,13 +190,7 @@ def search(self, train_data, test_data, timeout=60 * 60 * 24):
             else:
                 raise TimeoutError
         except (multiprocessing.TimeoutError, TimeoutError) as e:
-            # if no model found in the time limit, raise TimeoutError
-            if self.model_count == 0:
-                # convert multiprocessing.TimeoutError to builtin TimeoutError for ux
-                raise TimeoutError("search Timeout") from e
-            # else return the result found in the time limit
-            else:
-                return
+            raise TimeoutError from e
         finally:
             # terminate and join the subprocess to prevent any resource leak
             pool.terminate()


Test patch:
diff --git a/tests/common.py b/tests/common.py
--- a/tests/common.py
+++ b/tests/common.py
@@ -1,4 +1,6 @@
 import os
+from copy import deepcopy
+
 import numpy as np
 
 from autokeras.constant import Constant
@@ -210,8 +212,12 @@ def get_classification_data_loaders():
 
 def clean_dir(path):
     for f in os.listdir(path):
+        full_path = os.path.join(path, f)
         if f != '.gitkeep':
-            os.remove(os.path.join(path, f))
+            if os.path.isfile(full_path):
+                os.remove(full_path)
+            else:
+                os.rmdir(full_path)
 
 
 class MockProcess(object):
@@ -236,3 +242,9 @@ def get(self, timeout=None):
 
     def terminate(self):
         pass
+
+
+def simple_transform(graph):
+    graph.to_wider_model(5, 64)
+    return [deepcopy(graph)]
+
diff --git a/tests/test_image_supervised.py b/tests/test_image_supervised.py
--- a/tests/test_image_supervised.py
+++ b/tests/test_image_supervised.py
@@ -1,11 +1,10 @@
-from copy import deepcopy
 from unittest.mock import patch
 
 
 import pytest
 
 from autokeras.image_supervised import *
-from tests.common import clean_dir, MockProcess
+from tests.common import clean_dir, MockProcess, simple_transform
 
 
 def mock_train(**kwargs):
@@ -34,10 +33,6 @@ def test_x_float_exception():
     assert str(info.value) == 'x_train should only contain numerical data.'
 
 
-def simple_transform(graph):
-    return [deepcopy(graph), deepcopy(graph)]
-
-
 @patch('multiprocessing.Pool', new=MockProcess)
 @patch('autokeras.search.ModelTrainer.train_model', side_effect=mock_train)
 def test_fit_predict(_):
@@ -58,11 +53,9 @@ def test_fit_predict(_):
 
 
 @patch('multiprocessing.Pool', new=MockProcess)
-@patch('autokeras.search.ModelTrainer.train_model', side_effect=mock_train)
-def test_timeout(_):
-    Constant.MAX_ITER_NUM = 1
-    Constant.MAX_MODEL_NUM = 4
-    Constant.SEARCH_MAX_ITER = 1
+def test_timeout():
+    # Constant.MAX_MODEL_NUM = 4
+    Constant.SEARCH_MAX_ITER = 1000
     Constant.T_MIN = 0.8
     Constant.DATA_AUGMENTATION = False
     path = 'tests/resources/temp'
@@ -77,7 +70,7 @@ def test_timeout(_):
 
 @patch('multiprocessing.Pool', new=MockProcess)
 @patch('autokeras.search.ModelTrainer.train_model', side_effect=mock_train)
-def test_timout_resume(_):
+def test_timeout_resume(_):
     Constant.MAX_ITER_NUM = 1
     # make it impossible to complete within 10sec
     Constant.MAX_MODEL_NUM = 1000
@@ -92,7 +85,6 @@ def test_timout_resume(_):
     clf.n_epochs = 100
     clf.fit(train_x, train_y, 15)
     history_len = len(clf.load_searcher().history)
-    print(history_len)
     assert history_len != 0
     results = clf.predict(test_x)
     assert len(results) == 100
diff --git a/tests/test_search.py b/tests/test_search.py
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -1,4 +1,3 @@
-from copy import deepcopy
 from unittest.mock import patch
 
 from autokeras.loss_function import classification_loss
@@ -6,16 +5,11 @@
 from autokeras.search import *
 
 from tests.common import clean_dir, MockProcess, get_classification_data_loaders, get_add_skip_model, \
-    get_concat_skip_model
+    get_concat_skip_model, simple_transform
 
 default_test_path = 'tests/resources/temp'
 
 
-def simple_transform(graph):
-    graph.to_concat_skip_model(1, 5)
-    return [deepcopy(graph)]
-
-
 def mock_train(**_):
     return 1, 0
 
@@ -72,13 +66,8 @@ def test_graph_duplicate():
     assert not same_graph(get_concat_skip_model().extract_descriptor(), get_add_skip_model().extract_descriptor())
 
 
-def simple_transform2(graph):
-    graph.to_wider_model(5, 64)
-    return [deepcopy(graph)]
-
-
 @patch('multiprocessing.Pool', new=MockProcess)
-@patch('autokeras.bayesian.transform', side_effect=simple_transform2)
+@patch('autokeras.bayesian.transform', side_effect=simple_transform)
 @patch('autokeras.search.ModelTrainer.train_model', side_effect=mock_train)
 def test_max_acq(_, _1):
     train_data, test_data = get_classification_data_loaders()
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -4,7 +4,7 @@
 from autokeras.loss_function import classification_loss, regression_loss
 from autokeras.metric import Accuracy, MSE
 from autokeras.utils import ModelTrainer, temp_folder_generator
-from tests.common import get_classification_data_loaders, get_regression_data_loaders
+from tests.common import get_classification_data_loaders, get_regression_data_loaders, clean_dir
 
 
 def test_model_trainer_classification():
@@ -19,7 +19,11 @@ def test_model_trainer_regression():
     ModelTrainer(model, train_data, test_data, MSE, regression_loss, False).train_model(max_iter_num=3)
 
 
-@patch('tempfile.gettempdir', return_value="dummy_path/")
+@patch('tempfile.gettempdir', return_value="tests/resources/temp/")
 def test_temp_folder_generator(_):
+    path = 'tests/resources/temp'
+    clean_dir(path)
     path = temp_folder_generator()
-    assert path == "dummy_path/autokeras"
+    assert path == "tests/resources/temp/autokeras"
+    path = 'tests/resources/temp'
+    clean_dir(path)