diff --git a/bob/pad/face/algorithm/VideoCascadeSvmPadAlgorithm.py b/bob/pad/face/algorithm/VideoCascadeSvmPadAlgorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..c5690a61a2488918f2c806fd4a746f0de6dd6f0a
--- /dev/null
+++ b/bob/pad/face/algorithm/VideoCascadeSvmPadAlgorithm.py
@@ -0,0 +1,1050 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+"""
+Created on Wed May 17 09:43:09 2017
+
+@author: Olegs Nikisins
+"""
+
+#==============================================================================
+# Import what is needed here:
+
+from bob.pad.base.algorithm import Algorithm
+
+import numpy as np
+
+import bob.learn.libsvm
+
+import bob.learn.linear
+
+import bob.io.base
+
+import os
+
+import fnmatch
+
+from bob.bio.video.utils import FrameContainer
+
+#==============================================================================
+# Main body :
+
+class VideoCascadeSvmPadAlgorithm(Algorithm):
+    """
+    This class is designed to train the **cascede** of SVMs given Frame Containers
+    with features of real and attack classes. The procedure is the following:
+
+    1. First, the input data is mean-std normalized.
+
+    2. Second, the PCA is trained on normalized input features. Only the
+       features of the **real** class are used in PCA training, both
+       for one-class and two-class SVMs.
+
+    3. The features are next projected given trained PCA machine.
+
+    4. Prior to SVM training the features are again mean-std normalized.
+
+    5. Next SVM machine is trained for each N projected features. First, preojected
+       features corresponding to highest eigenvalues are selected. N is usually small
+       N = (2, 3). So, if N = 2, the first SVM is trained for projected features 1 and 2,
+       second SVM is trained for projected features 3 and 4, and so on.
+
+    6. These SVMs then form a cascade of classifiers. The input feature vector is then
+       projected using PCA machine and passed through all classifiers in the cascade.
+       The decision is then made by majority voting.
+
+    Both one-class SVM and two-class SVM cascades can be trained.
+    In this implementation the grid search of SVM parameters is not supported.
+
+    **Parameters:**
+
+    ``machine_type`` : :py:class:`str`
+        A type of the SVM machine. Please check ``bob.learn.libsvm`` for
+        more details. Default: 'C_SVC'.
+
+    ``kernel_type`` : :py:class:`str`
+        A type of kerenel for the SVM machine. Please check ``bob.learn.libsvm``
+        for more details. Default: 'RBF'.
+
+    ``svm_kwargs`` : :py:class:`dict`
+        Dictionary containing the hyper-parameters of the SVM.
+        Default: {'cost': 1, 'gamma': 0}.
+
+    ``N`` : :py:class:`int`
+        The number of features to be used for training a single SVM machine
+        in the cascade. Default: 2.
+
+    ``pos_scores_slope`` : :py:class:`float`
+        The positive scores returned by SVM cascade will be multiplied by this
+        constant prior to majority voting. Default: 0.01 .
+
+    ``frame_level_scores_flag`` : :py:class:`bool`
+        Return scores for each frame individually if True. Otherwise, return a
+        single score per video. Default: False.
+    """
+
+    def __init__(self,
+                 machine_type = 'C_SVC',
+                 kernel_type = 'RBF',
+                 svm_kwargs = {'cost': 1, 'gamma': 0},
+                 N = 2,
+                 pos_scores_slope = 0.01,
+                 frame_level_scores_flag = False):
+
+
+        Algorithm.__init__(self,
+                           machine_type = machine_type,
+                           kernel_type = kernel_type,
+                           svm_kwargs = svm_kwargs,
+                           N = N,
+                           pos_scores_slope = pos_scores_slope,
+                           frame_level_scores_flag = frame_level_scores_flag,
+                           performs_projection=True,
+                           requires_projector_training=True)
+
+        self.machine_type = machine_type
+        self.kernel_type = kernel_type
+        self.svm_kwargs = svm_kwargs
+        self.N = N
+        self.pos_scores_slope = pos_scores_slope
+        self.frame_level_scores_flag = frame_level_scores_flag
+
+        self.pca_projector_file_name = "pca_projector" # pca machine will be saved to .hdf5 file with this name
+        self.svm_projector_file_name = "svm_projector" # svm machines will be saved to .hdf5 files with this name augumented by machine number
+
+        self.pca_machine = None
+        self.svm_machines = None
+
+
+    #==========================================================================
+    def convert_frame_cont_to_array(self, frame_container):
+        """
+        This function converts a single Frame Container into an array of features.
+        The rows are samples, the columns are features.
+
+        **Parameters:**
+
+        ``frame_container`` : object
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames.
+            The rows are samples, the columns are features.
+        """
+
+        feature_vectors = []
+
+        frame_dictionary = {}
+
+        for frame in frame_container:
+
+            frame_dictionary[frame[0]] = frame[1]
+
+        for idx, _ in enumerate(frame_container):
+
+            # Frames are stored in a mixed order, therefore we get them using incrementing frame index:
+            feature_vectors.append(frame_dictionary[str(idx)])
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def convert_list_of_frame_cont_to_array(self, frame_containers):
+        """
+        This function converts a list of Frame containers into an array of features.
+        Features from different frame containers (individuals) are concatenated into the
+        same list. This list is then converted to an array. The rows are samples,
+        the columns are features.
+
+        **Parameters:**
+
+        ``frame_containers`` : [FrameContainer]
+            A list of Frame Containers, , see ``bob.bio.video.utils.FrameContainer``.
+            Each frame Container contains feature vectors for the particular individual/person.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames of all individuals.
+        """
+
+        feature_vectors = []
+
+        for frame_container in frame_containers:
+
+            video_features_array = self.convert_frame_cont_to_array(frame_container)
+
+            feature_vectors.append( video_features_array )
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def comp_prediction_precision(self, machine, real, attack):
+        """
+        This function computes the precision of the predictions as a ratio
+        of correctly classified samples to the total number of samples.
+
+        **Parameters:**
+
+        ``machine`` : object
+            A pre-trained SVM machine.
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Array of features representing the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Array of features representing the attack class.
+
+        **Returns:**
+
+        ``precision`` : :py:class:`float`
+            The precision of the predictions.
+        """
+
+        labels_real = machine.predict_class(real)
+
+        labels_attack = machine.predict_class(attack)
+
+        samples_num = len(labels_real) + len(labels_attack)
+
+        precision = ( np.sum(labels_real == 1) + np.sum(labels_attack == -1) ).astype( np.float ) / samples_num
+
+        return precision
+
+
+    #==========================================================================
+    def mean_std_normalize(self, features, features_mean= None, features_std = None):
+        """
+        The features in the input 2D array are mean-std normalized.
+        The rows are samples, the columns are features. If ``features_mean``
+        and ``features_std`` are provided, then these vectors will be used for
+        normalization. Otherwise, the mean and std of the features is
+        computed on the fly.
+
+        **Parameters:**
+
+        ``features`` : 2D :py:class:`numpy.ndarray`
+            Array of features to be normalized.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features. Default: None.
+
+        ``features_std`` : 2D :py:class:`numpy.ndarray`
+            Standart deviation of the features. Default: None.
+
+        **Returns:**
+
+        ``features_norm`` : 2D :py:class:`numpy.ndarray`
+            Normalized array of features.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        features = np.copy(features)
+
+        # Compute mean and std if not given:
+        if features_mean is None:
+
+            features_mean = np.mean(features, axis=0)
+
+            features_std = np.std(features, axis=0)
+
+        row_norm_list = []
+
+        for row in features: # row is a sample
+
+            row_norm = (row - features_mean) / features_std
+
+            row_norm_list.append(row_norm)
+
+        features_norm = np.vstack(row_norm_list)
+
+        return features_norm, features_mean, features_std
+
+
+    #==========================================================================
+    def norm_train_data(self, real, attack, one_class_flag):
+        """
+        Mean-std normalization of input data arrays. If ``one_class_flag = True``
+        the ``attack`` argument can be anything, it will be skipped.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class. If ``one_class_flag = True``
+            this argument can be anything, it will be skipped.
+
+        ``one_class_flag`` : :py:class:`bool`
+            If ``True``, only real features will be used in the computation of
+            mean and std normalization vectors. Otherwise both sets are used.
+
+        **Returns:**
+
+        ``real_norm`` : 2D :py:class:`numpy.ndarray`
+            Mean-std normalized training features for the real class.
+
+        ``attack_norm`` : 2D :py:class:`numpy.ndarray`
+            Mean-std normalized training features for the attack class.
+            Or an empty list if ``one_class_flag = True``.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        if not( one_class_flag ): # two-class SVM case
+
+            features = np.vstack([real, attack])
+            features_norm, features_mean, features_std = self.mean_std_normalize(features)
+            real_norm =   features_norm[0:real.shape[0], :] # The array is now normalized
+            attack_norm = features_norm[real.shape[0]:, :] # The array is now normalized
+
+        else: # one-class SVM case
+
+            real_norm, features_mean, features_std = self.mean_std_normalize(real) # use only real class to compute normalizers
+            attack_norm = []
+#            attack_norm = self.mean_std_normalize(attack, features_mean, features_std)
+
+        return real_norm, attack_norm, features_mean, features_std
+
+
+    #==========================================================================
+    def train_pca(self, data):
+        """
+        Train PCA given input array of feature vectors. The data is mean-std
+        normalized prior to PCA training.
+
+        **Parameters:**
+
+        ``data`` : 2D :py:class:`numpy.ndarray`
+            Array of feature vectors of the size (N_samples x N_features).
+            The features must be already mean-std normalized.
+
+        **Returns:**
+
+        ``machine`` : :py:class:`bob.learn.linear.Machine`
+            The PCA machine that has been trained. The mean-std normalizers are
+            also set in the machine.
+
+        ``eig_vals`` : 1D :py:class:`numpy.ndarray`
+            The eigen-values of the PCA projection.
+        """
+
+        # 1. Normalize the training data:
+        data_norm, features_mean, features_std = self.mean_std_normalize(data)
+
+        trainer = bob.learn.linear.PCATrainer() # Creates a PCA trainer
+
+        [machine, eig_vals] = trainer.train(data_norm)  # Trains the machine with the given data
+
+        # Set the normalizers for the PCA machine, needed to normalize the test samples.
+        machine.input_subtract = features_mean # subtract the mean of train data
+        machine.input_divide   = features_std  # divide by std of train data
+
+        return machine, eig_vals
+
+
+    #==========================================================================
+    def train_svm(self, real, attack, machine_type, kernel_type, svm_kwargs):
+        """
+        One-class or two class-SVM is trained in this method given input features.
+        The value of ``attack`` argument is not important in the case of one-class SVM.
+        Prior to training the data is mean-std normalized.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class. If machine_type == 'ONE_CLASS'
+            this argument can be anything, it will be skipped.
+
+        ``machine_type`` : :py:class:`str`
+            A type of the SVM machine. Please check ``bob.learn.libsvm`` for
+            more details.
+
+        ``kernel_type`` : :py:class:`str`
+            A type of kerenel for the SVM machine. Please check ``bob.learn.libsvm``
+            for more details.
+
+        ``svm_kwargs`` : :py:class:`dict`
+            Dictionary containing the hyper-parameters of the SVM.
+
+        **Returns:**
+
+        ``machine`` : object
+            A trained SVM machine. The mean-std normalizers are also set in the
+            machine.
+        """
+
+        one_class_flag = (machine_type == 'ONE_CLASS') # True if one-class SVM is used
+
+        # Mean-std normalize the data before training
+        real, attack, features_mean, features_std = self.norm_train_data(real, attack, one_class_flag)
+        # real and attack - are now mean-std normalized
+
+        trainer = bob.learn.libsvm.Trainer(machine_type = machine_type,
+                                           kernel_type = kernel_type,
+                                           probability = True)
+
+        for key in svm_kwargs.keys():
+
+            setattr(trainer, key, svm_kwargs[key]) # set the hyper-parameters of the SVM
+
+        if not( one_class_flag ): # two-class SVM case
+
+            data = [real, attack] # data for final training
+
+        else: # one-class SVM case
+
+            data = [real] # only real class used for training
+
+        machine = trainer.train(data) # train the machine
+
+        # add the normalizers to the trained SVM machine
+        machine.input_subtract = features_mean # subtract the mean of train data
+        machine.input_divide   = features_std  # divide by std of train data
+
+        return machine
+
+
+    #==========================================================================
+    def get_data_start_end_idx(self, data, N):
+        """
+        Get indexes to select the subsets of data related to the cascades.
+        First (n_machines - 1) SVMs will be trained using N features.
+        Last SVM will be trained using remaining features, which is less or
+        equal to N.
+
+        **Parameters:**
+
+        ``data`` : 2D :py:class:`numpy.ndarray`
+            Data array containing the training features. The dimensionality is
+            (N_samples x N_features).
+
+        ``N`` : :py:class:`int`
+            Number of features per single SVM.
+
+        **Returns:**
+
+        ``idx_start`` : [int]
+            Starting indexes for data subsets.
+
+        ``idx_end`` : [int]
+            End indexes for data subsets.
+
+        ``n_machines`` : :py:class:`int`
+            Number of SVMs to be trained.
+        """
+
+        n_features = data.shape[1]
+
+        n_machines = np.int(n_features/N)
+
+        if (n_features - n_machines*N) > 1: # if more than one feature remains
+
+            machines_num = range(0, n_machines, 1)
+
+            idx_start = [item*N for item in machines_num]
+
+            idx_end = [(item+1)*N for item in machines_num]
+
+            idx_start.append( n_machines*N )
+
+            idx_end.append( n_features )
+
+            n_machines = n_machines + 1
+
+        else:
+
+            machines_num = range(0, n_machines, 1)
+
+            idx_start = [item*N for item in machines_num]
+
+            idx_end = [(item+1)*N for item in machines_num]
+
+        return idx_start, idx_end, n_machines
+
+
+    #==========================================================================
+    def train_svm_cascade(self, real, attack, machine_type, kernel_type, svm_kwargs, N):
+        """
+        Train a cascade of SVMs, one SVM machine per N features. N is usually small
+        N = (2, 3). So, if N = 2, the first SVM is trained for features 1 and 2,
+        second SVM is trained for features 3 and 4, and so on.
+
+        Both one-class and two-class SVM cascades can be trained. The value of
+        ``attack`` argument is not important in the case of one-class SVM.
+
+        The data is mean-std normalized prior to SVM cascade training.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class. If machine_type == 'ONE_CLASS'
+            this argument can be anything, it will be skipped.
+
+        ``machine_type`` : :py:class:`str`
+            A type of the SVM machine. Please check ``bob.learn.libsvm`` for
+            more details.
+
+        ``kernel_type`` : :py:class:`str`
+            A type of kerenel for the SVM machine. Please check ``bob.learn.libsvm``
+            for more details.
+
+        ``svm_kwargs`` : :py:class:`dict`
+            Dictionary containing the hyper-parameters of the SVM.
+
+        ``N`` : :py:class:`int`
+            The number of features to be used for training a single SVM machine
+            in the cascade.
+
+        **Returns:**
+
+        ``machines`` : :py:class:`dict`
+            A dictionary containing a cascade of trained SVM machines.
+        """
+
+        one_class_flag = (machine_type == 'ONE_CLASS') # True if one-class SVM is used
+
+        idx_start, idx_end, n_machines = self.get_data_start_end_idx(real, N)
+
+        machines = {}
+
+        for machine_num in range(0, n_machines, 1):
+
+            if not(one_class_flag): # two-class SVM
+
+                real_subset     = real[:, idx_start[machine_num] : idx_end[machine_num] ] # both real and attack classes are used
+                attack_subset = attack[:, idx_start[machine_num] : idx_end[machine_num] ]
+
+            else: # one-class SVM case
+
+                real_subset     = real[:, idx_start[machine_num] : idx_end[machine_num] ] # only the real class is used
+                attack_subset = []
+
+            machine = self.train_svm(real_subset, attack_subset, machine_type, kernel_type, svm_kwargs)
+
+            machines[ str(machine_num) ] = machine
+
+            del machine
+
+        return machines
+
+
+    #==========================================================================
+    def train_pca_svm_cascade(self, real, attack, machine_type, kernel_type, svm_kwargs, N):
+        """
+        This function is designed to train the **cascede** of SVMs given
+        features of real and attack classes. The procedure is the following:
+
+        1. First, the PCA machine is trained also incorporating mean-std
+           feature normalization. Only the features of the **real** class are
+           used in PCA training, both for one-class and two-class SVMs.
+
+        2. The features are next projected given trained PCA machine.
+
+        3. Next, SVM machine is trained for each N projected features. Prior to
+           SVM training the features are again mean-std normalized. First, preojected
+           features corresponding to highest eigenvalues are selected. N is usually small
+           N = (2, 3). So, if N = 2, the first SVM is trained for projected features 1 and 2,
+           second SVM is trained for projected features 3 and 4, and so on.
+
+        Both one-class SVM and two-class SVM cascades can be trained.
+        In this implementation the grid search of SVM parameters is not supported.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class. If machine_type == 'ONE_CLASS'
+            this argument can be anything, it will be skipped.
+
+        ``machine_type`` : :py:class:`str`
+            A type of the SVM machine. Please check ``bob.learn.libsvm`` for
+            more details.
+
+        ``kernel_type`` : :py:class:`str`
+            A type of kerenel for the SVM machine. Please check ``bob.learn.libsvm``
+            for more details.
+
+        ``svm_kwargs`` : :py:class:`dict`
+            Dictionary containing the hyper-parameters of the SVM.
+
+        ``N`` : :py:class:`int`
+            The number of features to be used for training a single SVM machine
+            in the cascade.
+
+        **Returns:**
+
+        ``pca_machine`` : object
+            A trained PCA machine.
+
+        ``svm_machines`` : :py:class:`dict`
+            A cascade of SVM machines.
+        """
+
+        one_class_flag = (machine_type == 'ONE_CLASS') # True if one-class SVM is used
+
+        # 1. Train PCA using normalized features of the real class:
+        pca_machine, _ = self.train_pca(real) # the mean-std normalizers are already set in this machine
+
+        # 2. Project the features given PCA machine:
+        if not(one_class_flag):
+            projected_real = pca_machine(real) # the normalizers are already set for the PCA machine, therefore non-normalized data is passed in
+            projected_attack = pca_machine(attack) # the normalizers are already set for the PCA machine, therefore non-normalized data is passed in
+
+        else:
+            projected_real = pca_machine(real) # the normalizers are already set for the PCA machine, therefore non-normalized data is passed in
+            projected_attack = []
+
+        # 3. Train a cascade of SVM machines using **projected** data
+        svm_machines = self.train_svm_cascade(projected_real, projected_attack, machine_type, kernel_type, svm_kwargs, N)
+
+        return pca_machine, svm_machines
+
+
+    #==========================================================================
+    def save_machine(self, projector_file, projector_file_name, machine):
+        """
+        Saves the machine to the hdf5 file. The name of the file is specified in
+        ``projector_file_name`` string. The location is specified in the
+        path component of the ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to save the trained projector to, as
+            returned by ``bob.pad.base`` framework. In this function only the path
+            component is used.
+
+        ``projector_file_name`` : :py:class:`str`
+            The relative name of the file to save the machine to. Name without
+            extension.
+
+        ``machine`` : object
+            The machine to be saved.
+        """
+
+        extension = ".hdf5"
+
+        resulting_file_name = os.path.join( os.path.split(projector_file)[0], projector_file_name + extension )
+
+        f = bob.io.base.HDF5File(resulting_file_name, 'w') # open hdf5 file to save to
+
+        machine.save(f) # save the machine and normalization parameters
+
+        del f
+
+
+    #==========================================================================
+    def save_cascade_of_machines(self, projector_file, projector_file_name, machines):
+        """
+        Saves a cascade of machines to the hdf5 files. The name of the file is
+        specified in ``projector_file_name`` string and will be augumented with
+        a number of the machine. The location is specified in the path component
+        of the ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to save the trained projector to, as
+            returned by ``bob.pad.base`` framework. In this function only the path
+            component is used.
+
+        ``projector_file_name`` : :py:class:`str`
+            The relative name of the file to save the machine to. This name will
+            be augumented with a number of the machine. Name without extension.
+
+        ``machines`` : :py:class:`dict`
+            A cascade of machines. The key in the dictionary is the number of
+            the machine, value is the machine itself.
+        """
+
+        for key in machines:
+
+            augumented_projector_file_name = projector_file_name + key
+
+            machine = machines[key]
+
+            self.save_machine(projector_file, augumented_projector_file_name, machine)
+
+
+    #==========================================================================
+    def train_projector(self, training_features, projector_file):
+        """
+        Train PCA and cascade of SVMs for feature projection and save them
+        to files. The ``requires_projector_training = True`` flag must be set
+        to True to enable this function.
+
+        **Parameters:**
+
+        ``training_features`` : [[FrameContainer], [FrameContainer]]
+            A list containing two elements: [0] - a list of Frame Containers with
+            feature vectors for the real class; [1] - a list of Frame Containers with
+            feature vectors for the attack class.
+
+        ``projector_file`` : :py:class:`str`
+            The file to save the trained projector to, as returned by the
+            ``bob.pad.base`` framework. In this class the names of the files to
+            save the projectors to are modified, see ``save_machine`` and
+            ``save_cascade_of_machines`` methods of this class for more details.
+        """
+
+        # training_features[0] - training features for the REAL class.
+        real = self.convert_list_of_frame_cont_to_array(training_features[0]) # output is array
+        # training_features[1] - training features for the ATTACK class.
+        attack = self.convert_list_of_frame_cont_to_array(training_features[1]) # output is array
+
+        # Train the PCA machine and cascade of SVMs
+        pca_machine, svm_machines = self.train_pca_svm_cascade(real = real,
+                                                               attack = attack,
+                                                               machine_type = self.machine_type,
+                                                               kernel_type = self.kernel_type,
+                                                               svm_kwargs = self.svm_kwargs,
+                                                               N = self.N)
+
+        # Save the PCA machine
+        self.save_machine(projector_file, self.pca_projector_file_name, pca_machine)
+
+        # Save the cascade of SVMs:
+        self.save_cascade_of_machines(projector_file, self.svm_projector_file_name, svm_machines)
+
+
+    #==========================================================================
+    def load_machine(self, projector_file, projector_file_name):
+        """
+        Loads the machine from the hdf5 file. The name of the file is specified in
+        ``projector_file_name`` string. The location is specified in the
+        path component of the ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to load the trained projector from, as
+            returned by ``bob.pad.base`` framework. In this function only the path
+            component is used.
+
+        ``projector_file_name`` : :py:class:`str`
+            The relative name of the file to load the machine from. Name without
+            extension.
+
+        **Returns:**
+
+        ``machine`` : object
+            A machine loaded from file.
+        """
+
+        extension = ".hdf5"
+
+        resulting_file_name = os.path.join( os.path.split(projector_file)[0], projector_file_name + extension ) # name of the file
+
+        f = bob.io.base.HDF5File(resulting_file_name, 'r') # file to read the machine from
+
+        if "pca_" in projector_file_name:
+
+            machine = bob.learn.linear.Machine(f)
+
+        if "svm_" in projector_file_name:
+
+            machine = bob.learn.libsvm.Machine(f)
+
+        del f
+
+        return machine
+
+
+    #==========================================================================
+    def get_cascade_file_names(self, projector_file, projector_file_name):
+        """
+        Get the list of file-names storing the cascade of machines. The location
+        of the files is specified in the path component of the ``projector_file``
+        argument.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to load the trained projector from, as
+            returned by ``bob.pad.base`` framework. In this function only the path
+            component is used.
+
+        ``projector_file_name`` : :py:class:`str`
+            The **common** string in the names of files storing the
+            cascade of pretrained machines. Name without extension.
+
+        **Returns:**
+
+        ``cascade_file_names`` : [str]
+            A list of of **relative** file-names storing the cascade of machines.
+        """
+
+        path = os.path.split(projector_file)[0] # directory containing files storing the cascade of machines.
+
+        files = []
+
+        for f in os.listdir( path ):
+
+            if fnmatch.fnmatch( f, projector_file_name + "*" ):
+
+                files.append(f)
+
+        return files
+
+
+    #==========================================================================
+    def load_cascade_of_machines(self, projector_file, projector_file_name):
+        """
+        Loades a cascade of machines from the hdf5 files. The name of the file is
+        specified in ``projector_file_name`` string and will be augumented with
+        a number of the machine. The location is specified in the path component
+        of the ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to load the trained projector from, as
+            returned by ``bob.pad.base`` framework. In this function only the path
+            component is used.
+
+        ``projector_file_name`` : :py:class:`str`
+            The relative name of the file to load the machine from. This name will
+            be augumented with a number of the machine. Name without extension.
+
+        **Returns:**
+
+        ``machines`` : :py:class:`dict`
+            A cascade of machines. The key in the dictionary is the number of
+            the machine, value is the machine itself.
+        """
+
+        files = self.get_cascade_file_names(projector_file, projector_file_name) # files storing the cascade
+
+        machines = {}
+
+        for idx, _ in enumerate(files):
+
+            machine = self.load_machine( projector_file, projector_file_name + str(idx) )
+
+            machines[ str(idx) ] = machine
+
+        return machines
+
+
+    #==========================================================================
+    def load_projector(self, projector_file):
+        """
+        Load the pretrained PCA machine and a cascade of SVM classifiers from
+        files to perform feature projection.
+        This function sets the arguments ``self.pca_machine`` and ``self.svm_machines``
+        of this class with loaded machines.
+
+        The function must be capable of reading the data saved with the
+        :py:meth:`train_projector` method of this class.
+
+        Please register `performs_projection = True` in the constructor to
+        enable this function.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            The file to read the projector from, as returned by the
+            ``bob.pad.base`` framework. In this class the names of the files to
+            read the projectors from are modified, see ``load_machine`` and
+            ``load_cascade_of_machines`` methods of this class for more details.
+        """
+
+        # Load the PCA machine
+        pca_machine = self.load_machine(projector_file, self.pca_projector_file_name)
+
+        # Load the cascade of SVMs:
+        svm_machines = self.load_cascade_of_machines(projector_file, self.svm_projector_file_name)
+
+        self.pca_machine = pca_machine
+        self.svm_machines = svm_machines
+
+
+    #==========================================================================
+    def combine_scores_of_svm_cascade(self, scores_array, pos_scores_slope):
+        """
+        First, multiply positive scores by constant ``pos_scores_slope`` in the
+        input 2D array. The constant is usually small, making the impact of negative
+        scores more significant.
+        Second, the a single score per sample is obtained by avaraging the
+        **pre-modified** scores of the cascade.
+
+        **Parameters:**
+
+        ``scores_array`` : 2D :py:class:`numpy.ndarray`
+            2D score array of the size (N_samples x N_scores).
+
+        ``pos_scores_slope`` : :py:class:`float`
+            The positive scores returned by SVM cascade will be multiplied by this
+            constant prior to majority voting. Default: 0.01 .
+
+        **Returns:**
+
+        ``scores`` : 1D :py:class:`numpy.ndarray`
+            Vector of scores. Scores for the real class are expected to be
+            higher, than the scores of the negative / attack class.
+        """
+
+        cols = []
+
+        for col in scores_array.T:
+
+            idx_vec = np.where(col>=0)
+
+            col[idx_vec] *= pos_scores_slope # multiply positive scores by the constant
+
+            cols.append(col)
+
+        scores_array_modified = np.stack(cols, axis=1)
+
+        scores = np.mean(scores_array_modified, axis = 1)
+
+        return scores
+
+
+    #==========================================================================
+    def project(self, feature):
+        """
+        This function computes a vector of scores for each sample in the input
+        array of features. The following steps are apllied:
+
+        1. Convert input array to numpy array if necessary.
+
+        2. Project features using pretrained PCA machine.
+
+        3. Apply the cascade of SVMs to the preojected features.
+
+        4. Compute a single score per sample by combining the scores produced
+           by the cascade of SVMs. The combination is done using
+           ``combine_scores_of_svm_cascade`` method of this class.
+
+        Set ``performs_projection = True`` in the constructor to enable this function.
+        It is assured that the :py:meth:`load_projector` was **called before** the
+        ``project`` function is executed.
+
+        **Parameters:**
+
+        ``feature`` : FrameContainer or 2D :py:class:`numpy.ndarray`
+            Two types of inputs are accepted.
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+            Or a 2D feature array of the size (N_samples x N_features).
+
+        **Returns:**
+
+        ``scores`` : 1D :py:class:`numpy.ndarray`
+            Vector of scores. Scores for the real class are expected to be
+            higher, than the scores of the negative / attack class.
+        """
+
+        # 1. Convert input array to numpy array if necessary.
+        if isinstance(feature, FrameContainer): # if FrameContainer convert to 2D numpy array
+
+            features_array = self.convert_frame_cont_to_array(feature)
+
+        else:
+
+            features_array = feature
+
+        # 2. Project features using pretrained PCA machine.
+        pca_projected_features = self.pca_machine(features_array)
+
+        # 3. Apply the cascade of SVMs to the preojected features.
+        all_scores = []
+
+        idx_start, idx_end, n_machines = self.get_data_start_end_idx(pca_projected_features, self.N)
+
+        for machine_num in range(0, n_machines, 1): # iterate over SVM machines
+
+            svm_machine = self.svm_machines[ str(machine_num) ] # select a machine
+
+            # subset of PCA projected features to be passed to SVM machine
+            pca_projected_features_subset = pca_projected_features[:, idx_start[machine_num] : idx_end[machine_num] ]
+
+            # for two-class SVM select the scores corresponding to the real class only, done by [:,0]. Index [0] selects the class Index [1] selects the score..
+            single_machine_scores = svm_machine.predict_class_and_scores( pca_projected_features_subset )[1][:,0]
+
+            all_scores.append(single_machine_scores)
+
+        all_scores_array   = np.stack(all_scores, axis = 1).astype(np.float)
+
+        # 4. Combine the scores:
+
+        one_class_flag = (svm_machine.machine_type == 'ONE_CLASS') # True if one-class SVM is used
+
+        if not(one_class_flag):
+
+            scores = np.mean(all_scores_array, axis = 1) # compute mean for two-class SVM
+
+        else: # one class SVM case
+
+            scores = self.combine_scores_of_svm_cascade(all_scores_array, self.pos_scores_slope)
+
+        return scores
+
+
+    #==========================================================================
+    def score(self, toscore):
+        """
+        Returns a probability of a sample being a real class.
+
+        **Parameters:**
+
+        ``toscore`` : 1D or 2D :py:class:`numpy.ndarray`
+            2D in the case of two-class SVM.
+            An array containing class probabilities for each frame.
+            First column contains probabilities for each frame being a real class.
+            Second column contains probabilities for each frame being an attack class.
+            1D in the case of one-class SVM.
+            Vector with scores for each frame defining belonging to the real class.
+
+        **Returns:**
+
+        ``score`` : [:py:class:`float`]
+            If ``frame_level_scores_flag = False`` a single score is returned.
+            One score per video. This score is placed into a list, because
+            the ``score`` must be an iterable.
+            Score is a probability of a sample being a real class.
+            If ``frame_level_scores_flag = True`` a list of scores is returned.
+            One score per frame/sample.
+        """
+
+        if self.frame_level_scores_flag:
+
+            score = list(toscore)
+
+        else:
+
+            score = [np.mean( toscore )] # compute a single score per video
+
+        return score
+
+
+
+
+
diff --git a/bob/pad/face/algorithm/VideoGmmPadAlgorithm.py b/bob/pad/face/algorithm/VideoGmmPadAlgorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..39511ae5ddde544955ef91e8462f10ba597e6bde
--- /dev/null
+++ b/bob/pad/face/algorithm/VideoGmmPadAlgorithm.py
@@ -0,0 +1,476 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Aug 28 16:47:47 2017
+
+@author: Olegs Nikisins
+"""
+
+#==============================================================================
+# Import what is needed here:
+
+from bob.pad.base.algorithm import Algorithm
+
+from bob.bio.video.utils import FrameContainer
+
+import numpy as np
+
+import bob.io.base
+
+from sklearn import mixture
+
+
+#==============================================================================
+# Main body :
+
+class VideoGmmPadAlgorithm(Algorithm):
+    """
+    This class is designed to train a GMM based PAD system. The GMM is trained
+    using data of one class (real class) only. The procedure is the following:
+
+    1. First, the training data is mean-std normalized using mean and std of the
+       real class only.
+
+    2. Second, the GMM with ``n_components`` Gaussians is trained using samples
+       of the real class.
+
+    3. The input features are next classified using pre-trained GMM machine.
+
+    **Parameters:**
+
+    ``n_components`` : :py:class:`int`
+        Number of Gaussians in the GMM. Default: 1 .
+
+    ``random_state`` : :py:class:`int`
+        A seed for the random number generator used in the initialization of
+        the GMM. Default: 7 .
+
+    ``frame_level_scores_flag`` : :py:class:`bool`
+        Return scores for each frame individually if True. Otherwise, return a
+        single score per video. Default: False.
+    """
+
+    def __init__(self,
+                 n_components = 1,
+                 random_state = 3,
+                 frame_level_scores_flag = False):
+
+
+        Algorithm.__init__(self,
+                           n_components = n_components,
+                           random_state = random_state,
+                           frame_level_scores_flag = frame_level_scores_flag,
+                           performs_projection=True,
+                           requires_projector_training=True)
+
+        self.n_components = n_components
+
+        self.random_state = random_state
+
+        self.frame_level_scores_flag = frame_level_scores_flag
+
+        self.machine = None # this argument will be updated with pretrained GMM machine
+
+        self.features_mean = None # this argument will be updated with features mean
+
+        self.features_std = None # this argument will be updated with features std
+
+        # names of the arguments of the pretrained GMM machine to be saved/loaded to/from HDF5 file:
+        self.gmm_param_keys = ["covariance_type", "covariances_", "lower_bound_", "means_", "n_components", "weights_", "converged_", "precisions_", "precisions_cholesky_" ]
+
+
+    #==========================================================================
+    def convert_frame_cont_to_array(self, frame_container):
+        """
+        This function converts a single Frame Container into an array of features.
+        The rows are samples, the columns are features.
+
+        **Parameters:**
+
+        ``frame_container`` : object
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames.
+            The rows are samples, the columns are features.
+        """
+
+        feature_vectors = []
+
+        frame_dictionary = {}
+
+        for frame in frame_container:
+
+            frame_dictionary[frame[0]] = frame[1]
+
+        for idx, _ in enumerate(frame_container):
+
+            # Frames are stored in a mixed order, therefore we get them using incrementing frame index:
+            feature_vectors.append(frame_dictionary[str(idx)])
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def convert_list_of_frame_cont_to_array(self, frame_containers):
+        """
+        This function converts a list of Frame containers into an array of features.
+        Features from different frame containers (individuals) are concatenated into the
+        same list. This list is then converted to an array. The rows are samples,
+        the columns are features.
+
+        **Parameters:**
+
+        ``frame_containers`` : [FrameContainer]
+            A list of Frame Containers, , see ``bob.bio.video.utils.FrameContainer``.
+            Each frame Container contains feature vectors for the particular individual/person.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames of all individuals.
+        """
+
+        feature_vectors = []
+
+        for frame_container in frame_containers:
+
+            video_features_array = self.convert_frame_cont_to_array(frame_container)
+
+            feature_vectors.append( video_features_array )
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def mean_std_normalize(self, features, features_mean= None, features_std = None):
+        """
+        The features in the input 2D array are mean-std normalized.
+        The rows are samples, the columns are features. If ``features_mean``
+        and ``features_std`` are provided, then these vectors will be used for
+        normalization. Otherwise, the mean and std of the features is
+        computed on the fly.
+
+        **Parameters:**
+
+        ``features`` : 2D :py:class:`numpy.ndarray`
+            Array of features to be normalized.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features. Default: None.
+
+        ``features_std`` : 2D :py:class:`numpy.ndarray`
+            Standart deviation of the features. Default: None.
+
+        **Returns:**
+
+        ``features_norm`` : 2D :py:class:`numpy.ndarray`
+            Normalized array of features.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        features = np.copy(features)
+
+        # Compute mean and std if not given:
+        if features_mean is None:
+
+            features_mean = np.mean(features, axis=0)
+
+            features_std = np.std(features, axis=0)
+
+        row_norm_list = []
+
+        for row in features: # row is a sample
+
+            row_norm = (row - features_mean) / features_std
+
+            row_norm_list.append(row_norm)
+
+        features_norm = np.vstack(row_norm_list)
+
+        return features_norm, features_mean, features_std
+
+
+    #==========================================================================
+    def train_gmm(self, real, n_components, random_state):
+        """
+        Train GMM classifier given real class. Prior to the training the data is
+        mean-std normalized.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``n_components`` : :py:class:`int`
+            Number of Gaussians in the GMM. Default: 1 .
+
+        ``random_state`` : :py:class:`int`
+            A seed for the random number generator used in the initialization of
+            the GMM. Default: 7 .
+
+        **Returns:**
+
+        ``machine`` : object
+            A trained GMM machine.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        features_norm, features_mean, features_std = self.mean_std_normalize(real)
+        # real is now mean-std normalized
+
+        machine = mixture.GaussianMixture(n_components = n_components,
+                                          random_state = random_state,
+                                          covariance_type = 'full')
+
+        machine.fit( features_norm )
+
+        return machine, features_mean, features_std
+
+
+    #==========================================================================
+    def save_gmm_machine_and_mean_std(self, projector_file, machine, features_mean, features_std):
+        """
+        Saves the GMM machine, features mean and std to the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to save the data to, as returned by
+            ``bob.pad.base`` framework.
+
+        ``machine`` : object
+            The GMM machine to be saved. As returned by sklearn.linear_model
+            module.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        f = bob.io.base.HDF5File(projector_file, 'w') # open hdf5 file to save to
+
+        for key in self.gmm_param_keys:
+
+            data = getattr( machine, key )
+
+            f.set( key, data )
+
+        f.set( "features_mean", features_mean )
+
+        f.set( "features_std", features_std )
+
+        del f
+
+
+    #==========================================================================
+    def train_projector(self, training_features, projector_file):
+        """
+        Train GMM for feature projection and save it to file.
+        The ``requires_projector_training = True`` flag must be set to True
+        to enable this function.
+
+        **Parameters:**
+
+        ``training_features`` : [[FrameContainer], [FrameContainer]]
+            A list containing two elements: [0] - a list of Frame Containers with
+            feature vectors for the real class; [1] - a list of Frame Containers with
+            feature vectors for the attack class.
+
+        ``projector_file`` : :py:class:`str`
+            The file to save the trained projector to, as returned by the
+            ``bob.pad.base`` framework.
+        """
+
+        # training_features[0] - training features for the REAL class.
+        real = self.convert_list_of_frame_cont_to_array(training_features[0]) # output is array
+
+        # training_features[1] - training features for the ATTACK class.
+#        attack = self.convert_list_of_frame_cont_to_array(training_features[1]) # output is array
+
+        # Train the GMM machine and get normalizers:
+        machine, features_mean, features_std = self.train_gmm(real = real,
+                                                              n_components = self.n_components,
+                                                              random_state = self.random_state)
+
+        # Save the GNN machine and normalizers:
+        self.save_gmm_machine_and_mean_std(projector_file, machine, features_mean, features_std)
+
+
+    #==========================================================================
+    def load_gmm_machine_and_mean_std(self, projector_file):
+        """
+        Loads the machine, features mean and std from the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to load the trained projector from, as
+            returned by ``bob.pad.base`` framework.
+
+        **Returns:**
+
+        ``machine`` : object
+            The loaded GMM machine. As returned by sklearn.mixture module.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        f = bob.io.base.HDF5File(projector_file, 'r') # file to read the machine from
+
+        # initialize the machine:
+        machine = mixture.GaussianMixture()
+
+        # set the params of the machine:
+        for key in self.gmm_param_keys:
+
+            data = f.read(key)
+
+            setattr(machine, key, data)
+
+        features_mean = f.read("features_mean")
+
+        features_std = f.read("features_std")
+
+        del f
+
+        return machine, features_mean, features_std
+
+
+    #==========================================================================
+    def load_projector(self, projector_file):
+        """
+        Loads the machine, features mean and std from the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        This function sets the arguments ``self.machine``, ``self.features_mean``
+        and ``self.features_std`` of this class with loaded machines.
+
+        The function must be capable of reading the data saved with the
+        :py:meth:`train_projector` method of this class.
+
+        Please register `performs_projection = True` in the constructor to
+        enable this function.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            The file to read the projector from, as returned by the
+            ``bob.pad.base`` framework. In this class the names of the files to
+            read the projectors from are modified, see ``load_machine`` and
+            ``load_cascade_of_machines`` methods of this class for more details.
+        """
+
+        machine, features_mean, features_std = self.load_gmm_machine_and_mean_std(projector_file)
+
+        self.machine = machine
+
+        self.features_mean = features_mean
+
+        self.features_std = features_std
+
+
+    #==========================================================================
+    def project(self, feature):
+        """
+        This function computes a vector of scores for each sample in the input
+        array of features. The following steps are applied:
+
+        1. First, the input data is mean-std normalized using mean and std of the
+           real class only.
+
+        2. The input features are next classified using pre-trained GMM machine.
+
+        Set ``performs_projection = True`` in the constructor to enable this function.
+        It is assured that the :py:meth:`load_projector` was **called before** the
+        ``project`` function is executed.
+
+        **Parameters:**
+
+        ``feature`` : FrameContainer or 2D :py:class:`numpy.ndarray`
+            Two types of inputs are accepted.
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+            Or a 2D feature array of the size (N_samples x N_features).
+
+        **Returns:**
+
+        ``scores`` : 1D :py:class:`numpy.ndarray`
+            Vector of scores. Scores for the real class are expected to be
+            higher, than the scores of the negative / attack class.
+            In this case scores are the weighted log probabilities.
+        """
+
+        # 1. Convert input array to numpy array if necessary.
+        if isinstance(feature, FrameContainer): # if FrameContainer convert to 2D numpy array
+
+            features_array = self.convert_frame_cont_to_array(feature)
+
+        else:
+
+            features_array = feature
+
+        features_array_norm, _, _ = self.mean_std_normalize(features_array, self.features_mean, self.features_std)
+
+        scores = self.machine.score_samples( features_array_norm )
+
+        return scores
+
+
+    #==========================================================================
+    def score(self, toscore):
+        """
+        Returns a probability of a sample being a real class.
+
+        **Parameters:**
+
+        ``toscore`` : 1D :py:class:`numpy.ndarray`
+            Vector with scores for each frame/sample defining the probability
+            of the frame being a sample of the real class.
+
+        **Returns:**
+
+        ``score`` : [:py:class:`float`]
+            If ``frame_level_scores_flag = False`` a single score is returned.
+            One score per video. This score is placed into a list, because
+            the ``score`` must be an iterable.
+            Score is a probability of a sample being a real class.
+            If ``frame_level_scores_flag = True`` a list of scores is returned.
+            One score per frame/sample.
+        """
+
+        if self.frame_level_scores_flag:
+
+            score = list(toscore)
+
+        else:
+
+            score = [np.mean( toscore )] # compute a single score per video
+
+        return score
+
diff --git a/bob/pad/face/algorithm/VideoLRPadAlgorithm.py b/bob/pad/face/algorithm/VideoLRPadAlgorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff05a55b20dcce2a16d70f5def6cab98328fa6a4
--- /dev/null
+++ b/bob/pad/face/algorithm/VideoLRPadAlgorithm.py
@@ -0,0 +1,589 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Aug 25 09:29:02 2017
+
+@author: Olegs Nikisins
+"""
+
+#==============================================================================
+# Import what is needed here:
+
+from bob.pad.base.algorithm import Algorithm
+
+from bob.bio.video.utils import FrameContainer
+
+import numpy as np
+
+from sklearn import linear_model
+
+import bob.io.base
+
+
+#==============================================================================
+# Main body :
+
+class VideoLRPadAlgorithm(Algorithm):
+    """
+    This class is designed to train Logistic Regression classifier given Frame Containers
+    with features of real and attack classes. The procedure is the following:
+
+    1. First, the input data is mean-std normalized using mean and std of the
+       real class only.
+
+    2. Second, the Logistic Regression classifier is trained on normalized
+       input features.
+
+    3. The input features are next classified using pre-trained LR machine.
+
+    **Parameters:**
+
+    ``C`` : :py:class:`float`
+        Inverse of regularization strength in LR classifier; must be a positive.
+        Like in support vector machines, smaller values specify stronger
+        regularization. Default: 1.0 .
+
+    ``frame_level_scores_flag`` : :py:class:`bool`
+        Return scores for each frame individually if True. Otherwise, return a
+        single score per video. Default: ``False``.
+
+    ``subsample_train_data_flag`` : :py:class:`bool`
+        Uniformly subsample the training data if ``True``. Default: ``False``.
+
+    ``subsampling_step`` : :py:class:`int`
+        Training data subsampling step, only valid is
+        ``subsample_train_data_flag = True``. Default: 10 .
+
+    ``subsample_videos_flag`` : :py:class:`bool`
+        Uniformly subsample the training videos if ``True``. Default: ``False``.
+
+    ``video_subsampling_step`` : :py:class:`int`
+        Training videos subsampling step, only valid is
+        ``subsample_videos_flag = True``. Default: 3 .
+    """
+
+    def __init__(self,
+                 C = 1,
+                 frame_level_scores_flag = False,
+                 subsample_train_data_flag = False,
+                 subsampling_step = 10,
+                 subsample_videos_flag = False,
+                 video_subsampling_step = 3):
+
+
+        Algorithm.__init__(self,
+                           C = C,
+                           frame_level_scores_flag = frame_level_scores_flag,
+                           subsample_train_data_flag = subsample_train_data_flag,
+                           subsampling_step = subsampling_step,
+                           subsample_videos_flag = subsample_videos_flag,
+                           video_subsampling_step = video_subsampling_step,
+                           performs_projection=True,
+                           requires_projector_training=True)
+
+        self.C = C
+
+        self.frame_level_scores_flag = frame_level_scores_flag
+
+        self.subsample_train_data_flag = subsample_train_data_flag
+
+        self.subsampling_step = subsampling_step
+
+        self.subsample_videos_flag = subsample_videos_flag
+
+        self.video_subsampling_step = video_subsampling_step
+
+        self.lr_machine = None # this argument will be updated with pretrained LR machine
+
+        self.features_mean = None # this argument will be updated with features mean
+        self.features_std = None # this argument will be updated with features std
+
+        # names of the arguments of the pretrained LR machine to be saved/loaded to/from HDF5 file:
+        self.lr_param_keys = ["C", "classes_", "coef_", "intercept_"]
+
+
+    #==========================================================================
+    def convert_frame_cont_to_array(self, frame_container):
+        """
+        This function converts a single Frame Container into an array of features.
+        The rows are samples, the columns are features.
+
+        **Parameters:**
+
+        ``frame_container`` : object
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames.
+            The rows are samples, the columns are features.
+        """
+
+        feature_vectors = []
+
+        frame_dictionary = {}
+
+        for frame in frame_container:
+
+            frame_dictionary[frame[0]] = frame[1]
+
+        for idx, _ in enumerate(frame_container):
+
+            # Frames are stored in a mixed order, therefore we get them using incrementing frame index:
+            feature_vectors.append(frame_dictionary[str(idx)])
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def convert_list_of_frame_cont_to_array(self, frame_containers):
+        """
+        This function converts a list of Frame containers into an array of features.
+        Features from different frame containers (individuals) are concatenated into the
+        same list. This list is then converted to an array. The rows are samples,
+        the columns are features.
+
+        **Parameters:**
+
+        ``frame_containers`` : [FrameContainer]
+            A list of Frame Containers, , see ``bob.bio.video.utils.FrameContainer``.
+            Each frame Container contains feature vectors for the particular individual/person.
+
+        **Returns:**
+
+        ``features_array`` : 2D :py:class:`numpy.ndarray`
+            An array containing features for all frames of all individuals.
+        """
+
+        feature_vectors = []
+
+        for frame_container in frame_containers:
+
+            video_features_array = self.convert_frame_cont_to_array(frame_container)
+
+            feature_vectors.append( video_features_array )
+
+        features_array = np.vstack(feature_vectors)
+
+        return features_array
+
+
+    #==========================================================================
+    def mean_std_normalize(self, features, features_mean= None, features_std = None):
+        """
+        The features in the input 2D array are mean-std normalized.
+        The rows are samples, the columns are features. If ``features_mean``
+        and ``features_std`` are provided, then these vectors will be used for
+        normalization. Otherwise, the mean and std of the features is
+        computed on the fly.
+
+        **Parameters:**
+
+        ``features`` : 2D :py:class:`numpy.ndarray`
+            Array of features to be normalized.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features. Default: None.
+
+        ``features_std`` : 2D :py:class:`numpy.ndarray`
+            Standart deviation of the features. Default: None.
+
+        **Returns:**
+
+        ``features_norm`` : 2D :py:class:`numpy.ndarray`
+            Normalized array of features.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        features = np.copy(features)
+
+        # Compute mean and std if not given:
+        if features_mean is None:
+
+            features_mean = np.mean(features, axis=0)
+
+            features_std = np.std(features, axis=0)
+
+        row_norm_list = []
+
+        for row in features: # row is a sample
+
+            row_norm = (row - features_mean) / features_std
+
+            row_norm_list.append(row_norm)
+
+        features_norm = np.vstack(row_norm_list)
+
+        return features_norm, features_mean, features_std
+
+
+    #==========================================================================
+    def norm_train_data(self, real, attack):
+        """
+        Mean-std normalization of input data arrays. The mean and std normalizers
+        are computed using real class only.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class.
+
+        **Returns:**
+
+        ``real_norm`` : 2D :py:class:`numpy.ndarray`
+            Mean-std normalized training features for the real class.
+
+        ``attack_norm`` : 2D :py:class:`numpy.ndarray`
+            Mean-std normalized training features for the attack class.
+            Or an empty list if ``one_class_flag = True``.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        real_norm, features_mean, features_std = self.mean_std_normalize(real)
+
+        attack_norm, _, _ = self.mean_std_normalize(attack, features_mean, features_std)
+
+        return real_norm, attack_norm, features_mean, features_std
+
+
+    #==========================================================================
+    def train_lr(self, real, attack, C):
+        """
+        Train LR classifier given real and attack classes. Prior to training
+        the data is mean-std normalized.
+
+        **Parameters:**
+
+        ``real`` : 2D :py:class:`numpy.ndarray`
+            Training features for the real class.
+
+        ``attack`` : 2D :py:class:`numpy.ndarray`
+            Training features for the attack class.
+
+        ``C`` : :py:class:`float`
+            Inverse of regularization strength in LR classifier; must be a positive.
+            Like in support vector machines, smaller values specify stronger
+            regularization. Default: 1.0 .
+
+        **Returns:**
+
+        ``machine`` : object
+            A trained LR machine.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        real, attack, features_mean, features_std = self.norm_train_data(real, attack)
+        # real and attack - are now mean-std normalized
+
+        X = np.vstack([real, attack])
+
+        Y = np.hstack( [ np.zeros(len(real) ), np.ones(len(attack) ) ] )
+
+        machine = linear_model.LogisticRegression( C = C )
+
+        machine.fit(X, Y)
+
+        return machine, features_mean, features_std
+
+
+    #==========================================================================
+    def save_lr_machine_and_mean_std(self, projector_file, machine, features_mean, features_std):
+        """
+        Saves the LR machine, features mean and std to the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to save the data to, as returned by
+            ``bob.pad.base`` framework.
+
+        ``machine`` : object
+            The LR machine to be saved. As returned by sklearn.linear_model
+            module.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        f = bob.io.base.HDF5File(projector_file, 'w') # open hdf5 file to save to
+
+        for key in self.lr_param_keys: # ["C", "classes_", "coef_", "intercept_"]
+
+            data = getattr( machine, key )
+
+            f.set( key, data )
+
+        f.set( "features_mean", features_mean )
+
+        f.set( "features_std", features_std )
+
+        del f
+
+
+    #==========================================================================
+    def subsample_train_videos(self, training_features, step):
+        """
+        Uniformly select subset of frmae containes from the input list
+
+        **Parameters:**
+
+        ``training_features`` : [FrameContainer]
+            A list of FrameContainers
+
+        ``step`` : :py:class:`int`
+            Data selection step.
+
+        **Returns:**
+
+        ``training_features_subset`` : [FrameContainer]
+            A list with selected FrameContainers
+        """
+
+        indexes = range(0, len(training_features), step)
+
+        training_features_subset = [training_features[x] for x in indexes]
+
+        return training_features_subset
+
+
+    #==========================================================================
+    def train_projector(self, training_features, projector_file):
+        """
+        Train LR for feature projection and save them to files.
+        The ``requires_projector_training = True`` flag must be set to True
+        to enable this function.
+
+        **Parameters:**
+
+        ``training_features`` : [[FrameContainer], [FrameContainer]]
+            A list containing two elements: [0] - a list of Frame Containers with
+            feature vectors for the real class; [1] - a list of Frame Containers with
+            feature vectors for the attack class.
+
+        ``projector_file`` : :py:class:`str`
+            The file to save the trained projector to, as returned by the
+            ``bob.pad.base`` framework.
+        """
+
+        # training_features[0] - training features for the REAL class.
+        # training_features[1] - training features for the ATTACK class.
+
+        if self.subsample_videos_flag: # subsample videos of the real class
+
+            real = self.convert_list_of_frame_cont_to_array( self.subsample_train_videos(training_features[0], self.video_subsampling_step) ) # output is array
+
+        else:
+
+            real = self.convert_list_of_frame_cont_to_array(training_features[0]) # output is array
+
+        if self.subsample_train_data_flag:
+
+            real = real[range(0,len(real), self.subsampling_step), :]
+
+        if self.subsample_videos_flag: # subsample videos of the real class
+
+            attack = self.convert_list_of_frame_cont_to_array( self.subsample_train_videos(training_features[1], self.video_subsampling_step) ) # output is array
+
+        else:
+
+            attack = self.convert_list_of_frame_cont_to_array(training_features[1]) # output is array
+
+        if self.subsample_train_data_flag:
+
+            attack = attack[range(0,len(attack), self.subsampling_step), :]
+
+        # Train the LR machine and get normalizers:
+        machine, features_mean, features_std = self.train_lr(real = real,
+                                                             attack = attack,
+                                                             C = self.C)
+
+        # Save the LR machine and normalizers:
+        self.save_lr_machine_and_mean_std(projector_file, machine, features_mean, features_std)
+
+
+    #==========================================================================
+    def load_lr_machine_and_mean_std(self, projector_file):
+        """
+        Loads the machine, features mean and std from the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            Absolute name of the file to load the trained projector from, as
+            returned by ``bob.pad.base`` framework.
+
+        **Returns:**
+
+        ``machine`` : object
+            The loaded LR machine. As returned by sklearn.linear_model module.
+
+        ``features_mean`` : 1D :py:class:`numpy.ndarray`
+            Mean of the features.
+
+        ``features_std`` : 1D :py:class:`numpy.ndarray`
+            Standart deviation of the features.
+        """
+
+        f = bob.io.base.HDF5File(projector_file, 'r') # file to read the machine from
+
+        # initialize the machine:
+        machine = linear_model.LogisticRegression()
+
+        # set the params of the machine:
+        for key in self.lr_param_keys: # ["C", "classes_", "coef_", "intercept_"]
+
+            data = f.read(key)
+
+            setattr(machine, key, data)
+
+        features_mean = f.read("features_mean")
+
+        features_std = f.read("features_std")
+
+        del f
+
+        return machine, features_mean, features_std
+
+
+    #==========================================================================
+    def load_projector(self, projector_file):
+        """
+        Loads the machine, features mean and std from the hdf5 file.
+        The absolute name of the file is specified in ``projector_file`` string.
+
+        This function sets the arguments ``self.lr_machine``, ``self.features_mean``
+        and ``self.features_std`` of this class with loaded machines.
+
+        The function must be capable of reading the data saved with the
+        :py:meth:`train_projector` method of this class.
+
+        Please register `performs_projection = True` in the constructor to
+        enable this function.
+
+        **Parameters:**
+
+        ``projector_file`` : :py:class:`str`
+            The file to read the projector from, as returned by the
+            ``bob.pad.base`` framework. In this class the names of the files to
+            read the projectors from are modified, see ``load_machine`` and
+            ``load_cascade_of_machines`` methods of this class for more details.
+        """
+
+        lr_machine, features_mean, features_std = self.load_lr_machine_and_mean_std(projector_file)
+
+        self.lr_machine = lr_machine
+
+        self.features_mean = features_mean
+
+        self.features_std = features_std
+
+
+    #==========================================================================
+    def project(self, feature):
+        """
+        This function computes a vector of scores for each sample in the input
+        array of features. The following steps are apllied:
+
+        1. First, the input data is mean-std normalized using mean and std of the
+           real class only.
+
+        2. The input features are next classified using pre-trained LR machine.
+
+        Set ``performs_projection = True`` in the constructor to enable this function.
+        It is assured that the :py:meth:`load_projector` was **called before** the
+        ``project`` function is executed.
+
+        **Parameters:**
+
+        ``feature`` : FrameContainer or 2D :py:class:`numpy.ndarray`
+            Two types of inputs are accepted.
+            A Frame Container conteining the features of an individual,
+            see ``bob.bio.video.utils.FrameContainer``.
+            Or a 2D feature array of the size (N_samples x N_features).
+
+        **Returns:**
+
+        ``scores`` : 1D :py:class:`numpy.ndarray`
+            Vector of scores. Scores for the real class are expected to be
+            higher, than the scores of the negative / attack class.
+            In this case scores are probabilities.
+        """
+
+        # 1. Convert input array to numpy array if necessary.
+        if isinstance(feature, FrameContainer): # if FrameContainer convert to 2D numpy array
+
+            features_array = self.convert_frame_cont_to_array(feature)
+
+        else:
+
+            features_array = feature
+
+        features_array_norm, _, _ = self.mean_std_normalize(features_array, self.features_mean, self.features_std)
+
+        scores = self.lr_machine.predict_proba( features_array_norm )[:,0]
+
+        return scores
+
+
+    #==========================================================================
+    def score(self, toscore):
+        """
+        Returns a probability of a sample being a real class.
+
+        **Parameters:**
+
+        ``toscore`` : 1D :py:class:`numpy.ndarray`
+            Vector with scores for each frame/sample defining the probability
+            of the frame being a sample of the real class.
+
+        **Returns:**
+
+        ``score`` : [:py:class:`float`]
+            If ``frame_level_scores_flag = False`` a single score is returned.
+            One score per video. This score is placed into a list, because
+            the ``score`` must be an iterable.
+            Score is a probability of a sample being a real class.
+            If ``frame_level_scores_flag = True`` a list of scores is returned.
+            One score per frame/sample.
+        """
+
+        if self.frame_level_scores_flag:
+
+            score = list(toscore)
+
+        else:
+
+            score = [np.mean( toscore )] # compute a single score per video
+
+        return score
+
+
+
+
diff --git a/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py b/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
index d84b07529f7faf4dffbad287b20137794e275172..6fb38d1c9257d4107944b7d1ce115bfb23c871c8 100644
--- a/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
+++ b/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
@@ -453,7 +453,7 @@ class VideoSvmPadAlgorithm(Algorithm):
 
 
     #==========================================================================
