1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 __all__ = ['DiscreteBoostedClassifier', 'OnlineDiscreteBoostedClassifier']
26
27 from math import log, exp, sqrt
28 from numpy import array, where, zeros, ones, dot, prod
29 from numpy import exp as NP_exp
30 from numpy import log as NP_log
31 from numpy import sqrt as NP_sqrt
32
33 from pycv.cs.ml.cla import AdditiveClassifier
34 from pycv.cs.ml import OnlineLearningInterface
35
36
37
38
39
41 """Discrete Boosted Classifier of this form:
42 F_M(x) = preceeding_classifier(x) + \sum_{m=1}^M c_m f_m(x) + b,
43 where
44 c_m: coefficient, >= 0
45 f_m(x): a binary classifier outputing {-1,1}
46 b: shifting amount, default is 0
47 """
48
49 - def __init__(self, sc=None, weaks=[], c=array([],'d'), b=0):
50 """Initialize the DiscreteBoostedClassifier with some parameters.
51
52 :Parameters:
53 sc : ScoringClassifier
54 a ScoringClassifier to preceed this classifier,
55 or None if there's no classifier to preceed
56 weaks : list
57 list of weak classifiers trained
58 c : numpy.array of real values
59 array of coefficients for weak classifiers
60 b : double
61 threshold of the classifier
62 """
63 AdditiveClassifier.__init__(self, sc)
64 self.M = len(weaks)
65 self.weaks = weaks
66 self.c = array(c)
67 self.b = b
68
70 """Return the score of the classifier before being aggregated."""
71 p = array([w.predict(input_point, *args, **kwds) for w in self.weaks])
72
73 return (self.c*(p*2-1)).sum()+self.b
74
75 - def score(self, input_point, *args, **kwds):
78 score.__doc__ = AdditiveClassifier.score.__doc__
79
81 """Refine the classifier.
82
83 Refine the classifier by throwing away weak classifiers with zero
84 coefficients.
85
86 Returns the filtering array so superclass(es) can filter their data.
87 """
88 filterarray = (self.c >= 1.0e-10)
89 self.c = self.c[filterarray]
90 self.weaks = [self.weaks[m] for m in xrange(len(self.weaks)) if filterarray[m]]
91 self.M = len(self.weaks)
92 return filterarray
93
95 self.c /= self.c.sum()
96
97
100 """DiscreteBoostedClassifier with an ability to learn online."""
101
102 - def __init__(self, sc=None, weaks=[], c=array([],'d'), k=1.0, \
103 skewness_balancing=0, polarity_balancing=1):
104 """Initialize the OnlineDiscreteBoostedClassifier with some parameters
105
106 :Parameters:
107 sc : ScoringClassifier
108 a ScoringClassifier to preceed this classifier,
109 or None if there's no classifier to preceed
110 weaks : list
111 list of weak classifiers trained
112 c : numpy.array of real values
113 array of coefficients for weak classifiers
114 k : double
115 false negatives penalized k times more than false positives
116 skewness_balancing : int
117 type of skewness balancing among weak classifiers
118 0 = no balancing at all, this is the original AdaBoost's
119 method
120 1 = asymmetric weight balancing, Viola-Jones (NIPS'02)
121 2 = skewness balancing, Pham-Cham (CVPR'07)
122 polarity_balancing : int
123 use polarity balancing?
124 0 = no polarity balancing, same as Oza-Rusell (ICSMC'05)
125 1 = polarity balancing, Pham-Cham (CVPR'07)
126 """
127 DiscreteBoostedClassifier.__init__(self, sc=sc, weaks=weaks, c=c, b=0)
128 M = len(weaks)
129 self.M = M
130 self.k = k
131 self.skewness_balancing = skewness_balancing
132 self.polarity_balancing = polarity_balancing
133 self.tw = 0
134 if polarity_balancing == 1:
135 self.g = zeros(M)
136 self.v = ones((M,2,2))
137 elif polarity_balancing == 0:
138 self.v = ones((M,2))
139 else:
140 raise IndexError('Out of bound is the value of polarity_balancing')
141
142 - def learn( self, input_point, j, weight = None, *args, **kwds):
143 """Learn incrementally
144
145 Learn incrementally with a new input point, its class, and optionally
146 its weight. Other parameters like k and balancing are derived from
147 the class itself.
148
149 TODO: Re-test this function extensively.
150
151 Input:
152 input_point: a new input point
153 j: its corresponding class
154 w: optionally its weight, or 1 if not specified
155 polaritybalancing: use polarity balancing?
156 0 = no polarity balancing, same as Oza-Rusell (ICSMC'05)
157 1 = polarity balancing, Pham-Cham (CVPR'07)
158 """
159 M = self.M
160 a = zeros(M)
161 e = zeros(M)
162 kk = zeros(M)
163 if self.skewness_balancing == 1:
164 k2 = exp(log(self.k)/self.M)
165 elif self.skewness_balancing == 2:
166 logk = log(self.k)
167
168 v = 1.0 if weight is None else weight
169 self.tw += v
170
171 for m in xrange(self.M):
172
173 if self.skewness_balancing == 0:
174 if m == 0:
175 kk[m] = self.k
176 else:
177 kk[m] = 1.0
178 elif self.skewness_balancing == 1:
179 kk[m] = k2
180 elif self.skewness_balancing == 2:
181 log_k_m = (logk-NP_log(kk[:m]).sum() + (M-m-1)*self.g[m]) / (M-m)
182 kk[m] = exp(log_k_m)
183
184
185 k3 = sqrt(kk[m])
186 if j != 0:
187 w = v*k3
188 else:
189 w = v/k3
190
191
192 self.weaks[m].learn(input_point,j,w)
193
194
195 j2 = self.weaks[m].predict(input_point, *args, **kwds)
196
197
198 if self.polarity_balancing == 1:
199 self.v[m,j,j2] += v
200 a[m] = self.v[m,1].sum() / self.v[m].sum()
201 if j2 > 0:
202 v *= a[m] * 0.5 * self.tw / self.v[m,j,j2]
203 else:
204 v *= (1-a[m]) * 0.5 * self.tw / self.v[m,j,j2]
205 else:
206 j3 = int(j == j2)
207 self.v[m,j3] += v
208 v *= 0.5 * self.tw / self.v[m,j3]
209
210
211 if self.polarity_balancing == 1:
212 self.g[m] = log((1-a[m])/a[m])
213 e[m] = (self.v[m,0,1]/k3 + self.v[m,1,0]*k3) / \
214 ((self.v[m,0].sum())/k3 + (self.v[m,1].sum())*k3)
215 else:
216 e[m] = self.v[m,0] / self.v[m].sum()
217 self.c[m] = 0.5 * log((1-e[m])/e[m])
218