From f20bd6857acd56378b28b13c19d2fd31b91f7ca1 Mon Sep 17 00:00:00 2001
From: Rakesh Mehta <rakesh.mehta@idiap.ch>
Date: Tue, 20 Aug 2013 14:02:00 +0200
Subject: [PATCH] Trainer tests added

---
 xbob/boosting/core/trainers.py          |  51 ++++++++++-----------
 xbob/boosting/tests/datafile.hdf5       | Bin 0 -> 10144 bytes
 xbob/boosting/tests/test_trainer_lut.py |  56 ++++++++++++++++++++++--
 3 files changed, 79 insertions(+), 28 deletions(-)
 create mode 100644 xbob/boosting/tests/datafile.hdf5

diff --git a/xbob/boosting/core/trainers.py b/xbob/boosting/core/trainers.py
index 575da62..0446277 100644
--- a/xbob/boosting/core/trainers.py
+++ b/xbob/boosting/core/trainers.py
@@ -181,7 +181,7 @@ class LutMachine():
 
 
 
-    def get_weak_scores(self, fset):
+    def get_weak_scores(self, features):
 	""" Function computes classification results according to the LUT machine
 
         Function classifies the features based on a single LUT machine. 
@@ -193,13 +193,13 @@ class LutMachine():
         weak_scores: The classification scores of the features based on current weak classifier"""
 
         # Initialize
-        num_samp = len(fset)
+        num_samp = len(features)
         num_outputs = len(self.luts[0])
         weak_scores = numpy.zeros([num_samp,num_outputs])
 
         # Compute weak scores
-        for oi in range(num_outputs):
-            weak_scores[:,oi] = numpy.transpose(self.luts[fset[:,self.selected_indices[oi]],oi])
+        for output_index in range(num_outputs):
+            weak_scores[:,output_index] = numpy.transpose(self.luts[features[:,self.selected_indices[output_index]],output_index])
         return weak_scores
 
 
@@ -233,9 +233,7 @@ class LutTrainer():
         """
         self.num_entries = num_entries
         self.num_outputs = num_outputs
-        self.luts = numpy.ones((num_entries, num_outputs), dtype = numpy.int)
         self.selection_type = selection_type
-        self.selected_indices = numpy.zeros([num_outputs,1], 'int16')
     
 
 
@@ -261,8 +259,8 @@ class LutTrainer():
         """
 
         # Initializations
-        num_outputs = loss_grad.shape[1]
-        fea_grad = numpy.zeros([self.num_entries, num_outputs])
+        # num_outputs = loss_grad.shape[1]
+        fea_grad = numpy.zeros([self.num_entries, self.num_outputs])
         lut_machine = LutMachine(self.num_outputs, self.num_entries)
 
         # Compute the sum of the gradient based on the feature values or the loss associated with each 
@@ -270,6 +268,7 @@ class LutTrainer():
         sum_loss = self.compute_grad_sum(loss_grad, fea)
 
 
+
         # Select the most discriminative index (or indices) for classification which minimizes the loss
         #  and compute the sum of gradient for that index
        
@@ -280,10 +279,10 @@ class LutTrainer():
 
             selected_indices = [numpy.argmin(col) for col in numpy.transpose(sum_loss)]
 
-            for oi in range(num_outputs):
-                curr_id = sum_loss[:,oi].argmin()
-                fea_grad[:,oi] = self.compute_grad_hist(loss_grad[:,oi],fea[:,curr_id])
-                lut_machine.selected_indices[oi] = curr_id
+            for output_index in range(self.num_outputs):
+                curr_id = sum_loss[:,output_index].argmin()
+                fea_grad[:,output_index] = self.compute_grad_hist(loss_grad[:,output_index],fea[:,curr_id])
+                lut_machine.selected_indices[output_index] = curr_id
 
 
         elif self.selection_type == 'shared':
@@ -293,10 +292,11 @@ class LutTrainer():
 
             accum_loss = numpy.sum(sum_loss,1)
             selected_findex = accum_loss.argmin()
-            lut_machine.selected_indices = selected_findex*numpy.ones([num_outputs,1],'int16')
+            lut_machine.selected_indices = selected_findex*numpy.ones([self.num_outputs,1],'int16')
+
+            for output_index in range(self.num_outputs):
+                fea_grad[:,output_index] = self.compute_grad_hist(loss_grad[:,output_index],fea[:,selected_findex])
 
-            for oi in range(num_outputs):
-                fea_grad[:,oi] = self.compute_grad_hist(loss_grad[:,oi],fea[:,selected_findex])
      
         # Assign the values to LookUp Table
         lut_machine.luts[fea_grad <= 0.0] = -1
@@ -323,14 +323,14 @@ class LutTrainer():
         # initialize values
         num_fea = len(fea[0])
         num_samp = len(fea)
-        num_outputs = len(loss_grad[0])
-        sum_loss = numpy.zeros([num_fea,num_outputs])
+        sum_loss = numpy.zeros([num_fea,self.num_outputs])
        
         # Compute the loss for each feature