-    def norm_train_cv_data(self, real_train, real_cv, attack_train, attack_cv):
+    def norm_train_cv_data(self, real_train, real_cv, attack_train, attack_cv, one_class_flag = False):
         """
         Mean-std normalization of train and cross-validation data arrays.
 
@@ -471,6 +471,11 @@ class VideoSvmPadAlgorithm(Algorithm):
         ``attack_cv`` : 2D :py:class:`numpy.ndarray`
             Subset of cross-validation features for the attack class.
 
+        ``one_class_flag`` : :py:class:`bool`
+            If set to ``True``, only positive/real samples will be used to
+            compute the mean and std normalization vectors. Set to ``True`` if
+            using one-class SVM. Default: False.
+
         **Returns:**
 
         ``real_train_norm`` : 2D :py:class:`numpy.ndarray`
@@ -485,18 +490,30 @@ class VideoSvmPadAlgorithm(Algorithm):
         ``attack_cv_norm`` : 2D :py:class:`numpy.ndarray`
             Normalized subset of cross-validation features for the attack class.
         """
+        if not(one_class_flag):
+
+            features_train = np.vstack([real_train, attack_train])
+
+            features_train_norm, features_mean, features_std = self.mean_std_normalize(features_train)
+
+            real_train_norm = features_train_norm[0:real_train.shape[0], :]
 
