# HG changeset patch # User James Bergstra # Date 1233780919 18000 # Node ID 546795d7cbaf740f91ae266e4988f1dc5cade455 # Parent ac6e7ce28f7061eeaa966b5d3c3b35db5d31b770 added new way of writing logistic regression diff -r ac6e7ce28f70 -r 546795d7cbaf pylearn/algorithms/logistic_regression.py --- a/pylearn/algorithms/logistic_regression.py Sat Jan 24 17:25:41 2009 -0500 +++ b/pylearn/algorithms/logistic_regression.py Wed Feb 04 15:55:19 2009 -0500 @@ -94,6 +94,8 @@ #FIX : Guillaume suggested a convention: plugin handlers (dataset_factory, minimizer_factory, # etc.) should never provide default arguments for parameters, and accept **kwargs to catch # irrelevant parameters. +#SOLUTION: the jobman deals in nested dictionaries. This means that there is no [dumb] reason that +# irrelevant arguments should be passed at all. class _fit_logreg_defaults(object): minimizer_algo = 'dummy' #minimizer_lr = 0.001 @@ -103,9 +105,6 @@ batchsize = 8 verbose = 1 -# consider pre-importing each file in algorithms, datasets (possibly with try/catch around each -# import so that this import failure is ignored) - def fit_logistic_regression_online(state, channel=lambda *args, **kwargs:None): #use stochastic gradient descent state.use_defaults(_fit_logreg_defaults) @@ -189,3 +188,62 @@ updates = dict((p, p - self.lr * g) for p, g in zip(self.params, gparams))) +class LogReg_New(module.FancyModule): + """A symbolic module for performing multi-class logistic regression.""" + + params = property( + lambda self: [p for p in [self.w, self.b] if p.owner is None], + doc="WRITEME" + ) + + def __init__(self, n_in=None, n_out=None, w=None, b=None): + super(LogRegNew, self).__init__() #boilerplate + + self.n_in = n_in + self.n_out = n_out + + self.w = w if w is not None else module.Member(T.dmatrix()) + self.b = b if b is not None else module.Member(T.dvector()) + + def l1(self): + return abs(self.w).sum() + + def l2(self): + return (self.w**2).sum() + + def activation(self, input): + return T.dot(self.input, self.w) + self.b + + def softmax(self, input): + return nnet.softmax(self.activation(input)) + + def argmax(self, input): + return T.max_and_argmax(self.linear_output(input))[1] + + def xent(self, input, target): + """The cross-entropy between the prediction from `input`, and the true `target`. + + This function returns a symbolic vector, with the cross-entropy for each row in + `input`. + + Hint: To sum these costs into a scalar value, use "xent(input, target).sum()" + """ + return target * T.log(self.softmax(input)) + + def errors(self, input, target): + """The zero-one error of the prediction from `input`, with respect to the true `target`. + + This function returns a symbolic vector, with the incorrectness of each prediction + (made row-wise from `input`). + + Hint: Count errors with "errors(input, target).sum()", and get the error-rate with + "errors(input, target).mean()" + + """ + return T.neq(self.argmax(input), self.target) + + def _instance_initialize(self, obj): + obj.w = N.zeros((self.n_in, self.n_out)) + obj.b = N.zeros(self.n_out) + obj.__pp_hide__ = ['params'] +