diff learner.py @ 134:3f4e5c9bdc5e

Fixes to ApplyFunctionDataSet and other things to make learner and mlp work
author Yoshua Bengio <bengioy@iro.umontreal.ca>
date Fri, 09 May 2008 17:38:57 -0400
parents b4657441dd65
children 0d8e721cc63c b7ca3545186b
line wrap: on
line diff
--- a/learner.py	Fri May 09 13:38:54 2008 -0400
+++ b/learner.py	Fri May 09 17:38:57 2008 -0400
@@ -1,6 +1,7 @@
 
-from dataset import AttributesHolder,AbstractFunction
-import compile
+from dataset import AttributesHolder,AbstractFunction,ApplyFunctionDataSet,DataSet,CachedDataSet
+import theano
+from theano import compile
 from theano import tensor as t
     
 class Learner(AttributesHolder):
@@ -132,22 +133,16 @@
         """
         return self.names2attributes(self.attributeNames(),return_copy)
 
-    def names2attributes(self,names,return_copy=False):
+    def names2attributes(self,names):
         """
         Private helper function that maps a list of attribute names to a list
         of (optionally copies) values of attributes.
         """
-        if return_copy:
-            return [copy.deepcopy(self.__getattribute__(name).data) for name in names]
-        else:
-            return [self.__getattribute__(name).data for name in names]
-
-    def updateInputAttributes(self):
-        """
-        A subset of self.attributeNames() which are the names of attributes needed by update() in order
-        to do its work.
-        """
-        raise AbstractFunction()
+        res=[]
+        for name in names:
+            assert name in names
+            res.append(self.__getattribute__(name))
+        return res
 
     def useInputAttributes(self):
         """
@@ -156,15 +151,6 @@
         """
         raise AbstractFunction()
 
-    def updateOutputAttributes(self):
-        """
-        A subset of self.attributeNames() which are the names of attributes modified/created by update() in order
-        to do its work.
-
-        By default these are inferred from the various update output attributes:
-        """
-        return ["parameters"] + self.updateMinibatchOutputAttributes() + self.updateEndOutputAttributes()
-
     def useOutputAttributes(self):
         """
         A subset of self.attributeNames() which are the names of attributes modified/created by use() in order
@@ -210,6 +196,7 @@
 
     def __init__(self):
         Learner.__init__(self)
+        self.use_functions_dictionary={}
 
     def defaultOutputFields(self, input_fields):
         """
@@ -232,7 +219,7 @@
             for attribute in stats_collector_inputs:
                 if attribute not in input_fields:
                     output_fields.append(attribute)
-        key = (input_fields,output_fields)
+        key = (tuple(input_fields),tuple(output_fields))
         if key not in self.use_functions_dictionary:
             use_input_attributes = self.useInputAttributes()
             use_output_attributes = self.useOutputAttributes()
@@ -240,7 +227,7 @@
                                           self.names2OpResults(output_fields+use_output_attributes))
             def f(*input_field_values):
                 input_attribute_values = self.names2attributes(use_input_attributes)
-                results = complete_f(*(input_field_values + input_attribute_values))
+                results = complete_f(*(list(input_field_values) + input_attribute_values))
                 output_field_values = results[0:len(output_fields)]
                 output_attribute_values = results[len(output_fields):len(results)]
                 if use_output_attributes:
@@ -276,13 +263,11 @@
 
     def __init__(self):
         TLearner.__init__(self)
-        self.update_minibatch_function = compile.function
-        (self.names2OpResults(self.updateMinibatchOutputAttributes()+
-                              self.updateMinibatchInputFields()),
-                 self.names2OpResults(self.updateMinibatchOutputAttributes()))
-        self.update_end_function = compile.function
-        (self.names2OpResults(self.updateEndInputAttributes()),
-         self.names2OpResults(self.updateEndOutputAttributes()))
+        self.update_minibatch_function = compile.function(self.names2OpResults(self.updateMinibatchOutputAttributes()+
+                                                                               self.updateMinibatchInputFields()),
+                                                          self.names2OpResults(self.updateMinibatchOutputAttributes()))
+        self.update_end_function = compile.function(self.names2OpResults(self.updateEndInputAttributes()),
+                                                    self.names2OpResults(self.updateEndOutputAttributes()))
 
     def allocate(self, minibatch):
         """
@@ -316,18 +301,17 @@
 
     def updateEnd(self):
         self.setAttributes(self.updateEndOutputAttributes(),
-                           self.update_end_function
-                           (self.names2attributes(self.updateEndInputAttributes())))
+                           self.update_end_function(*self.names2attributes(self.updateEndInputAttributes())))
         self.parameters = self.names2attributes(self.parameterAttributes())
         
     def updateMinibatch(self,minibatch):
         # make sure all required fields are allocated and initialized
         self.allocate(minibatch)
+        input_attributes = self.names2attributes(self.updateMinibatchInputAttributes())
+        input_fields = minibatch(*self.updateMinibatchInputFields())
         self.setAttributes(self.updateMinibatchOutputAttributes(),
                            # concatenate the attribute values and field values and then apply update fn
-                           self.update_minibatch_function(*(self.names2attributes
-                                                            (self.updateMinibatchInputAttributes()))
-                                                          + minibatch(self.updateMinibatchInputFields())))
+                           self.update_minibatch_function(*(input_attributes+input_fields)))
         
     def isLastEpoch(self):
         """
@@ -387,6 +371,24 @@
                             for param in old_params])
         MinibatchUpdatesTLearner.__init__(self)
         
+
+    def namesOfAttributesToComputeOutputs(self,output_names):
+        """
+        The output_names are attribute names (not the corresponding Result names, which have leading _).
+        Return the corresponding input names
+        """
+        all_inputs = t.gof.graph.inputs(self.names2OpResults(output_names))
+        # remove constants and leading '_' in name
+
+        return [r.name for r in all_inputs if isinstance(r,theano.Result) and \
+                not isinstance(r,theano.Constant) and not isinstance(r,theano.Value)]
+        #inputs = []
+        #for r in all_inputs:
+        #    if isinstance(r,theano.Result) and \
+        #    not isinstance(r,theano.Constant) and not isinstance(r,theano.Value):
+        #       inputs.append(r.name)
+        #return inputs
+        
     def isLastEpoch(self):
         return self.truly_online
 
@@ -397,6 +399,11 @@
         return ["new_"+name for name in self.parameterAttributes()]
     
     def updateEndInputAttributes(self):
+        return self.namesOfAttributesToComputeOutputs(self.updateEndOutputAttributes())
+
+    def useInputAttributes(self):
         return self.parameterAttributes()
 
+    def useOutputAttributes(self):
+        return []