From 13c7964dbfa216cbe9868c421377790045dc5116 Mon Sep 17 00:00:00 2001
From: Olegs NIKISINS <onikisins@italix03.idiap.ch>
Date: Mon, 29 May 2017 13:31:57 +0200
Subject: [PATCH] Changed the LBP+SVM pipeline settings to partially match
 Ivana's paper

---
 .../face/algorithm/VideoSvmPadAlgorithm.py    | 81 +++++++++++++++++--
 .../config/extractor/video_lbp_histogram.py   | 25 ++----
 bob/pad/face/config/grid.py                   |  4 +-
 .../config/preprocessor/video_face_crop.py    | 14 ++--
 setup.py                                      |  5 +-
 5 files changed, 92 insertions(+), 37 deletions(-)

diff --git a/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py b/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
index a6225ecb..ef921338 100644
--- a/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
+++ b/bob/pad/face/algorithm/VideoSvmPadAlgorithm.py
@@ -17,6 +17,10 @@ import numpy as np
 
 import bob.learn.libsvm
 
+import bob.io.base
+
+import os
+
 #==============================================================================
 # Main body :
 
@@ -52,6 +56,10 @@ class VideoSvmPadAlgorithm(Algorithm):
 
     ``mean_std_norm_flag`` : :py:class:`bool`
         Perform mean-std normalization of data if set to True. Default: False.
+
+    ``frame_level_scores`` : :py:class:`bool`
+        Return scores for each frame individually if True. Otherwise, return a
+        single score per video. Default: False.
     """
 
     def __init__(self,
@@ -59,7 +67,8 @@ class VideoSvmPadAlgorithm(Algorithm):
                  kernel_type = 'RBF',
                  n_samples = 10000,
                  trainer_grid_search_params = { 'cost': [2**p for p in range(-5, 16, 2)], 'gamma': [2**p for p in range(-15, 4, 2)]},
-                 mean_std_norm_flag = False):
+                 mean_std_norm_flag = False,
+                 frame_level_scores = False):
 
 
         Algorithm.__init__(self,
@@ -68,6 +77,7 @@ class VideoSvmPadAlgorithm(Algorithm):
                            n_samples = n_samples,
                            trainer_grid_search_params = trainer_grid_search_params,
                            mean_std_norm_flag = mean_std_norm_flag,
+                           frame_level_scores = frame_level_scores,
                            performs_projection=True,
                            requires_projector_training=True)
 
@@ -76,6 +86,7 @@ class VideoSvmPadAlgorithm(Algorithm):
         self.n_samples = n_samples
         self.trainer_grid_search_params = trainer_grid_search_params
         self.mean_std_norm_flag = mean_std_norm_flag
+        self.frame_level_scores = frame_level_scores
         self.machine = None
 
 
@@ -434,7 +445,8 @@ class VideoSvmPadAlgorithm(Algorithm):
     def train_svm(self, training_features, n_samples = 10000,
                   machine_type = 'C_SVC', kernel_type = 'RBF',
                   trainer_grid_search_params = { 'cost': [2**p for p in range(-5, 16, 2)], 'gamma': [2**p for p in range(-15, 4, 2)]},
-                  mean_std_norm_flag = False):
+                  mean_std_norm_flag = False,
+                  projector_file = ""):
         """
         First, this function tunes the hyper-parameters of the SVM classifier using
         grid search on the sub-sets of training data. Train and cross-validation
@@ -469,6 +481,12 @@ class VideoSvmPadAlgorithm(Algorithm):
         ``mean_std_norm_flag`` : :py:class:`bool`
             Perform mean-std normalization of data if set to True. Default: False.
 
+        ``projector_file`` : :py:class:`str`
+            The name of the file to save the trained projector to. Only the path
+            of this file is used in this function. The file debug_data.hdf5 will
+            be save in this path. This file contains information, which might be
+            usefull for debugging.
+
         **Returns:**
 
         ``machine`` : object
@@ -525,6 +543,18 @@ class VideoSvmPadAlgorithm(Algorithm):
 
             setattr(trainer, key, selected_params[key]) # set the params of trainer
 
+        # Save the data, which is usefull for debugging.
+        debug_file = os.path.join( os.path.split(projector_file)[0], "debug_data.hdf5" )
+        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']
+        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])
+        del f
+
         # 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.
@@ -574,10 +604,14 @@ class VideoSvmPadAlgorithm(Algorithm):
                                  machine_type = self.machine_type,
                                  kernel_type = self.kernel_type,
                                  trainer_grid_search_params = self.trainer_grid_search_params,
-                                 mean_std_norm_flag = self.mean_std_norm_flag)
+                                 mean_std_norm_flag = self.mean_std_norm_flag,
+                                 projector_file = projector_file)
+
+        f = bob.io.base.HDF5File(projector_file, 'w') # open hdf5 file to save to
 
+        machine.save(f) # save the machine and normalization parameters
 
-        machine.save(projector_file)
+        del f
 
 
     #==========================================================================
