We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError: 'NoneType' object has no attribute 'continue_learning'
If no algorithm is set from the .yaml file (it is the case in kmeans, svm, and others), the training code will always fail with this error:

```
AttributeError: 'NoneType' object has no attribute 'continue_learning'
```

This is cause by [this code in main_loop at pylab2/train.py](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/train.py#L147):

```
        if self.algorithm is None:
          while True:
            if self.exceeded_time_budget(t0, time_budget):
                break
            continue_learning = \
                self.algorithm.continue_learning(self.model)
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pylearn2/train.py`
Content:
```
1 """Module containing the Train class and support functionality."""
2 __authors__ = "Ian Goodfellow"
3 __copyright__ = "Copyright 2010-2012, Universite de Montreal"
4 __credits__ = ["Ian Goodfellow"]
5 __license__ = "3-clause BSD"
6 __maintainer__ = "LISA Lab"
7 __email__ = "pylearn-dev@googlegroups"
8 from datetime import datetime
9 import os
10 import sys
11 import logging
12 import warnings
13 from pylearn2.utils import serial
14 from pylearn2.utils.string_utils import preprocess
15 from pylearn2.monitor import Monitor
16 from pylearn2.space import NullSpace
17 from pylearn2.utils.timing import log_timing, total_seconds
18 from pylearn2.utils import sharedX
19 
20 
21 log = logging.getLogger(__name__)
22 
23 
24 class Train(object):
25     """
26     A class representing the main loop of the training script.  Trains the
27     specified model using the specified algorithm on the specified dataset.
28     After each call to the training algorithm, the model is saved to
29     `save_path`. May be enhanced with `TrainExtension` plugins.
30 
31     Parameters
32     ----------
33     dataset : `pylearn2.datasets.dataset.Dataset`
34     model : `pylearn2.models.model.Model`
35     algorithm : \
36         `pylearn2.training_algorithms.training_algorithm.TrainingAlgorithm`, \
37         optional
38     save_path : str, optional
39         Path to save (with pickle / joblib) the model.
40     save_freq : int, optional
41         Frequency of saves, in epochs. A frequency of zero disables
42         automatic saving altogether. A frequency of 1 saves every
43         epoch. A frequency of 2 saves every other epoch, etc.
44         (default=0, i.e. never save). Note: when automatic saving is
45         enabled (eg save_freq > 0), the model is always saved after
46         learning, even when the final epoch is not a multiple of
47         `save_freq`.
48     extensions : iterable, optional
49         A collection of `TrainExtension` objects whose callbacks are
50         triggered at various points in learning.
51     allow_overwrite : bool, optional
52         If `True`, will save the model to save_path even if there is
53         already something there. Otherwise, will raise an error if the
54         `save_path` is already occupied.
55     """
56 
57     def __init__(self, dataset, model, algorithm=None, save_path=None,
58                  save_freq=0, extensions=None, allow_overwrite=True):
59         self.allow_overwrite = allow_overwrite
60         self.first_save = True
61         self.dataset = dataset
62         self.model = model
63         self.algorithm = algorithm
64         if save_path is not None:
65             if save_freq == 0:
66                 warnings.warn('save_path specified but save_freq is 0 '
67                               '(never save). Is this intentional?')
68             self.save_path = preprocess(save_path)
69         else:
70             if save_freq > 0:
71                 phase_variable = 'PYLEARN2_TRAIN_PHASE'
72                 if phase_variable in os.environ:
73                     phase = 'phase%d' % os.environ[phase_variable]
74                     tokens = [os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'],
75                               phase, 'pkl']
76                 else:
77                     tokens = os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'], 'pkl'
78                 self.save_path = '.'.join(tokens)
79         self.save_freq = save_freq
80 
81         if hasattr(self.dataset, 'yaml_src'):
82             self.model.dataset_yaml_src = self.dataset.yaml_src
83         else:
84             warnings.warn("dataset has no yaml src, model won't know what " +
85                           "data it was trained on")
86 
87         self.extensions = extensions if extensions is not None else []
88         self.training_seconds = sharedX(value=0,
89                                         name='training_seconds_this_epoch')
90         self.total_seconds = sharedX(value=0, name='total_seconds_last_epoch')
91 
92     def setup_extensions(self):
93         """ Calls setup on all extensions."""
94         for ext in self.extensions:
95             ext.setup(self.model, self.dataset, self.algorithm)
96 
97     def exceeded_time_budget(self, t0, time_budget):
98         """
99         .. todo::
100 
101             WRITEME
102         """
103         dt = total_seconds(datetime.now() - t0)
104         if time_budget is not None and dt >= time_budget:
105             log.warning("Time budget exceeded (%.3f/%d seconds).",
106                         dt, time_budget)
107             self.model.monitor.time_budget_exceeded = True
108             return True
109         else:
110             return False
111 
112     def setup(self):
113         """
114         Sets up the main loop. This is also called at the start of the
115         main loop, so you need only call it if you're using a driver
116         script that replaces the main loop with something else.
117         """
118         self.model.monitor = Monitor.get_monitor(self.model)
119         self.model.monitor.time_budget_exceeded = False
120         if self.algorithm is not None:
121             self.algorithm.setup(model=self.model, dataset=self.dataset)
122         self.setup_extensions()
123 
124         # Model.censor_updates is used by the training algorithm to
125         # enforce constraints after each step of learning. Here we
126         # make sure the constraints are enforced from the start.
127         self.model.enforce_constraints()
128 
129     def main_loop(self, time_budget=None):
130         """
131         Repeatedly runs an epoch of the training algorithm, runs any
132         epoch-level callbacks, and saves the model.
133 
134         Parameters
135         ----------
136         time_budget : int, optional
137             The maximum number of seconds before interrupting
138             training. Default is `None`, no time limit.
139         """
140         t0 = datetime.now()
141         self.setup()
142         if self.algorithm is None:
143             while True:
144                 if self.exceeded_time_budget(t0, time_budget):
145                     break
146                 continue_learning = \
147                     self.algorithm.continue_learning(self.model)
148                 extension_continue = self.run_callbacks_and_monitoring()
149                 assert continue_learning in [True, False, 0, 1]
150                 if not continue_learning or not extension_continue:
151                     break
152 
153                 rval = self.model.train_all(dataset=self.dataset)
154                 if rval is not None:
155                     raise ValueError("Model.train_all should not return " +
156                                      "anything. Use Model.continue_learning " +
157                                      "to control whether learning continues.")
158                 self.model.monitor.report_epoch()
159                 extension_continue = self.run_callbacks_and_monitoring()
160                 freq = self.save_freq
161                 epochs_seen = self.model.monitor.get_epochs_seen()
162                 if freq > 0 and epochs_seen % freq == 0:
163                     self.save()
164         else:
165             if not hasattr(self.model, 'monitor'):
166                 # TODO: is this really necessary? I just put this error here
167                 # to prevent an AttributeError later, but I think we could
168                 # rewrite to avoid the AttributeError
169                 raise RuntimeError("The algorithm is responsible for setting"
170                                    " up the Monitor, but failed to.")
171             if len(self.model.monitor._datasets) > 0:
172                 # This monitoring channel keeps track of a shared variable,
173                 # which does not need inputs nor data.
174                 self.training_seconds.__doc__ = """\
175 The number of seconds that were spent in actual training during the most
176 recent epoch. This excludes seconds that were spent running callbacks for
177 the extensions, computing monitoring channels, etc."""
178                 self.model.monitor.add_channel(
179                     name="training_seconds_this_epoch",
180                     ipt=None,
181                     val=self.training_seconds,
182                     data_specs=(NullSpace(), ''),
183                     dataset=self.model.monitor._datasets[0])
184                 self.total_seconds.__doc__ = """\
185 The number of seconds that were spent on the entirety of processing for the
186 previous epoch. This includes not only training but also the computation of
187 the monitoring channels, running TrainExtension callbacks, etc. This value
188 is reported for the *previous* epoch because the amount of time spent on
189 monitoring for this epoch is not known until the monitoring channels have
190 already been reported."""
191                 self.model.monitor.add_channel(
192                     name="total_seconds_last_epoch",
193                     ipt=None,
194                     val=self.total_seconds,
195                     data_specs=(NullSpace(), ''),
196                     dataset=self.model.monitor._datasets[0])
197 
198             while True:
199                 if self.exceeded_time_budget(t0, time_budget):
200                     break
201 
202                 with log_timing(log, None, level=logging.DEBUG,
203                                 callbacks=[self.total_seconds.set_value]):
204                     with log_timing(
205                             log, None, final_msg='Time this epoch:',
206                             callbacks=[self.training_seconds.set_value]):
207 
208                         continue_learning = (
209                             self.algorithm.continue_learning(self.model)
210                         )
211                         extension_continue = (
212                             self.run_callbacks_and_monitoring()
213                         )
214                         assert continue_learning in [True, False, 0, 1]
215                         if not continue_learning or not extension_continue:
216                             break
217 
218                         rval = self.algorithm.train(dataset=self.dataset)
219                     if rval is not None:
220                         raise ValueError("TrainingAlgorithm.train should not "
221                                          "return anything. Use "
222                                          "TrainingAlgorithm.continue_learning "
223                                          "to control whether learning "
224                                          "continues.")
225                     self.model.monitor.report_epoch()
226                     freq = self.save_freq
227                     epochs_seen = self.model.monitor.get_epochs_seen()
228                     if freq > 0 and epochs_seen % self.save_freq == 0:
229                         self.save()
230 
231         self.model.monitor.training_succeeded = True
232 
233         if self.save_freq > 0:
234             self.save()
235 
236     def run_callbacks_and_monitoring(self):
237         """
238         Runs the monitor, then calls Extension.on_monitor for all extensions.
239 
240         Returns
241         -------
242         continue_learning : bool
243             If `False`, signals that at least one train
244             extension wants to stop learning.
245         """
246         self.model.monitor()
247         continue_learning = True
248         for extension in self.extensions:
249             try:
250                 extension.on_monitor(self.model, self.dataset, self.algorithm)
251             except TypeError:
252                 logging.warning('Failure during callback ' + str(extension))
253                 raise
254             # We catch an exception here instead of relying on return
255             # values for backward compatibility. Lots of extensions
256             # exist that don't return anything, currently.
257             except StopIteration:
258                 log.info("Extension requested training halt.")
259                 continue_learning = False
260         return continue_learning
261 
262     def save(self):
263         """Saves the model."""
264         #TODO-- save state of training algorithm so training can be
265         # resumed after a crash
266         for extension in self.extensions:
267             extension.on_save(self.model, self.dataset, self.algorithm)
268         if self.save_path is not None:
269             with log_timing(log, 'Saving to ' + self.save_path):
270                 if self.first_save and (not self.allow_overwrite) \
271                    and os.path.exists(self.save_path):
272                     # Every job overwrites its own output on the second save
273                     # and every save thereafter. The "allow_overwrite" flag
274                     # only pertains to overwriting the output of previous jobs.
275                     raise IOError("Trying to overwrite file when not allowed.")
276                 try:
277                     # Make sure that saving does not serialize the dataset
278                     self.dataset._serialization_guard = SerializationGuard()
279                     serial.save(self.save_path, self.model,
280                                 on_overwrite='backup')
281                 finally:
282                     self.dataset._serialization_guard = None
283             self.first_save = False
284 
285 
286 class SerializationGuard(object):
287     """
288     This class exists to make objects that cannot be serialized. It is used to
289     make sure you don't accidentally put pointers to objects that should not
290     be serialized, such as the dataset, into objects that Train automatically
291     serializes, such as the Model.
292     """
293 
294     def __getstate__(self):
295         """
296         This method is called when someone attempts to serialize the object.
297         This method raises an exception to prevent the serialization from
298         occurring.
299         """
300         raise IOError("You tried to serialize something that should not"
301                       " be serialized.")
302 
303 
304 if __name__ == "__main__":
305     logging.basicConfig(level=logging.ERROR)
306     log.error("You probably meant to run scripts/train.py")
307     sys.exit(1)
308
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pylearn2/train.py b/pylearn2/train.py
--- a/pylearn2/train.py
+++ b/pylearn2/train.py
@@ -143,8 +143,7 @@
             while True:
                 if self.exceeded_time_budget(t0, time_budget):
                     break
-                continue_learning = \
-                    self.algorithm.continue_learning(self.model)
+                continue_learning = self.model.continue_learning()
                 extension_continue = self.run_callbacks_and_monitoring()
                 assert continue_learning in [True, False, 0, 1]
                 if not continue_learning or not extension_continue:

{"golden_diff": "diff --git a/pylearn2/train.py b/pylearn2/train.py\n--- a/pylearn2/train.py\n+++ b/pylearn2/train.py\n@@ -143,8 +143,7 @@\n             while True:\n                 if self.exceeded_time_budget(t0, time_budget):\n                     break\n-                continue_learning = \\\n-                    self.algorithm.continue_learning(self.model)\n+                continue_learning = self.model.continue_learning()\n                 extension_continue = self.run_callbacks_and_monitoring()\n                 assert continue_learning in [True, False, 0, 1]\n                 if not continue_learning or not extension_continue:\n", "issue": "AttributeError: 'NoneType' object has no attribute 'continue_learning'\nIf no algorithm is set from the .yaml file (it is the case in kmeans, svm, and others), the training code will always fail with this error:\n\n```\nAttributeError: 'NoneType' object has no attribute 'continue_learning'\n```\n\nThis is cause by [this code in main_loop at pylab2/train.py](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/train.py#L147):\n\n```\n        if self.algorithm is None:\n          while True:\n            if self.exceeded_time_budget(t0, time_budget):\n                break\n            continue_learning = \\\n                self.algorithm.continue_learning(self.model)\n```\n\n", "before_files": [{"content": "\"\"\"Module containing the Train class and support functionality.\"\"\"\n__authors__ = \"Ian Goodfellow\"\n__copyright__ = \"Copyright 2010-2012, Universite de Montreal\"\n__credits__ = [\"Ian Goodfellow\"]\n__license__ = \"3-clause BSD\"\n__maintainer__ = \"LISA Lab\"\n__email__ = \"pylearn-dev@googlegroups\"\nfrom datetime import datetime\nimport os\nimport sys\nimport logging\nimport warnings\nfrom pylearn2.utils import serial\nfrom pylearn2.utils.string_utils import preprocess\nfrom pylearn2.monitor import Monitor\nfrom pylearn2.space import NullSpace\nfrom pylearn2.utils.timing import log_timing, total_seconds\nfrom pylearn2.utils import sharedX\n\n\nlog = logging.getLogger(__name__)\n\n\nclass Train(object):\n    \"\"\"\n    A class representing the main loop of the training script.  Trains the\n    specified model using the specified algorithm on the specified dataset.\n    After each call to the training algorithm, the model is saved to\n    `save_path`. May be enhanced with `TrainExtension` plugins.\n\n    Parameters\n    ----------\n    dataset : `pylearn2.datasets.dataset.Dataset`\n    model : `pylearn2.models.model.Model`\n    algorithm : \\\n        `pylearn2.training_algorithms.training_algorithm.TrainingAlgorithm`, \\\n        optional\n    save_path : str, optional\n        Path to save (with pickle / joblib) the model.\n    save_freq : int, optional\n        Frequency of saves, in epochs. A frequency of zero disables\n        automatic saving altogether. A frequency of 1 saves every\n        epoch. A frequency of 2 saves every other epoch, etc.\n        (default=0, i.e. never save). Note: when automatic saving is\n        enabled (eg save_freq > 0), the model is always saved after\n        learning, even when the final epoch is not a multiple of\n        `save_freq`.\n    extensions : iterable, optional\n        A collection of `TrainExtension` objects whose callbacks are\n        triggered at various points in learning.\n    allow_overwrite : bool, optional\n        If `True`, will save the model to save_path even if there is\n        already something there. Otherwise, will raise an error if the\n        `save_path` is already occupied.\n    \"\"\"\n\n    def __init__(self, dataset, model, algorithm=None, save_path=None,\n                 save_freq=0, extensions=None, allow_overwrite=True):\n        self.allow_overwrite = allow_overwrite\n        self.first_save = True\n        self.dataset = dataset\n        self.model = model\n        self.algorithm = algorithm\n        if save_path is not None:\n            if save_freq == 0:\n                warnings.warn('save_path specified but save_freq is 0 '\n                              '(never save). Is this intentional?')\n            self.save_path = preprocess(save_path)\n        else:\n            if save_freq > 0:\n                phase_variable = 'PYLEARN2_TRAIN_PHASE'\n                if phase_variable in os.environ:\n                    phase = 'phase%d' % os.environ[phase_variable]\n                    tokens = [os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'],\n                              phase, 'pkl']\n                else:\n                    tokens = os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'], 'pkl'\n                self.save_path = '.'.join(tokens)\n        self.save_freq = save_freq\n\n        if hasattr(self.dataset, 'yaml_src'):\n            self.model.dataset_yaml_src = self.dataset.yaml_src\n        else:\n            warnings.warn(\"dataset has no yaml src, model won't know what \" +\n                          \"data it was trained on\")\n\n        self.extensions = extensions if extensions is not None else []\n        self.training_seconds = sharedX(value=0,\n                                        name='training_seconds_this_epoch')\n        self.total_seconds = sharedX(value=0, name='total_seconds_last_epoch')\n\n    def setup_extensions(self):\n        \"\"\" Calls setup on all extensions.\"\"\"\n        for ext in self.extensions:\n            ext.setup(self.model, self.dataset, self.algorithm)\n\n    def exceeded_time_budget(self, t0, time_budget):\n        \"\"\"\n        .. todo::\n\n            WRITEME\n        \"\"\"\n        dt = total_seconds(datetime.now() - t0)\n        if time_budget is not None and dt >= time_budget:\n            log.warning(\"Time budget exceeded (%.3f/%d seconds).\",\n                        dt, time_budget)\n            self.model.monitor.time_budget_exceeded = True\n            return True\n        else:\n            return False\n\n    def setup(self):\n        \"\"\"\n        Sets up the main loop. This is also called at the start of the\n        main loop, so you need only call it if you're using a driver\n        script that replaces the main loop with something else.\n        \"\"\"\n        self.model.monitor = Monitor.get_monitor(self.model)\n        self.model.monitor.time_budget_exceeded = False\n        if self.algorithm is not None:\n            self.algorithm.setup(model=self.model, dataset=self.dataset)\n        self.setup_extensions()\n\n        # Model.censor_updates is used by the training algorithm to\n        # enforce constraints after each step of learning. Here we\n        # make sure the constraints are enforced from the start.\n        self.model.enforce_constraints()\n\n    def main_loop(self, time_budget=None):\n        \"\"\"\n        Repeatedly runs an epoch of the training algorithm, runs any\n        epoch-level callbacks, and saves the model.\n\n        Parameters\n        ----------\n        time_budget : int, optional\n            The maximum number of seconds before interrupting\n            training. Default is `None`, no time limit.\n        \"\"\"\n        t0 = datetime.now()\n        self.setup()\n        if self.algorithm is None:\n            while True:\n                if self.exceeded_time_budget(t0, time_budget):\n                    break\n                continue_learning = \\\n                    self.algorithm.continue_learning(self.model)\n                extension_continue = self.run_callbacks_and_monitoring()\n                assert continue_learning in [True, False, 0, 1]\n                if not continue_learning or not extension_continue:\n                    break\n\n                rval = self.model.train_all(dataset=self.dataset)\n                if rval is not None:\n                    raise ValueError(\"Model.train_all should not return \" +\n                                     \"anything. Use Model.continue_learning \" +\n                                     \"to control whether learning continues.\")\n                self.model.monitor.report_epoch()\n                extension_continue = self.run_callbacks_and_monitoring()\n                freq = self.save_freq\n                epochs_seen = self.model.monitor.get_epochs_seen()\n                if freq > 0 and epochs_seen % freq == 0:\n                    self.save()\n        else:\n            if not hasattr(self.model, 'monitor'):\n                # TODO: is this really necessary? I just put this error here\n                # to prevent an AttributeError later, but I think we could\n                # rewrite to avoid the AttributeError\n                raise RuntimeError(\"The algorithm is responsible for setting\"\n                                   \" up the Monitor, but failed to.\")\n            if len(self.model.monitor._datasets) > 0:\n                # This monitoring channel keeps track of a shared variable,\n                # which does not need inputs nor data.\n                self.training_seconds.__doc__ = \"\"\"\\\nThe number of seconds that were spent in actual training during the most\nrecent epoch. This excludes seconds that were spent running callbacks for\nthe extensions, computing monitoring channels, etc.\"\"\"\n                self.model.monitor.add_channel(\n                    name=\"training_seconds_this_epoch\",\n                    ipt=None,\n                    val=self.training_seconds,\n                    data_specs=(NullSpace(), ''),\n                    dataset=self.model.monitor._datasets[0])\n                self.total_seconds.__doc__ = \"\"\"\\\nThe number of seconds that were spent on the entirety of processing for the\nprevious epoch. This includes not only training but also the computation of\nthe monitoring channels, running TrainExtension callbacks, etc. This value\nis reported for the *previous* epoch because the amount of time spent on\nmonitoring for this epoch is not known until the monitoring channels have\nalready been reported.\"\"\"\n                self.model.monitor.add_channel(\n                    name=\"total_seconds_last_epoch\",\n                    ipt=None,\n                    val=self.total_seconds,\n                    data_specs=(NullSpace(), ''),\n                    dataset=self.model.monitor._datasets[0])\n\n            while True:\n                if self.exceeded_time_budget(t0, time_budget):\n                    break\n\n                with log_timing(log, None, level=logging.DEBUG,\n                                callbacks=[self.total_seconds.set_value]):\n                    with log_timing(\n                            log, None, final_msg='Time this epoch:',\n                            callbacks=[self.training_seconds.set_value]):\n\n                        continue_learning = (\n                            self.algorithm.continue_learning(self.model)\n                        )\n                        extension_continue = (\n                            self.run_callbacks_and_monitoring()\n                        )\n                        assert continue_learning in [True, False, 0, 1]\n                        if not continue_learning or not extension_continue:\n                            break\n\n                        rval = self.algorithm.train(dataset=self.dataset)\n                    if rval is not None:\n                        raise ValueError(\"TrainingAlgorithm.train should not \"\n                                         \"return anything. Use \"\n                                         \"TrainingAlgorithm.continue_learning \"\n                                         \"to control whether learning \"\n                                         \"continues.\")\n                    self.model.monitor.report_epoch()\n                    freq = self.save_freq\n                    epochs_seen = self.model.monitor.get_epochs_seen()\n                    if freq > 0 and epochs_seen % self.save_freq == 0:\n                        self.save()\n\n        self.model.monitor.training_succeeded = True\n\n        if self.save_freq > 0:\n            self.save()\n\n    def run_callbacks_and_monitoring(self):\n        \"\"\"\n        Runs the monitor, then calls Extension.on_monitor for all extensions.\n\n        Returns\n        -------\n        continue_learning : bool\n            If `False`, signals that at least one train\n            extension wants to stop learning.\n        \"\"\"\n        self.model.monitor()\n        continue_learning = True\n        for extension in self.extensions:\n            try:\n                extension.on_monitor(self.model, self.dataset, self.algorithm)\n            except TypeError:\n                logging.warning('Failure during callback ' + str(extension))\n                raise\n            # We catch an exception here instead of relying on return\n            # values for backward compatibility. Lots of extensions\n            # exist that don't return anything, currently.\n            except StopIteration:\n                log.info(\"Extension requested training halt.\")\n                continue_learning = False\n        return continue_learning\n\n    def save(self):\n        \"\"\"Saves the model.\"\"\"\n        #TODO-- save state of training algorithm so training can be\n        # resumed after a crash\n        for extension in self.extensions:\n            extension.on_save(self.model, self.dataset, self.algorithm)\n        if self.save_path is not None:\n            with log_timing(log, 'Saving to ' + self.save_path):\n                if self.first_save and (not self.allow_overwrite) \\\n                   and os.path.exists(self.save_path):\n                    # Every job overwrites its own output on the second save\n                    # and every save thereafter. The \"allow_overwrite\" flag\n                    # only pertains to overwriting the output of previous jobs.\n                    raise IOError(\"Trying to overwrite file when not allowed.\")\n                try:\n                    # Make sure that saving does not serialize the dataset\n                    self.dataset._serialization_guard = SerializationGuard()\n                    serial.save(self.save_path, self.model,\n                                on_overwrite='backup')\n                finally:\n                    self.dataset._serialization_guard = None\n            self.first_save = False\n\n\nclass SerializationGuard(object):\n    \"\"\"\n    This class exists to make objects that cannot be serialized. It is used to\n    make sure you don't accidentally put pointers to objects that should not\n    be serialized, such as the dataset, into objects that Train automatically\n    serializes, such as the Model.\n    \"\"\"\n\n    def __getstate__(self):\n        \"\"\"\n        This method is called when someone attempts to serialize the object.\n        This method raises an exception to prevent the serialization from\n        occurring.\n        \"\"\"\n        raise IOError(\"You tried to serialize something that should not\"\n                      \" be serialized.\")\n\n\nif __name__ == \"__main__\":\n    logging.basicConfig(level=logging.ERROR)\n    log.error(\"You probably meant to run scripts/train.py\")\n    sys.exit(1)\n", "path": "pylearn2/train.py"}], "after_files": [{"content": "\"\"\"Module containing the Train class and support functionality.\"\"\"\n__authors__ = \"Ian Goodfellow\"\n__copyright__ = \"Copyright 2010-2012, Universite de Montreal\"\n__credits__ = [\"Ian Goodfellow\"]\n__license__ = \"3-clause BSD\"\n__maintainer__ = \"LISA Lab\"\n__email__ = \"pylearn-dev@googlegroups\"\nfrom datetime import datetime\nimport os\nimport sys\nimport logging\nimport warnings\nfrom pylearn2.utils import serial\nfrom pylearn2.utils.string_utils import preprocess\nfrom pylearn2.monitor import Monitor\nfrom pylearn2.space import NullSpace\nfrom pylearn2.utils.timing import log_timing, total_seconds\nfrom pylearn2.utils import sharedX\n\n\nlog = logging.getLogger(__name__)\n\n\nclass Train(object):\n    \"\"\"\n    A class representing the main loop of the training script.  Trains the\n    specified model using the specified algorithm on the specified dataset.\n    After each call to the training algorithm, the model is saved to\n    `save_path`. May be enhanced with `TrainExtension` plugins.\n\n    Parameters\n    ----------\n    dataset : `pylearn2.datasets.dataset.Dataset`\n    model : `pylearn2.models.model.Model`\n    algorithm : \\\n        `pylearn2.training_algorithms.training_algorithm.TrainingAlgorithm`, \\\n        optional\n    save_path : str, optional\n        Path to save (with pickle / joblib) the model.\n    save_freq : int, optional\n        Frequency of saves, in epochs. A frequency of zero disables\n        automatic saving altogether. A frequency of 1 saves every\n        epoch. A frequency of 2 saves every other epoch, etc.\n        (default=0, i.e. never save). Note: when automatic saving is\n        enabled (eg save_freq > 0), the model is always saved after\n        learning, even when the final epoch is not a multiple of\n        `save_freq`.\n    extensions : iterable, optional\n        A collection of `TrainExtension` objects whose callbacks are\n        triggered at various points in learning.\n    allow_overwrite : bool, optional\n        If `True`, will save the model to save_path even if there is\n        already something there. Otherwise, will raise an error if the\n        `save_path` is already occupied.\n    \"\"\"\n\n    def __init__(self, dataset, model, algorithm=None, save_path=None,\n                 save_freq=0, extensions=None, allow_overwrite=True):\n        self.allow_overwrite = allow_overwrite\n        self.first_save = True\n        self.dataset = dataset\n        self.model = model\n        self.algorithm = algorithm\n        if save_path is not None:\n            if save_freq == 0:\n                warnings.warn('save_path specified but save_freq is 0 '\n                              '(never save). Is this intentional?')\n            self.save_path = preprocess(save_path)\n        else:\n            if save_freq > 0:\n                phase_variable = 'PYLEARN2_TRAIN_PHASE'\n                if phase_variable in os.environ:\n                    phase = 'phase%d' % os.environ[phase_variable]\n                    tokens = [os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'],\n                              phase, 'pkl']\n                else:\n                    tokens = os.environ['PYLEARN2_TRAIN_FILE_FULL_STEM'], 'pkl'\n                self.save_path = '.'.join(tokens)\n        self.save_freq = save_freq\n\n        if hasattr(self.dataset, 'yaml_src'):\n            self.model.dataset_yaml_src = self.dataset.yaml_src\n        else:\n            warnings.warn(\"dataset has no yaml src, model won't know what \" +\n                          \"data it was trained on\")\n\n        self.extensions = extensions if extensions is not None else []\n        self.training_seconds = sharedX(value=0,\n                                        name='training_seconds_this_epoch')\n        self.total_seconds = sharedX(value=0, name='total_seconds_last_epoch')\n\n    def setup_extensions(self):\n        \"\"\" Calls setup on all extensions.\"\"\"\n        for ext in self.extensions:\n            ext.setup(self.model, self.dataset, self.algorithm)\n\n    def exceeded_time_budget(self, t0, time_budget):\n        \"\"\"\n        .. todo::\n\n            WRITEME\n        \"\"\"\n        dt = total_seconds(datetime.now() - t0)\n        if time_budget is not None and dt >= time_budget:\n            log.warning(\"Time budget exceeded (%.3f/%d seconds).\",\n                        dt, time_budget)\n            self.model.monitor.time_budget_exceeded = True\n            return True\n        else:\n            return False\n\n    def setup(self):\n        \"\"\"\n        Sets up the main loop. This is also called at the start of the\n        main loop, so you need only call it if you're using a driver\n        script that replaces the main loop with something else.\n        \"\"\"\n        self.model.monitor = Monitor.get_monitor(self.model)\n        self.model.monitor.time_budget_exceeded = False\n        if self.algorithm is not None:\n            self.algorithm.setup(model=self.model, dataset=self.dataset)\n        self.setup_extensions()\n\n        # Model.censor_updates is used by the training algorithm to\n        # enforce constraints after each step of learning. Here we\n        # make sure the constraints are enforced from the start.\n        self.model.enforce_constraints()\n\n    def main_loop(self, time_budget=None):\n        \"\"\"\n        Repeatedly runs an epoch of the training algorithm, runs any\n        epoch-level callbacks, and saves the model.\n\n        Parameters\n        ----------\n        time_budget : int, optional\n            The maximum number of seconds before interrupting\n            training. Default is `None`, no time limit.\n        \"\"\"\n        t0 = datetime.now()\n        self.setup()\n        if self.algorithm is None:\n            while True:\n                if self.exceeded_time_budget(t0, time_budget):\n                    break\n                continue_learning = self.model.continue_learning()\n                extension_continue = self.run_callbacks_and_monitoring()\n                assert continue_learning in [True, False, 0, 1]\n                if not continue_learning or not extension_continue:\n                    break\n\n                rval = self.model.train_all(dataset=self.dataset)\n                if rval is not None:\n                    raise ValueError(\"Model.train_all should not return \" +\n                                     \"anything. Use Model.continue_learning \" +\n                                     \"to control whether learning continues.\")\n                self.model.monitor.report_epoch()\n                extension_continue = self.run_callbacks_and_monitoring()\n                freq = self.save_freq\n                epochs_seen = self.model.monitor.get_epochs_seen()\n                if freq > 0 and epochs_seen % freq == 0:\n                    self.save()\n        else:\n            if not hasattr(self.model, 'monitor'):\n                # TODO: is this really necessary? I just put this error here\n                # to prevent an AttributeError later, but I think we could\n                # rewrite to avoid the AttributeError\n                raise RuntimeError(\"The algorithm is responsible for setting\"\n                                   \" up the Monitor, but failed to.\")\n            if len(self.model.monitor._datasets) > 0:\n                # This monitoring channel keeps track of a shared variable,\n                # which does not need inputs nor data.\n                self.training_seconds.__doc__ = \"\"\"\\\nThe number of seconds that were spent in actual training during the most\nrecent epoch. This excludes seconds that were spent running callbacks for\nthe extensions, computing monitoring channels, etc.\"\"\"\n                self.model.monitor.add_channel(\n                    name=\"training_seconds_this_epoch\",\n                    ipt=None,\n                    val=self.training_seconds,\n                    data_specs=(NullSpace(), ''),\n                    dataset=self.model.monitor._datasets[0])\n                self.total_seconds.__doc__ = \"\"\"\\\nThe number of seconds that were spent on the entirety of processing for the\nprevious epoch. This includes not only training but also the computation of\nthe monitoring channels, running TrainExtension callbacks, etc. This value\nis reported for the *previous* epoch because the amount of time spent on\nmonitoring for this epoch is not known until the monitoring channels have\nalready been reported.\"\"\"\n                self.model.monitor.add_channel(\n                    name=\"total_seconds_last_epoch\",\n                    ipt=None,\n                    val=self.total_seconds,\n                    data_specs=(NullSpace(), ''),\n                    dataset=self.model.monitor._datasets[0])\n\n            while True:\n                if self.exceeded_time_budget(t0, time_budget):\n                    break\n\n                with log_timing(log, None, level=logging.DEBUG,\n                                callbacks=[self.total_seconds.set_value]):\n                    with log_timing(\n                            log, None, final_msg='Time this epoch:',\n                            callbacks=[self.training_seconds.set_value]):\n\n                        continue_learning = (\n                            self.algorithm.continue_learning(self.model)\n                        )\n                        extension_continue = (\n                            self.run_callbacks_and_monitoring()\n                        )\n                        assert continue_learning in [True, False, 0, 1]\n                        if not continue_learning or not extension_continue:\n                            break\n\n                        rval = self.algorithm.train(dataset=self.dataset)\n                    if rval is not None:\n                        raise ValueError(\"TrainingAlgorithm.train should not \"\n                                         \"return anything. Use \"\n                                         \"TrainingAlgorithm.continue_learning \"\n                                         \"to control whether learning \"\n                                         \"continues.\")\n                    self.model.monitor.report_epoch()\n                    freq = self.save_freq\n                    epochs_seen = self.model.monitor.get_epochs_seen()\n                    if freq > 0 and epochs_seen % self.save_freq == 0:\n                        self.save()\n\n        self.model.monitor.training_succeeded = True\n\n        if self.save_freq > 0:\n            self.save()\n\n    def run_callbacks_and_monitoring(self):\n        \"\"\"\n        Runs the monitor, then calls Extension.on_monitor for all extensions.\n\n        Returns\n        -------\n        continue_learning : bool\n            If `False`, signals that at least one train\n            extension wants to stop learning.\n        \"\"\"\n        self.model.monitor()\n        continue_learning = True\n        for extension in self.extensions:\n            try:\n                extension.on_monitor(self.model, self.dataset, self.algorithm)\n            except TypeError:\n                logging.warning('Failure during callback ' + str(extension))\n                raise\n            # We catch an exception here instead of relying on return\n            # values for backward compatibility. Lots of extensions\n            # exist that don't return anything, currently.\n            except StopIteration:\n                log.info(\"Extension requested training halt.\")\n                continue_learning = False\n        return continue_learning\n\n    def save(self):\n        \"\"\"Saves the model.\"\"\"\n        #TODO-- save state of training algorithm so training can be\n        # resumed after a crash\n        for extension in self.extensions:\n            extension.on_save(self.model, self.dataset, self.algorithm)\n        if self.save_path is not None:\n            with log_timing(log, 'Saving to ' + self.save_path):\n                if self.first_save and (not self.allow_overwrite) \\\n                   and os.path.exists(self.save_path):\n                    # Every job overwrites its own output on the second save\n                    # and every save thereafter. The \"allow_overwrite\" flag\n                    # only pertains to overwriting the output of previous jobs.\n                    raise IOError(\"Trying to overwrite file when not allowed.\")\n                try:\n                    # Make sure that saving does not serialize the dataset\n                    self.dataset._serialization_guard = SerializationGuard()\n                    serial.save(self.save_path, self.model,\n                                on_overwrite='backup')\n                finally:\n                    self.dataset._serialization_guard = None\n            self.first_save = False\n\n\nclass SerializationGuard(object):\n    \"\"\"\n    This class exists to make objects that cannot be serialized. It is used to\n    make sure you don't accidentally put pointers to objects that should not\n    be serialized, such as the dataset, into objects that Train automatically\n    serializes, such as the Model.\n    \"\"\"\n\n    def __getstate__(self):\n        \"\"\"\n        This method is called when someone attempts to serialize the object.\n        This method raises an exception to prevent the serialization from\n        occurring.\n        \"\"\"\n        raise IOError(\"You tried to serialize something that should not\"\n                      \" be serialized.\")\n\n\nif __name__ == \"__main__\":\n    logging.basicConfig(level=logging.ERROR)\n    log.error(\"You probably meant to run scripts/train.py\")\n    sys.exit(1)\n", "path": "pylearn2/train.py"}]}