-        features_train = np.vstack([real_train, attack_train])
+            attack_train_norm = features_train_norm[real_train.shape[0]:, :]
 
-        features_train_norm, features_mean, features_std = self.mean_std_normalize(features_train)
+            real_cv_norm, _, _ = self.mean_std_normalize(real_cv, features_mean, features_std)
 
-        real_train_norm = features_train_norm[0:real_train.shape[0], :]
+            attack_cv_norm, _, _ = self.mean_std_normalize(attack_cv, features_mean, features_std)
 
-        attack_train_norm = features_train_norm[real_train.shape[0]:, :]
+        else: # one-class SVM case
 
-        real_cv_norm, _, _ = self.mean_std_normalize(real_cv, features_mean, features_std)
+            #only real class used for training in one class SVM:
+            real_train_norm, features_mean, features_std = self.mean_std_normalize(real_train)
 
-        attack_cv_norm, _, _ = self.mean_std_normalize(attack_cv, features_mean, features_std)
+            attack_train_norm, _, _ = self.mean_std_normalize(attack_train, features_mean, features_std)
+
+            real_cv_norm, _, _ = self.mean_std_normalize(real_cv, features_mean, features_std)
+
+            attack_cv_norm, _, _ = self.mean_std_normalize(attack_cv, features_mean, features_std)
 
         return real_train_norm, real_cv_norm, attack_train_norm, attack_cv_norm
 
