# HG changeset patch # User Olivier Delalleau # Date 1243266230 14400 # Node ID 88f5b75a4afe38707c10313e9b3e0f4760e3d7ab # Parent bf29e201515fb23f5b859ae12e83230e7ebca9af Added new option 'ignore_missing' to deal with missing values in input diff -r bf29e201515f -r 88f5b75a4afe pylearn/algorithms/sandbox/DAA_inputs_groups.py --- a/pylearn/algorithms/sandbox/DAA_inputs_groups.py Mon May 25 11:42:25 2009 -0400 +++ b/pylearn/algorithms/sandbox/DAA_inputs_groups.py Mon May 25 11:43:50 2009 -0400 @@ -46,12 +46,26 @@ def __init__(self, input = None, auxinput = None, in_size=None, auxin_size= None, n_hid=1, regularize = False, tie_weights = False, hid_fn = 'sigmoid_act', - reconstruction_cost_function=cost.cross_entropy, interface = True,**init): + reconstruction_cost_function=cost.cross_entropy, interface = True, + ignore_missing=False, + **init): """ :param regularize: WRITEME :param tie_weights: WRITEME :param hid_fn: WRITEME :param reconstruction_cost: Should return one cost per example (row) + :param ignore_missing: if True, the input will be scanned in order to + detect missing values, and these values will be replaced by zeros. + Also, the reconstruction cost will be computed only on non missing + components. + If False, the presence of missing values may cause crashes or other + weird and unexpected behavior. + Please note that this option only affects the permanent input, not + auxilary ones (that should never contain missing values). In fact, + in the current implementation, auxiliary inputs cannot be used when + this option is True. + Another side effect of the current crappy way it is implemented is + that the reconstruction cost is not properly computed. :todo: Default noise level for all daa levels """ print '\t\t**** DAAig.__init__ ****' @@ -72,12 +86,19 @@ self.tie_weights = tie_weights self.reconstruction_cost_function = reconstruction_cost_function self.interface = interface + self.ignore_missing = ignore_missing assert hid_fn in ('sigmoid_act','tanh_act','softsign_act') self.hid_fn = eval(hid_fn) ### DECLARE MODEL VARIABLES and default self.input = input + if self.ignore_missing and self.input is not None: + no_missing = fill_missing_with_zeros(self.input) + self.input = no_missing[0] # Missing values replaced by zeros. + self.input_missing_mask = no_missing[1] # Missingness pattern. + else: + self.input_missing_mask = None self.noisy_input = None self.auxinput = auxinput self.idx_list = T.ivector('idx_list') if not(self.auxinput is None) else None @@ -243,6 +264,18 @@ return self.random.binomial(T.shape(self.input), 1, 1 - self.noise_level) * self.input def reconstruction_costs(self, rec): + if self.ignore_missing and self.input is not None: + # Note: the following code is very ugly. It is just a hack to + # ensure that the gradient w.r.t. missing coordinates is (close to) + # zero. It is neither efficient nor elegant. + # The idea is to put a very big negative value in the + # reconstruction for these missing inputs (whose target is 0), so + # that the gradient is 1/(1 - rec) ~= 0. + # This will in particular screw up the cost computations. + zero = rec * 0 + rec = (rec * T.neq(self.input_missing_mask, zero) + + (zero - 1e100) * T.eq(self.input_missing_mask, zero)) + if self.input is None: return self.reconstruction_cost_function(scaninputs(self.idx_list,self.auxinput), rec) if self.auxinput is None: