changeset 647:546795d7cbaf

added new way of writing logistic regression
author James Bergstra <bergstrj@iro.umontreal.ca>
date Wed, 04 Feb 2009 15:55:19 -0500
parents ac6e7ce28f70
children 4a7d413c3425
files pylearn/algorithms/logistic_regression.py
diffstat 1 files changed, 61 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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']
+