Belle II Software  release-05-02-19
keras_relational.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 # Dennis Weyland 2017
5 
6 from keras.layers.core import Reshape
7 from keras.layers import activations
8 from keras.activations import sigmoid, tanh
9 from keras.engine.topology import Layer
10 from keras import backend as K
11 import numpy as np
12 
13 
14 class Relations(Layer):
15  """
16  This is a class which implements Relational Layer into Keras.
17  Relational Layer compares every combination of two feature groups with shared weights.
18  Use this class as every other Layer in Keras.
19  Relevant Paper: https://arxiv.org/abs/1706.01427
20  RN(O) = f_phi(sum_phi(g_theta(o_i,o_j)))
21  For flexibility reason only the part g(o_i,o_j) is modelled
22  f_phi corresponds to a MLP net
23  To sum over all permutations please use GlobalAveragePooling1D from keras.
24  """
25 
26  def __init__(self, number_features, hidden_feature_shape=[30, 30, 30, 30], activation=tanh, **kwargs):
27  """
28  Init class.
29  """
30 
31 
32  self.number_features = number_features
33 
34  self.number_groups = 0
35 
36  self.hidden_feature_shape = hidden_feature_shape
37 
38  self.activation = activations.get(activation)
39 
40  self.group_len = 0
41 
42  self.variables = []
43 
44  self.combinations = 0
45 
46  super(Relations, self).__init__(**kwargs)
47 
48  def build(self, input_shape):
49  """
50  Build all weights for Relations Layer
51  :param input_shape: Input shape of tensor
52  :return: Nothing
53  """
54  # only accept 2D layers
55  assert(len(input_shape) == 3)
56 
57  self.number_groups = input_shape[1]
58 
59  self.group_len = input_shape[2]
60 
61  self.combinations = np.int32(np.math.factorial(self.number_groups) / (2 * np.math.factorial(self.number_groups - 2)))
62 
63  dense_shape = [2 * self.group_len] + self.hidden_feature_shape + [self.number_features]
64 
65  for i in range(len(dense_shape[:-1])):
66  weights = self.add_weight(name='relation_weights_{}'.format(i),
67  shape=list(dense_shape[i:i + 2]), initializer='glorot_uniform', trainable=True)
68  bias = self.add_weight(name='relation_weights_{}'.format(i),
69  shape=(dense_shape[i + 1],), initializer='zeros', trainable=True)
70 
71  self.variables.append([weights, bias])
72 
73  super(Relations, self).build(input_shape)
74 
75  def call(self, inputs):
76  """
77  Compute Relational Layer
78  :param inputs: input tensor
79  :return: output tensor
80  """
81  input_groups = [inputs[:, i, :] for i in range(self.number_groups)]
82  outputs = []
83  for index, group1 in enumerate(input_groups[:-1]):
84  for group2 in input_groups[index + 1:]:
85  net = K.dot(K.concatenate([group1, group2]), self.variables[0][0])
86  net = K.bias_add(net, self.variables[0][1])
87  for variables in self.variables[1:]:
88  net = self.activation(net)
89  net = K.dot(net, variables[0])
90  net = K.bias_add(net, variables[1])
91  outputs.append(sigmoid(net))
92 
93  flat_result = K.concatenate(outputs)
94  return Reshape((self.combinations, self.number_features,))(flat_result)
95 
96  def compute_output_shape(self, input_shape):
97  """
98  Compute Output shape
99  :return: Output shape
100  """
101  # only 2D layers
102  assert(len(input_shape) == 3)
103 
104  self.combinations = np.int32(np.math.factorial(self.number_groups) / (2 * np.math.factorial(self.number_groups - 2)))
105 
106  return (input_shape[0], self.combinations, self.number_features)
107 
108  def get_config(self):
109  """
110  Config required for saving parameters in keras model.
111  """
112  config = {
113  'number_features': self.number_features,
114  'hidden_feature_shape': self.hidden_feature_shape,
115  'activation': activations.serialize(self.activation)
116  }
117  base_config = super(Relations, self).get_config()
118  return dict(list(base_config.items()) + list(config.items()))
119 
120 
121 class EnhancedRelations(Layer):
122  """
123  This is a class which implements Relational Layer into Keras.
124  See Class Relations for details.
125  EnhanceRelations use an additional input for passing event information to every comparison:
126  RN(O) = f_phi(sum_phi(g_theta(o_i,o_j,q)))
127  q is fed in as second one dimensional input.
128  """
129 
130  def __init__(self, number_features, hidden_feature_shape=[30, 30, 30, 30], activation=tanh, **kwargs):
131  """
132  Init class.
133  """
134 
135 
136  self.number_features = number_features
137 
138  self.number_groups = 0
139 
140  self.hidden_feature_shape = hidden_feature_shape
141 
142  self.activation = activations.get(activation)
143 
144  self.group_len = 0
145 
146  self.variables = []
147 
148  self.combinations = 0
149 
150  self.question_len = 0
151 
152  super(EnhancedRelations, self).__init__(**kwargs)
153 
154  def build(self, input_shape):
155  """
156  Build all weights for Relations Layer
157  :param input_shape: Input shape of tensor
158  :return: Nothing
159  """
160  # accept only 2 inputs
161  assert(len(input_shape) == 2)
162  # first input should be a 2D layers
163  assert(len(input_shape[0]) == 3)
164  # second input should be a 1D layers
165  assert(len(input_shape[1]) == 2)
166 
167  self.number_groups = input_shape[0][1]
168 
169  self.group_len = input_shape[0][2]
170 
171  self.question_len = input_shape[1][1]
172 
173  self.combinations = np.int32(np.math.factorial(self.number_groups) / (2 * np.math.factorial(self.number_groups - 2)))
174 
175  dense_shape = [2 * self.group_len + self.question_len] + self.hidden_feature_shape + [self.number_features]
176 
177  for i in range(len(dense_shape[:-1])):
178  weights = self.add_weight(name='relation_weights_{}'.format(i),
179  shape=list(dense_shape[i:i + 2]), initializer='glorot_uniform', trainable=True)
180  bias = self.add_weight(name='relation_weights_{}'.format(i),
181  shape=(dense_shape[i + 1],), initializer='zeros', trainable=True)
182 
183  self.variables.append([weights, bias])
184 
185  super(EnhancedRelations, self).build(input_shape)
186 
187  def call(self, inputs):
188  """
189  Compute Relational Layer
190  :param inputs: input tensor
191  :return: output tensor
192  """
193  input_groups = [inputs[0][:, i, :] for i in range(self.number_groups)]
194  questions = inputs[1]
195  outputs = []
196  for index, group1 in enumerate(input_groups[:-1]):
197  for group2 in input_groups[index + 1:]:
198  net = K.dot(K.concatenate([group1, group2, questions]), self.variables[0][0])
199  net = K.bias_add(net, self.variables[0][1])
200  for variables in self.variables[1:]:
201  net = self.activation(net)
202  net = K.dot(net, variables[0])
203  net = K.bias_add(net, variables[1])
204  outputs.append(sigmoid(net))
205 
206  flat_result = K.concatenate(outputs)
207  return Reshape((self.combinations, self.number_features,))(flat_result)
208 
209  def compute_output_shape(self, input_shape):
210  """
211  Compute Output shape
212  :return: Output shape
213  """
214  # accept only 2 inputs
215  assert(len(input_shape) == 2)
216  # first input should be a 2D layers
217  assert(len(input_shape[0]) == 3)
218  # second input should be a 1D layers
219  assert(len(input_shape[1]) == 2)
220 
221  self.combinations = np.int32(np.math.factorial(self.number_groups) / (2 * np.math.factorial(self.number_groups - 2)))
222 
223  return (input_shape[0][0], self.combinations, self.number_features)
224 
225  def get_config(self):
226  """
227  Config required for saving parameters in keras model.
228  """
229  config = {
230  'number_features': self.number_features,
231  'hidden_feature_shape': self.hidden_feature_shape,
232  'activation': activations.serialize(self.activation)
233  }
234  base_config = super(EnhancedRelations, self).get_config()
235  return dict(list(base_config.items()) + list(config.items()))
keras_relational.Relations
Definition: keras_relational.py:14
keras_relational.Relations.group_len
group_len
how many neurons has one comparable object
Definition: keras_relational.py:40
keras_relational.EnhancedRelations.get_config
def get_config(self)
Definition: keras_relational.py:225
keras_relational.Relations.build
def build(self, input_shape)
Definition: keras_relational.py:48
keras_relational.EnhancedRelations.question_len
question_len
size of second input vector
Definition: keras_relational.py:150
keras_relational.EnhancedRelations
Definition: keras_relational.py:121
keras_relational.EnhancedRelations.build
def build(self, input_shape)
Definition: keras_relational.py:154
keras_relational.Relations.__init__
def __init__(self, number_features, hidden_feature_shape=[30, 30, 30, 30], activation=tanh, **kwargs)
Definition: keras_relational.py:26
keras_relational.EnhancedRelations.compute_output_shape
def compute_output_shape(self, input_shape)
Definition: keras_relational.py:209
keras_relational.EnhancedRelations.call
def call(self, inputs)
Definition: keras_relational.py:187
keras_relational.Relations.get_config
def get_config(self)
Definition: keras_relational.py:108
keras_relational.EnhancedRelations.variables
variables
saves weights for call
Definition: keras_relational.py:146
keras_relational.EnhancedRelations.number_groups
number_groups
Number of groups in input.
Definition: keras_relational.py:138
keras_relational.EnhancedRelations.combinations
combinations
number of relation combinations
Definition: keras_relational.py:148
keras_relational.Relations.hidden_feature_shape
hidden_feature_shape
shape of hidden layers used for extracting relations
Definition: keras_relational.py:36
keras_relational.EnhancedRelations.number_features
number_features
Number of features.
Definition: keras_relational.py:136
keras_relational.EnhancedRelations.group_len
group_len
how many neurons has one comparable object
Definition: keras_relational.py:144
keras_relational.EnhancedRelations.hidden_feature_shape
hidden_feature_shape
shape of hidden layers used for extracting relations
Definition: keras_relational.py:140
keras_relational.Relations.variables
variables
saves weights for call
Definition: keras_relational.py:42
keras_relational.Relations.compute_output_shape
def compute_output_shape(self, input_shape)
Definition: keras_relational.py:96
keras_relational.Relations.call
def call(self, inputs)
Definition: keras_relational.py:75
keras_relational.Relations.number_features
number_features
Number of features.
Definition: keras_relational.py:32
keras_relational.Relations.number_groups
number_groups
Number of groups in input.
Definition: keras_relational.py:34
keras_relational.Relations.combinations
combinations
number of relation combinations
Definition: keras_relational.py:44
keras_relational.EnhancedRelations.activation
activation
activation used for hidden layer in shared weights.
Definition: keras_relational.py:142
keras_relational.Relations.activation
activation
activation used for hidden layer in shared weights.
Definition: keras_relational.py:38
keras_relational.EnhancedRelations.__init__
def __init__(self, number_features, hidden_feature_shape=[30, 30, 30, 30], activation=tanh, **kwargs)
Definition: keras_relational.py:130