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