@@ -569,12 +586,15 @@ class VideoSvmPadAlgorithm(Algorithm):
             A trained SVM machine.
         """
 
+        one_class_flag = (machine_type == 'ONE_CLASS') # True if one-class SVM is used
+
         # get the data for the hyper-parameter grid-search:
         real_train, real_cv, attack_train, attack_cv = self.prepare_data_for_hyper_param_grid_search(training_features, n_samples)
 
         if mean_std_norm_flag:
             # normalize the data:
-            real_train, real_cv, attack_train, attack_cv = self.norm_train_cv_data(real_train, real_cv, attack_train, attack_cv)
+            real_train, real_cv, attack_train, attack_cv = self.norm_train_cv_data(real_train, real_cv, attack_train, attack_cv,
+                                                                                   one_class_flag)
 
         precisions_cv = [] # for saving the precision on the cross-validation set
 
@@ -593,7 +613,13 @@ class VideoSvmPadAlgorithm(Algorithm):
 
                 setattr(trainer, key, trainer_grid_search_param[key]) # set the params of trainer
 
-            data  = [np.copy(real_train), np.copy(attack_train)] # data used for training the machine in the grid-search
+            if not( one_class_flag ): # two-class SVM case
+
+                data  = [np.copy(real_train), np.copy(attack_train)] # data used for training the machine in the grid-search
+
+            else: # one class SVM case
+
+                data = [np.copy(real_train)] # only real class is used for training
 
             machine = trainer.train(data) # train the machine
 
@@ -626,8 +652,10 @@ class VideoSvmPadAlgorithm(Algorithm):
             debug_dict = {}
             debug_dict['precisions_train'] = precisions_train
             debug_dict['precisions_cv'] = precisions_cv
-            debug_dict['cost'] = selected_params['cost']
-            debug_dict['gamma'] = selected_params['gamma']
+
+            for key in selected_params.keys():
+                debug_dict[key] = selected_params[key]
+
             f = bob.io.base.HDF5File(debug_file, 'w') # open hdf5 file to save the debug data
             for key in debug_dict.keys():
                 f.set(key, debug_dict[key])
@@ -640,10 +668,18 @@ class VideoSvmPadAlgorithm(Algorithm):
 
         if mean_std_norm_flag:
             # Normalize the data:
-            features = np.vstack([real, attack])
-            features_norm, features_mean, features_std = self.mean_std_normalize(features)
-            real =   features_norm[0:real.shape[0], :] # The array is now normalized
-            attack = features_norm[real.shape[0]:, :] # The array is now normalized
+            if not( one_class_flag ): # two-class SVM case
+
+                features = np.vstack([real, attack])
+                features_norm, features_mean, features_std = self.mean_std_normalize(features)
+                real =   features_norm[0:real.shape[0], :] # The array is now normalized
+                attack = features_norm[real.shape[0]:, :] # The array is now normalized
+
+            else: # one-class SVM case
+
+                real, features_mean, features_std = self.mean_std_normalize(real) # use only real class to compute normalizers
+                attack = self.mean_std_normalize(attack, features_mean, features_std)
+                # ``real`` and ``attack`` arrays are now normalizaed
 
         if reduced_train_data_flag:
 
@@ -651,7 +687,13 @@ class VideoSvmPadAlgorithm(Algorithm):
             real = self.select_quasi_uniform_data_subset(real, n_train_samples)
             attack = self.select_quasi_uniform_data_subset(attack, n_train_samples)
 
-        data = [np.copy(real), np.copy(attack)] # data for final training
+        if not( one_class_flag ): # two-class SVM case
+
+            data = [np.copy(real), np.copy(attack)] # data for final training
+
+        else: # one-class SVM case
+
+            data = [np.copy(real)] # only real class used for training
 
         machine = trainer.train(data) # train the machine
 
@@ -743,17 +785,26 @@ class VideoSvmPadAlgorithm(Algorithm):
 
         **Returns:**
 
-        ``probabilities`` : 2D :py:class:`numpy.ndarray`
+        ``probabilities`` : 1D or 2D :py:class:`numpy.ndarray`
+            2D in the case of two-class SVM.
             An array containing class probabilities for each frame.
             First column contains probabilities for each frame being a real class.
             Second column contains probabilities for each frame being an attack class.
+            1D in the case of one-class SVM.
+            Vector with scores for each frame defining belonging to the real class.
             Must be writable with the ``write_feature`` function and
             readable with the ``read_feature`` function.
         """
 
         features_array = self.convert_frame_cont_to_array(feature)
 
