ADDED: SVM-ARD kernel relevance determination
[mldemos:mldemos.git] / _AlgorithmsPlugins / KernelMethods / classifierSVM.cpp
1 /*********************************************************************\r
2 MLDemos: A User-Friendly visualization toolkit for machine learning\r
3 Copyright (C) 2010  Basilio Noris\r
4 Contact: mldemos@b4silio.com\r
5 \r
6 This library is free software; you can redistribute it and/or\r
7 modify it under the terms of the GNU Lesser General Public\r
8 License as published by the Free Software Foundation; either\r
9 version 2.1 of the License, or (at your option) any later version.\r
10 \r
11 This library is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
14 Library General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU Lesser General Public\r
17 License along with this library; if not, write to the Free\r
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
19 *********************************************************************/\r
20 #include <public.h>\r
21 #include "classifierSVM.h"\r
22 #include <nlopt/nlopt.hpp>\r
23 #include <QDebug>\r
24 #include <iostream>\r
25 #include <fstream>\r
26 \r
27 using namespace std;\r
28 \r
29 ClassifierSVM::ClassifierSVM()\r
30     : svm(0), node(0), x_space(0)\r
31 {\r
32     dim = 2;\r
33     bMultiClass = true;\r
34     classCount = 0;\r
35     // default values\r
36     param.svm_type = C_SVC;\r
37     //param.svm_type = EPSILON_SVR;\r
38     param.kernel_type = RBF;\r
39     param.gamma = 0.1;\r
40     param.C = 100;\r
41     param.nu = 0.1;\r
42     param.p = 0.3;\r
43 \r
44     param.degree = 1;\r
45     param.coef0 = 0;\r
46     param.shrinking = 1;\r
47     param.probability = 0;\r
48     param.eps = 1e-6;\r
49     param.cache_size = 400;\r
50     param.nr_weight = 0;\r
51     param.weight_label = NULL;\r
52     param.weight = NULL;\r
53     param.kernel_weight = NULL;\r
54     param.kernel_dim = 0;\r
55     param.kernel_norm = 1.;\r
56     param.normalizeKernel = false;\r
57 }\r
58 \r
59 ClassifierSVM::~ClassifierSVM()\r
60 {\r
61     DEL(node);\r
62     DEL(svm);\r
63     DEL(x_space);\r
64 }\r
65 \r
66 void ClassifierSVM::SetParams(int svmType, float svmC, u32 kernelType, float kernelParam)\r
67 {\r
68     // default values\r
69     param.svm_type = svmType;\r
70     param.C = svmC;\r
71     param.nu = svmC;\r
72     param.eps = 0.01;\r
73 \r
74     param.coef0 = 0;\r
75     param.gamma = 1;\r
76 \r
77     switch(kernelType)\r
78     {\r
79     case 0:\r
80         param.kernel_type = LINEAR;\r
81         param.degree = 1;\r
82         break;\r
83     case 1:\r
84         param.kernel_type = POLY;\r
85         param.degree = (u32)kernelParam;\r
86         break;\r
87     case 2:\r
88         param.kernel_type = RBF;\r
89         param.gamma = kernelParam;\r
90         break;\r
91     case 3:\r
92         param.kernel_type = SIGMOID;\r
93         param.gamma = kernelParam;\r
94         break;\r
95     }\r
96 }\r
97 \r
98 struct OptData\r
99 {\r
100     svm_model *svm;\r
101     svm_problem *problem;\r
102 };\r
103 \r
104 double getSVMObjectiveFunction(const svm_model *svm, const double *x, const svm_problem *problem)\r
105 {\r
106     svm_parameter param = svm->param;\r
107     switch(param.kernel_type)\r
108     {\r
109     case LINEAR:\r
110         return 0.;\r
111         break;\r
112     case POLY:\r
113         param.degree = x[0];\r
114         param.gamma = 1. / x[1];\r
115         param.coef0 = x[2];\r
116         break;\r
117     case RBF:\r
118         param.gamma = 1. / x[0];\r
119         break;\r
120     case SIGMOID:\r
121         param.coef0 = x[0];\r
122         break;\r
123     case RBFWEIGH:\r
124     {\r
125         param.gamma = 1. / x[0];\r
126         FOR(i, param.kernel_dim)\r
127         {\r
128             param.kernel_weight[i] = x[i+1];\r
129         }\r
130     }\r
131         break;\r
132     }\r
133     svm_model *newSVM = svm_train(problem, &param);\r
134     double value = svm_get_dual_objective_function(newSVM);\r
135     qDebug() << "value:" << value << "gamma:" << 1. / param.gamma;\r
136     delete newSVM;\r
137     return value;\r
138 }\r
139 \r
140 double svmObjectiveFunction(unsigned n, const double *x, double *gradient /* NULL if not needed */, void *func_data)\r
141 {\r
142     OptData *data = (OptData*)func_data;\r
143 \r
144     double objective = getSVMObjectiveFunction(data->svm, x, data->problem);\r
145     if(gradient)\r
146     {\r
147         double *dx = new double[n];\r
148         double delta = 1e-2;\r
149         FOR(i, n)\r
150         {\r
151             memcpy(dx, x, n*sizeof(double));\r
152             dx[i] += delta;\r
153             double dError = getSVMObjectiveFunction(data->svm, dx, data->problem);\r
154             gradient[i] = (dError - objective)/delta;\r
155         }\r
156         delete [] dx;\r
157     }\r
158 \r
159     return objective;\r
160 }\r
161 \r
162 void ClassifierSVM::Optimize(svm_problem *problem)\r
163 {\r
164     OptData *data = new OptData;\r
165     data->svm = svm;\r
166     data->problem = problem;\r
167 \r
168     int optDim = 1;\r
169     switch(svm->param.kernel_type)\r
170     {\r
171     case POLY:\r
172         optDim = 3;\r
173         break;\r
174     case RBF:\r
175         optDim = 1;\r
176         break;\r
177     case RBFWEIGH:\r
178         optDim = dim + 1;\r
179         break;\r
180     }\r
181 \r
182     //nlopt::opt opt(nlopt::LN_AUGLAG, optDim);\r
183     nlopt::opt opt(nlopt::LN_COBYLA, optDim);\r
184     //nlopt::opt opt(nlopt::LN_NELDERMEAD, optDim);\r
185     //nlopt::opt opt(nlopt::LN_NEWUOA, optDim);\r
186     //nlopt::opt opt(nlopt::LN_PRAXIS, optDim);\r
187     //nlopt::opt opt(nlopt::LN_BOBYQA, optDim);\r
188     //nlopt::opt opt(nlopt::LN_SBPLX, optDim);\r
189 \r
190     opt.set_max_objective(svmObjectiveFunction, (void*)data);\r
191 \r
192     opt.set_maxeval(100);\r
193     vector<double> lowerBounds(optDim, 0.001);\r
194     opt.set_xtol_abs(0.001);\r
195 \r
196     vector<double> x(optDim), xOpt;\r
197 \r
198     vector<double> steps(optDim,0.1);\r
199     switch(svm->param.kernel_type)\r
200     {\r
201     case POLY:\r
202         x[0] = svm->param.degree;\r
203         x[1] = 1. / svm->param.gamma;\r
204         x[2] = svm->param.coef0;\r
205         steps[0] = 1;\r
206         lowerBounds[0] = 1;\r
207         break;\r
208     case RBF:\r
209         x[0] = 1. / svm->param.gamma;\r
210         break;\r
211     case SIGMOID:\r
212         x[0] = svm->param.coef0;\r
213         break;\r
214     case RBFWEIGH:\r
215     {\r
216         x[0] = 1. / svm->param.gamma;\r
217         FOR(i, svm->param.kernel_dim)\r
218         {\r
219             x[i+1] = svm->param.kernel_weight[i];\r
220         }\r
221     }\r
222         break;\r
223     }\r
224     opt.set_initial_step(steps);\r
225     opt.set_lower_bounds(lowerBounds);\r
226 \r
227     try\r
228     {\r
229         // do the actual optimization\r
230         xOpt = opt.optimize(x);\r
231         param = svm->param;\r
232         switch(param.kernel_type)\r
233         {\r
234         case POLY:\r
235             param.degree = xOpt[0];\r
236             param.gamma = 1. / xOpt[1];\r
237             param.coef0 = xOpt[2];\r
238             break;\r
239         case RBF:\r
240             param.gamma = 1. / xOpt[0];\r
241             break;\r
242         case SIGMOID:\r
243             param.coef0 = xOpt[0];\r
244             break;\r
245         case RBFWEIGH:\r
246         {\r
247             param.gamma = 1. / xOpt[0];\r
248             FOR(i, param.kernel_dim)\r
249             {\r
250                 param.kernel_weight[i] = xOpt[i+1];\r
251             }\r
252         }\r
253             break;\r
254         }\r
255         delete svm;\r
256         svm = svm_train(problem, &param);\r
257     }\r
258     catch(std::exception e)\r
259     {\r
260         qDebug() << "caught exception while optimizing";\r
261     }\r
262     delete data;\r
263 }\r
264 \r
265 double kernelFunction(svm_model *svm, int d)\r
266 {\r
267     // sum_i sum_j (a_i*a_j*y_i*y_j*k(x_i,x_j)*(x_i-x_j)*(x_i-x_j))\r
268     double accumulator = 0;\r
269     int nsv = svm->l;\r
270     int nclass = svm->nr_class-1;\r
271     for(int c=0; c<nclass; c++)\r
272     {\r
273         double *sv_coef = svm->sv_coef[c];\r
274         double sum = 0;\r
275         for(int i=0; i<nsv; i++)\r
276         {\r
277             for(int j=0; j<=i; j++)\r
278             {\r
279                 double diff = svm->SV[i][d].value-svm->SV[j][d].value;\r
280                 double value = -sv_coef[i] * sv_coef[j] * Kernel::k_function(svm->SV[i],svm->SV[j],svm->param) * diff * diff;\r
281                 sum += j==i ? value : 2*value;\r
282             }\r
283         }\r
284         // sum_i sum_j (a_i*a_j*y_i*y_j*k(x_i,x_j))\r
285         accumulator += 0.5*sum;\r
286     }\r
287     return 1. - accumulator;\r
288 }\r
289 \r
290 void ClassifierSVM::OptimizeGradient(svm_problem *problem)\r
291 {\r
292     if( param.kernel_type == LINEAR) return;\r
293     if( param.kernel_type == POLY) return Optimize(problem);\r
294     qDebug() << "optimizing kernel weights";\r
295 \r
296     double gamma = param.gamma;\r
297     if( param.kernel_type == RBF)\r
298     {\r
299         param.kernel_type = RBFWEIGH;\r
300         param.kernel_dim = dim;\r
301         param.kernel_weight = new double[dim];\r
302         FOR(d, dim) param.kernel_weight[d] = param.gamma;\r
303         param.gamma = 1;\r
304         svm->param = param;\r
305     }\r
306     //delete svm;\r
307     //svm = svm_train(problem, &param);\r
308 \r
309     // we begin by computing the kernel dimension\r
310     dvec sigmas(dim, gamma), newSigmas(dim, gamma);\r
311     dvec deltas(dim, 0);\r
312 \r
313     //double oldObj = svm_get_dual_objective_function(svm);\r
314     double oldObj = 0;\r
315     qDebug() << "Initial objective function" << oldObj;\r
316     double gammaStep = 5;\r
317     int iterations = 100;\r
318     bool bAllZeros = true;\r
319     FOR(it, iterations)\r
320     {\r
321         //QString s1, s2;\r
322         double norm=0;\r
323         FOR(d, dim)\r
324         {\r
325             double delta = kernelFunction(svm, d);\r
326             deltas[d] = delta;\r
327             //s1 += QString("%1 ").arg(delta);\r
328             norm += deltas[d]*deltas[d];\r
329         }\r
330         norm = sqrt(norm);\r
331         // find the step size\r
332         //gammaStep = 2;\r
333         double obj;\r
334 \r
335         int gammaIter = 10;\r
336         FOR(i, gammaIter)\r
337         {\r
338             QString s;\r
339             FOR(d, dim)\r
340             {\r
341                 //if(fabs(deltas[d]) <= 1e-4) continue;\r
342                 newSigmas[d] = sigmas[d] - deltas[d]*gammaStep;\r
343                 newSigmas[d] = max(0.,newSigmas[d]);\r
344                 s += QString("%1 ").arg(1./newSigmas[d],0,'f',3);\r
345             }\r
346             FOR(d, dim) param.kernel_weight[d] = newSigmas[d];\r
347             DEL(svm);\r
348             svm = svm_train(problem, &param);\r
349             obj = svm_get_dual_objective_function(svm);\r
350             qDebug() << "it" << it << i << "obj" << obj << "(" << oldObj << ")" << "gamma step" << gammaStep << "gamma" << s;\r
351             if(obj < oldObj)\r
352             {\r
353                 break;\r
354             }\r
355             gammaStep *= 0.5;\r
356         }\r
357         FOR(d, dim) sigmas[d] = newSigmas[d];\r
358         if(obj > oldObj)\r
359         {\r
360             DEL(svm);\r
361             FOR(d, dim) param.kernel_weight[d] = sigmas[d];\r
362             svm = svm_train(problem, &param);\r
363             break;\r
364         }\r
365 \r
366         //qDebug() << "iteration" << it << "norm" << norm;\r
367         //qDebug() << "\tobjective function" << obj;\r
368         //qDebug() << "\tdelta" << s1;\r
369         //qDebug() << "\tgamma" << s2;\r
370         if(fabs(oldObj-obj) < 1e-5) break;\r
371         oldObj = obj;\r
372     }\r
373 }\r
374 \r
375 void ClassifierSVM::Train(std::vector< fvec > samples, ivec labels)\r
376 {\r
377     svm_problem problem;\r
378 \r
379     dim = samples[0].size();\r
380     problem.l = samples.size();\r
381     problem.y = new double[problem.l];\r
382     problem.x = new svm_node *[problem.l];\r
383     KILL(x_space);\r
384     x_space = new svm_node[(dim +1)*problem.l];\r
385 \r
386     classMap.clear();\r
387     int cnt=0;\r
388     FOR(i, labels.size()) if(!classMap.count(labels[i])) classMap[labels[i]] = cnt++;\r
389     for(map<int,int>::iterator it=classMap.begin(); it != classMap.end(); it++) inverseMap[it->second] = it->first;\r
390     ivec newLabels(labels.size());\r
391     FOR(i, labels.size()) newLabels[i] = classMap[labels[i]];\r
392 \r
393     FOR(i, problem.l)\r
394     {\r
395         FOR(j, dim )\r
396         {\r
397             x_space[(dim +1)*i + j].index = j+1;\r
398             x_space[(dim +1)*i + j].value = samples[i][j];\r
399         }\r
400         x_space[(dim +1)*i + dim ].index = -1;\r
401         problem.x[i] = &x_space[(dim +1)*i];\r
402         problem.y[i] = newLabels[i];\r
403     }\r
404 \r
405     delete(svm);\r
406     DEL(node);\r
407     svm = svm_train(&problem, &param);\r
408 \r
409     if(bOptimize) OptimizeGradient(&problem);\r
410 \r
411     delete [] problem.x;\r
412     delete [] problem.y;\r
413 \r
414     int maxClass = 0;\r
415     FOR(j, newLabels.size()) maxClass = max(maxClass, newLabels[j]);\r
416 \r
417     classCount = svm->nr_class;\r
418     //classCount = maxClass;\r
419     FOR(i, classCount)\r
420     {\r
421         classes[i] = svm->label[i];\r
422         //qDebug() << "classes: " << i << classes[i];\r
423     }\r
424     //FOR(j, labels.size()) qDebug() << "label:" << j << labels[j];\r
425 \r
426 }\r
427 \r
428 float ClassifierSVM::Test( const fvec &sample )\r
429 {\r
430     int data_dimension = sample.size();\r
431     if(!svm) return 0;\r
432     float estimate;\r
433     if(!node) node = new svm_node[data_dimension+1];\r
434     FOR(i, data_dimension)\r
435     {\r
436         node[i].index = i+1;\r
437         node[i].value = sample[i];\r
438     }\r
439     node[data_dimension].index = -1;\r
440     estimate = (float)svm_predict(svm, node);\r
441     return estimate;\r
442 }\r
443 \r
444 float ClassifierSVM::Test( const fVec &sample )\r
445 {\r
446     int data_dimension = 2;\r
447     if(!svm) return 0;\r
448     float estimate;\r
449     if(!node)\r
450     {\r
451         node = new svm_node[data_dimension+1];\r
452         node[data_dimension].index = -1;\r
453     }\r
454     FOR(i, data_dimension)\r
455     {\r
456         node[i].index = i+1;\r
457         node[i].value = sample._[i];\r
458     }\r
459     estimate = (float)svm_predict(svm, node);\r
460     return estimate;\r
461 }\r
462 \r
463 fvec ClassifierSVM::TestMulti(const fvec &sample)\r
464 {\r
465     if(classCount == 2)\r
466     {\r
467         fvec res(1);\r
468         res[0] = Test(sample);\r
469         return res;\r
470     }\r
471     int maxClass = classCount;\r
472     FOR(i, classCount) maxClass = max(maxClass, classes[i]);\r
473     fvec resp(maxClass,0);\r
474     int data_dimension = sample.size();\r
475     if(!svm) return resp;\r
476     if(!node)\r
477     {\r
478         node = new svm_node[data_dimension+1];\r
479         node[data_dimension].index = -1;\r
480     }\r
481     FOR(i, data_dimension)\r
482     {\r
483         node[i].index = i+1;\r
484         node[i].value = sample[i];\r
485     }\r
486     double *decisions = new double[classCount];\r
487     svm_predict_votes(svm, node, decisions);\r
488     //int max = 0;\r
489     FOR(i, classCount)\r
490     {\r
491         resp[classes[i]] = decisions[i];\r
492         //if(resp[max] < resp[classes[i]]) max = i;\r
493     }\r
494     //resp[max] += classCount;\r
495     delete [] decisions;\r
496     return resp;\r
497 }\r
498 \r
499 const char *ClassifierSVM::GetInfoString()\r
500 {\r
501     if(!svm) return NULL;\r
502     char *text = new char[1024];\r
503     sprintf(text, "%s\n", param.svm_type == NU_SVC ? "nu-SVM" : "C-SVM");\r
504     sprintf(text, "%sKernel: ", text);\r
505     switch(param.kernel_type)\r
506     {\r
507     case LINEAR:\r
508         sprintf(text, "%s linear\n", text);\r
509         break;\r
510     case POLY:\r
511         sprintf(text, "%s polynomial (deg: %d bias: %.3f width: %f)\n", text, param.degree, param.coef0, param.gamma);\r
512         break;\r
513     case RBF:\r
514         sprintf(text, "%s rbf (gamma: %f)\n", text, param.gamma);\r
515         break;\r
516     case SIGMOID:\r
517         sprintf(text, "%s sigmoid (%f %f)\n", text, param.gamma, param.coef0);\r
518         break;\r
519     }\r
520     sprintf(text, "%sC: %f \t nu: %f\n", text, param.C, param.nu);\r
521     sprintf(text, "%sSupport Vectors: %d\n", text, svm->l);\r
522     return text;\r
523 }\r
524 \r
525 void ClassifierSVM::SaveModel(std::string filename)\r
526 {\r
527     std::cout << "saving SVM model";\r
528     if(!svm)\r
529     {\r
530         std::cout << "Error: Nothing to save!" << std::endl;\r
531         return; // nothing to save!\r
532     }\r
533 \r
534     // Save the dataset to a file\r
535     std::ofstream file(filename.c_str());\r
536 \r
537     if(!file){\r
538         std::cout << "Error: Could not open the file!" << std::endl;\r
539         return;\r
540     }\r
541 \r
542     file << dim << " " << classCount << endl;\r
543     file << param.svm_type << " " << param.kernel_type << endl;\r
544     file << (param.kernel_weight==0 ? 0 : param.kernel_dim) << " ";\r
545     if(param.kernel_weight)\r
546     {\r
547         FOR(i, param.kernel_dim) file << param.kernel_weight[i] << " ";\r
548         file << endl;\r
549     }\r
550     file << param.eps << " " << param.C << " " << param.nu << " " << param.p << endl;\r
551     file << (param.weight_label==0 ? 0 : param.nr_weight);\r
552     FOR(i, param.nr_weight) file << " " << param.weight_label[i];\r
553     FOR(i, param.nr_weight) file << " " << param.weight[i];\r
554     file << endl;\r
555     file << param.normalizeKernel << " " << param.kernel_norm << " " << param.cache_size << " " << param.shrinking << " " << param.probability << endl;\r
556 \r
557     if(param.kernel_type == POLY) file << param.degree << " ";\r
558     if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID) file << param.gamma << " ";\r
559     if(param.kernel_type == POLY || param.kernel_type == SIGMOID) file << param.coef0;\r
560     file << endl;\r
561 \r
562     file << svm->nr_class << " " << svm->l << endl;\r
563     FOR(i, svm->nr_class*(svm->nr_class-1)/2) file << svm->rho[i] << " ";\r
564     file << endl;\r
565 \r
566     file << (svm->label!=0) << " " << (svm->probA!=0) << " " << (svm->probB!=0) << " " << (svm->nSV!=0) << endl;\r
567     if(svm->label)\r
568     {\r
569         FOR(i, svm->nr_class) file << svm->label[i] << " ";\r
570         file << endl;\r
571     }\r
572     if(svm->probA)\r
573     {\r
574         FOR(i, svm->nr_class*(svm->nr_class-1)/2) file << svm->probA[i] << " ";\r
575         file << endl;\r
576     }\r
577     if(svm->probB)\r
578     {\r
579         FOR(i, svm->nr_class*(svm->nr_class-1)/2) file << svm->probB[i] << " ";\r
580         file << endl;\r
581     }\r
582     if(svm->nSV)\r
583     {\r
584         FOR(i, svm->nr_class) file << svm->nSV[i] << " ";\r
585         file << endl;\r
586     }\r
587 \r
588     file << (param.kernel_type == PRECOMPUTED) << endl;\r
589     FOR(i, svm->l)\r
590     {\r
591         FOR(j, svm->nr_class-1) file << svm->sv_coef[j][i] << " ";\r
592 \r
593         const svm_node *p = svm->SV[i];\r
594 \r
595         if(param.kernel_type == PRECOMPUTED) file << (int)(p->value) << " ";\r
596         else\r
597         {\r
598             while(p->index != -1)\r
599             {\r
600                 file << p->index << " " << p->value << " ";\r
601                 p++;\r
602             }\r
603         }\r
604         file << endl;\r
605     }\r
606 \r
607     file << type << " " << bOptimize << endl;\r
608 \r
609     for(map<int,int>::iterator it=inverseMap.begin(); it != inverseMap.end(); it++)\r
610     {\r
611         file << it->first << " " << it->second << " ";\r
612     }\r
613     file << endl;\r
614     for(map<int,int>::iterator it=classMap.begin(); it != classMap.end(); it++)\r
615     {\r
616         file << it->first << " " << it->second << " ";\r
617     }\r
618     file << endl;\r
619 \r
620     file.close();\r
621 }\r
622 \r
623 //#define Malloc(type,n) (type *)malloc((n)*sizeof(type))\r
624 #define Malloc(type,n) new type[n]\r
625 bool ClassifierSVM::LoadModel(std::string filename)\r
626 {\r
627     std::cout << "Loading SVM model" << std::endl;\r
628     if(svm) DEL(svm);\r
629     if(node) DEL(node);\r
630     if(x_space) DEL(x_space);\r
631 \r
632     std::ifstream file(filename.c_str());\r
633     if(!file.is_open()){\r
634         std::cout << "Error: Could not open the file!" << std::endl;\r
635         return false;\r
636     }\r
637 \r
638     file >> dim >> classCount;\r
639 \r
640     svm = new svm_model;\r
641     file >> param.svm_type >> param.kernel_type;\r
642     file >> param.kernel_dim;\r
643     if(param.kernel_dim)\r
644     {\r
645         param.kernel_weight= Malloc(double, param.kernel_dim);\r
646         FOR(i, param.kernel_dim) file >> param.kernel_weight[i];\r
647     }\r
648     file >> param.eps >> param.C >> param.nu >> param.p;\r
649     file >> param.nr_weight;\r
650     if(param.nr_weight)\r
651     {\r
652         param.weight_label = Malloc(int, param.nr_weight);\r
653         param.weight = Malloc(double, param.nr_weight);\r
654         FOR(i, param.nr_weight) file >> param.weight_label[i];\r
655         FOR(i, param.nr_weight) file >> param.weight[i];\r
656     }\r
657     file >> param.normalizeKernel >> param.kernel_norm >> param.cache_size >> param.shrinking >> param.probability;\r
658 \r
659     if(param.kernel_type == POLY) file >> param.degree;\r
660     if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID) file >> param.gamma;\r
661     if(param.kernel_type == POLY || param.kernel_type == SIGMOID) file >> param.coef0;\r
662 \r
663     file >> svm->nr_class >> svm->l;\r
664     svm->rho = Malloc(double, svm->nr_class*(svm->nr_class-1)/2);\r
665     FOR(i, svm->nr_class*(svm->nr_class-1)/2) file >> svm->rho[i];\r
666 \r
667     int label, probA, probB, nSV;\r
668     file >> label >> probA >> probB >> nSV;\r
669     if(label)\r
670     {\r
671         svm->label = Malloc(int, svm->nr_class);\r
672         FOR(i, svm->nr_class) file >> svm->label[i];\r
673     }\r
674     if(probA)\r
675     {\r
676         svm->probA = Malloc(double, svm->nr_class*(svm->nr_class-1)/2);\r
677         FOR(i, svm->nr_class*(svm->nr_class-1)/2) file >> svm->probA[i];\r
678     }\r
679     if(probB)\r
680     {\r
681         svm->probB = Malloc(double, svm->nr_class*(svm->nr_class-1)/2);\r
682         FOR(i, svm->nr_class*(svm->nr_class-1)/2) file >> svm->probB[i];\r
683     }\r
684     if(nSV)\r
685     {\r
686         svm->nSV = Malloc(int, svm->nr_class);\r
687         FOR(i, svm->nr_class) file >> svm->nSV[i];\r
688     }\r
689 \r
690     bool bPrecomputed;\r
691     file >> bPrecomputed;\r
692 \r
693     svm->sv_coef = Malloc(double *, svm->nr_class-1);\r
694     svm->SV = Malloc(svm_node*, svm->l);\r
695     FOR(i, svm->nr_class-1) svm->sv_coef[i] = Malloc(double, svm->l);\r
696     ivec indices;\r
697     dvec values;\r
698     int index = 0;\r
699     double value = 0;\r
700     FOR(i, svm->l)\r
701     {\r
702         FOR(j, svm->nr_class-1) file >> svm->sv_coef[j][i];\r
703 \r
704         if(bPrecomputed)\r
705         {\r
706             param.kernel_type = PRECOMPUTED;\r
707             file >> value;\r
708         }\r
709         else\r
710         {\r
711             svm->SV[i] = Malloc(svm_node, dim + 1);\r
712             FOR(j, dim)\r
713             {\r
714                 file >> svm->SV[i][j].index;\r
715                 file >> svm->SV[i][j].value;\r
716             }\r
717             svm->SV[i][dim].index = -1;\r
718             svm->SV[i][dim].value = 0;\r
719         }\r
720     }\r
721 \r
722     file >> type >> bOptimize;\r
723     inverseMap.clear();\r
724     classMap.clear();\r
725     FOR(i, classCount)\r
726     {\r
727         int first, second;\r
728         file >> first >> second;\r
729         inverseMap[first] = second;\r
730     }\r
731     FOR(i, classCount)\r
732     {\r
733         int first, second;\r
734         file >> first >> second;\r
735         classMap[first] = second;\r
736     }\r
737 \r
738     classCount = svm->nr_class;\r
739     FOR(i, classCount)\r
740     {\r
741         classes[i] = svm->label[i];\r
742     }\r
743 \r
744     file.close();\r
745     svm->param = param;\r
746 \r
747     return true;\r
748 }\r