@@ -596,7 +630,11 @@ class VideoSvmPadAlgorithm(Algorithm):
             The file to read the projector from.
         """
 
-        self.machine = bob.learn.libsvm.Machine(projector_file)
+        f = bob.io.base.HDF5File(projector_file, 'a')
+
+        self.machine = bob.learn.libsvm.Machine(f)
+
+        del f
 
 
     #==========================================================================
@@ -648,22 +686,49 @@ class VideoSvmPadAlgorithm(Algorithm):
         **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 = np.mean(toscore, axis=0)[0]
+        if self.frame_level_scores:
+
+            score = toscore[:,0] # here score is a list containing scores for each frame
+
+        else:
+
+            score = np.mean(toscore, axis=0)[0] # compute a single score per video
 
         return score
 
 
     #==========================================================================
     def score_for_multiple_projections(self, toscore):
-        """Returns the difference between log likelihoods of being real or attack"""
+        """
+        Returns a list of scores computed by the score method of this class.
+
+        **Parameters:**
+
+        ``toscore`` : 2D :py:class:`numpy.ndarray`
+            An array containing scores computed by score() method of this class.
+
+        **Returns:**
+
+        ``list_of_scores`` : list
+            A list containing the scores.
+        """
 
 #        import ipdb; ipdb.set_trace()
 
-        return [self.score(toscore)]
+        if self.frame_level_scores:
+
+            list_of_scores = self.score(toscore)
+
+        else:
+
+            list_of_scores = [self.score(toscore)]
+
+        return list_of_scores
 
 
 
diff --git a/bob/pad/face/config/extractor/video_lbp_histogram.py b/bob/pad/face/config/extractor/video_lbp_histogram.py
index d9d3e96c..ee0ec7f7 100644
--- a/bob/pad/face/config/extractor/video_lbp_histogram.py
+++ b/bob/pad/face/config/extractor/video_lbp_histogram.py
@@ -6,25 +6,16 @@ from bob.pad.face.extractor import VideoLBPHistogram
 #=======================================================================================
 # Define instances here:
 
-lbptype='regular'
+lbptype='uniform'
 elbptype='regular'
-rad=3
+rad=1
 neighbors=8
 circ=False
 dtype=None
 
-video_lbp_histogram_extractor_n8r3 = VideoLBPHistogram(lbptype=lbptype,
-                                                       elbptype=elbptype,
-                                                       rad=rad,
-                                                       neighbors=neighbors,
-                                                       circ=circ,
-                                                       dtype=dtype)
-
-lbptype='uniform'
-
-video_lbp_histogram_extractor_n8r3_uniform = VideoLBPHistogram(lbptype=lbptype,
-                                                       elbptype=elbptype,
-                                                       rad=rad,
-                                                       neighbors=neighbors,
-                                                       circ=circ,
-                                                       dtype=dtype)
\ No newline at end of file
+video_lbp_histogram_extractor_n8r1_uniform = VideoLBPHistogram(lbptype=lbptype,
+                                                               elbptype=elbptype,
+                                                               rad=rad,
+                                                               neighbors=neighbors,
+                                                               circ=circ,
+                                                               dtype=dtype)
diff --git a/bob/pad/face/config/grid.py b/bob/pad/face/config/grid.py
index 3cddf7e5..12d4c405 100644
--- a/bob/pad/face/config/grid.py
+++ b/bob/pad/face/config/grid.py
@@ -19,7 +19,7 @@ idiap = Grid(
     number_of_enrollment_jobs=32,
     enrollment_queue='8G-io-big',
 
-    number_of_scoring_jobs=50,
+    number_of_scoring_jobs=1,
     scoring_queue='8G-io-big',
     )
 
@@ -39,6 +39,6 @@ idiap_user_machines = Grid(
     number_of_enrollment_jobs=32,
     enrollment_queue='8G',
 
-    number_of_scoring_jobs=50,
+    number_of_scoring_jobs=1,
     scoring_queue='8G',
     )
diff --git a/bob/pad/face/config/preprocessor/video_face_crop.py b/bob/pad/face/config/preprocessor/video_face_crop.py
index b210d189..61eaf725 100644
--- a/bob/pad/face/config/preprocessor/video_face_crop.py
+++ b/bob/pad/face/config/preprocessor/video_face_crop.py
@@ -6,15 +6,15 @@ from bob.pad.face.preprocessor import VideoFaceCrop
 #=======================================================================================
 # Define instances here:
 
-cropped_image_size = (100, 100) # The size of the resulting face
-cropped_positions = { 'topleft' : (0,0) , 'bottomright' : cropped_image_size}
+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
-color_channel = 'gray'   # Convert image to gray-scale format
+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
+color_channel = 'gray'        # Convert image to gray-scale format
 
-video_face_crop_preproc_100_100 = VideoFaceCrop(cropped_image_size = cropped_image_size,
+video_face_crop_preproc_64_64 = VideoFaceCrop(cropped_image_size = cropped_image_size,
                                                 cropped_positions = cropped_positions,
                                                 fixed_positions = fixed_positions,
                                                 mask_sigma = mask_sigma,
diff --git a/setup.py b/setup.py
index 53dab1e9..791a68e8 100644
--- a/setup.py
+++ b/setup.py
@@ -100,13 +100,12 @@ setup(
 
         # registered preprocessors:
         'bob.pad.preprocessor': [
-            'video-face-crop-preproc-100 = bob.pad.face.config.preprocessor.video_face_crop:video_face_crop_preproc_100_100',
+            'video-face-crop-preproc-64 = bob.pad.face.config.preprocessor.video_face_crop:video_face_crop_preproc_64_64',
             ],
 
         # registered preprocessors:
         'bob.pad.extractor': [
-            'video-lbp-histogram-extractor-n8r3 = bob.pad.face.config.extractor.video_lbp_histogram:video_lbp_histogram_extractor_n8r3',
-            'video-lbp-histogram-extractor-n8r3-uniform = bob.pad.face.config.extractor.video_lbp_histogram:video_lbp_histogram_extractor_n8r3_uniform',
+            'video-lbp-histogram-extractor-n8r1-uniform = bob.pad.face.config.extractor.video_lbp_histogram:video_lbp_histogram_extractor_n8r1_uniform',
             ],
 
         # registered algorithms:
-- 
GitLab