-        probabilities = self.machine.predict_class_and_probabilities(features_array)[1]
+        if not( self.machine_type == 'ONE_CLASS' ): # two-class SVM case
+
+            probabilities = self.machine.predict_class_and_probabilities(features_array)[1]
+
+        else:
+
+            probabilities = self.machine.predict_class_and_scores(features_array)[1]
 
         return probabilities
 
@@ -765,26 +816,32 @@ class VideoSvmPadAlgorithm(Algorithm):
 
         **Parameters:**
 
-        ``toscore`` : 2D :py:class:`numpy.ndarray`
+        ``toscore`` : 1D or 2D :py:class:`numpy.ndarray`
+            2D in the case of two-class SVM.
             An array containing class probabilities for each frame.
             First column contains probabilities for each frame being a real class.
             Second column contains probabilities for each frame being an attack class.
+            1D in the case of one-class SVM.
+            Vector with scores for each frame defining belonging to the real class.
 
         **Returns:**
 
-        ``score`` : :py:class:`float`
-            or a list of scores containing individual score for each frame.
-            A score value for the object ``toscore``.
-            A probability of a sample being a real class.
+        ``score`` : :py:class:`float` or a 1D :py:class:`numpy.ndarray`
+            If ``frame_level_scores_flag = False`` a single score is returned.
+            One score per video.
+            Score is a probability of a sample being a real class.
+            If ``frame_level_scores_flag = True`` a 1D array of scores is returned.
+            One score per frame.
+            Score is a probability of a sample being a real class.
         """
 
         if self.frame_level_scores_flag:
 
-            score = toscore[:,0] # here score is a list containing scores for each frame
+            score = toscore[:,0] # here score is a 1D array containing scores for each frame
 
         else:
 
-            score = np.mean(toscore, axis=0)[0] # compute a single score per video
+            score = np.mean( toscore[:,0] ) # compute a single score per video
 
         return score
 
@@ -796,8 +853,13 @@ class VideoSvmPadAlgorithm(Algorithm):
 
         **Parameters:**
 
-        ``toscore`` : 2D :py:class:`numpy.ndarray`
-            An array containing scores computed by score() method of this class.
+        ``toscore`` : 1D or 2D :py:class:`numpy.ndarray`
+            2D in the case of two-class SVM.
+            An array containing class probabilities for each frame.
+            First column contains probabilities for each frame being a real class.
+            Second column contains probabilities for each frame being an attack class.
+            1D in the case of one-class SVM.
+            Vector with scores for each frame defining belonging to the real class.
 
         **Returns:**
 
@@ -805,13 +867,15 @@ class VideoSvmPadAlgorithm(Algorithm):
             A list containing the scores.
         """
 
-        if self.frame_level_scores_flag:
+        scores = self.score(toscore) # returns float score or 1D array of scores
+
+        if isinstance(scores, np.float): # if a single score
 
