diff --git a/bob/pad/base/algorithm/SVMCascadePCA.py b/bob/pad/base/algorithm/SVMCascadePCA.py
new file mode 100644
index 0000000000000000000000000000000000000000..09f06c0c50a059f3559dd00340a34d3dc2f25a80
--- /dev/null
+++ b/bob/pad/base/algorithm/SVMCascadePCA.py
@@ -0,0 +1,877 @@
+#!/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
+
+from bob.pad.base.utils import convert_frame_cont_to_array, mean_std_normalize
+
+#==============================================================================
+# Main body :
+
+class SVMCascadePCA(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 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 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 = 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 = convert_list_of_frame_cont_to_array(training_features[0]) # output is array
+        # training_features[1] - training features for the ATTACK class.
+        attack = 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 = 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/base/algorithm/__init__.py b/bob/pad/base/algorithm/__init__.py
index cc2b6aa927747d32350ae70d2bcf82c691242cd7..05d16266a81910299064bca66b092cde61df45e9 100644
--- a/bob/pad/base/algorithm/__init__.py
+++ b/bob/pad/base/algorithm/__init__.py
@@ -2,6 +2,7 @@ from .Algorithm import Algorithm
 from .SVM import SVM
 from .OneClassGMM import OneClassGMM
 from .LogRegr import LogRegr
+from .SVMCascadePCA import SVMCascadePCA
 
 def __appropriate__(*args):
     """Says object was actually declared here, and not in the import module.
@@ -26,5 +27,6 @@ __appropriate__(
     SVM,
     OneClassGMM,
     LogRegr,
+    SVMCascadePCA,
 )
 __all__ = [_ for _ in dir() if not _.startswith('_')]