Repository: lisa-lab/pylearn2

Issue:
Update default training algorithm to support multiple monitoring datasets
Just follow SGD or BGD for an example



Discussion:
@sinahonari: I think you are already using DefaultTrainingAlgorithm, so this one is for you.

ok


Resolving patch:
diff --git a/pylearn2/training_algorithms/default.py b/pylearn2/training_algorithms/default.py
--- a/pylearn2/training_algorithms/default.py
+++ b/pylearn2/training_algorithms/default.py
@@ -29,7 +29,8 @@ def __init__(self, batch_size=None, batches_per_iter=1000,
             WRITEME
         monitoring_batches : int
             WRITEME
-        monitoring_dataset : WRITEME
+        monitoring_dataset: Dataset or dict
+            A Dataset or a dictionary mapping string dataset names to Datasets
         termination_criterion : WRITEME
             If specified, can cause the algorithm to terminate before \
             `model.learn_batch` says to
@@ -37,7 +38,8 @@ def __init__(self, batch_size=None, batches_per_iter=1000,
         self.batch_size, self.batches_per_iter = batch_size, batches_per_iter
         if monitoring_dataset is None:
             assert monitoring_batches == -1
-        self.monitoring_dataset = monitoring_dataset
+
+        self._set_monitoring_dataset(monitoring_dataset)
         self.monitoring_batches = monitoring_batches
         self.bSetup = False
         self.termination_criterion = termination_criterion
@@ -74,33 +76,42 @@ def setup(self, model, dataset):
             source_tuple = mapping.flatten(source, return_tuple=True)
             # Then, build a flat tuple of these Theano variables
             ipt = tuple(sp.make_theano_batch(name='monitor_%s' % src)
-                    for (sp, src) in safe_zip(space_tuple, source_tuple))
+                        for (sp, src) in safe_zip(space_tuple, source_tuple))
             # Finally, organize them back into a structure expected by the
             # monitoring channels of the model
             nested_ipt = mapping.nest(ipt)
 
-            self.monitor.add_dataset(dataset=self.monitoring_dataset,
-                                mode="sequential",
-                                batch_size=self.batch_size,
-                                num_batches=self.monitoring_batches)
-
             channels = model.get_monitoring_channels(nested_ipt)
             if not isinstance(channels, dict):
                 raise TypeError("model.get_monitoring_channels must return a "
                                 "dictionary, but it returned " + str(channels))
-            for name in channels:
-                J = channels[name]
-                if isinstance(J, tuple):
-                    assert len(J) == 2
-                    J, prereqs = J
+
+            for dataset_name in self.monitoring_dataset:
+                if dataset_name == '':
+                    prefix = ''
                 else:
-                    prereqs = None
+                    prefix = dataset_name + '_'
+                monitoring_dataset = self.monitoring_dataset[dataset_name]
+
+                self.monitor.add_dataset(dataset=monitoring_dataset,
+                                         mode="sequential",
+                                         batch_size=self.batch_size)
+
+                for name in channels:
+                    J = channels[name]
+                    if isinstance(J, tuple):
+                        assert len(J) == 2
+                        J, prereqs = J
+                    else:
+                        prereqs = None
+
+                    self.monitor.add_channel(name=prefix + name,
+                                             ipt=nested_ipt,
+                                             val=J,
+                                             dataset=monitoring_dataset,
+                                             prereqs=prereqs,
+                                             data_specs=(space, source))
 
-                self.monitor.add_channel(name=name,
-                                         ipt=nested_ipt,
-                                         val=J,
-                                         prereqs=prereqs,
-                                         data_specs=(space, source))
         self.first = True
         self.bSetup = True
 
@@ -130,7 +141,7 @@ def train(self, dataset):
 
         # Make sure we didn't exit training loop because Model.learn
         # hasn't been updated to new interface yet.
-        if learn_more not in [True,False]:
+        if learn_more not in [True, False]:
             msg = ('The learn method of model %s did not return a boolean ' +
                    'value. Please update your model accordingly.')
             raise ValueError(msg % str(model))


Test patch:
diff --git a/pylearn2/training_algorithms/tests/test_default.py b/pylearn2/training_algorithms/tests/test_default.py
new file mode 100644
--- /dev/null
+++ b/pylearn2/training_algorithms/tests/test_default.py
@@ -0,0 +1,41 @@
+import numpy as np
+
+from pylearn2.datasets.dense_design_matrix import DenseDesignMatrix
+from pylearn2.training_algorithms.default import DefaultTrainingAlgorithm
+from pylearn2.models.s3c import S3C, E_Step, Grad_M_Step
+
+
+def test_multiple_monitoring_datasets():
+    # tests that DefaultTrainingAlgorithm can take multiple
+    # monitoring datasets.
+
+    BATCH_SIZE = 2
+    BATCHES = 3
+    NUM_FEATURES = 4
+    dim = 3
+    m = 10
+
+    rng = np.random.RandomState([2014, 02, 25])
+    X = rng.randn(m, dim)
+    Y = rng.randn(m, dim)
+
+    train = DenseDesignMatrix(X=X)
+    test = DenseDesignMatrix(X=Y)
+
+    algorithm = DefaultTrainingAlgorithm(
+        batch_size=BATCH_SIZE,
+        batches_per_iter=BATCHES,
+        monitoring_dataset={'train': train, 'test': test})
+
+    model = S3C(nvis=NUM_FEATURES, nhid=1,
+                irange=.01, init_bias_hid=0., init_B=1.,
+                min_B=1., max_B=1., init_alpha=1.,
+                min_alpha=1., max_alpha=1., init_mu=0.,
+                m_step=Grad_M_Step(learning_rate=0.),
+                e_step=E_Step(h_new_coeff_schedule=[1.]))
+
+    algorithm.setup(model=model, dataset=train)
+    algorithm.train(dataset=train)
+
+if __name__ == '__main__':
+    test_multiple_monitoring_datasets()