-            list_of_scores = self.score(toscore)
+            list_of_scores = [scores]
 
         else:
 
-            list_of_scores = [self.score(toscore)]
+            list_of_scores = list(scores)
 
         return list_of_scores
 
diff --git a/bob/pad/face/algorithm/__init__.py b/bob/pad/face/algorithm/__init__.py
index 77265bf492e0f894c2d938013414ba689bb20ab1..eeb27d59b563e895d3bd2f975fc87cb24060a228 100644
--- a/bob/pad/face/algorithm/__init__.py
+++ b/bob/pad/face/algorithm/__init__.py
@@ -1,5 +1,7 @@
 from .VideoSvmPadAlgorithm import VideoSvmPadAlgorithm
-
+from .VideoCascadeSvmPadAlgorithm import VideoCascadeSvmPadAlgorithm
+from .VideoLRPadAlgorithm import VideoLRPadAlgorithm
+from .VideoGmmPadAlgorithm import VideoGmmPadAlgorithm
 
 def __appropriate__(*args):
     """Says object was actually declared here, and not in the import module.
@@ -9,7 +11,7 @@ def __appropriate__(*args):
     Parameters
     ----------
     *args
-        The objects that you want sphinx to beleive that are defined here.
+        The objects that you want sphinx to believe that are defined here.
 
     Resolves `Sphinx referencing issues <https//github.com/sphinx-
     doc/sphinx/issues/3048>`
@@ -21,5 +23,8 @@ def __appropriate__(*args):
 
 __appropriate__(
     VideoSvmPadAlgorithm,
+    VideoCascadeSvmPadAlgorithm,
+    VideoLRPadAlgorithm,
+    VideoGmmPadAlgorithm,
 )
 __all__ = [_ for _ in dir() if not _.startswith('_')]
diff --git a/bob/pad/face/config/algorithm/video_cascade_svm_pad_algorithm.py b/bob/pad/face/config/algorithm/video_cascade_svm_pad_algorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0ee742ea33ee5226ca752f5caabadb0d4569ed4
--- /dev/null
+++ b/bob/pad/face/config/algorithm/video_cascade_svm_pad_algorithm.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+
+from bob.pad.face.algorithm import VideoCascadeSvmPadAlgorithm
+
+
+#=======================================================================================
+# Define instances here:
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.2}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n2_gamma_02 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.1}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n2_gamma_01 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.05}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n2_gamma_005 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.01}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n2_gamma_001 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.1}
+N = 10
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n10_gamma_01 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.05}
+N = 10
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n10_gamma_005 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.01}
+N = 10
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n10_gamma_001 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.005}
+N = 10
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n10_gamma_0005 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.5}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_05 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.2}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_02 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.1}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_01 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.05}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_005 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.01}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_001 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.005}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_0005 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.001}
+N = 20
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n20_gamma_0001 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.1}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = False
+
+algorithm_n2_gamma_01_video_level = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+
+# Test the cascade of two-class SVMs.
+
+MACHINE_TYPE = 'C_SVC'
+KERNEL_TYPE = 'RBF'
+TRAINER_GRID_SEARCH_PARAMS = {'cost': 1, 'gamma': 0.01}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_n2_two_class_svm_c1_gamma_001 = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                                                      kernel_type = KERNEL_TYPE,
+                                                                      svm_kwargs = TRAINER_GRID_SEARCH_PARAMS,
+                                                                      N = N,
+                                                                      pos_scores_slope = POS_SCORES_SLOPE,
+                                                                      frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+
+
+
+
diff --git a/bob/pad/face/config/algorithm/video_gmm_pad_algorithm.py b/bob/pad/face/config/algorithm/video_gmm_pad_algorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..e46e285d97a7fbbf9561b62a488d90bd4d5eac15
--- /dev/null
+++ b/bob/pad/face/config/algorithm/video_gmm_pad_algorithm.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+
+from bob.pad.face.algorithm import VideoGmmPadAlgorithm
+
+
+#=======================================================================================
+# Define instances here:
+
+N_COMPONENTS = 2
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_2 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 3
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_3 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 4
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_4 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 5
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_5 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 6
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_6 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 7
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_7 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 8
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_8 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 9
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_9 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 10
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_10 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+# above 10 Gaussians:
+
+N_COMPONENTS = 12
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_12 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 14
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_14 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 16
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_16 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 18
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_18 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 20
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_20 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+# above 20 Gaussians:
+
+N_COMPONENTS = 25
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_25 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 30
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_30 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 35
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_35 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 40
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_40 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 45
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_45 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+#=======================================================================================
+# above 50 Gaussians:
+
+N_COMPONENTS = 60
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_60 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 70
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_70 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 80
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_80 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 90
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_90 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 100
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_100 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+
+#=======================================================================================
+# 50 Gaussians, different random seeds:
+
+N_COMPONENTS = 50
+RANDOM_STATE = 0
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_0 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 1
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_1 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 2
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_2 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 3
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_3 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 4
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_4 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 5
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_5 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 6
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_6 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 7
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_7 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 8
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_8 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+N_COMPONENTS = 50
+RANDOM_STATE = 9
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm_gmm_50_9 = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                        random_state = RANDOM_STATE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+
+
diff --git a/bob/pad/face/config/qm_lr.py b/bob/pad/face/config/qm_lr.py
new file mode 100644
index 0000000000000000000000000000000000000000..11c4404c7ce2b42d67a5a40259010ec166c3fa75
--- /dev/null
+++ b/bob/pad/face/config/qm_lr.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+"""
+This file contains configurations to run Image Quality Measures (IQM) and LR based face PAD algorithm.
+The settings of the preprocessor and extractor are tuned for the Replay-attack database.
+The IQM features used in this algorithm/resource are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+sub_directory = 'qm_lr'
+"""
+Sub-directory where results will be placed.
+
+You may change this setting using the ``--sub-directory`` command-line option
+or the attribute ``sub_directory`` in a configuration file loaded **after**
+this resource.
+"""
+
+
+#=======================================================================================
+# define preprocessor:
+
+from ..preprocessor import VideoFaceCrop
+
+CROPPED_IMAGE_SIZE = (64, 64) # The size of the resulting face
+CROPPED_POSITIONS = {'topleft' : (0,0) , 'bottomright' : CROPPED_IMAGE_SIZE}
+FIXED_POSITIONS = None
+MASK_SIGMA = None             # The sigma for random values areas outside image
+MASK_NEIGHBORS = 5            # The number of neighbors to consider while extrapolating
+MASK_SEED = None              # The seed for generating random values during extrapolation
+CHECK_FACE_SIZE_FLAG = True   # Check the size of the face
+MIN_FACE_SIZE = 50
+USE_LOCAL_CROPPER_FLAG = True # Use the local face cropping class (identical to Ivana's paper)
+RGB_OUTPUT_FLAG = True        # Return RGB cropped face using local cropper
+
+preprocessor = VideoFaceCrop(cropped_image_size = CROPPED_IMAGE_SIZE,
+                             cropped_positions = CROPPED_POSITIONS,
+                             fixed_positions = FIXED_POSITIONS,
+                             mask_sigma = MASK_SIGMA,
+                             mask_neighbors = MASK_NEIGHBORS,
+                             mask_seed = None,
+                             check_face_size_flag = CHECK_FACE_SIZE_FLAG,
+                             min_face_size = MIN_FACE_SIZE,
+                             use_local_cropper_flag = USE_LOCAL_CROPPER_FLAG,
+                             rgb_output_flag = RGB_OUTPUT_FLAG)
+"""
+In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
+The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
+below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
+"""
+
+
+#=======================================================================================
+# define extractor:
+
+from ..extractor import VideoQualityMeasure
+
+GALBALLY=True
+MSU=True
+DTYPE=None
+
+extractor = VideoQualityMeasure(galbally=GALBALLY,
+                                msu=MSU,
+                                dtype=DTYPE)
+"""
+In the feature extraction stage the Image Quality Measures are extracted from each frame of the preprocessed RGB video.
+The features to be computed are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+# define algorithm:
+
+from ..algorithm import VideoLRPadAlgorithm
+
+C = 1. # The regularization parameter for the LR classifier
+FRAME_LEVEL_SCORES_FLAG = True # Return one score per frame
+
+algorithm = VideoLRPadAlgorithm(C = C,
+                                frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+
+"""
+The Logistic Regression is used to classify the data into *real* and *attack* classes.
+One score is produced for each frame of the input video, ``frame_level_scores_flag = True``.
+The sub-sampling of training data is not used here, sub-sampling flags have default ``False``
+values.
+"""
+
+
diff --git a/bob/pad/face/config/qm_one_class_gmm.py b/bob/pad/face/config/qm_one_class_gmm.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6e877049f39b169fae692cd43c8a6c90b044438
--- /dev/null
+++ b/bob/pad/face/config/qm_one_class_gmm.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+"""
+This file contains configurations to run Image Quality Measures (IQM) and one-class GMM based face PAD algorithm.
+The settings of the preprocessor and extractor are tuned for the Replay-attack database.
+The IQM features used in this algorithm/resource are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+sub_directory = 'qm_one_class_gmm'
+"""
+Sub-directory where results will be placed.
+
+You may change this setting using the ``--sub-directory`` command-line option
+or the attribute ``sub_directory`` in a configuration file loaded **after**
+this resource.
+"""
+
+
+#=======================================================================================
+# define preprocessor:
+
+from ..preprocessor import VideoFaceCrop
+
+CROPPED_IMAGE_SIZE = (64, 64) # The size of the resulting face
+CROPPED_POSITIONS = {'topleft' : (0,0) , 'bottomright' : CROPPED_IMAGE_SIZE}
+FIXED_POSITIONS = None
+MASK_SIGMA = None             # The sigma for random values areas outside image
+MASK_NEIGHBORS = 5            # The number of neighbors to consider while extrapolating
+MASK_SEED = None              # The seed for generating random values during extrapolation
+CHECK_FACE_SIZE_FLAG = True   # Check the size of the face
+MIN_FACE_SIZE = 50
+USE_LOCAL_CROPPER_FLAG = True # Use the local face cropping class (identical to Ivana's paper)
+RGB_OUTPUT_FLAG = True        # Return RGB cropped face using local cropper
+
+preprocessor = VideoFaceCrop(cropped_image_size = CROPPED_IMAGE_SIZE,
+                             cropped_positions = CROPPED_POSITIONS,
+                             fixed_positions = FIXED_POSITIONS,
+                             mask_sigma = MASK_SIGMA,
+                             mask_neighbors = MASK_NEIGHBORS,
+                             mask_seed = None,
+                             check_face_size_flag = CHECK_FACE_SIZE_FLAG,
+                             min_face_size = MIN_FACE_SIZE,
+                             use_local_cropper_flag = USE_LOCAL_CROPPER_FLAG,
+                             rgb_output_flag = RGB_OUTPUT_FLAG)
+"""
+In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
+The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
+below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
+"""
+
+
+#=======================================================================================
+# define extractor:
+
+from ..extractor import VideoQualityMeasure
+
+GALBALLY=True
+MSU=True
+DTYPE=None
+
+extractor = VideoQualityMeasure(galbally=GALBALLY,
+                                msu=MSU,
+                                dtype=DTYPE)
+"""
+In the feature extraction stage the Image Quality Measures are extracted from each frame of the preprocessed RGB video.
+The features to be computed are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+# define algorithm:
+
+from ..algorithm import VideoGmmPadAlgorithm
+
+N_COMPONENTS = 50
+RANDOM_STATE = 3
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm = VideoGmmPadAlgorithm(n_components = N_COMPONENTS,
+                                 random_state = RANDOM_STATE,
+                                 frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+"""
+The GMM with 50 clusters is trained using samples from the real class only. The pre-trained
+GMM is next used to classify the data into *real* and *attack* classes.
+One score is produced for each frame of the input video, ``frame_level_scores_flag = True``.
+"""
+
+
+
+
+
diff --git a/bob/pad/face/config/qm_one_class_svm_aggregated_db.py b/bob/pad/face/config/qm_one_class_svm_aggregated_db.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4cbe08f2d7bd6784e8ef7e039d047c806a7f064
--- /dev/null
+++ b/bob/pad/face/config/qm_one_class_svm_aggregated_db.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+"""
+This file contains configurations to run Image Quality Measures (IQM) and one-class SVM based face PAD algorithm.
+The settings of the preprocessor and extractor are tuned for the Replay-attack database.
+In the SVM algorithm the amount of training data is reduced speeding-up the training for
+large data sets, such as Aggregated PAD database.
+The IQM features used in this algorithm/resource are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+sub_directory = 'qm_one_class_svm_aggregated_db'
+"""
+Sub-directory where results will be placed.
+
+You may change this setting using the ``--sub-directory`` command-line option
+or the attribute ``sub_directory`` in a configuration file loaded **after**
+this resource.
+"""
+
+
+#=======================================================================================
+# define preprocessor:
+
+from ..preprocessor import VideoFaceCrop
+
+CROPPED_IMAGE_SIZE = (64, 64) # The size of the resulting face
+CROPPED_POSITIONS = {'topleft' : (0,0) , 'bottomright' : CROPPED_IMAGE_SIZE}
+FIXED_POSITIONS = None
+MASK_SIGMA = None             # The sigma for random values areas outside image
+MASK_NEIGHBORS = 5            # The number of neighbors to consider while extrapolating
+MASK_SEED = None              # The seed for generating random values during extrapolation
+CHECK_FACE_SIZE_FLAG = True   # Check the size of the face
+MIN_FACE_SIZE = 50
+USE_LOCAL_CROPPER_FLAG = True # Use the local face cropping class (identical to Ivana's paper)
+RGB_OUTPUT_FLAG = True        # Return RGB cropped face using local cropper
+
+preprocessor = VideoFaceCrop(cropped_image_size = CROPPED_IMAGE_SIZE,
+                             cropped_positions = CROPPED_POSITIONS,
+                             fixed_positions = FIXED_POSITIONS,
+                             mask_sigma = MASK_SIGMA,
+                             mask_neighbors = MASK_NEIGHBORS,
+                             mask_seed = None,
+                             check_face_size_flag = CHECK_FACE_SIZE_FLAG,
+                             min_face_size = MIN_FACE_SIZE,
+                             use_local_cropper_flag = USE_LOCAL_CROPPER_FLAG,
+                             rgb_output_flag = RGB_OUTPUT_FLAG)
+"""
+In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
+The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
+below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
+"""
+
+
+#=======================================================================================
+# define extractor:
+
+from ..extractor import VideoQualityMeasure
+
+GALBALLY=True
+MSU=True
+DTYPE=None
+
+extractor = VideoQualityMeasure(galbally=GALBALLY,
+                                msu=MSU,
+                                dtype=DTYPE)
+"""
+In the feature extraction stage the Image Quality Measures are extracted from each frame of the preprocessed RGB video.
+The features to be computed are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+# define algorithm:
+
+from ..algorithm import VideoSvmPadAlgorithm
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+N_SAMPLES = 50000
+TRAINER_GRID_SEARCH_PARAMS = {'nu': [0.001, 0.01, 0.05, 0.1], 'gamma': [0.01, 0.1, 1, 10]}
+MEAN_STD_NORM_FLAG = True       # enable mean-std normalization
+FRAME_LEVEL_SCORES_FLAG = True  # one score per frame(!) in this case
+SAVE_DEBUG_DATA_FLAG = True     # save the data, which might be useful for debugging
+REDUCED_TRAIN_DATA_FLAG = False # DO NOT reduce the amount of training data in the final training stage
+N_TRAIN_SAMPLES = 50000         # number of training samples per class in the final SVM training stage (NOT considered, because REDUCED_TRAIN_DATA_FLAG = False)
+
+algorithm = VideoSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                 kernel_type = KERNEL_TYPE,
+                                 n_samples = N_SAMPLES,
+                                 trainer_grid_search_params = TRAINER_GRID_SEARCH_PARAMS,
+                                 mean_std_norm_flag = MEAN_STD_NORM_FLAG,
+                                 frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG,
+                                 save_debug_data_flag = SAVE_DEBUG_DATA_FLAG,
+                                 reduced_train_data_flag = REDUCED_TRAIN_DATA_FLAG,
+                                 n_train_samples = N_TRAIN_SAMPLES)
+"""
+The one-class SVM algorithm with RBF kernel is used to classify the data into *real* and *attack* classes.
+One score is produced for each frame of the input video, ``frame_level_scores_flag = True``.
+The grid search of SVM parameters is used to select the successful settings.
+The grid search is done on the subset of training data.
+The size of this subset is defined by ``n_samples`` parameter.
+The final training of the SVM is done on all training data ``reduced_train_data_flag = False``.
+The data is also mean-std normalized, ``mean_std_norm_flag = True``.
+"""
+
+
diff --git a/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py b/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6aecc930def955b11cb8cf8849e762732468885
--- /dev/null
+++ b/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+"""
+This file contains configurations to run Image Quality Measures (IQM) and SVM based face PAD baseline.
+The settings of the preprocessor and extractor are tuned for the Replay-attack database.
+In the SVM algorithm the amount of training data is reduced speeding-up the training for
+large data sets, such as Aggregated PAD database.
+The IQM features used in this algorithm/resource are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+sub_directory = 'qm_svm_aggregated_db'
+"""
+Sub-directory where results will be placed.
+
+You may change this setting using the ``--sub-directory`` command-line option
+or the attribute ``sub_directory`` in a configuration file loaded **after**
+this resource.
+"""
+
+
+#=======================================================================================
+# define preprocessor:
+
+from ..preprocessor import VideoFaceCrop
+
+CROPPED_IMAGE_SIZE = (64, 64) # The size of the resulting face
+CROPPED_POSITIONS = {'topleft' : (0,0) , 'bottomright' : CROPPED_IMAGE_SIZE}
+FIXED_POSITIONS = None
+MASK_SIGMA = None             # The sigma for random values areas outside image
+MASK_NEIGHBORS = 5            # The number of neighbors to consider while extrapolating
+MASK_SEED = None              # The seed for generating random values during extrapolation
+CHECK_FACE_SIZE_FLAG = True   # Check the size of the face
+MIN_FACE_SIZE = 50
+USE_LOCAL_CROPPER_FLAG = True # Use the local face cropping class (identical to Ivana's paper)
+RGB_OUTPUT_FLAG = True        # Return RGB cropped face using local cropper
+
+preprocessor = VideoFaceCrop(cropped_image_size = CROPPED_IMAGE_SIZE,
+                             cropped_positions = CROPPED_POSITIONS,
+                             fixed_positions = FIXED_POSITIONS,
+                             mask_sigma = MASK_SIGMA,
+                             mask_neighbors = MASK_NEIGHBORS,
+                             mask_seed = None,
+                             check_face_size_flag = CHECK_FACE_SIZE_FLAG,
+                             min_face_size = MIN_FACE_SIZE,
+                             use_local_cropper_flag = USE_LOCAL_CROPPER_FLAG,
+                             rgb_output_flag = RGB_OUTPUT_FLAG)
+"""
+In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
+The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
+below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
+"""
+
+
+#=======================================================================================
+# define extractor:
+
+from ..extractor import VideoQualityMeasure
+
+GALBALLY=True
+MSU=True
+DTYPE=None
+
+extractor = VideoQualityMeasure(galbally=GALBALLY,
+                                msu=MSU,
+                                dtype=DTYPE)
+"""
+In the feature extraction stage the Image Quality Measures are extracted from each frame of the preprocessed RGB video.
+The features to be computed are introduced in the following papers: [WHJ15]_ and [CBVM16]_.
+"""
+
+
+#=======================================================================================
+# define algorithm:
+
+from ..algorithm import VideoCascadeSvmPadAlgorithm
+
+MACHINE_TYPE = 'ONE_CLASS'
+KERNEL_TYPE = 'RBF'
+SVM_KWARGS = {'nu': 0.001, 'gamma': 0.5}
+N = 2
+POS_SCORES_SLOPE = 0.01
+FRAME_LEVEL_SCORES_FLAG = True
+
+algorithm = VideoCascadeSvmPadAlgorithm(machine_type = MACHINE_TYPE,
+                                        kernel_type = KERNEL_TYPE,
+                                        svm_kwargs = SVM_KWARGS,
+                                        N = N,
+                                        pos_scores_slope = POS_SCORES_SLOPE,
+                                        frame_level_scores_flag = FRAME_LEVEL_SCORES_FLAG)
+"""
+The cascade of one-class SVMs with RBF kernel is used to classify the data into *real* and *attack* classes.
+One score is produced for each frame of the input video, ``frame_level_scores_flag = True``.
+A single SVM in the cascade is trained using two features ``N = 2``.
+The positive scores produced by the cascade are reduced by multiplying them with a constant
+``pos_scores_slope = 0.01``.
+"""
+
diff --git a/bob/pad/face/config/qm_svm_aggregated_db.py b/bob/pad/face/config/qm_svm_aggregated_db.py
index 4bd54236a09e56ef66fb503daef7baa2ee5a7182..a9deb1a554649e8000398d15d13878ba07faa00b 100644
--- a/bob/pad/face/config/qm_svm_aggregated_db.py
+++ b/bob/pad/face/config/qm_svm_aggregated_db.py
@@ -110,3 +110,7 @@ The data is also mean-std normalized, ``mean_std_norm_flag = True``.
 """
 
 
+
+
+
+
diff --git a/bob/pad/face/database/aggregated_db.py b/bob/pad/face/database/aggregated_db.py
index 353c2d681d6c0f114dd8d1d2a66af383ae2e33e7..9087f3e747db1c3a21f6a5ede62883e843bd92d9 100644
--- a/bob/pad/face/database/aggregated_db.py
+++ b/bob/pad/face/database/aggregated_db.py
@@ -200,7 +200,32 @@ class AggregatedDbPadFile(PadFile):
 class AggregatedDbPadDatabase(PadDatabase):
     """
     A high level implementation of the Database class for the Aggregated Database
