Mercurial > pylearn
comparison sandbox/denoising_aa.py @ 409:cf22ebfc90eb
Moved denoising AA to sandbox
author | Joseph Turian <turian@gmail.com> |
---|---|
date | Thu, 10 Jul 2008 17:33:28 -0400 |
parents | denoising_aa.py@eded3cb54930 |
children |
comparison
equal
deleted
inserted
replaced
407:b9f545594207 | 409:cf22ebfc90eb |
---|---|
1 """ | |
2 A denoising auto-encoder | |
3 | |
4 @warning: You should use this interface. It is not complete and is not functional. | |
5 Instead, use:: | |
6 ssh://projects@lgcm.iro.umontreal.ca/repos/denoising_aa | |
7 """ | |
8 | |
9 import theano | |
10 from theano.formula import * | |
11 from learner import * | |
12 from theano import tensor as t | |
13 from nnet_ops import * | |
14 import math | |
15 from misc import * | |
16 from misc_theano import * | |
17 from theano.tensor_random import binomial | |
18 | |
19 def hiding_corruption_formula(seed,average_fraction_hidden): | |
20 """ | |
21 Return a formula for the corruption process, in which a random | |
22 subset of the input numbers are hidden (mapped to 0). | |
23 | |
24 @param seed: seed of the random generator | |
25 @type seed: anything that numpy.random.RandomState accepts | |
26 | |
27 @param average_fraction_hidden: the probability with which each | |
28 input number is hidden (set to 0). | |
29 @type average_fraction_hidden: 0 <= real number <= 1 | |
30 """ | |
31 class HidingCorruptionFormula(Formulas): | |
32 x = t.matrix() | |
33 corrupted_x = x * binomial(seed,x,1,fraction_sampled) | |
34 | |
35 return HidingCorruptionFormula() | |
36 | |
37 def squash_affine_formula(squash_function=sigmoid): | |
38 """ | |
39 Simply does: squash_function(b + xW) | |
40 By convention prefix the parameters by _ | |
41 """ | |
42 class SquashAffineFormula(Formulas): | |
43 x = t.matrix() # of dimensions minibatch_size x n_inputs | |
44 _b = t.row() # of dimensions 1 x n_outputs | |
45 _W = t.matrix() # of dimensions n_inputs x n_outputs | |
46 a = _b + t.dot(x,_W) # of dimensions minibatch_size x n_outputs | |
47 y = squash_function(a) | |
48 return SquashAffineFormula() | |
49 | |
50 def gradient_descent_update_formula(): | |
51 class GradientDescentUpdateFormula(Formula): | |
52 param = t.matrix() | |
53 learning_rate = t.scalar() | |
54 cost = t.column() # cost of each example in a minibatch | |
55 param_update = t.add_inplace(param, -learning_rate*t.sgrad(cost)) | |
56 return gradient_descent_update_formula() | |
57 | |
58 def probabilistic_classifier_loss_formula(): | |
59 class ProbabilisticClassifierLossFormula(Formulas): | |
60 a = t.matrix() # of dimensions minibatch_size x n_classes, pre-softmax output | |
61 target_class = t.ivector() # dimension (minibatch_size) | |
62 nll, probability_predictions = crossentropy_softmax_1hot(a, target_class) # defined in nnet_ops.py | |
63 return ProbabilisticClassifierLossFormula() | |
64 | |
65 def binomial_cross_entropy_formula(): | |
66 class BinomialCrossEntropyFormula(Formulas): | |
67 a = t.matrix() # pre-sigmoid activations, minibatch_size x dim | |
68 p = sigmoid(a) # model prediction | |
69 q = t.matrix() # target binomial probabilities, minibatch_size x dim | |
70 # using the identity softplus(a) - softplus(-a) = a, | |
71 # we obtain that q log(p) + (1-q) log(1-p) = q a - softplus(a) | |
72 nll = -t.sum(q*a - softplus(-a)) | |
73 # next line was missing... hope it's all correct above | |
74 return BinomialCrossEntropyFormula() | |
75 | |
76 def squash_affine_autoencoder_formula(hidden_squash=t.tanh, | |
77 reconstruction_squash=sigmoid, | |
78 share_weights=True, | |
79 reconstruction_nll_formula=binomial_cross_entropy_formula(), | |
80 update_formula=gradient_descent_update_formula): | |
81 if share_weights: | |
82 autoencoder = squash_affine_formula(hidden_squash).rename(a='code_a') + \ | |
83 squash_affine_formula(reconstruction_squash).rename(x='hidden',y='reconstruction',_b='_c') + \ | |
84 reconstruction_nll_formula | |
85 else: | |
86 autoencoder = squash_affine_formula(hidden_squash).rename(a='code_a',_W='_W1') + \ | |
87 squash_affine_formula(reconstruction_squash).rename(x='hidden',y='reconstruction',_b='_c',_W='_W2') + \ | |
88 reconstruction_nll_formula | |
89 autoencoder = autoencoder + [update_formula().rename(cost = 'nll', | |
90 param = p) | |
91 for p in autoencoder.get_all('_.*')] | |
92 return autoencoder | |
93 | |
94 | |
95 # @todo: try other corruption formulae. The above is the default one. | |
96 # not quite used in the ICML paper... (had a fixed number of 0s). | |
97 | |
98 class DenoisingAutoEncoder(LearningAlgorithm): | |
99 | |
100 def __init__(self,n_inputs,n_hidden_per_layer, | |
101 learning_rate=0.1, | |
102 max_n_epochs=100, | |
103 L1_regularizer=0, | |
104 init_range=1., | |
105 corruption_formula = hiding_corruption_formula(), | |
106 autoencoder = squash_affine_autoencoder_formula(), | |
107 minibatch_size=None,linker = "c|py"): | |
108 for name,val in locals().items(): | |
109 if val is not self: self.__setattribute__(name,val) | |
110 self.denoising_autoencoder_formula = corruption_formula + autoencoder.rename(x='corrupted_x') | |
111 | |
112 def __call__(self, training_set=None): | |
113 """ Allocate and optionnaly train a model | |
114 | |
115 @TODO enables passing in training and valid sets, instead of cutting one set in 80/20 | |
116 """ | |
117 model = DenoisingAutoEncoderModel(self) | |
118 if training_set: | |
119 print 'DenoisingAutoEncoder(): what do I do if training_set????' | |
120 # copied from old mlp_factory_approach: | |
121 if len(trainset) == sys.maxint: | |
122 raise NotImplementedError('Learning from infinite streams is not supported') | |
123 nval = int(self.validation_portion * len(trainset)) | |
124 nmin = len(trainset) - nval | |
125 assert nmin >= 0 | |
126 minset = trainset[:nmin] #real training set for minimizing loss | |
127 valset = trainset[nmin:] #validation set for early stopping | |
128 best = model | |
129 for stp in self.early_stopper(): | |
130 model.update( | |
131 minset.minibatches([input, target], minibatch_size=min(32, | |
132 len(trainset)))) | |
133 #print 'mlp.__call__(), we did an update' | |
134 if stp.set_score: | |
135 stp.score = model(valset, ['loss_01']) | |
136 if (stp.score < stp.best_score): | |
137 best = copy.copy(model) | |
138 model = best | |
139 # end of the copy from mlp_factory_approach | |
140 | |
141 return model | |
142 | |
143 | |
144 def compile(self, inputs, outputs): | |
145 return theano.function(inputs,outputs,unpack_single=False,linker=self.linker) | |
146 | |
147 class DenoisingAutoEncoderModel(LearnerModel): | |
148 def __init__(self,learning_algorithm,params): | |
149 self.learning_algorithm=learning_algorithm | |
150 self.params=params | |
151 v = learning_algorithm.v | |
152 self.update_fn = learning_algorithm.compile(learning_algorithm.denoising_autoencoder_formula.inputs, | |
153 learning_algorithm.denoising_autoencoder_formula.outputs) | |
154 | |
155 def update(self, training_set, train_stats_collector=None): | |
156 | |
157 print 'dont update you crazy frog!' | |
158 | |
159 # old stuff | |
160 | |
161 # self._learning_rate = t.scalar('learning_rate') # this is the symbol | |
162 # self.L1_regularizer = L1_regularizer | |
163 # self._L1_regularizer = t.scalar('L1_regularizer') | |
164 # self._input = t.matrix('input') # n_examples x n_inputs | |
165 # self._W = t.matrix('W') | |
166 # self._b = t.row('b') | |
167 # self._c = t.row('b') | |
168 # self._regularization_term = self._L1_regularizer * t.sum(t.abs(self._W)) | |
169 # self._corrupted_input = corruption_process(self._input) | |
170 # self._hidden = t.tanh(self._b + t.dot(self._input, self._W.T)) | |
171 # self._reconstruction_activations =self._c+t.dot(self._hidden,self._W) | |
172 # self._nll,self._output = crossentropy_softmax_1hot(Print("output_activations")(self._output_activations),self._target_vector) | |
173 # self._output_class = t.argmax(self._output,1) | |
174 # self._class_error = t.neq(self._output_class,self._target_vector) | |
175 # self._minibatch_criterion = self._nll + self._regularization_term / t.shape(self._input)[0] | |
176 # OnlineGradientTLearner.__init__(self) | |
177 | |
178 # def attributeNames(self): | |
179 # return ["parameters","b1","W2","b2","W2", "L2_regularizer","regularization_term"] | |
180 | |
181 # def parameterAttributes(self): | |
182 # return ["b1","W1", "b2", "W2"] | |
183 | |
184 # def updateMinibatchInputFields(self): | |
185 # return ["input","target"] | |
186 | |
187 # def updateEndOutputAttributes(self): | |
188 # return ["regularization_term"] | |
189 | |
190 # def lossAttribute(self): | |
191 # return "minibatch_criterion" | |
192 | |
193 # def defaultOutputFields(self, input_fields): | |
194 # output_fields = ["output", "output_class",] | |
195 # if "target" in input_fields: | |
196 # output_fields += ["class_error", "nll"] | |
197 # return output_fields | |
198 | |
199 # def allocate(self,minibatch): | |
200 # minibatch_n_inputs = minibatch["input"].shape[1] | |
201 # if not self._n_inputs: | |
202 # self._n_inputs = minibatch_n_inputs | |
203 # self.b1 = numpy.zeros((1,self._n_hidden)) | |
204 # self.b2 = numpy.zeros((1,self._n_outputs)) | |
205 # self.forget() | |
206 # elif self._n_inputs!=minibatch_n_inputs: | |
207 # # if the input changes dimension on the fly, we resize and forget everything | |
208 # self.forget() | |
209 | |
210 # def forget(self): | |
211 # if self._n_inputs: | |
212 # r = self._init_range/math.sqrt(self._n_inputs) | |
213 # self.W1 = numpy.random.uniform(low=-r,high=r, | |
214 # size=(self._n_hidden,self._n_inputs)) | |
215 # r = self._init_range/math.sqrt(self._n_hidden) | |
216 # self.W2 = numpy.random.uniform(low=-r,high=r, | |
217 # size=(self._n_outputs,self._n_hidden)) | |
218 # self.b1[:]=0 | |
219 # self.b2[:]=0 | |
220 # self._n_epochs=0 | |
221 | |
222 # def isLastEpoch(self): | |
223 # self._n_epochs +=1 | |
224 # return self._n_epochs>=self._max_n_epochs |