Package pycv :: Package cs :: Package ml :: Package cla :: Package boost :: Module boosting
[hide private]
[frames] | no frames]

Source Code for Module pycv.cs.ml.cla.boost.boosting

  1  # PyCV - A Computer Vision Package for Python Incorporating Fast Training of Face Detection 
  2   
  3  # Copyright 2007 Nanyang Technological University, Singapore. 
  4  # Authors: Minh-Tri Pham, Viet-Dung D. Hoang, and Tat-Jen Cham. 
  5   
  6  # This file is part of PyCV. 
  7   
  8  # PyCV is free software: you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public  
 10  # License as published by the Free Software Foundation, either version  
 11  # 3 of the License, or (at your option) any later version. 
 12   
 13  # PyCV is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17   
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 20   
 21  # --------------------------------------------------------------------- 
 22  #!/usr/bin/env python 
 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  # Boosted Classifiers 
 38  #------------------------------------------------------------------------------- 
 39   
40 -class DiscreteBoostedClassifier(AdditiveClassifier):
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
69 - def current_score(self, input_point, *args, **kwds):
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 #return where(p,self.c,-self.c).sum() 73 return (self.c*(p*2-1)).sum()+self.b
74
75 - def score(self, input_point, *args, **kwds):
76 return self.preceeding_score(input_point, *args, **kwds) + \ 77 self.current_score(input_point, *args, **kwds)
78 score.__doc__ = AdditiveClassifier.score.__doc__ 79
80 - def refine(self):
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
94 - def normalize_c(self):
95 self.c /= self.c.sum()
96 97
98 -class OnlineDiscreteBoostedClassifier(DiscreteBoostedClassifier, \ 99 OnlineLearningInterface):
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 # total weights 134 if polarity_balancing == 1: # Pham-Cham (CVPR'07 oral) 135 self.g = zeros(M) # gamma 136 self.v = ones((M,2,2)) # Pham-Cham's v 137 elif polarity_balancing == 0: # Oza-Rusell (ICSMC'05) 138 self.v = ones((M,2)) # Oza-Rusell's lambda 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 # compute k_m 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 # update weights to deal with k_m 185 k3 = sqrt(kk[m]) 186 if j != 0: # positive 187 w = v*k3 188 else: 189 w = v/k3 190 191 # update weak classifier 192 self.weaks[m].learn(input_point,j,w) 193 194 # rerun 195 j2 = self.weaks[m].predict(input_point, *args, **kwds) 196 197 # propagate the weights 198 if self.polarity_balancing == 1: # Pham-Cham 199 self.v[m,j,j2] += v 200 a[m] = self.v[m,1].sum() / self.v[m].sum() 201 if j2 > 0: # predicted as positive 202 v *= a[m] * 0.5 * self.tw / self.v[m,j,j2] 203 else: # predicted as negative 204 v *= (1-a[m]) * 0.5 * self.tw / self.v[m,j,j2] 205 else: # Oza-Rusell 206 j3 = int(j == j2) 207 self.v[m,j3] += v 208 v *= 0.5 * self.tw / self.v[m,j3] 209 210 # update other parameters 211 if self.polarity_balancing == 1: # Pham-Cham 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: # Oza-Rusell 216 e[m] = self.v[m,0] / self.v[m].sum() 217 self.c[m] = 0.5 * log((1-e[m])/e[m])
218