-    uniting 3 databases: REPLAY-ATTACK, REPLAY-MOBILE and MSU MFSD.
+    uniting 3 databases: REPLAY-ATTACK, REPLAY-MOBILE and MSU MFSD. Currently this
+    database supports 3 protocols, which are listed in the ``available_protocols``
+    argument of this class.
+
+    Available protocols are:
+
+    1. "grandtest" - this protocol is using all the data available in the
+       databases Replay-Attack, Replay-Mobile, MSU MFSD.
+
+    2. "photo-photo-video" - this protocol is used to test the system on
+       unseen types of attacks. In this case the attacks are splitted
+       as follows:
+       'train' set - only **photo** attacks are used for training,
+       'dev' set   - only **photo** attacks are used for threshold tuning,
+       'eval' set  - only **video** attacks are used in final evaluation.
+       In this case the final performance is estimated on previously
+       unseen **video** attacks.
+
+    3. "video-video-photo" - this protocol is used to test the system on
+       unseen types of attacks. In this case the attacks are splitted
+       as follows:
+       'train' set - only **video** attacks are used for training,
+       'dev' set   - only **video** attacks are used for threshold tuning,
+       'eval' set  - only **photo** attacks are used in final evaluation.
+       In this case the final performance is estimated on previously
+       unseen **photo** attacks.
     """
 
     def __init__(
@@ -243,6 +268,9 @@ class AggregatedDbPadDatabase(PadDatabase):
         self.low_level_group_names = ('train', 'devel', 'test') # group names in the low-level database interface
         self.high_level_group_names = ('train', 'dev', 'eval') # names are expected to be like that in objects() function
 
+        # A list of available protocols:
+        self.available_protocols = ['grandtest', 'photo-photo-video', 'video-video-photo']
+
         # Always use super to call parent class methods.
         super(AggregatedDbPadDatabase, self).__init__(
             name = 'aggregated_db',
@@ -252,6 +280,200 @@ class AggregatedDbPadDatabase(PadDatabase):
             **kwargs)
 
 
+    #==========================================================================
+    def get_files_given_single_group(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
+        """
+        This function returns 3 lists of files for Raplay-Attack, Replay-Mobile
+        and MSU MFSD databases, which fulfill the given restrictions. This
+        function for the groups parameter accepts a single string ONLY, which
+        determines the low level name of the group, see ``low_level_group_names``
+        argument of this class for available options.
+
+        Keyword parameters:
+
+        ``groups`` : :py:class:`str`
+            The group of which the clients should be returned.
+            One element of ('train', 'devel', 'test').
+
+        ``protocol`` : :py:class:`str`
+            The protocol for which the clients should be retrieved.
+            Available options are defined in the ``available_protocols`` argument
+            of the class. So far the following protocols are available:
+
+            1. "grandtest" - this protocol is using all the data available in the
+               databases Replay-Attack, Replay-Mobile, MSU MFSD.
+
+            2. "photo-photo-video" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **photo** attacks are used for training,
+               'dev' set   - only **photo** attacks are used for threshold tuning,
+               'eval' set  - only **video** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **video** attacks.
+
+           3. "video-video-photo" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **video** attacks are used for training,
+               'dev' set   - only **video** attacks are used for threshold tuning,
+               'eval' set  - only **photo** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **photo** attacks.
+
+        ``purposes`` : :py:class:`str`
+            OR a list of strings.
+            The purposes for which File objects should be retrieved.
+            Usually it is either 'real' or 'attack'.
+
+        ``model_ids``
+            This parameter is not supported in PAD databases yet
+
+        **Returns:**
+
+        ``replay_files`` : [File]
+            A list of files corresponding to Replay-Attack database.
+
+        ``replaymobile_files`` : [File]
+            A list of files corresponding to Replay-Mobile database.
+
+        ``msu_mfsd_files`` : [File]
+            A list of files corresponding to MSU MFSD database.
+        """
+
+        # with grandtest protocol
+        if protocol == 'grandtest' or protocol is None or groups is None:
+
+            replay_files = self.replay_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
+
+            replaymobile_files = self.replaymobile_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
+
+            msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, **kwargs)
+
+        if protocol == 'photo-photo-video':
+
+            if groups == 'train' or groups ==  'devel': # the group names are low-level here: ('train', 'devel', 'test')
+
+                replay_files = self.replay_db.objects(protocol='photo', groups=groups, cls=purposes, **kwargs)
+
+                replaymobile_files = self.replaymobile_db.objects(protocol='grandtest', groups=groups, cls=purposes, sample_type='photo', **kwargs)
+
+                msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, instrument = ('print', ''), **kwargs)
+
+            if groups == 'test':
+
+                replay_files = self.replay_db.objects(protocol='video', groups=groups, cls=purposes, **kwargs)
+
+                replaymobile_files = self.replaymobile_db.objects(protocol='grandtest', groups=groups, cls=purposes, sample_type='video', **kwargs)
+
+                msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, instrument = ('video_hd', 'video_mobile', ''), **kwargs)
+
+        if protocol == 'video-video-photo':
+
+            if groups == 'train' or groups ==  'devel': # the group names are low-level here: ('train', 'devel', 'test')
+
+                replay_files = self.replay_db.objects(protocol='video', groups=groups, cls=purposes, **kwargs)
+
+                replaymobile_files = self.replaymobile_db.objects(protocol='grandtest', groups=groups, cls=purposes, sample_type='video', **kwargs)
+
+                msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, instrument = ('video_hd', 'video_mobile', ''), **kwargs)
+
+            if groups == 'test':
+
+                replay_files = self.replay_db.objects(protocol='photo', groups=groups, cls=purposes, **kwargs)
+
+                replaymobile_files = self.replaymobile_db.objects(protocol='grandtest', groups=groups, cls=purposes, sample_type='photo', **kwargs)
+
+                msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, instrument = ('print', ''), **kwargs)
+
+        return replay_files, replaymobile_files, msu_mfsd_files
+
+
+    #==========================================================================
+    def get_files_given_groups(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
+        """
+        This function returns 3 lists of files for Raplay-Attack, Replay-Mobile
+        and MSU MFSD databases, which fulfill the given restrictions. This
+        function for the groups parameter accepts a single string OR a list
+        of strings with multiple groups. Group names are low level, see
+        ``low_level_group_names`` argument of the class for available options.
+
+        Keyword parameters:
+
+        ``groups`` : :py:class:`str`
+            OR a list of strings.
+            The groups of which the clients should be returned.
+            Usually, groups are one or more elements of ('train', 'devel', 'test').
+
+        ``protocol`` : :py:class:`str`
+            The protocol for which the clients should be retrieved.
+            Available options are defined in the ``available_protocols`` argument
+            of the class. So far the following protocols are available:
+
+            1. "grandtest" - this protocol is using all the data available in the
+               databases Replay-Attack, Replay-Mobile, MSU MFSD.
+
+            2. "photo-photo-video" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **photo** attacks are used for training,
+               'dev' set   - only **photo** attacks are used for threshold tuning,
+               'eval' set  - only **video** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **video** attacks.
+
+           3. "video-video-photo" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **video** attacks are used for training,
+               'dev' set   - only **video** attacks are used for threshold tuning,
+               'eval' set  - only **photo** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **photo** attacks.
+
+        ``purposes`` : :py:class:`str`
+            OR a list of strings.
+            The purposes for which File objects should be retrieved.
+            Usually it is either 'real' or 'attack'.
+
+        ``model_ids``
+            This parameter is not supported in PAD databases yet
+
+        **Returns:**
+
+        ``replay_files`` : [File]
+            A list of files corresponding to Replay-Attack database.
+
+        ``replaymobile_files`` : [File]
+            A list of files corresponding to Replay-Mobile database.
+
+        ``msu_mfsd_files`` : [File]
+            A list of files corresponding to MSU MFSD database.
+        """
+
+        if isinstance(groups, str) or groups is None: # if a single group is given
+
+            groups = [groups]
+
+        replay_files = []
+
+        replaymobile_files = []
+
+        msu_mfsd_files = []
+
+        for group in groups:
+
+            files = self.get_files_given_single_group(groups = group, protocol = protocol, purposes = purposes, model_ids = model_ids, **kwargs)
+
+            replay_files += files[0]
+
+            replaymobile_files += files[1]
+
+            msu_mfsd_files += files[2]
+
+        return replay_files, replaymobile_files, msu_mfsd_files
+
+
     #==========================================================================
     def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
         """
