Mercurial > pylearn
diff learner.py @ 92:c4726e19b8ec
Finished first draft of TLearner
author | Yoshua Bengio <bengioy@iro.umontreal.ca> |
---|---|
date | Mon, 05 May 2008 18:14:32 -0400 |
parents | 3499918faa9d |
children | c4916445e025 |
line wrap: on
line diff
--- a/learner.py Mon May 05 11:49:40 2008 -0400 +++ b/learner.py Mon May 05 18:14:32 2008 -0400 @@ -57,7 +57,7 @@ """ raise NotImplementedError - def attribute_names(self): + def attributeNames(self): """ A Learner may have attributes that it wishes to export to other objects. To automate such export, sub-classes should define here the names (list of strings) of these attributes. @@ -85,7 +85,111 @@ or by a stats collector. - defaultOutputFields(input_fields): return a list of default dataset output fields when None are provided by the caller of use. - - - + - update_start(), update_end(), update_minibatch(minibatch): functions + executed at the beginning, the end, and in the middle + (for each minibatch) of the update method. This model only + works for 'online' or one-short learning that requires + going only once through the training data. For more complicated + models, more specialized subclasses of TLearner should be used + or a learning-algorithm specific update method should be defined. + + The following naming convention is assumed and important. + Attributes whose names are listed in attributeNames() can be of any type, + but those that can be referenced as input/output dataset fields or as + output attributes in 'use' or as input attributes in the stats collector + should be associated with a Theano Result variable. If the exported attribute + name is <name>, the corresponding Result name (an internal attribute of + the TLearner, created in the sub-class constructor) should be _<name>. + Typically <name> will be numpy ndarray and _<name> will be the corresponding + Theano Tensor (for symbolic manipulation). """ + + def __init__(self): + Learner.__init__(self) + + def _minibatchwise_use_functions(self, input_fields, output_fields, stats_collector): + """ + Private helper function called by the generic TLearner.use. It returns a function + that can map the given input fields to the given output fields (along with the + attributes that the stats collector needs for its computation. + """ + if not output_fields: + output_fields = self.defaultOutputFields(input_fields) + if stats_collector: + stats_collector_inputs = stats_collector.inputUpdateAttributes() + for attribute in stats_collector_inputs: + if attribute not in input_fields: + output_fields.append(attribute) + key = (input_fields,output_fields) + if key not in self.use_functions_dictionary: + self.use_functions_dictionary[key]=Function(self._names2attributes(input_fields), + self._names2attributes(output_fields)) + return self.use_functions_dictionary[key] + + def attributes(self,return_copy=False): + """ + Return a list with the values of the learner's attributes (or optionally, a deep copy). + """ + return self.names2attributes(self.attributeNames()) + + def _names2attributes(self,names,return_Result=False, return_copy=False): + """ + Private helper function that maps a list of attribute names to a list + of (optionally copies) values or of the Result objects that own these values. + """ + if return_Result: + if return_copy: + return [copy.deepcopy(self.__getattr__(name)) for name in names] + else: + return [self.__getattr__(name) for name in names] + else: + if return_copy: + return [copy.deepcopy(self.__getattr__(name).data) for name in names] + else: + return [self.__getattr__(name).data for name in names] + + def use(self,input_dataset,output_fieldnames=None,output_attributes=None, + test_stats_collector=None,copy_inputs=True): + """ + The learner tries to compute in the output dataset the output fields specified + """ + minibatchwise_use_function = _minibatchwise_use_functions(input_dataset.fieldNames(), + output_fieldnames, + test_stats_collector) + virtual_output_dataset = ApplyFunctionDataSet(input_dataset, + minibatchwise_use_function, + True,DataSet.numpy_vstack, + DataSet.numpy_hstack) + # actually force the computation + output_dataset = CachedDataSet(virtual_output_dataset,True) + if copy_inputs: + output_dataset = input_dataset | output_dataset + # copy the wanted attributes in the dataset + if output_attributes: + assert set(output_attributes) <= set(self.attributeNames()) + output_dataset.setAttributes(output_attributes, + self._names2attributes(output_attributes,return_copy=True)) + if test_stats_collector: + test_stats_collector.update(output_dataset) + output_dataset.setAttributes(test_stats_collector.attributeNames(), + test_stats_collector.attributes()) + return output_dataset + + def update_start(self): pass + def update_end(self): pass + def update_minibatch(self,minibatch): + raise AbstractFunction() + def update(self,training_set,train_stats_collector=None): + + self.update_start() + for minibatch in training_set.minibatches(self.training_set_input_fields, + minibatch_size=self.minibatch_size): + self.update_minibatch(minibatch) + if train_stats_collector: + minibatch_set = minibatch.examples() + minibatch_set.setAttributes(self.attributeNames(),self.attributes()) + train_stats_collector.update(minibatch_set) + self.update_end() + return self.use +