Commit 55f0635f authored by Rakesh MEHTA's avatar Rakesh MEHTA
Browse files

Added the LBP based test and one vs all test scripts

parent bbed2538
......@@ -3,6 +3,7 @@
; Mon 16 Apr 08:29:18 2012 CEST
[buildout]
prefixes = /idiap/group/torch5spro/releases/bob-1.2.0/install/linux-x86_64-release
parts = scripts
develop = .
eggs = xbob.boosting
......
......@@ -92,6 +92,9 @@ setup(
'mnist_multi.py = xbob.boosting.scripts.mnist_multi:main',
'mnist_lbp.py = xbob.boosting.scripts.mnist_lbp:main',
'mnist_multi_lbp.py = xbob.boosting.scripts.mnist_multi_lbp:main',
'mnist_onevsall.py = xbob.boosting.scripts.mnist_onevsall:main',
'mnist_onevsall_lbp.py = xbob.boosting.scripts.mnist_onevsall_lbp:main',
'mnist_onevsall_block_lbp.py = xbob.boosting.scripts.mnist_onevsall_block_lbp:main',
],
# tests that are _exported_ (that can be executed by other packages) can
......
import core
import features
import util
......@@ -105,7 +105,7 @@ class Boost:
"""
self.num_rnds = 100
self. num_entries = 256
self.num_entries = 256
self.loss_type = 'log'
self.lut_selection = 'indep'
self.weak_trainer_type = trainer_type
......@@ -115,7 +115,7 @@ class Boost:
def train(self, fset, targets):
""" The function to traine a boosting machine.
""" The function to train a boosting machine.
The function boosts the discrete features (fset) and returns a strong classifier
as a combintaion of weak classifier.
......@@ -142,7 +142,7 @@ class Boost:
num_samp = fset.shape[0]
pred_scores = numpy.zeros([num_samp,num_op])
loss_class = losses.LOSS_FUNCTIONS[self.loss_type]
loss_ = loss_class()
loss_func = loss_class()
# For lut trainer the features should be integers
#if(self.weak_trainer_type == 'LutTrainer'):
......@@ -153,30 +153,26 @@ class Boost:
# For each round of boosting initialize a new weak trainer
if(self.weak_trainer_type == 'LutTrainer'):
wl = trainers.LutTrainer(self.num_entries, self.lut_selection, num_op )
weak_trainer = trainers.LutTrainer(self.num_entries, self.lut_selection, num_op )
elif (self.weak_trainer_type == 'StumpTrainer'):
wl = trainers.StumpTrainer()
weak_trainer = trainers.StumpTrainer()
# Compute the gradient of the loss function, l'(y,f(x)) using loss_ class
loss_grad = loss_.update_loss_grad(targets,pred_scores)
loss_grad = loss_func.update_loss_grad(targets,pred_scores)
# Select the best weak trainer for current round of boosting
curr_weak_trainer = wl.compute_weak_trainer(fset, loss_grad)
curr_weak_trainer = weak_trainer.compute_weak_trainer(fset, loss_grad)
# Compute the classification scores of the samples based only on the current round weak classifier (g_r)
curr_pred_scores = wl.get_weak_scores(fset)
curr_pred_scores = weak_trainer.get_weak_scores(fset)
# Initialize the start point for lbfgs minimization
f0 = numpy.zeros(num_op)
# Perform lbfgs minimization and compute the scale (alpha_r) for current weak trainer
ls_res = optimize.fmin_l_bfgs_b(loss_.loss_sum, f0, fprime = loss_.loss_grad_sum, args = (targets, pred_scores, curr_pred_scores))
alpha = ls_res[0]
lbfgs_struct = optimize.fmin_l_bfgs_b(loss_func.loss_sum, f0, fprime = loss_func.loss_grad_sum, args = (targets, pred_scores, curr_pred_scores))
alpha = lbfgs_struct[0]
# Update the prediction score after adding the score from the current weak classifier f(x) = f(x) + alpha_r*g_r
......
......@@ -38,7 +38,8 @@ class ExpLossFunction():
Return:
gradient: The loss gradient values for the samples """
loss = numpy.exp(-(targets * scores))
return -targets * loss
loss_grad = -targets * loss
return loss_grad
#return loss_grad
def loss_sum(self, *args):
......
import numpy as np
"""The module implements provide the interface for block based local feature extraction methods.
The features implemented are Local Binary Pattern and its variants (tLbp, dLBP, mLBP). The features
are extracted using blocks of different scale. Integral images are used to effeciently extract the
features. """
import numpy
import math
#import baseloss
import random
#import weaklearner
from pylab import *
class lbp_feature():
""" The class to extract block based LBP type features from the image.
The class provides function to extract LBP and its variants (tLBP, dLBP, mLBP) features from the
image. These features are extracted from the blocks of the images and the size of the blocks can be varied.
The number of neighbouring blocks are fixed to eight that correspond to the original LBP structure. """
def __init__(self, ftype):
"""The function to initilize the feature type.
The function initilizes the type of feature to be extracted. The type of feature can be one of the following
lbp: The original LBP features that take difference of center with the eight neighbours.
tlbp: It take the difference of the neighbours with the adjacent neighbour and central values is ignored.
dlbp: The difference between the pixels is taken along four different directions.
mlbp: The difference of the neighbouring values is taken with the average of neighbours and the central value."""
self.ftype = ftype
def integral_img(self,img):
int1 = cumsum(img,0)
int2 = cumsum(int1,1)
return int2
"""The function cumputes an intergal image for the given image.
The function computes the intergral image for the effecient computation of the block based features.
Inouts:
self: feature object
img: Input images
return:
int_img: The intergal image of the input image."""
integral_x = numpy.cumsum(img,0)
integral_img = numpy.cumsum(integral_x,1)
return integral_img
def get_features(self,img,cx,cy):
# Initializations
"""The function computes the block based local features at different scales.
The function extracts the block based local features at multiple scales from the image. The scale refers to
the size of the block used while computing the features. The feature captured at different scales are
concatenated together and the final feature vector is returned. The scale are varied from the lowest scale of 1
to maximum which is provided as the parameter to the function (cx, cy). Thus the features are extract with the
block size of {1,2,3...cy} x {1,2,3...cx}.
Inputs:
img: Image for extracting the features.
cx: The maximum columns for the block
cy: The maximum rows for the block
Return:
fvec: The concatenated feature vectors for all the scales."""
# Compute the intergal image and add zeros along row and col for block processing
int_imgc = self.integral_img(img)
rows, cols = img.shape
int_img = np.zeros([rows+1,cols+1])
int_img = numpy.zeros([rows+1,cols+1])
int_img[1:,1:] = int_imgc
# initialize
num_neighbours = 8
fvec = np.empty(0, dtype = 'uint8')
for isx in range(cx):
for isy in range(cy):
sx = isx +1
sy = isy +1
blk_int = int_img[sy+1:,sx+1:] + int_img[0:-(sy+1),0:-(sx+1)] - int_img[sy+1:,0:-(sx+1)] - int_img[0:-(sy+1),sx+1:]
blk_int = int_img[sy:,sx:] + int_img[0:-sy,0:-sx] - int_img[sy:,0:-sx] - int_img[0:-sy,sx:]
fmap_dimy = blk_int.shape[0] -2
coord = [[0,0],[0,1],[0,2],[1,2],[2,2],[2,1],[2,0],[1,0]]
fvec = numpy.empty(0, dtype = 'uint8')
# Vary the scale of the block and compute features
for xi in range(cx):
for yi in range(cy):
# Compute the sum of the blocks for the current scale
blk_int = int_img[yi+1:,xi+1:] + int_img[0:-(yi+1),0:-(xi+1)] - int_img[yi+1:,0:-(xi+1)] - int_img[0:-(yi+1),xi+1:]
# Initialize the size of the final feature map that will be obtained
fmap_dimy = blk_int.shape[0] -2
fmap_dimx = blk_int.shape[1] -2
coord = [[0,0],[0,1],[0,2],[1,2],[2,2],[2,1],[2,0],[1,0]]
# extract the specific feature from the image
if(self.ftype == 'lbp'):
fmap = self.lbp(coord, fmap_dimx, fmap_dimy, blk_int)
elif(self.ftype == 'tlbp'):
......@@ -44,14 +90,31 @@ class lbp_feature():
elif(self.ftype == 'mlbp'):
fmap = self.mlbp(coord, fmap_dimx, fmap_dimy, blk_int)
vec = np.reshape(fmap,fmap.shape[0]*fmap.shape[1],1)
fvec = np.hstack((fvec,vec))
# reshape feature image into vector
vec = numpy.reshape(fmap,fmap.shape[0]*fmap.shape[1],1)
# concatenate the vector
fvec = numpy.hstack((fvec,vec))
return fvec
def lbp(self, coord, fmap_dimx, fmap_dimy, blk_int):
"""Function to compute the LBP for a image at single scale.
The LBP features of the given image is computed and the feature map is returned
Inputs:
coord: The coordinates specify the neighbour to be considered.
fmap_dimx: feature map's dimension along the columns.
fmap_dimy: Feature maps dimension along the rows.
Return:
fmap: The lbp feature map
"""
num_neighbours = 8
blk_center = blk_int[1:1+fmap_dimy,1:1+fmap_dimx]
fmap = np.zeros([fmap_dimy, fmap_dimx])
fmap = numpy.zeros([fmap_dimy, fmap_dimx])
for ind in range(num_neighbours):
fmap = fmap + (2**ind)*(blk_int[coord[ind][0]:coord[ind][0] + fmap_dimy,coord[ind][1]:coord[ind][1] + fmap_dimx]>= blk_center)
return fmap
......@@ -59,7 +122,20 @@ class lbp_feature():
def tlbp(self, coord, fmap_dimx, fmap_dimy, blk_int):
fmap = np.zeros([fmap_dimy, fmap_dimx])
"""Function to compute the tLBP for a image at single scale.
The LBP features of the given image is computed and the feature map is returned
Inputs:
coord: The coordinates specify the neighbour to be considered.
fmap_dimx: feature map's dimension along the columns.
fmap_dimy: Feature maps dimension along the rows.
Return:
fmap: The lbp feature map
"""
fmap = numpy.zeros([fmap_dimy, fmap_dimx])
num_neighbour = 8
for ind in range(num_neighbours):
......@@ -70,9 +146,22 @@ class lbp_feature():
def dlbp(self, coord, fmap_dimx, fmap_dimy, blk_int):
"""Function to compute the dLBP for a image at single scale.
The LBP features of the given image is computed and the feature map is returned
Inputs:
coord: The coordinates specify the neighbour to be considered.
fmap_dimx: feature map's dimension along the columns.
fmap_dimy: Feature maps dimension along the rows.
Return:
fmap: The lbp feature map
"""
pc = blk_int[1:1+fmap_dimy,1:1+fmap_dimx]
num_neighbours = 8
fmap = np.zeros([fmap_dimy,fmap_dimx])
fmap = numpy.zeros([fmap_dimy,fmap_dimx])
for ind in range(num_neighbours/2):
pi = blk_int[coord[ind][0]:coord[ind][0]+ fmap_dimy,coord[ind][1]:coord[ind][1] + fmap_dimx]
pi4 = blk_int[coord[ind+4][0]:coord[ind+4][0]+ fmap_dimy,coord[ind+4][1]:coord[ind+4][1] + fmap_dimx]
......@@ -82,13 +171,26 @@ class lbp_feature():
def mlbp(self, coord, fmap_dimx, fmap_dimy, blk_int):
"""Function to compute the mLBP for a image at single scale.
The LBP features of the given image is computed and the feature map is returned
Inputs:
coord: The coordinates specify the neighbour to be considered.
fmap_dimx: feature map's dimension along the columns.
fmap_dimy: Feature maps dimension along the rows.
Return:
fmap: The lbp feature map
"""
num_neighbours = 8
pm = np.zeros([fmap_dimy,fmap_dimx])
pm = numpy.zeros([fmap_dimy,fmap_dimx])
for ind in range(num_neighbours):
pm = pm + blk_int[coord[ind][0]:coord[ind][0]+ fmap_dimy,coord[ind][1]:coord[ind][1] + fmap_dimx]
pm = pm/num_neighbours
fmap = np.zeros([fmap_dimy,fmap_dimx])
fmap = numpy.zeros([fmap_dimy,fmap_dimx])
for ind in range(num_neighbours):
pi = blk_int[coord[ind][0]:coord[ind][0]+ fmap_dimy,coord[ind][1]:coord[ind][1] + fmap_dimx]
fmap = fmap + (2**ind)*(pi >= pm)
......@@ -96,7 +198,19 @@ class lbp_feature():
def get_feature_number(self, dimy, dimx, scale_y, scale_x):
img = np.zeros([dimy, dimx])
"""The function gives the feature size for given size of image and scales
The number of features for the given parameters are computed
Inputs:
dimy: Number of rows of the image
dimx: Number of columns of the image
scale_y: The maximum block size along the rows
scale_x: The maximum block size along the columns.
Return:
The total number of features obtained for these parameters."""
img = numpy.zeros([dimy, dimx])
feature_vector = self.get_features(img, scale_y, scale_x)
return feature_vector.shape[0]
......
......@@ -52,6 +52,9 @@ def main():
label_train[label_train == digit2] = -1
label_test[label_test == digit2] = -1
print label_train.shape
print label_test.shape
# Initilize the trainer with 'LutTrainer' or 'StumpTrainer'
boost_trainer = boosting.Boost(args.trainer_type)
......
......@@ -15,8 +15,8 @@ import numpy
import sys, getopt
import argparse
import string
from xbob.boosting import boosting
from xbob.boosting import local_feature
from ..core import boosting
from ..features import local_feature
import xbob.db.mnist
def main():
......@@ -27,7 +27,7 @@ def main():
parser.add_argument('-l', default = 'exp', dest = "loss_type", type= str, choices = {'log','exp'}, help = "The type of the loss function. Logit and Exponential functions are the avaliable options")
parser.add_argument('-s', default = 'indep', dest = "selection_type", choices = {'indep', 'shared'}, type = str, help = "The feature selection type for the LUT based trainer. For multivarite case the features can be selected by sharing or independently ")
parser.add_argument('-n', default = 256, dest = "num_entries", type = int, help = "The number of entries in the LookUp table. It is the range of the feature values, e.g. if LBP features are used this values is 256.")
parser.add_argument('-f', default = 'lbp', dest = "feature_type", type = str, choices = {'lbp','dlbp','tlbp','mlbp'}, help = "The type of block based feature to be extracted from the images.")
args = parser.parse_args()
# Initializations
......@@ -59,7 +59,7 @@ def main():
# Extract the local features from the images
feature_extractor = local_feature.lbp_feature('lbp')
feature_extractor = local_feature.lbp_feature(args.feature_type)
scale_y = 4
scale_x = 4
num_fea = feature_extractor.get_feature_number(img_size,img_size,scale_y, scale_x)
......@@ -75,7 +75,7 @@ def main():
# Initilize the trainer with 'LutTrainer' or 'StumpTrainer'
boost_trainer = booster.Boost(args.trainer_type)
boost_trainer = boosting.Boost(args.trainer_type)
# Set the parameters for the boosting
boost_trainer.num_rnds = args.num_rnds
......
......@@ -22,7 +22,6 @@ import matplotlib.pyplot as mpl
def main():
parser = argparse.ArgumentParser(description = " The arguments for the boosting. ")
parser.add_argument('-t', default = 'LutTrainer',dest = "trainer_type", type = str, choices = {'StumpTrainer', 'LutTrainer'}, help = "This is the type of trainer used for the boosting." )
parser.add_argument('-r', default = 20, dest = "num_rnds", type = int, help = "The number of round for the boosting")
parser.add_argument('-l', default = 'exp', dest = "loss_type", type= str, choices = {'log','exp'}, help = "The type of the loss function. Logit and Exponential functions are the avaliable options")
parser.add_argument('-s', default = 'indep', dest = "selection_type", choices = {'indep', 'shared'}, type = str, help = "The feature selection type for the LUT based trainer. For multivarite case the features can be selected by sharing or independently ")
......@@ -55,7 +54,7 @@ def main():
# Initilize the trainer with 'LutTrainer' or 'StumpTrainer'
boost_trainer = boosting.Boost(args.trainer_type)
boost_trainer = boosting.Boost('LutTrainer')
# Set the parameters for the boosting
boost_trainer.num_rnds = args.num_rnds
......
#!/usr/bin/env python
"""The test script to perform the binary classification on the digits from the MNIST dataset.
The MNIST data is exported using the xbob.db.mnist module which provide the train and test
partitions for the digits. Block based LBP type (LBP, tLBP, mLBP) features are captured and the
available algorithms for classification is Lut based Boosting.
"""
import xbob.db.mnist
import numpy
import sys, getopt
import argparse
import string
from ..features import local_feature
from ..core import boosting
import matplotlib.pyplot
def main():
parser = argparse.ArgumentParser(description = " The arguments for the boosting. ")
parser.add_argument('-r', default = 20, dest = "num_rnds", type = int, help = "The number of round for the boosting")
parser.add_argument('-l', default = 'exp', dest = "loss_type", type= str, choices = {'log','exp'}, help = "The type of the loss function. Logit and Exponential functions are the avaliable options")
parser.add_argument('-s', default = 'indep', dest = "selection_type", choices = {'indep', 'shared'}, type = str, help = "The feature selection type for the LUT based trainer. For multivarite case the features can be selected by sharing or independently ")
parser.add_argument('-n', default = 256, dest = "num_entries", type = int, help = "The number of entries in the LookUp table. It is the range of the feature values, e.g. if LBP features are used this values is 256.")
parser.add_argument('-f', default = 'lbp', dest = "feature_type", type = str, choices = {'lbp', 'mlbp', 'tlbp', 'dlbp'}, help = "The type of LBP features to be extracted from the image to perform the classification. The features are extracted from the block of varying scales")
parser.add_argument('-sy', default = 4, dest = "scale_y", type = int, help = "The maximum scale for the block feature extraction along the y direction.")
parser.add_argument('-sx', default = 4, dest = "scale_x", type = int, help = "The maximum scale for the block feature extraction along the x direction.")
args = parser.parse_args()
# download the dataset
db_object = xbob.db.mnist.Database()
# Hardcode the number of digits and the image size
num_digits = 10
img_size = 28
# get the data (features and labels) for the selected digits from the xbob_db_mnist class functions
img_train, label_train = db_object.data('train',labels = range(num_digits))
img_test, label_test = db_object.data('test', labels = range(num_digits))
# Format the label data into int and change the class labels to -1 and +1
label_train = label_train.astype(int)
label_test = label_test.astype(int)
# initialize the label data for multivariate case
train_targets = -numpy.ones([img_train.shape[0],num_digits])
test_targets = -numpy.ones([img_test.shape[0],num_digits])
for i in range(num_digits):
train_targets[label_train == i,i] = 1
test_targets[label_test == i,i] = 1
# Extract the local features from the images
feature_extractor = local_feature.lbp_feature(args.feature_type)
scale_y = args.scale_y
scale_x = args.scale_x
num_fea = feature_extractor.get_feature_number(img_size,img_size,scale_y, scale_x)
train_fea = numpy.zeros([img_train.shape[0], num_fea],dtype = 'uint8')
test_fea = numpy.zeros([img_test.shape[0], num_fea], dtype = 'uint8')
for img_num in range(img_train.shape[0]):
img = img_train[img_num,:].reshape([img_size,img_size])
train_fea[img_num,:] = feature_extractor.get_features(img, scale_y, scale_x)
for img_num in range(img_test.shape[0]):
img = img_test[img_num,:].reshape([img_size,img_size])
test_fea[img_num,:] = feature_extractor.get_features(img, scale_y, scale_x)
# Initilize the trainer with LutTrainer
boost_trainer = boosting.Boost('LutTrainer')
# Set the parameters for the boosting
boost_trainer.num_rnds = args.num_rnds
boost_trainer.loss_type = args.loss_type
boost_trainer.selection_type = args.selection_type
boost_trainer.num_entries = args.num_entries
print "Starting boosting the features"
print train_fea.shape
# Perform boosting of the feature set samp
machine = boost_trainer.train(train_fea, train_targets)
# Classify the test samples (testsamp) using the boosited classifier generated above
prediction_labels = machine.classify(test_fea)
# Calulate the values for confusion matrix
score = numpy.zeros([10,10])
for i in range(num_digits):
prediction_i = prediction_labels[test_targets[:,i] == 1,:]
print prediction_i.shape
for j in range(num_digits):
score[i,j] = sum(prediction_i[:,j] == 1)
numpy.savetxt('conf_mat.out', score, delimiter=',')
cm = score/numpy.sum(score,1)
res = matplotlib.pyplot.imshow(cm, cmap=matplotlib.pyplot.cm.summer, interpolation='nearest')
for x in numpy.arange(cm.shape[0]):
for y in numpy.arange(cm.shape[1]):
col = 'white'
if cm[x,y] > 0.5: col = 'black'
matplotlib.pyplot.annotate('%.2f' % (100*cm[x,y],), xy=(y,x), color=col,
fontsize=8, horizontalalignment='center', verticalalignment='center')
classes = [str(k) for k in range(10)]
matplotlib.pyplot.xticks(numpy.arange(10), classes)
matplotlib.pyplot.yticks(numpy.arange(10), classes, rotation=90)
matplotlib.pyplot.ylabel("(Your prediction)")
matplotlib.pyplot.xlabel("(Real class)")
matplotlib.pyplot.title("Confusion Matrix (%s set) - in %%" % set_name)
matplotlib.pyplot.show()
# Calculate the accuracy in percentage for the curent classificaiton test
accuracy = 100*float(sum(numpy.sum(prediction_labels == test_targets,1) == num_digits))/float(prediction_labels.shape[0])
print "The average accuracy of classification is %f " % (accuracy)
if __name__ == "__main__":
main()
#!/usr/bin/env python
"""The test script to perform the binary classification on the digits from the MNIST dataset.
"""The test script to perform the multivariate classification on the digits from the MNIST dataset.
The MNIST data is exported using the xbob.db.mnist module which provide the train and test
partitions for the digits. Pixel values of grey scale images are used as features and the
available algorithms for classification are Lut based Boosting and Stump based Boosting.
The script test digits provided by the command line. Thus it conducts only one binary classifcation test.
partitions for the digits. LBP features are extracted and the available algorithms for
classification is Lut based Boosting.
"""
......@@ -15,9 +13,11 @@ import numpy
import sys, getopt
import argparse
import string
import bob
from ..util import confusion
from ..features import local_feature
from ..core import boosting
import matplotlib.pyplot as mpl
import matplotlib.pyplot
def main():
......@@ -27,100 +27,87 @@ def main():
parser.add_argument('-l', default = 'exp', dest = "loss_type", type= str, choices = {'log','exp'}, help = "The type of the loss function. Logit and Exponential functions are the avaliable options")
parser.add_argument('-s', default = 'indep', dest = "selection_type", choices = {'indep', 'shared'}, type = str, help = "The feature selection type for the LUT based trainer. For multivarite case the features can be selected by sharing or independently ")
parser.add_argument('-n', default = 256, dest = "num_entries", type = int, help = "The number of entries in the LookUp table. It is the range of the feature values, e.g. if LBP features are used this values is 256.")
parser.add_argument('-f', default = 'lbp', dest = "feature_type", type = str, choices = {'lbp', 'mlbp', 'tlbp', 'dlbp'}, help = "The type of LBP features to be extracted from the image to perform the classification. The features are extracted from the block of varying scales")
parser.add_argument('-d', default = 10, dest = "num_digits", type = int, help = "The number of digits to be considered for classification.")
args = parser.parse_args()
# download the dataset
db_object = xbob.db.mnist.Database()
# Hardcode the number of digits and the image size
num_digits = 10
num_digits = args.num_digits
img_size = 28
# get the data (features and labels) for the selected digits from the xbob_db_mnist class functions
img_train, label_train = db_object.data('train',labels = range(num_digits))
img_test, label_test = db_object.data('test', labels = range(num_digits))
train_img, label_train = db_object.data('train',labels = range(num_digits))
test_img, label_test = db_object.data('test', labels = range(num_digits))
# Format the label data into int and change the class labels to -1 and +1
label_train = label_train.astype(int)
label_test = label_test.astype(int)
# initialize the label data for multivariate case
train_targets = -numpy.ones([img_train.shape[0],num_digits])