From 3079463bc0ca4f880c3c6c86e919e6f885320205 Mon Sep 17 00:00:00 2001
From: Luc Giffon <luc.giffon@lis-lab.fr>
Date: Fri, 12 Jul 2019 15:50:35 +0200
Subject: [PATCH] add documentation to python files

---
 keras_kernel_functions.py | 28 +++++++++++++++++++++++++---
 nystrom_layer.py          | 21 +++++++++++++++++++--
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/keras_kernel_functions.py b/keras_kernel_functions.py
index 9ebd4cb..b967df1 100644
--- a/keras_kernel_functions.py
+++ b/keras_kernel_functions.py
@@ -19,7 +19,7 @@ def keras_linear_kernel(args, normalize=True, tanh_activation=False):
     :param args: list of size 2 containing x and y
     :param normalize: if True, normalize the input with l2 before computing the kernel function
     :param tanh_activation: if True apply tanh activation to the output
-    :return:
+    :return: The linear kernel between args[0] and args[1]
     """
     X = args[0]
     Y = args[1]
@@ -35,6 +35,17 @@ def keras_linear_kernel(args, normalize=True, tanh_activation=False):
 
 
 def keras_chi_square_CPD(args, epsilon=None, tanh_activation=True, normalize=False):
+    """
+    Chi square kernel (equivalent to `additive_chi2_kernel` in scikit-learn):
+
+    $k(x, y) = -Sum [(x - y)^2 / (x + y)]$
+
+    :param args: list of size 2 containing x and y
+    :param epsilon: very small value to add to the denominator so that we do not have zeros here
+    :param tanh_activation: if True apply tanh activation to the output
+    :param normalize: if True, normalize the input with l2 before computing the kernel function
+    :return: The chi square kernel between args[0] and args[1]
+    """
     X = args[0]
     Y = args[1]
     if normalize:
@@ -59,6 +70,17 @@ def keras_chi_square_CPD(args, epsilon=None, tanh_activation=True, normalize=Fal
 
 
 def keras_chi_square_CPD_exp(args, gamma, epsilon=None, tanh_activation=False, normalize=True):
+    """
+    Exponential chi square kernel (equivalent to `chi2_kernel` in scikit-learn):
+
+    $k(x, y) = exp(-gamma Sum [(x - y)^2 / (x + y)])$
+
+    :param args: list of size 2 containing x and y
+    :param epsilon: very small value to add to the denominator so that we do not have zeros here
+    :param tanh_activation: if True apply tanh activation to the output
+    :param normalize: if True, normalize the input with l2 before computing the kernel function
+    :return: The exponential chi square kernel between args[0] and args[1]
+    """
     result = keras_chi_square_CPD(args, epsilon, tanh_activation, normalize)
     result *= gamma
     return K.exp(result)
@@ -68,12 +90,12 @@ def keras_rbf_kernel(args, gamma, normalize=True, tanh_activation=False):
     """
     Compute the rbf kernel between each entry of X and each line of Y.
 
-    tf_rbf_kernel(x, y, gamma) = exp(- (||x - y||^2 * gamma))
+    $(x, y, gamma) = exp(- (||x - y||^2 * gamma))$
 
     :param X: A tensor of size n times d
     :param Y: A tensor of size m times d
     :param gamma: The bandwith of the kernel
-    :return:
+    :return: The RBF kernel between args[0] and args[1]
     """
     X = args[0]
     Y = args[1]
diff --git a/nystrom_layer.py b/nystrom_layer.py
index ebeb7f5..a610db6 100644
--- a/nystrom_layer.py
+++ b/nystrom_layer.py
@@ -10,7 +10,18 @@ from keras.preprocessing.image import ImageDataGenerator
 from keras_kernel_functions import keras_linear_kernel
 
 
-def datagen_fixed_batch_size(x, y, x_sub=None, p_datagen=ImageDataGenerator()):
+def datagen_fixed_batch_size(x, y, batch_size, x_sub=None, p_datagen=ImageDataGenerator()):
+    """
+    Wrap a data generator so that:
+     - it always output batches of the same size
+     - it gives a subsample along with each batch
+
+    :param x: observation data
+    :param y: label data
+    :param x_sub: list of base of subsample (each base must be of size batch_size)
+    :param p_datagen: the initial data generator to wrap
+    :return:
+    """
     if x_sub is None:
         x_sub = []
     for x_batch, y_batch in p_datagen.flow(x, y, batch_size=batch_size):
@@ -59,6 +70,8 @@ def init_number_subsample_bases(nys_size, batch_size):
         return quotient + 1, batch_size - remaining
 
 if __name__ == "__main__":
+    # model meta parameters
+    # ---------------------
     batch_size = 128
     epochs = 1
     num_classes = 10
@@ -126,11 +139,15 @@ if __name__ == "__main__":
     # weight matrix of the nystrom layer
     input_classifier = Dense(nys_size, use_bias=False, activation='linear')(kernel_vector) # metric matrix of the Nyström layer
 
+    # final softmax classification layer
+    # ----------------------------------
     classif = Dense(num_classes, activation="softmax")(input_classifier)
 
+    # finalization of model, compilation and training
+    # -----------------------------------------------
     model = Model([input_x] + input_repr_subsample, [classif])
     adam = Adam(lr=.1)
     model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])
-    model.fit_generator(datagen_fixed_batch_size(x_train, y_train, list_subsample_bases, datagen),
+    model.fit_generator(datagen_fixed_batch_size(x_train, y_train, batch_size, list_subsample_bases, datagen),
                         steps_per_epoch=int(x_train.shape[0] / batch_size),
                         epochs=epochs)
-- 
GitLab