-        for fi in range(num_fea):
-            for oi in range(num_outputs):
-                hist_grad = self.compute_grad_hist(loss_grad[:,oi],fea[:,fi])
-                sum_loss[fi,oi] = - sum(abs(hist_grad))
+        for feature_index in range(num_fea):
+            for output_index in range(self.num_outputs):
+                hist_grad = self.compute_grad_hist(loss_grad[:,output_index],fea[:,feature_index])
+                sum_loss[feature_index,output_index] = - sum(abs(hist_grad))
+                
 
 
         return sum_loss
@@ -339,7 +339,7 @@ class LutTrainer():
 
 
 
-    def compute_grad_hist(self, loss_grado,fval):
+    def compute_grad_hist(self, loss_grado,features):
         """ The function computes the loss for a single feature.
 
         Function computes sum of the loss gradient that have same feature values. 
@@ -350,12 +350,13 @@ class LutTrainer():
 
         return: hist_grad: The sum of the loss gradient"""
         # initialize the values
-        num_samp = len(fval)
+        num_samp = len(features)
         hist_grad = numpy.zeros([self.num_entries])
 
         # compute the sum of the gradient
-        for hi in range(self.num_entries):
-            hist_grad[hi] = sum(loss_grado[fval == hi])
+        for feature_value in range(self.num_entries):
+            
+            hist_grad[feature_value] = sum(loss_grado[features == feature_value])
         return hist_grad
 
 
diff --git a/xbob/boosting/tests/datafile.hdf5 b/xbob/boosting/tests/datafile.hdf5
new file mode 100644
index 0000000000000000000000000000000000000000..57b7d45c2c220d085e76b1ac3efc48b1ba5112cb
GIT binary patch
literal 10144
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
DxBgZx

literal 0
HcmV?d00001

diff --git a/xbob/boosting/tests/test_trainer_lut.py b/xbob/boosting/tests/test_trainer_lut.py
index 3a4c519..f5ed96f 100644
--- a/xbob/boosting/tests/test_trainer_lut.py
+++ b/xbob/boosting/tests/test_trainer_lut.py
@@ -4,9 +4,6 @@ import xbob.boosting
 import numpy
 import bob
 
-def get_single_feature():
-    num_feature = 100
-
 
 class TestLutTrainer(unittest.TestCase):
     """Class to test the LUT trainer """
@@ -32,10 +29,63 @@ class TestLutTrainer(unittest.TestCase):
 
 
 
+    def test_lut_selected_index(self):
+
+        num_samples = 100
+        max_feature = 20
+        dimension_feature = 10
+        
+        selected_index = 5
+        range_feature = max_feature
+        trainer = xbob.boosting.core.trainers.LutTrainer(range_feature,'indep', 1)   
+        
+        data_file = bob.io.File('xbob/boosting/tests/datafile.hdf5', 'r')
+        #features = bob.io.load('test_data.hdf5')
+        features = data_file.read()
+
+        x_train1 = numpy.copy(features)
+        x_train1[x_train1[:,selected_index] >=10, selected_index] = 9
+        x_train2 = numpy.copy(features) 
+        x_train2[x_train2[:,selected_index] < 10, selected_index] = 10
+        x_train = numpy.vstack((x_train1, x_train2))
+ 
+        y_train = numpy.vstack((numpy.ones([num_samples,1]),-numpy.ones([num_samples,1])))
+
+        scores = numpy.zeros([2*num_samples,1])
+        loss_grad = -y_train*(numpy.exp(y_train*scores))
+
+        machine = trainer.compute_weak_trainer(x_train, loss_grad)
+
+        self.assertTrue((machine.luts[0:9] == -1).all())   # The values of the LUT are negative of the classes sign
+        self.assertTrue((machine.luts[10:] ==  1).all())
+        
+
+
+    def test_lut_selected_index(self):
+
+        num_samples = 100
+        max_feature = 20
+        dimension_feature = 10
+        delta = 5
+        selected_index = 5
+        range_feature = max_feature + delta
+        trainer = xbob.boosting.core.trainers.LutTrainer(range_feature,'indep', 1)   
+        data_file = bob.io.File('xbob/boosting/tests/datafile.hdf5', 'r')
+
+        features = data_file.read()
 
+        x_train1 = numpy.copy(features)
+        x_train2 = numpy.copy(features) 
+        x_train = numpy.vstack((x_train1, x_train2))
+        x_train[0:num_samples,selected_index] = x_train[0:num_samples,selected_index] + delta
+        y_train = numpy.vstack((numpy.ones([num_samples,1]),-numpy.ones([num_samples,1])))
 
+        scores = numpy.zeros([2*num_samples,1])
+        loss_grad = -y_train*(numpy.exp(y_train*scores))
 
+        machine = trainer.compute_weak_trainer(x_train, loss_grad)
 
+        self.assertEqual(machine.selected_indices[0], selected_index)
 
 
     
-- 
GitLab