changeset 395:70019965f888

Basic, broken RBM implementation
author Joseph Turian <turian@gmail.com>
date Tue, 08 Jul 2008 20:14:21 -0400
parents f2d112dc53be
children e0c9357456e0
files sandbox/rbm/__init__.py sandbox/rbm/globals.py sandbox/rbm/main.py sandbox/rbm/model.py sandbox/rbm/parameters.py
diffstat 4 files changed, 139 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sandbox/rbm/globals.py	Tue Jul 08 20:14:21 2008 -0400
@@ -0,0 +1,12 @@
+"""
+Global variables.
+"""
+
+#INPUT_DIMENSION = 1000
+#INPUT_DIMENSION = 100
+INPUT_DIMENSION = 4
+HIDDEN_DIMENSION = 10
+#HIDDEN_DIMENSION = 4
+LEARNING_RATE = 0.1
+LR = LEARNING_RATE
+SEED = 666
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sandbox/rbm/main.py	Tue Jul 08 20:14:21 2008 -0400
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+"""
+    An RBM with binomial units trained with CD-1.
+
+    LIMITATIONS:
+       - Only does pure stochastic gradient (batchsize = 1).
+"""
+
+
+import numpy
+
+nonzero_instances = []
+nonzero_instances.append({0: 1, 1: 1})
+nonzero_instances.append({0: 1, 2: 1})
+
+#nonzero_instances.append({1: 0.1, 5: 0.5, 9: 1})
+#nonzero_instances.append({2: 0.3, 5: 0.5, 8: 0.8})
+##nonzero_instances.append({1: 0.2, 2: 0.3, 5: 0.5})
+
+import model
+model = model.Model()
+
+for i in xrange(100000):
+    # Select an instance
+    instance = nonzero_instances[i % len(nonzero_instances)]
+
+    # SGD update over instance
+    model.update(instance)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sandbox/rbm/model.py	Tue Jul 08 20:14:21 2008 -0400
@@ -0,0 +1,66 @@
+"""
+The model for an autoassociator for sparse inputs, using Ronan Collobert + Jason
+Weston's sampling trick (2008).
+"""
+
+import parameters
+
+import globals
+from globals import LR
+
+import numpy
+from numpy import dot
+import random
+random.seed(globals.SEED)
+
+import pylearn.nnet_ops
+
+def sigmoid(v):
+#    if x < -30.0: return 0.0
+#    if x > 30.0: return 1.0 
+    return 1.0 / (1.0 + numpy.exp(-v))
+
+def sample(v):
+    assert len(v.shape) == 1
+    x = numpy.zeros(v.shape)
+    for i in range(v.shape[0]):
+        assert v[i] >= 0 and v[i] <= 1
+        if random.random() < v[i]: x[i] = 0
+        else: x[i] = 1
+    return x
+
+class Model:
+    def __init__(self):
+        self.parameters = parameters.Parameters(randomly_initialize=True)
+
+    def update(self, instance):
+        """
+        Update the L{Model} using one training instance.
+        @param instance: A dict from feature index to (non-zero) value.
+        @todo: Should assert that nonzero_indices and zero_indices
+        are correct (i.e. are truly nonzero/zero).
+        """
+        v0 = numpy.zeros(globals.INPUT_DIMENSION)
+        for idx in instance.keys():
+            v0[idx] = instance[idx]
+
+        q0 = sigmoid(self.parameters.b + dot(v0, self.parameters.w))
+        h0 = sample(q0)
+        p0 = sigmoid(self.parameters.c + dot(h0, self.parameters.w.T))
+        v1 = sample(p0)
+        q1 = sigmoid(self.parameters.b + dot(v1, self.parameters.w))
+        print
+        print "v[0]:", v0
+        print "Q(h[0][i] = 1 | v[0]):", q0
+        print "h[0]:", h0
+        print "P(v[1][j] = 1 | h[0]):", p0
+        print "v[1]:", v1
+        print "Q(h[1][i] = 1 | v[1]):", q1
+
+        print h0.shape
+        print v0.T.shape
+        print dot(h0, v0.T)
+        print dot(q1, v1.T)
+        self.parameters.w += LR * (dot(h0, v0.T) - dot(q1, v1.T))
+        self.parameters.b += LR * (h0 - q1)
+        self.parameters.c += LR * (v0 - v1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sandbox/rbm/parameters.py	Tue Jul 08 20:14:21 2008 -0400
@@ -0,0 +1,33 @@
+"""
+Parameters (weights) used by the L{Model}.
+"""
+
+import numpy
+import globals
+
+class Parameters:
+    """
+    Parameters used by the L{Model}.
+    """
+    def __init__(self, input_dimension=globals.INPUT_DIMENSION, hidden_dimension=globals.HIDDEN_DIMENSION, randomly_initialize=False, seed=globals.SEED):
+        """
+        Initialize L{Model} parameters.
+        @param randomly_initialize: If True, then randomly initialize
+        according to the given seed. If False, then just use zeroes.
+        """
+        if randomly_initialize:
+            numpy.random.seed(seed)
+            self.w = (numpy.random.rand(input_dimension, hidden_dimension)-0.5)/input_dimension
+            self.b = numpy.zeros(hidden_dimension)
+            self.c = numpy.zeros(input_dimension)
+        else:
+            self.w = numpy.zeros((input_dimension, hidden_dimension))
+            self.b = numpy.zeros(hidden_dimension)
+            self.c = numpy.zeros(input_dimension)
+
+    def __str__(self):
+        s = ""
+        s += "w: %s\n" % self.w
+        s += "b: %s\n" % self.b
+        s += "c: %s\n" % self.c
+        return s