commit 434233eacd7b074f6232a38caff0537941073db3
parent 1ce979232de97cb635a26d4ec2a574464a567c61
Author: Étienne Simon <esimon@esimon.eu>
Date:   Wed, 23 Apr 2014 12:44:54 +0200
Add/Update relation (affine hadamard)
Diffstat:
10 files changed, 49 insertions(+), 33 deletions(-)
diff --git a/model.py b/model.py
@@ -88,9 +88,9 @@ class Model(object):
         left_negative, right_negative = self.embeddings.embed(inputs[3]), self.embeddings.embed(inputs[4])
         relation = self.relations.lookup(inputs[0])
 
-        score_positive = self.config['similarity'](self.relations.apply(left_positive, relation), right_positive)
-        score_left_negative = self.config['similarity'](self.relations.apply(left_negative, relation), right_positive)
-        score_right_negative = self.config['similarity'](self.relations.apply(left_positive, relation), right_negative)
+        score_positive = self.config['similarity'](self.relations.transform(left_positive, relation), right_positive)
+        score_left_negative = self.config['similarity'](self.relations.transform(left_negative, relation), right_positive)
+        score_right_negative = self.config['similarity'](self.relations.transform(left_positive, relation), right_negative)
         score_left = self.config['margin'] + score_positive - score_left_negative
         score_right = self.config['margin'] + score_positive - score_right_negative
 
@@ -106,8 +106,8 @@ class Model(object):
         relation = map(lambda r: T.addbroadcast(r, 0), relation)
         left_broadcasted = T.addbroadcast(left_positive, 0)
         right_broadcasted = T.addbroadcast(right_positive, 0)
-        left_score = self.config['similarity'](self.relations.apply(left_broadcasted, relation), right_positive)
-        right_score = self.config['similarity'](self.relations.apply(left_positive, relation), right_broadcasted)
+        left_score = self.config['similarity'](self.relations.transform(left_broadcasted, relation), right_positive)
+        right_score = self.config['similarity'](self.relations.transform(left_positive, relation), right_broadcasted)
 
         self.left_scoring_function = theano.function(inputs=list(inputs[0:3]), outputs=[left_score])
         self.right_scoring_function = theano.function(inputs=list(inputs[0:3]), outputs=[right_score])
diff --git a/relations/affine hadamard.py b/relations/affine hadamard.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python2
+
+from relations.base import *
+
+class Affine_hadamard(Base_relation):
+    """ Affine hadamard class.
+
+    This class has two parameters:
+    A -- the multiplicative vectors
+    B -- the additive vectors
+    """
+    def __init__(self, rng, number, dimension, tag):
+        """ Initialise the parameter. """
+        parameters = [ ('A', (dimension,)), ('B', (dimension,)) ]
+        super(Affine_hadamard, self).__init__(rng, number, parameters, tag)
+
+    def apply(self, inputs, a, b):
+        """ Apply the given relations to a given input. """
+        return a*inputs+b
diff --git a/relations/anisotropic homotheties.py b/relations/anisotropic homotheties.py
@@ -11,11 +11,9 @@ class Anisotropic_homotheties(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'P': (dimension,), 'S': (dimension,) }
+        parameters = [ ('P', (dimension,)), ('S', (dimension,)) ]
         super(Anisotropic_homotheties, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, p, s):
         """ Apply the given relations to a given input. """
-        p = relations[0]
-        s = relations[1]
         return p + (inputs-p)*s
diff --git a/relations/anisotropic scalings.py b/relations/anisotropic scalings.py
@@ -10,9 +10,9 @@ class Anisotropic_scalings(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'S': (dimension,) }
+        parameters = [ ('S', (dimension,)) ]
         super(Anisotropic_scalings, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, s):
         """ Apply the given relations to a given input. """
-        return relations[0] * inputs
+        return s * inputs
diff --git a/relations/base.py b/relations/base.py
@@ -21,9 +21,8 @@ class Base_relation(object):
         self.number = number
         self.parameters = []
 
-        for name, shape in parameters.iteritems():
+        for name, shape in parameters:
             dimension = sum(shape)
-            dimension = 1 if dimension==0 else dimension
             bound = numpy.sqrt(6. / dimension)
             values = rng.uniform(low=-bound, high=bound, size=(number,)+shape)
             values = values / numpy.sqrt(numpy.sum(values **2, axis=1))[:, numpy.newaxis]
@@ -33,7 +32,11 @@ class Base_relation(object):
 
     def lookup(self, relations):
         """ Embed given relations. """
-        return [ S.dot(relations, parameter) for parameter in self.parameters ]
+        return map(lambda parameter: S.dot(relations, parameter), self.parameters)
+
+    def transform(self, inputs, relations):
+        """ Transform the given input w.r.t. the given relations. """
+        return self.apply(inputs, *relations)
 
     def updates(self, cost, learning_rate):
         """ Compute the updates to perform a SGD step w.r.t. a given cost.
diff --git a/relations/homotheties.py b/relations/homotheties.py
@@ -12,11 +12,10 @@ class Homotheties(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'P': (dimension,), 'S': (1,) }
+        parameters = [ ('P', (dimension,)), ('S', (1,)) ]
         super(Homotheties, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, p, s):
         """ Apply the given relations to a given input. """
-        p = relations[0]
-        s = T.addbroadcast(relations[1], 1)
+        s = T.addbroadcast(s, 1)
         return p + (inputs-p)*s
diff --git a/relations/offsetted reflections.py b/relations/offsetted reflections.py
@@ -13,12 +13,10 @@ class Offsetted_reflections(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'H': (dimension,), 'O': (1,) }
+        parameters = [ ('H', (dimension,)), ('O', (1,)) ]
         super(Offsetted_reflections, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, h, o):
         """ Apply the given relations to a given input. """
-        h = relations[0]
-        o = relations[1]
         f = T.addbroadcast((T.sum(inputs*h, axis=1).dimshuffle(0, 'x') - o) / T.sum(h*h, axis=1).dimshuffle(0, 'x'), 1)
         return inputs - 2 * h * f
diff --git a/relations/point reflections.py b/relations/point reflections.py
@@ -10,9 +10,9 @@ class Point_reflections(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'P': (dimension,) }
+        parameters = [ ('P', (dimension,)) ]
         super(Point_reflections, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, p):
         """ Apply the given relations to a given input. """
-        return 2*relations[0] - inputs
+        return 2*p - inputs
diff --git a/relations/reflections.py b/relations/reflections.py
@@ -12,11 +12,10 @@ class Reflections(Base_relation):
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'H': (dimension,) }
+        parameters = [ ('H', (dimension,)) ]
         super(Reflections, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, h):
         """ Apply the given relations to a given input. """
-        h = relations[0]
         f = (T.sum(inputs*h, axis=1) / T.sum(h*h, axis=1)).dimshuffle(0, 'x')
         return inputs - 2 * h * f
diff --git a/relations/translations.py b/relations/translations.py
@@ -6,13 +6,13 @@ class Translations(Base_relation):
     """ Translations class.
 
     This class has one parameter:
-    R -- the translations
+    T -- the translations
     """
     def __init__(self, rng, number, dimension, tag):
         """ Initialise the parameter. """
-        parameters = { 'R': (dimension,) }
+        parameters = [ ('T', (dimension,)) ]
         super(Translations, self).__init__(rng, number, parameters, tag)
 
-    def apply(self, inputs, relations):
+    def apply(self, inputs, t):
         """ Apply the given relations to a given input. """
-        return relations[0] + inputs
+        return t + inputs