svm_struct.py 3.27 KB
Newer Older
1
2
3
#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
4
5
6
7
# This is an example illustrating the use of the structural SVM solver from the dlib C++
# Library.  This example will briefly introduce it and then walk through an example showing
# how to use it to create a simple multi-class classifier.  
#
8
9
10
11
12
13
14
15
16
17
18
19
20
#
# COMPILING THE DLIB PYTHON INTERFACE
#   Dlib comes with a compiled python interface for python 2.7 on MS Windows.  If
#   you are using another python version or operating system then you need to
#   compile the dlib python interface before you can use this file.  To do this,
#   run compile_dlib_python_module.bat.  This should work on any operating system
#   so long as you have CMake and boost-python installed.  On Ubuntu, this can be
#   done easily by running the command:  sudo apt-get install libboost-python-dev cmake


import dlib

def dot(a, b):
21
    "Compute the dot product between the two vectors a and b."
22
23
24
25
26
27
28
29
    return sum(i*j for i,j in zip(a,b))


class three_class_classifier_problem:
    C = 10
    be_verbose = True
    epsilon = 0.0001 

30

31
32
33
34
35
36
    def __init__(self, samples, labels):
        self.num_samples = len(samples)
        self.num_dimensions = len(samples[0])*3
        self.samples = samples
        self.labels = labels

37
38
39

    def make_psi(self, vector, label):
        psi = dlib.vector()
40
41
        psi.resize(self.num_dimensions)
        dims = len(vector)
42
        if (label == 0):
43
44
            for i in range(0,dims):
                psi[i] = vector[i]
45
        elif (label == 1):
46
47
            for i in range(dims,2*dims):
                psi[i] = vector[i-dims]
48
        else: # the label must be 2
49
50
            for i in range(2*dims,3*dims):
                psi[i] = vector[i-2*dims]
51
52
        return psi

53

54
55
    def get_truth_joint_feature_vector(self, idx):
        return self.make_psi(self.samples[idx], self.labels[idx])
56
57


58
    def separation_oracle(self, idx, current_solution):
59
60
61
62
63
64
65
66
67
        samp = samples[idx]
        dims = len(samp)
        scores = [0,0,0]
        # compute scores for each of the three classifiers
        scores[0] = dot(current_solution[0:dims], samp)
        scores[1] = dot(current_solution[dims:2*dims], samp)
        scores[2] = dot(current_solution[2*dims:3*dims], samp)

        # Add in the loss-augmentation
68
        if (labels[idx] != 0): 
69
            scores[0] += 1
70
        if (labels[idx] != 1): 
71
            scores[1] += 1
72
        if (labels[idx] != 2): 
73
74
75
            scores[2] += 1

        # Now figure out which classifier has the largest loss-augmented score.
76
        max_scoring_label = scores.index(max(scores))
77
78
79
80
81
        if (max_scoring_label == labels[idx]):
            loss = 0
        else:
            loss = 1

82
        psi = self.make_psi(samp, max_scoring_label)
83

84
        return loss,psi
85
86
87



88
89
samples = [[0,0,1], [0,1,0], [1,0,0]];
labels =  [0,1,2]
90
91
92
93
94

problem = three_class_classifier_problem(samples, labels)
weights = dlib.solve_structural_svm_problem(problem)
print weights

Davis King's avatar
Davis King committed
95
96
97
98
99
100
101
102
w1 = weights[0:3]
w2 = weights[3:6]
w3 = weights[6:9]

print "scores for class 1 sample: ", dot(w1, samples[0]), dot(w2,samples[0]), dot(w3, samples[0])
print "scores for class 2 sample: ", dot(w1, samples[1]), dot(w2,samples[1]), dot(w3, samples[1])
print "scores for class 3 sample: ", dot(w1, samples[2]), dot(w2,samples[2]), dot(w3, samples[2])