@@ -266,8 +488,29 @@ class AggregatedDbPadDatabase(PadDatabase):
 
         ``protocol`` : :py:class:`str`
             The protocol for which the clients should be retrieved.
-            The protocol is dependent on your database.
-            If you do not have protocols defined, just ignore this field.
+            Available options are defined in the ``available_protocols`` argument
+            of the class. So far the following protocols are available:
+
+            1. "grandtest" - this protocol is using all the data available in the
+               databases Replay-Attack, Replay-Mobile, MSU MFSD.
+
+            2. "photo-photo-video" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **photo** attacks are used for training,
+               'dev' set   - only **photo** attacks are used for threshold tuning,
+               'eval' set  - only **video** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **video** attacks.
+
+           3. "video-video-photo" - this protocol is used to test the system on
+               unseen types of attacks. In this case the attacks are splitted
+               as follows:
+               'train' set - only **video** attacks are used for training,
+               'dev' set   - only **video** attacks are used for threshold tuning,
+               'eval' set  - only **photo** attacks are used in final evaluation.
+               In this case the final performance is estimated on previously
+               unseen **photo** attacks.
 
         ``purposes`` : :py:class:`str`
             OR a list of strings.
@@ -287,15 +530,23 @@ class AggregatedDbPadDatabase(PadDatabase):
         groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names)
         # Since this database was designed for PAD experiments, nothing special
         # needs to be done here.
-        replay_files = self.replay_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
 
-        replaymobile_files = self.replaymobile_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
+        replay_files, replaymobile_files, msu_mfsd_files = self.get_files_given_groups(groups = groups,
+                                                                                       protocol = protocol,
+                                                                                       purposes = purposes,
+                                                                                       model_ids = model_ids,
+                                                                                       **kwargs)
 
-        msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, **kwargs)
+#            replay_files = self.replay_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
+#
+#            replaymobile_files = self.replaymobile_db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs)
+#
+#            msu_mfsd_files = self.msu_mfsd_db.objects(group=groups, cls=purposes, **kwargs)
 
         files = replay_files + replaymobile_files + msu_mfsd_files # append all files to a single list
 
         files = [AggregatedDbPadFile(f) for f in files]
+
         return files
 
 
@@ -343,17 +594,3 @@ class AggregatedDbPadDatabase(PadDatabase):
         annotations = hldi_db.annotations(f)
 
         return annotations
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/bob/pad/face/test/test_databases.py b/bob/pad/face/test/test_databases.py
index 6c628bd2b28e310221186721254cacc434da5f48..c7b9a76f1a44930e02bb390d4dd53281c95bcd8b 100644
--- a/bob/pad/face/test/test_databases.py
+++ b/bob/pad/face/test/test_databases.py
@@ -7,9 +7,10 @@ from nose.plugins.skip import SkipTest
 import bob.bio.base
 from bob.bio.base.test.utils import db_available
 
-@db_available('replay')
+
+@db_available('replay') # the name of the package
 def test_replay():
-    replay_database_instance = bob.bio.base.load_resource('replay', 'database', preferred_package='bob.pad.face', package_prefix='bob.pad.')
+    replay_database_instance = bob.bio.base.load_resource('replay-attack', 'database', preferred_package='bob.pad.face', package_prefix='bob.pad.') # replay-attack is the name of the configuration file
     try:
 
         assert len( replay_database_instance.objects(groups=['train', 'dev', 'eval']) )==  1200
@@ -41,7 +42,7 @@ def test_replaymobile():
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e)
 
 
-@db_available('msu_mfsd_mod') # the name of the package defining low-level interface of MSU MFSD
+@db_available('msu_mfsd_mod')
 def test_msu_mfsd():
     msu_mfsd = bob.bio.base.load_resource('msu-mfsd', 'database', preferred_package='bob.pad.face', package_prefix='bob.pad.')
     try:
@@ -58,3 +59,38 @@ def test_msu_mfsd():
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e)
 
 
+# Test the Aggregated database, which doesn't have a package
+def test_aggregated_db():
+    aggregated_db = bob.bio.base.load_resource('aggregated-db', 'database', preferred_package='bob.pad.face', package_prefix='bob.pad.')
+    try:
+
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval']) )==  2510
+        assert len( aggregated_db.objects(groups=['train', 'dev']) ) ==  1608
+        assert len( aggregated_db.objects(groups=['train']) ) ==  752
+
+        assert len( aggregated_db.objects(groups='train') ) ==  752
+        assert len( aggregated_db.objects(groups='dev') ) ==  856
+        assert len( aggregated_db.objects(groups='eval') ) ==  902
+
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval'], protocol = 'grandtest') ) ==  2510
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval'], protocol = 'grandtest', purposes='real') ) ==  660
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval'], protocol = 'grandtest', purposes='attack') ) == 1850
+
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval'], protocol = 'photo-photo-video')) ==  1664
+        assert len( aggregated_db.objects(groups=['train', 'dev'], protocol = 'photo-photo-video')) ==  1176
+        assert len( aggregated_db.objects(groups='eval',  protocol = 'photo-photo-video')) ==  488
+
+        assert len( aggregated_db.objects(groups=['train', 'dev', 'eval'], protocol = 'video-video-photo')) ==  1506
+        assert len( aggregated_db.objects(groups=['train', 'dev'], protocol = 'video-video-photo')) ==  872
+        assert len( aggregated_db.objects(groups='eval',  protocol = 'video-video-photo')) ==  634
+
+    except IOError as e:
+        raise SkipTest(
+            "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e)
+
+
+
+
+
+
+
diff --git a/requirements.txt b/requirements.txt
index 795e4100ff0332650da93fc9470405eefac9649e..4eff3ad6e2749acdbb9af39bbd8e6ca322a2f2e1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,4 +12,7 @@ bob.bio.video
 bob.io.image
 bob.ip.color
 bob.ip.qualitymeasure
-bob.learn.libsvm
\ No newline at end of file
+bob.learn.libsvm
+bob.learn.linear
+scikit-learn
+
diff --git a/setup.py b/setup.py
index efe8b2ab31e4fbd15b6e53cf718bd6631b88dc0f..25eaac9a091cf5f93670371c2423cdab5c203285 100644
--- a/setup.py
+++ b/setup.py
@@ -77,13 +77,25 @@ setup(
             'msu-mfsd = bob.pad.face.config.msu_mfsd',
             'aggregated-db = bob.pad.face.config.aggregated_db',
 
-            # baselines:
+            # baselines using SVM:
             'lbp-svm = bob.pad.face.config.lbp_svm',
             'lbp-svm-aggregated-db = bob.pad.face.config.lbp_svm_aggregated_db',
+
             'qm-svm = bob.pad.face.config.qm_svm',
             'qm-svm-aggregated-db = bob.pad.face.config.qm_svm_aggregated_db',
+
             'frame-diff-svm = bob.pad.face.config.frame_diff_svm',
             'frame-diff-svm-aggregated-db = bob.pad.face.config.frame_diff_svm_aggregated_db',
+
+            # baselines using one-class SVM
+            'qm-one-class-svm-aggregated-db = bob.pad.face.config.qm_one_class_svm_aggregated_db',
+            'qm-one-class-svm-cascade-aggregated-db = bob.pad.face.config.qm_one_class_svm_cascade_aggregated_db',
+
+            # baselines using LR:
+            'qm-lr = bob.pad.face.config.qm_lr', # this pipe-line can be used both for individual and Aggregated databases.
+
+            # baselines using GMM:
+            'qm-one-class-gmm = bob.pad.face.config.qm_one_class_gmm', # this pipe-line can be used both for individual and Aggregated databases.
             ],
 
         # registered preprocessors:
@@ -103,6 +115,66 @@ setup(
             'video-svm-pad-algorithm-10k-grid-mean-std = bob.pad.face.config.algorithm.video_svm_pad_algorithm:video_svm_pad_algorithm_10k_grid_mean_std',
             'video-svm-pad-algorithm-10k-grid-mean-std-frame-level = bob.pad.face.config.algorithm.video_svm_pad_algorithm:video_svm_pad_algorithm_10k_grid_mean_std_frame_level',
             'video-svm-pad-algorithm-default-svm-param-mean-std-frame-level = bob.pad.face.config.algorithm.video_svm_pad_algorithm:video_svm_pad_algorithm_default_svm_param_mean_std_frame_level',
+
+            # for grid search experiments with cascade of SVMs N = 2
+            'algorithm-n2-gamma-02 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_gamma_02',
+            'algorithm-n2-gamma-01 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_gamma_01',
+            'algorithm-n2-gamma-005 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_gamma_005',
+            'algorithm-n2-gamma-001 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_gamma_001',
+            'algorithm-n2-gamma-01-video-level = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_gamma_01_video_level',
+            'algorithm-n2-two-class-svm-c1-gamma-001 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n2_two_class_svm_c1_gamma_001',
+
+            # for grid search experiments with cascade of SVMs N = 10
+            'algorithm-n10-gamma-01 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n10_gamma_01',
+            'algorithm-n10-gamma-005 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n10_gamma_005',
+            'algorithm-n10-gamma-001 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n10_gamma_001',
+            'algorithm-n10-gamma-0005 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n10_gamma_0005',
+
+            # for grid search experiments with cascade of SVMs N = 20
+            'algorithm-n20-gamma-05 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_05',
+            'algorithm-n20-gamma-02 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_02',
+            'algorithm-n20-gamma-01 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_01',
+            'algorithm-n20-gamma-005 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_005',
+            'algorithm-n20-gamma-001 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_001',
+            'algorithm-n20-gamma-0005 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_0005',
+            'algorithm-n20-gamma-0001 = bob.pad.face.config.algorithm.video_cascade_svm_pad_algorithm:algorithm_n20_gamma_0001',
+
+            # for grid search experiments using GMM
+            'algorithm-gmm-2 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_2',
+            'algorithm-gmm-3 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_3',
+            'algorithm-gmm-4 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_4',
+            'algorithm-gmm-5 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_5',
+            'algorithm-gmm-6 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_6',
+            'algorithm-gmm-7 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_7',
+            'algorithm-gmm-8 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_8',
+            'algorithm-gmm-9 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_9',
+            'algorithm-gmm-10 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_10',
+            'algorithm-gmm-12 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_12',
+            'algorithm-gmm-14 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_14',
+            'algorithm-gmm-16 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_16',
+            'algorithm-gmm-18 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_18',
+            'algorithm-gmm-20 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_20',
+            'algorithm-gmm-25 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_25',
+            'algorithm-gmm-30 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_30',
+            'algorithm-gmm-35 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_35',
+            'algorithm-gmm-40 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_40',
+            'algorithm-gmm-45 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_45',
+            'algorithm-gmm-50 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50',
+            'algorithm-gmm-60 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_60',
+            'algorithm-gmm-70 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_70',
+            'algorithm-gmm-80 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_80',
+            'algorithm-gmm-90 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_90',
+            'algorithm-gmm-100 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_100',
+            'algorithm-gmm-50-0 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_0',
+            'algorithm-gmm-50-1 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_1',
+            'algorithm-gmm-50-2 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_2',
+            'algorithm-gmm-50-3 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_3',
+            'algorithm-gmm-50-4 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_4',
+            'algorithm-gmm-50-5 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_5',
+            'algorithm-gmm-50-6 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_6',
+            'algorithm-gmm-50-7 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_7',
+            'algorithm-gmm-50-8 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_8',
+            'algorithm-gmm-50-9 = bob.pad.face.config.algorithm.video_gmm_pad_algorithm:algorithm_gmm_50_9',
             ],
 
         # registered grid configurations: