1
2
3
4
5
6
7
8
9 """Wrap the libsvm package into a very simple class interface."""
10
11 __docformat__ = 'restructuredtext'
12
13 import numpy as N
14
15 import operator
16
17 from mvpa.base import warning
18 from mvpa.misc.state import StateVariable
19
20 from mvpa.clfs._svmbase import _SVM
21
22 from mvpa.clfs.libsvmc import _svm as svm
23 from sens import LinearSVMWeights
24
25 if __debug__:
26 from mvpa.base import debug
27
28
29
30 from mvpa.clfs.libsvmc._svmc import \
31 C_SVC, NU_SVC, EPSILON_SVR, \
32 NU_SVR, LINEAR, POLY, RBF, SIGMOID, \
33 PRECOMPUTED, ONE_CLASS
34
35
37 """Support Vector Machine Classifier.
38
39 This is a simple interface to the libSVM package.
40 """
41
42
43
44 probabilities = StateVariable(enabled=False,
45 doc="Estimates of samples probabilities as provided by LibSVM")
46
47 _KERNELS = { "linear": (svm.svmc.LINEAR, None, LinearSVMWeights),
48 "rbf" : (svm.svmc.RBF, ('gamma',), None),
49 "poly": (svm.svmc.POLY, ('gamma', 'degree', 'coef0'), None),
50 "sigmoid": (svm.svmc.SIGMOID, ('gamma', 'coef0'), None),
51 }
52
53
54
55 _KNOWN_PARAMS = [ 'epsilon', 'probability', 'shrinking',
56 'weight_label', 'weight']
57
58 _KNOWN_KERNEL_PARAMS = [ 'cache_size' ]
59
60 _KNOWN_IMPLEMENTATIONS = {
61 'C_SVC' : (svm.svmc.C_SVC, ('C',),
62 ('binary', 'multiclass'), 'C-SVM classification'),
63 'NU_SVC' : (svm.svmc.NU_SVC, ('nu',),
64 ('binary', 'multiclass'), 'nu-SVM classification'),
65 'ONE_CLASS' : (svm.svmc.ONE_CLASS, (),
66 ('oneclass',), 'one-class-SVM'),
67 'EPSILON_SVR' : (svm.svmc.EPSILON_SVR, ('C', 'tube_epsilon'),
68 ('regression',), 'epsilon-SVM regression'),
69 'NU_SVR' : (svm.svmc.NU_SVR, ('nu', 'tube_epsilon'),
70 ('regression',), 'nu-SVM regression')
71 }
72
73 _clf_internals = _SVM._clf_internals + [ 'libsvm' ]
74
75 - def __init__(self,
76 kernel_type='linear',
77 **kwargs):
78
79
80
81
82 """Interface class to LIBSVM classifiers and regressions.
83
84 Default implementation (C/nu/epsilon SVM) is chosen depending
85 on the given parameters (C/nu/tube_epsilon).
86 """
87
88 svm_impl = kwargs.get('svm_impl', None)
89
90
91 if svm_impl is None:
92 for arg, impl in [ ('tube_epsilon', 'EPSILON_SVR'),
93 ('C', 'C_SVC'),
94 ('nu', 'NU_SVC') ]:
95 if kwargs.has_key(arg):
96 svm_impl = impl
97 if __debug__:
98 debug('SVM', 'No implementation was specified. Since '
99 '%s is given among arguments, assume %s' %
100 (arg, impl))
101 break
102 if svm_impl is None:
103 svm_impl = 'C_SVC'
104 if __debug__:
105 debug('SVM', 'Assign C_SVC "by default"')
106 kwargs['svm_impl'] = svm_impl
107
108
109 _SVM.__init__(self, kernel_type, **kwargs)
110
111 self._svm_type = self._KNOWN_IMPLEMENTATIONS[svm_impl][0]
112
113 if 'nu' in self._KNOWN_PARAMS and 'epsilon' in self._KNOWN_PARAMS:
114
115
116 self.params['epsilon'].setDefault(0.001)
117
118 self.__model = None
119 """Holds the trained SVM."""
120
121
122
124 """Train SVM
125 """
126
127 if dataset.samples.dtype == 'float64':
128 src = dataset.samples
129 else:
130 src = dataset.samples.astype('double')
131
132 svmprob = svm.SVMProblem( dataset.labels.tolist(), src )
133
134
135 TRANSLATEDICT = {'epsilon': 'eps',
136 'tube_epsilon': 'p'}
137 args = []
138 for paramname, param in self.params.items.items() \
139 + self.kernel_params.items.items():
140 if paramname in TRANSLATEDICT:
141 argname = TRANSLATEDICT[paramname]
142 elif paramname in svm.SVMParameter.default_parameters:
143 argname = paramname
144 else:
145 if __debug__:
146 debug("SVM_", "Skipping parameter %s since it is not known"
147 "to libsvm" % paramname)
148 continue
149 args.append( (argname, param.value) )
150
151
152
153
154 libsvm_param = svm.SVMParameter(
155 kernel_type=self._kernel_type,
156 svm_type=self._svm_type,
157 **dict(args))
158 """Store SVM parameters in libSVM compatible format."""
159
160 if self.params.isKnown('C'):
161 C = self.params.C
162 if not operator.isSequenceType(C):
163
164 C = [C]
165
166 Cs = list(C[:])
167 for i in xrange(len(Cs)):
168 if Cs[i] < 0:
169 Cs[i] = self._getDefaultC(dataset.samples)*abs(Cs[i])
170 if __debug__:
171 debug("SVM", "Default C for %s was computed to be %s" %
172 (C[i], Cs[i]))
173
174 libsvm_param._setParameter('C', Cs[0])
175
176 if len(Cs)>1:
177 C0 = abs(C[0])
178 scale = 1.0/(C0)
179
180 if len(Cs) != len(dataset.uniquelabels):
181 raise ValueError, "SVM was parametrized with %d Cs but " \
182 "there are %d labels in the dataset" % \
183 (len(Cs), len(dataset.uniquelabels))
184 weight = [ c*scale for c in Cs ]
185 libsvm_param._setParameter('weight', weight)
186
187 self.__model = svm.SVMModel(svmprob, libsvm_param)
188
189
245
246
248 """Provide quick summary over the SVM classifier"""
249 s = super(SVM, self).summary()
250 if self.trained:
251 s += '\n # of SVs: %d' % self.__model.getTotalNSV()
252 try:
253 prm = svm.svmc.svm_model_param_get(self.__model.model)
254 C = svm.svmc.svm_parameter_C_get(prm)
255
256
257 inside_margin = N.sum(
258
259 N.abs(self.__model.getSVCoef())
260 >= 0.99*svm.svmc.svm_parameter_C_get(prm))
261 s += ' #bounded SVs:%d' % inside_margin
262 s += ' used C:%5g' % C
263 except:
264 pass
265 return s
266
267
269 """Untrain libsvm's SVM: forget the model
270 """
271 if __debug__:
272 debug("SVM", "Untraining %s and destroying libsvm model" % self)
273 super(SVM, self).untrain()
274 del self.__model
275 self.__model = None
276
277 model = property(fget=lambda self: self.__model)
278 """Access to the SVM model."""
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351 try:
352
353 if __debug__ and "LIBSVM" in debug.active:
354 debug("LIBSVM", "Setting verbosity for libsvm to 255")
355 svm.svmc.svm_set_verbosity(255)
356 else:
357 svm.svmc.svm_set_verbosity(0)
358 except AttributeError:
359 warning("Available LIBSVM has no way to control verbosity of the output")
360
361
362 LinearSVMWeights._LEGAL_CLFS = [SVM]
363