00001
00038
00039
00040 #define _SCL_SECURE_NO_WARNINGS
00041
00042 #include <math.h>
00043 #include <fstream>
00044 #include <iostream>
00045 #include <LinAlg/LinAlg.h>
00046 #include <LinAlg/VecMat.h>
00047 #include <ReClaM/Svm.h>
00048 #include <ReClaM/QuadraticProgram.h>
00049 #include <ReClaM/GaussianProcess.h>
00050
00051
00052 using namespace std;
00053
00054
00056
00057
00058 SVM::SVM(KernelFunction* pKernel, bool bSignOutput)
00059 {
00060 kernel = pKernel;
00061 signOutput = bSignOutput;
00062
00063 x = NULL;
00064 bOwnMemory = false;
00065
00066 examples = 0;
00067 inputDimension = 0;
00068 outputDimension = 1;
00069
00070 parameter.resize(1, false);
00071 parameter = 0.0;
00072 }
00073
00074 SVM::SVM(KernelFunction* pKernel, const Array<double>& input, bool bSignOutput)
00075 {
00076 kernel = pKernel;
00077 signOutput = bSignOutput;
00078
00079 x = NULL;
00080 bOwnMemory = false;
00081
00082 examples = 0;
00083 inputDimension = 0;
00084 outputDimension = 1;
00085
00086 SetTrainingData(input);
00087 }
00088
00089 SVM::~SVM()
00090 {
00091 if (bOwnMemory) delete x;
00092 }
00093
00094
00095 void SVM::SetTrainingData(const Array<double>& input, bool copy)
00096 {
00097 if (bOwnMemory) delete x;
00098
00099 if (copy)
00100 {
00101 x = new Array<double> (input);
00102 bOwnMemory = true;
00103 }
00104 else
00105 {
00106 x = &input;
00107 bOwnMemory = false;
00108 }
00109
00110 examples = input.dim(0);
00111 inputDimension = input.dim(1);
00112
00113 parameter.resize(examples + 1, false);
00114 parameter = 0.0;
00115 }
00116
00117 void SVM::model(const Array<double>& input, Array<double>& output)
00118 {
00119 unsigned int i;
00120 double a;
00121 double alpha;
00122 if (input.ndim() == 1)
00123 {
00124 output.resize(1, false);
00125 a = parameter(examples);
00126 for (i = 0; i < examples; i++)
00127 {
00128 alpha = parameter(i);
00129 if (alpha != 0.0)
00130 {
00131 a += alpha * kernel->eval((*x)[i], input);
00132 }
00133 }
00134 if (signOutput) output(0) = (a > 0.0) ? 1.0 : -1.0;
00135 else output(0) = a;
00136 }
00137 else if (input.ndim() == 2)
00138 {
00139 int j, jc = input.dim(0);
00140 output.resize(jc, 1, false);
00141 for (j = 0; j < jc; j++)
00142 {
00143 a = parameter(examples);
00144 const ArrayReference<double> ii = input[j];
00145 for (i = 0; i < examples; i++)
00146 {
00147 alpha = parameter(i);
00148 if (alpha != 0.0)
00149 {
00150 a += alpha * kernel->eval((*x)[i], ii);
00151 }
00152 }
00153 if (signOutput) output(j, 0) = (a > 0.0) ? 1.0 : -1.0;
00154 else output(j, 0) = a;
00155 }
00156 }
00157 else throw SHARKEXCEPTION("[SVM::model] invalid dimension");
00158 }
00159
00160 double SVM::model(const Array<double>& input)
00161 {
00162 unsigned int i;
00163 double a;
00164 double alpha;
00165 if (input.ndim() == 1)
00166 {
00167 a = parameter(examples);
00168 for (i = 0; i < examples; i++)
00169 {
00170 alpha = parameter(i);
00171 if (alpha != 0.0)
00172 {
00173 a += alpha * kernel->eval((*x)[i], input);
00174 }
00175 }
00176 }
00177 else throw SHARKEXCEPTION("[SVM::model] invalid dimension");
00178 if (signOutput) return(a > 0.0) ? 1.0 : -1.0;
00179 else return a;
00180 }
00181
00182 void SVM::modelDerivative(const Array<double>& input, Array<double>& derivative)
00183 {
00184 unsigned int i;
00185 double v;
00186 if (input.ndim() == 1)
00187 {
00188 derivative.resize(1, examples + 1, false);
00189 derivative = 0.0;
00190 for (i = 0; i < examples; i++)
00191 {
00192 v = kernel->eval((*x)[i], input);
00193 derivative(0, i) = v;
00194 }
00195 derivative(0, examples) = 1.0;
00196 }
00197 else throw SHARKEXCEPTION("[SVM::modelDerivative] invalid dimension");
00198 }
00199
00200 void SVM::modelDerivative(const Array<double>& input, Array<double>& output, Array<double>& derivative)
00201 {
00202 unsigned int i;
00203 double a, v;
00204 if (input.ndim() == 1)
00205 {
00206 derivative.resize(1, examples + 1, false);
00207 derivative = 0.0;
00208 output.resize(1, false);
00209 a = parameter(examples);
00210 for (i = 0; i < examples; i++)
00211 {
00212 v = kernel->eval((*x)[i], input);
00213 a += parameter(i) * v;
00214 derivative(0, i) = v;
00215 }
00216 output(0) = a;
00217 derivative(0, examples) = 1.0;
00218 }
00219 else throw SHARKEXCEPTION("[SVM::modelDerivative] invalid dimension");
00220 }
00221
00222 bool SVM::LoadSVMModel(std::istream& is)
00223 {
00224 char buffer[50];
00225 unsigned int t, d;
00226
00227
00228 is.read(buffer, 21);
00229
00230 buffer[21] = 0;
00231 if (strcmp(buffer, "Shark SVM model\r\nSV: ") != 0) return false;
00232 if (! is.good()) return false;
00233
00234
00235 is >> examples;
00236
00237 is.read(buffer, 7); buffer[7] = 0;
00238 if (strcmp(buffer, "\r\nDIM: ") != 0) return false;
00239 if (! is.good()) return false;
00240
00241
00242 is >> inputDimension;
00243
00244 is.read(buffer, 10); buffer[10] = 0;
00245 if (strcmp(buffer, "\r\nkernel: ") != 0) return false;
00246 if (! is.good()) return false;
00247
00248
00249 is >> (*kernel);
00250
00251 is.read(buffer, 14); buffer[14] = 0;
00252 if (strcmp(buffer, "coefficients: ") != 0) return false;
00253 if (! is.good()) return false;
00254
00255
00256 parameter.resize(examples + 1, false);
00257 for (t = 0; t < examples; t++)
00258 {
00259 is >> parameter(t);
00260 is.read(buffer, 1);
00261 if (buffer[0] != ' ') return false;
00262 }
00263
00264 is >> parameter(examples);
00265
00266 is.read(buffer, 2); buffer[2] = 0;
00267 if (strcmp(buffer, "\r\n") != 0) return false;
00268 if (! is.good()) return false;
00269
00270
00271 Array<double>* sv = new Array<double> (examples, inputDimension);
00272 for (t = 0; t < examples; t++)
00273 {
00274 for (d = 0; d < inputDimension; d++)
00275 {
00276 is >> (*sv)(t, d);
00277 if (d < inputDimension - 1)
00278 {
00279 is.read(buffer, 1);
00280 if (buffer[0] != ' ') return false;
00281 }
00282 }
00283
00284 is.read(buffer, 2); buffer[2] = 0;
00285 if (strcmp(buffer, "\r\n") != 0) return false;
00286
00287 if (! is.good()) return false;
00288 }
00289
00290 bOwnMemory = true;
00291 x = sv;
00292
00293 return true;
00294 }
00295
00296 bool SVM::SaveSVMModel(std::ostream& os)
00297 {
00298 unsigned int t, d;
00299 unsigned int T = 0;
00300 for (t = 0; t < examples; t++) if (parameter(t) != 0.0) T++;
00301
00302
00303 os.write("Shark SVM model\r\nSV: ", 21);
00304
00305
00306 os << T;
00307
00308 os.write("\r\nDIM: ", 7);
00309 if (! os.good()) return false;
00310
00311
00312 os << inputDimension;
00313
00314 os.write("\r\nkernel: ", 10);
00315 if (! os.good()) return false;
00316
00317
00318 os << (*kernel);
00319
00320 os.write("coefficients: ", 14);
00321 if (! os.good()) return false;
00322
00323
00324 for (t = 0; t < examples; t++) if (parameter(t) != 0.0) os << parameter(t) << " ";
00325 os << parameter(examples) << "\r\n";
00326 if (! os.good()) return false;
00327
00328
00329 for (t = 0; t < examples; t++)
00330 {
00331 if (parameter(t) != 0.0)
00332 {
00333 for (d = 0; d < inputDimension; d++)
00334 {
00335 os << (*x)(t, d);
00336 if (d < inputDimension - 1) os << " ";
00337 }
00338 os.write("\r\n", 2);
00339 if (! os.good()) return false;
00340 }
00341 }
00342
00343 return true;
00344 }
00345
00346
00347 SVM* SVM::ImportLibsvmModel(std::istream& is)
00348 {
00349 char buffer[256];
00350 int status;
00351 int i;
00352
00353 LinearKernel* linear = NULL;
00354 PolynomialKernel* poly = NULL;
00355 RBFKernel* rbf = NULL;
00356 KernelFunction* pKernel = NULL;
00357 double b = 0.0;
00358 int examples = -1;
00359 int dimension = -1;
00360 while (true)
00361 {
00362 status = ReadToken(is, buffer, sizeof(buffer), "\n");
00363 if (status > 1000) return NULL;
00364
00365 if (memcmp(buffer, "svm_type ", 9) == 0)
00366 {
00367 if (strcmp(buffer + 9, "c_svc") != 0) return NULL;
00368 }
00369 else if (memcmp(buffer, "kernel_type ", 12) == 0)
00370 {
00371 if (strcmp(buffer + 12, "linear") == 0)
00372 {
00373 linear = new LinearKernel();
00374 pKernel = linear;
00375 }
00376 else if (strcmp(buffer + 12, "rbf") == 0)
00377 {
00378 rbf = new RBFKernel(1.0);
00379 pKernel = rbf;
00380 }
00381 else if (strcmp(buffer + 12, "polynomial") == 0)
00382 {
00383 poly = new PolynomialKernel(1, 1.0);
00384 pKernel = poly;
00385 }
00386 else return NULL;
00387 }
00388 else if (memcmp(buffer, "degree ", 7) == 0)
00389 {
00390 if (poly != NULL)
00391 {
00392 poly->setParameter(0, atof(buffer + 7));
00393 }
00394 }
00395 else if (memcmp(buffer, "gamma ", 6) == 0)
00396 {
00397 if (rbf != NULL)
00398 {
00399 rbf->setParameter(0, atof(buffer + 6));
00400 }
00401 }
00402 else if (memcmp(buffer, "coef0 ", 6) == 0)
00403 {
00404 if (poly != NULL)
00405 {
00406 poly->setParameter(1, atof(buffer + 6));
00407 }
00408 }
00409 else if (memcmp(buffer, "nr_class ", 9) == 0)
00410 {
00411 if (strcmp(buffer + 9, "2") != 0) return NULL;
00412 }
00413 else if (memcmp(buffer, "total_sv ", 9) == 0)
00414 {
00415 examples = atoi(buffer + 9);
00416 }
00417 else if (memcmp(buffer, "rho ", 4) == 0)
00418 {
00419 b = atof(buffer + 4);
00420 }
00421 else if (memcmp(buffer, "label ", 6) == 0)
00422 {
00423 if (strcmp(buffer + 6, "1 -1") != 0) return NULL;
00424 }
00425 else if (strcmp(buffer, "SV") == 0)
00426 {
00427 break;
00428 }
00429 else
00430 {
00431
00432 }
00433 }
00434 if (examples == -1) return NULL;
00435 if (pKernel == NULL) return NULL;
00436
00437
00438 int start = is.tellg();
00439 for (i = 0; i < examples; i++)
00440 {
00441
00442 status = ReadToken(is, buffer, sizeof(buffer), " ");
00443 if (status != ' ') return NULL;
00444
00445 while (true)
00446 {
00447
00448 status = ReadToken(is, buffer, sizeof(buffer), ":\n");
00449 if (status > 1000) return NULL;
00450 if (status == '\n') break;
00451 int index = atoi(buffer);
00452 if (index >= dimension) dimension = index + 1;
00453
00454
00455 status = ReadToken(is, buffer, sizeof(buffer), " \n");
00456 if (status > 1000) return NULL;
00457 if (status == '\n') break;
00458 }
00459 }
00460 if (dimension == -1) return NULL;
00461
00462
00463 SVM* pSVM = new SVM(pKernel);
00464 Array<double>* sv = new Array<double> (examples, dimension);
00465 *sv = 0.0;
00466 pSVM->parameter.resize(examples + 1, false);
00467 pSVM->parameter(examples) = b;
00468 pSVM->examples = examples;
00469 pSVM->inputDimension = dimension;
00470
00471
00472 is.seekg(start, ios::beg);
00473 for (i = 0; i < examples; i++)
00474 {
00475
00476 status = ReadToken(is, buffer, sizeof(buffer), " ");
00477 if (status != ' ') return NULL;
00478 pSVM->parameter(i) = atof(buffer);
00479
00480 while (true)
00481 {
00482
00483 status = ReadToken(is, buffer, sizeof(buffer), ":\n");
00484 if (status > 1000) return NULL;
00485 if (status == '\n') break;
00486 int index = atoi(buffer);
00487 if (index >= dimension) dimension = index + 1;
00488
00489
00490 status = ReadToken(is, buffer, sizeof(buffer), " \n");
00491 if (status > 1000) return NULL;
00492 (*sv)(i, index) = atof(buffer);
00493 if (status == '\n') break;
00494 }
00495 }
00496
00497 pSVM->x = sv;
00498 pSVM->bOwnMemory = true;
00499
00500 return pSVM;
00501 }
00502
00503
00504 SVM* SVM::ImportSvmlightModel(std::istream& is)
00505 {
00506 char buffer[256];
00507 int status;
00508 KernelFunction* pKernel;
00509
00510
00511 status = DiscardUntil(is, "\n");
00512 if (status != '\n') return NULL;
00513
00514
00515 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00516 if (status > 1000) return NULL;
00517 if (status == '#') DiscardUntil(is, "\n");
00518 int kernel = atoi(buffer);
00519
00520
00521 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00522 if (status > 1000) return NULL;
00523 if (status == '#') DiscardUntil(is, "\n");
00524 int degree = atoi(buffer);
00525
00526
00527 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00528 if (status > 1000) return NULL;
00529 if (status == '#') DiscardUntil(is, "\n");
00530 double gamma = atof(buffer);
00531
00532
00533 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00534 if (status > 1000) return NULL;
00535 if (status == '#') DiscardUntil(is, "\n");
00536 double s = atof(buffer);
00537
00538
00539 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00540 if (status > 1000) return NULL;
00541 if (status == '#') DiscardUntil(is, "\n");
00542 double r = atof(buffer);
00543
00544
00545 status = DiscardUntil(is, "\n");
00546 if (status > 1000) return NULL;
00547
00548
00549 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00550 if (status > 1000) return NULL;
00551 if (status == '#') DiscardUntil(is, "\n");
00552 int dimension = atoi(buffer) + 1;
00553
00554
00555 status = DiscardUntil(is, "\n");
00556 if (status > 1000) return NULL;
00557
00558
00559 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00560 if (status > 1000) return NULL;
00561 if (status == '#') DiscardUntil(is, "\n");
00562 int examples = atoi(buffer) - 1;
00563
00564
00565 status = ReadToken(is, buffer, sizeof(buffer), "#\n");
00566 if (status > 1000) return NULL;
00567 if (status == '#') DiscardUntil(is, "\n");
00568 double b = atof(buffer);
00569
00570
00571 if (kernel == 0) pKernel = new LinearKernel();
00572 else if (kernel == 1)
00573 {
00574 if (s == 0.0) return NULL;
00575 pKernel = new PolynomialKernel(degree, r / s);
00576 }
00577 else if (kernel == 2) pKernel = new RBFKernel(gamma);
00578 else return NULL;
00579 SVM* pSVM = new SVM(pKernel);
00580 Array<double>* sv = new Array<double> (examples, dimension);
00581 *sv = 0.0;
00582 pSVM->parameter.resize(examples + 1, false);
00583 pSVM->parameter(examples) = b;
00584 pSVM->examples = examples;
00585 pSVM->inputDimension = dimension;
00586
00587
00588 int i, index;
00589 for (i = 0; i < examples; i++)
00590 {
00591
00592 status = ReadToken(is, buffer, sizeof(buffer), " ");
00593 if (status > 1000) return NULL;
00594 pSVM->parameter(i) = atof(buffer);
00595
00596 while (true)
00597 {
00598
00599 status = ReadToken(is, buffer, sizeof(buffer), ":#\n");
00600 if (status > 1000) return NULL;
00601 if (status == '#')
00602 {
00603 if (DiscardUntil(is, "\n") > 1000) return NULL;
00604 break;
00605 }
00606 else if (status == '\n') break;
00607 index = atoi(buffer);
00608
00609
00610 status = ReadToken(is, buffer, sizeof(buffer), " #\n");
00611 if (status > 1000) return NULL;
00612 (*sv)(i, index) = atof(buffer);
00613 if (status == '#')
00614 {
00615 if (DiscardUntil(is, "\n") > 1000) return NULL;
00616 break;
00617 }
00618 else if (status == '\n') break;
00619 }
00620 }
00621
00622 pSVM->x = sv;
00623 pSVM->bOwnMemory = true;
00624
00625 return pSVM;
00626 }
00627
00628 void SVM::MakeSparse()
00629 {
00630 if (! bOwnMemory) return;
00631
00632
00633 int i, ic = getExamples();
00634 std::vector<int> map;
00635 for (i = 0; i < ic; i++)
00636 {
00637 if (parameter(i) != 0.0)
00638 {
00639 map.push_back(i);
00640 }
00641 }
00642 int s, sc = map.size();
00643
00644
00645 int dim = x->dim(1);
00646 Array<double> p(sc + 1);
00647 Array<double>* xx = new Array<double>(sc, dim);
00648
00649 for (s = 0; s < sc; s++)
00650 {
00651 i = map[s];
00652 (*xx)[s] = (*x)[i];
00653 p(s) = parameter(i);
00654 }
00655 p(sc) = parameter(ic);
00656
00657 parameter = p;
00658 examples = sc;
00659 delete x;
00660 x = xx;
00661 }
00662
00663
00664 int SVM::ReadToken(std::istream& is, char* buffer, int maxlength, const char* separators)
00665 {
00666 int i;
00667 int s, sc = strlen(separators);
00668 char c;
00669 for (i = 0; i < maxlength - 1; i++)
00670 {
00671 if (is.readsome(&c, 1) == 0) return 1001;
00672 if (is.bad()) return 1002;
00673 for (s = 0; s < sc; s++) if (separators[s] == c) break;
00674 if (s < sc)
00675 {
00676 buffer[i] = 0;
00677 return separators[s];
00678 }
00679 buffer[i] = c;
00680 }
00681 buffer[i] = 0;
00682 return 1003;
00683 }
00684
00685
00686 int SVM::DiscardUntil(std::istream& is, const char* separators)
00687 {
00688 int s, sc = strlen(separators);
00689 char c;
00690 while (true)
00691 {
00692 if (is.readsome(&c, 1) == 0) return 1001;
00693 if (is.bad()) return 1002;
00694 for (s = 0; s < sc; s++) if (separators[s] == c) return c;
00695 }
00696 }
00697
00698
00700
00701
00702 MultiClassSVM::MultiClassSVM(KernelFunction* pKernel, unsigned int numberOfClasses, bool bOrthogonalVectors, bool bNumberOutput)
00703 {
00704 this->kernel = pKernel;
00705 this->classes = numberOfClasses;
00706 this->examples = 0;
00707 this->bOwnMemory = false;
00708 this->numberOutput = bNumberOutput;
00709
00710 prototypes.resize(classes, classes, false);
00711 if (bOrthogonalVectors)
00712 {
00713 prototypes = 0.0;
00714 unsigned int i;
00715 for (i = 0; i < classes; i++) prototypes(i, i) = 1.0;
00716 }
00717 else
00718 {
00719 throw SHARKEXCEPTION("[MultiClassSVM::MultiClassSVM] simplex vector initialization not implemented yet");
00720 }
00721
00722 inputDimension = 0;
00723 outputDimension = (numberOutput ? 1 : classes);
00724 x = NULL;
00725 }
00726
00727 MultiClassSVM::MultiClassSVM(KernelFunction* pKernel, Array<double> prototypes, bool bNumberOutput)
00728 {
00729 SIZE_CHECK(prototypes.ndim() == 2);
00730 SIZE_CHECK(prototypes.dim(0) == prototypes.dim(1));
00731
00732 this->kernel = pKernel;
00733 this->classes = prototypes.dim(0);
00734 this->examples = 0;
00735 this->bOwnMemory = false;
00736 this->numberOutput = bNumberOutput;
00737 this->prototypes = prototypes;
00738
00739 inputDimension = 0;
00740 outputDimension = (numberOutput ? 1 : classes);
00741 x = NULL;
00742 }
00743
00744 MultiClassSVM::~MultiClassSVM()
00745 {
00746 if (bOwnMemory) delete x;
00747 }
00748
00749
00750 void MultiClassSVM::SetTrainingData(const Array<double>& input, bool copy)
00751 {
00752 SIZE_CHECK(input.ndim() == 2);
00753 if (bOwnMemory) delete x;
00754
00755 examples = input.dim(0);
00756 inputDimension = input.dim(1);
00757
00758 parameter.resize(examples * classes + classes, false);
00759 parameter = 0.0;
00760
00761 if (copy)
00762 {
00763 x = new Array<double>(input);
00764 bOwnMemory = true;
00765 }
00766 else
00767 {
00768 x = &input;
00769 bOwnMemory = false;
00770 }
00771 }
00772
00773 void MultiClassSVM::model(const Array<double>& input, Array<double>& output)
00774 {
00775 if (numberOutput)
00776 {
00777 Array<double> tmp(classes);
00778 if (input.ndim() == 1)
00779 {
00780 output.resize(1, false);
00781 Predict(input, tmp);
00782 output(0) = VectorToClass(tmp);
00783 }
00784 else if (input.ndim() == 2)
00785 {
00786 unsigned int i, ic = input.dim(0);
00787 output.resize(ic, 1, false);
00788 for (i = 0; i < ic; i++)
00789 {
00790 Predict(input[i], tmp);
00791 output(i, 0) = VectorToClass(tmp);
00792 }
00793 }
00794 else throw SHARKEXCEPTION("[MultiClassSVM::model] invalid dimension");
00795 }
00796 else
00797 {
00798 if (input.ndim() == 1)
00799 {
00800 output.resize(classes, false);
00801 Predict(input, output);
00802 }
00803 else if (input.ndim() == 2)
00804 {
00805 unsigned int i, ic = input.dim(0);
00806 output.resize(ic, classes, false);
00807 for (i = 0; i < ic; i++)
00808 {
00809 Predict(input[i], output[i]);
00810 }
00811 }
00812 else throw SHARKEXCEPTION("[MultiClassSVM::model] invalid dimension");
00813 }
00814 }
00815
00816 unsigned int MultiClassSVM::model(const Array<double>& input)
00817 {
00818 SIZE_CHECK(input.ndim() == 1);
00819 SIZE_CHECK(input.dim(0) == inputDimension);
00820
00821 Array<double> tmp(classes);
00822 Predict(input, tmp);
00823 return VectorToClass(tmp);
00824 }
00825
00826 void MultiClassSVM::Normalize()
00827 {
00828 unsigned int c;
00829 unsigned int i, j;
00830 for (c = 0; c < classes; c++)
00831 {
00832
00833 double norm2 = 0.0;
00834 for (i = 0; i < examples; i++)
00835 {
00836 for (j = 0; j < i; j++)
00837 {
00838 double k = kernel->eval((*x)[i], (*x)[j]);
00839 norm2 += 2.0 * parameter(classes * i + c) * parameter(classes * j + c) * k;
00840 }
00841 double k = kernel->eval((*x)[i], (*x)[i]);
00842 norm2 += parameter(classes * i + c) * parameter(classes * i + c) * k;
00843 }
00844
00845
00846 double norm = sqrt(norm2);
00847 for (i = 0; i < examples; i++) parameter(classes*i + c) /= norm;
00848 }
00849 }
00850
00851 unsigned int MultiClassSVM::VectorToClass(const Array<double>& v)
00852 {
00853 SIZE_CHECK(v.ndim() == 1);
00854 SIZE_CHECK(v.dim(0) == classes);
00855
00856 unsigned int c, i, best = 0;
00857 double scp, bestscp = -1e100;
00858 for (c = 0; c < classes; c++)
00859 {
00860 scp = 0.0;
00861 for (i = 0; i < classes; i++)
00862 {
00863 scp += v(i) * prototypes(c, i);
00864 }
00865 if (scp > bestscp)
00866 {
00867 bestscp = scp;
00868 best = c;
00869 }
00870 }
00871
00872 return best;
00873 }
00874
00875
00876 void MultiClassSVM::Predict(const Array<double>& input, Array<double>& output)
00877 {
00878 unsigned int c, e, m;
00879 output = 0.0;
00880
00881 for (e = 0; e < examples; e++)
00882 {
00883 double k = kernel->eval((*x)[e], input);
00884 for (c = 0; c < classes; c++)
00885 {
00886 for (m = 0; m < classes; m++)
00887 {
00888 output(m) += getAlpha(e, c) * k * prototypes(c, m);
00889 }
00890 }
00891 }
00892
00893 for (c = 0; c < classes; c++)
00894 {
00895 for (m = 0; m < classes; m++)
00896 {
00897 output(m) += getOffset(c) * prototypes(c, m);
00898 }
00899 }
00900 }
00901
00902
00903 void MultiClassSVM::Predict(const Array<double>& input, ArrayReference<double> output)
00904 {
00905 unsigned int c, e, m;
00906 output = 0.0;
00907
00908 for (e = 0; e < examples; e++)
00909 {
00910 double k = kernel->eval((*x)[e], input);
00911 for (c = 0; c < classes; c++)
00912 {
00913 for (m = 0; m < classes; m++)
00914 {
00915 output(m) += getAlpha(e, c) * k * prototypes(c, m);
00916 }
00917 }
00918 }
00919
00920 for (c = 0; c < classes; c++)
00921 {
00922 for (m = 0; m < classes; m++)
00923 {
00924 output(m) += getOffset(c) * prototypes(c, m);
00925 }
00926 }
00927 }
00928
00929
00931
00932
00933 MetaSVM::MetaSVM(SVM* pSVM, unsigned int numberOfHyperParameters)
00934 {
00935 svm = pSVM;
00936 kernel = pSVM->getKernel();
00937 hyperparameters = numberOfHyperParameters;
00938
00939 unsigned int k, kc = kernel->getParameterDimension();
00940 parameter.resize(hyperparameters + kc, false);
00941 parameter = 0.0;
00942 for (k = 0; k < kc; k++) parameter(k + hyperparameters) = kernel->getParameter(k);
00943 }
00944
00945 MetaSVM::MetaSVM(MultiClassSVM* pSVM, unsigned int numberOfHyperParameters)
00946 {
00947 svm = pSVM;
00948 kernel = pSVM->getKernel();
00949 hyperparameters = numberOfHyperParameters;
00950
00951 unsigned int k, kc = kernel->getParameterDimension();
00952 parameter.resize(hyperparameters + kc, false);
00953 parameter = 0.0;
00954 for (k = 0; k < kc; k++) parameter(k + hyperparameters) = kernel->getParameter(k);
00955 }
00956
00957 MetaSVM::~MetaSVM()
00958 {
00959 }
00960
00961
00962 void MetaSVM::model(const Array<double>& input, Array<double>& output)
00963 {
00964 svm->model(input, output);
00965 }
00966
00967 void MetaSVM::setParameter(unsigned int index, double value)
00968 {
00969 Model::setParameter(index, value);
00970 if (index >= hyperparameters)
00971 {
00972
00973 kernel->setParameter(index - hyperparameters, value);
00974 }
00975 }
00976
00977 bool MetaSVM::isFeasible()
00978 {
00979 return (kernel->isFeasible());
00980 }
00981
00982
00984
00985
00986 C_SVM::C_SVM(SVM* pSVM, double Cplus, double Cminus, bool norm2, bool unconst)
00987 : MetaSVM(pSVM, 1)
00988 {
00989 C_ratio = Cminus / Cplus;
00990 norm2penalty = norm2;
00991 exponential = unconst;
00992
00993 setParameter(0, (exponential) ? log(Cplus) : Cplus);
00994 }
00995
00996 C_SVM::~C_SVM()
00997 {
00998 }
00999
01000
01001 void C_SVM::PrepareDerivative()
01002 {
01003 if (norm2penalty) throw SHARKEXCEPTION("[C_SVM::PrepareDerivative] PrepareDerivative works only in the 1-norm case.");
01004
01005 SVM* svm = getSVM();
01006 const Array<double>& pt = svm->getPoints();
01007 int a, ac = svm->getExamples();
01008 int s, sc = svm->getParameterDimension();
01009 int k, kc = kernel->getParameterDimension();
01010 int pc = getParameterDimension();
01011 Array<double> der;
01012
01013 alpha_b_Derivative.resize(sc, pc, false);
01014 alpha_b_Derivative = 0.0;
01015
01016
01017 std::vector<int> fi;
01018 std::vector<int> ri;
01019 for (a = 0; a < ac; a++)
01020 {
01021 double alpha = svm->getAlpha(a);
01022 if (alpha != 0.0)
01023 {
01024 if ((alpha == -C_minus) || (alpha == C_plus)) ri.push_back(a);
01025 else fi.push_back(a);
01026 }
01027 }
01028 int f, fc = fi.size();
01029 int r, rc = ri.size();
01030 fi.push_back(ac);
01031
01032 Array2D<double> H(fc + 1, fc + 1);
01033 Array2D<double> H_inv(fc + 1, fc + 1);
01034 Array2D<double> R(fc + 1, rc);
01035 Array<double> dH(kc, fc + 1, fc + 1);
01036 Array<double> dR(kc, fc + 1, rc);
01037 Array<double> alpha_f(fc + 1);
01038 Array<double> alpha_r(rc);
01039 for (f = 0; f < fc; f++) alpha_f(f) = svm->getAlpha(fi[f]);
01040 alpha_f(fc) = svm->getOffset();
01041 for (r = 0; r < rc; r++) alpha_r(r) = svm->getAlpha(ri[r]);
01042
01043
01044 for (f = 0; f < fc; f++)
01045 {
01046 int f2;
01047 for (f2 = 0; f2 < f; f2++)
01048 {
01049 H(f, f2) = H(f2, f) = kernel->evalDerivative(pt[fi[f]], pt[fi[f2]], der);
01050 for (k = 0; k < kc; k++)
01051 {
01052 dH(k, f, f2) = dH(k, f2, f) = der(k);
01053 }
01054 }
01055 H(f, f) = kernel->evalDerivative(pt[fi[f]], pt[fi[f]], der);
01056 for (k = 0; k < kc; k++)
01057 {
01058 dH(k, f, f) = der(k);
01059 }
01060 H(fc, f) = H(f, fc) = 1.0;
01061 for (k = 0; k < kc; k++) dH(k, fc, f) = dH(k, f, fc) = 0.0;
01062 }
01063 H(fc, fc) = 0.0;
01064 for (k = 0; k < kc; k++) dH(k, fc, fc) = 0.0;
01065
01066
01067
01068 g_inverse(H, H_inv, 200, 1e-10, true);
01069
01070
01071 for (r = 0; r < rc; r++)
01072 {
01073 for (f = 0; f < fc; f++)
01074 {
01075 R(f, r) = kernel->evalDerivative(pt[fi[f]], pt[ri[r]], der);
01076 for (k = 0; k < kc; k++)
01077 {
01078 dR(k, f, r) = der(k);
01079 }
01080 }
01081 R(fc, r) = 1.0;
01082 for (k = 0; k < kc; k++) dR(k, fc, r) = 0.0;
01083 }
01084
01085 der.resize(fc + 1, false);
01086
01087
01088 if (rc > 0)
01089 {
01090 Array<double> y(rc);
01091 for (r = 0; r < rc; r++) y(r) = ((alpha_r(r) > 0.0) ? 1.0 : -1.0);
01092 Array<double> Ry(fc + 1);
01093 matColVec(Ry, R, y);
01094 matColVec(der, H_inv, Ry);
01095 for (f = 0; f <= fc; f++) alpha_b_Derivative(fi[f], 0) = -der(f);
01096 for (r = 0; r < rc; r++) alpha_b_Derivative(ri[r], 0) = ((alpha_r(r) > 0.0) ? 1.0 : -C_ratio);
01097 if (exponential)
01098 {
01099 for (s = 0; s < sc; s++) alpha_b_Derivative(s, 0) *= C_plus;
01100 }
01101 }
01102
01103
01104 for (k = 0; k < kc; k++)
01105 {
01106 Array<double> sum(fc + 1);
01107 Array<double> tmp(fc + 1);
01108 matColVec(sum, dH[k], alpha_f);
01109 matColVec(tmp, dR[k], alpha_r);
01110 for (f = 0; f <= fc; f++) sum(f) += tmp(f);
01111 matColVec(der, H_inv, sum);
01112 for (f = 0; f <= fc; f++) alpha_b_Derivative(fi[f], k + 1) = -der(f);
01113 }
01114 }
01115
01116 void C_SVM::modelDerivative(const Array<double>& input, Array<double>& derivative)
01117 {
01118 SVM* svm = getSVM();
01119 const Array<double>& pt = svm->getPoints();
01120 int k, kc = kernel->getParameterDimension();
01121 int a, ac = svm->getExamples();
01122 int pc = getParameterDimension();
01123
01124 derivative.resize(1, pc, false);
01125 for (k = 0; k <= kc; k++) derivative(0, k) = alpha_b_Derivative(ac, k);
01126
01127 Array<double> der(pc);
01128
01129 for (a = 0; a < ac; a++)
01130 {
01131 double alpha = svm->getAlpha(a);
01132 double ker = kernel->evalDerivative(input, pt[a], der);
01133 derivative(0, 0) += ker * alpha_b_Derivative(a, 0);
01134 for (k = 0; k < kc; k++)
01135 {
01136 derivative(0, k + 1) += alpha * der(k) + ker * alpha_b_Derivative(a, k + 1);
01137 }
01138 }
01139 }
01140
01141 void C_SVM::setParameter(unsigned int index, double value)
01142 {
01143 MetaSVM::setParameter(index, value);
01144 if (index == 0)
01145 {
01146
01147 if (exponential)
01148 {
01149 value = exp(value);
01150 }
01151 C_plus = value;
01152 C_minus = C_ratio * value;
01153 }
01154 }
01155
01156 bool C_SVM::isFeasible()
01157 {
01158 return (C_plus > 0.0 && MetaSVM::isFeasible());
01159 }
01160
01161
01163
01164
01165 OneClassSVM::OneClassSVM(SVM* pSVM, double fractionNu)
01166 : MetaSVM(pSVM, 1)
01167 {
01168 setParameter(0, fractionNu);
01169 }
01170
01171 OneClassSVM::~OneClassSVM()
01172 {
01173 }
01174
01175
01176 void OneClassSVM::setParameter(unsigned int index, double value)
01177 {
01178 MetaSVM::setParameter(index, value);
01179 if (index == 0)
01180 {
01181
01182
01183
01184
01185 nu = value;
01186 }
01187 }
01188
01189 bool OneClassSVM::isFeasible()
01190 {
01191 return (nu > 0.0 && MetaSVM::isFeasible());
01192 }
01193
01194
01196
01197
01198 Epsilon_SVM::Epsilon_SVM(SVM* pSVM, double C, double epsilon, bool unconst)
01199 : MetaSVM(pSVM, 2)
01200 {
01201 this->C = C;
01202 this->epsilon = epsilon;
01203
01204 exponential = unconst;
01205
01206 setParameter(0, (exponential) ? log(C) : C);
01207 setParameter(1, (exponential) ? log(epsilon) : epsilon);
01208 }
01209
01210 Epsilon_SVM::~Epsilon_SVM()
01211 {
01212 }
01213
01214
01215 void Epsilon_SVM::setParameter(unsigned int index, double value)
01216 {
01217 if (index < hyperparameters)
01218 {
01219 Model::setParameter(index, value);
01220 if (index == 0)
01221 {
01222 if (exponential) C = exp(value); else C = value;
01223 }
01224 else
01225 {
01226 if (exponential) epsilon = exp(value); else epsilon = value;
01227 }
01228 }
01229 else
01230 {
01231 MetaSVM::setParameter(index, value);
01232 }
01233 }
01234
01235 bool Epsilon_SVM::isFeasible()
01236 {
01237 return (C > 0.0 && epsilon > 0.0 && MetaSVM::isFeasible());
01238 }
01239
01240
01242
01243
01244 RegularizationNetwork::RegularizationNetwork(SVM* pSVM, double gamma)
01245 : MetaSVM(pSVM, 1)
01246 {
01247 parameter(0) = gamma;
01248 }
01249
01250 RegularizationNetwork::~RegularizationNetwork()
01251 {
01252 }
01253
01254
01255 bool RegularizationNetwork::isFeasible()
01256 {
01257 return (parameter(0) > 0.0 && MetaSVM::isFeasible());
01258 }
01259
01260
01262
01263
01264 AllInOneMcSVM::AllInOneMcSVM(MultiClassSVM* pSVM, double C)
01265 : MetaSVM(pSVM, 1)
01266 {
01267 parameter(0) = C;
01268 }
01269
01270 AllInOneMcSVM::~AllInOneMcSVM()
01271 {
01272 }
01273
01274
01275 bool AllInOneMcSVM::isFeasible()
01276 {
01277 return (parameter(0) > 0.0 && MetaSVM::isFeasible());
01278 }
01279
01280
01282
01283
01284 CrammerSingerMcSVM::CrammerSingerMcSVM(MultiClassSVM* pSVM, double beta)
01285 : MetaSVM(pSVM, 1)
01286 {
01287 parameter(0) = beta;
01288 }
01289
01290 CrammerSingerMcSVM::~CrammerSingerMcSVM()
01291 {
01292 }
01293
01294
01295 bool CrammerSingerMcSVM::isFeasible()
01296 {
01297 return (parameter(0) > 0.0 && MetaSVM::isFeasible());
01298 }
01299
01300
01302
01303
01304 OVAMcSVM::OVAMcSVM(MultiClassSVM* pSVM, double C)
01305 : MetaSVM(pSVM, 1)
01306 {
01307 parameter(0) = C;
01308 }
01309
01310 OVAMcSVM::~OVAMcSVM()
01311 {
01312 }
01313
01314
01315 bool OVAMcSVM::isFeasible()
01316 {
01317 return (parameter(0) > 0.0 && MetaSVM::isFeasible());
01318 }
01319
01320
01322
01323
01324 OCCMcSVM::OCCMcSVM(MultiClassSVM* pSVM, double C)
01325 : MetaSVM(pSVM, 1)
01326 {
01327 parameter(0) = C;
01328 }
01329
01330 OCCMcSVM::~OCCMcSVM()
01331 {
01332 }
01333
01334
01335 bool OCCMcSVM::isFeasible()
01336 {
01337 return (parameter(0) > 0.0 && MetaSVM::isFeasible());
01338 }
01339
01340
01342
01343
01344 SVM_Optimizer::SVM_Optimizer()
01345 {
01346 solver = NULL;
01347 matrix = NULL;
01348 cache = NULL;
01349
01350 printInfo = false;
01351 accuracy = 0.001;
01352 cacheMB = 100;
01353 maxIter = -1;
01354 maxSeconds = -1;
01355
01356 optimal = true;
01357 }
01358
01359 SVM_Optimizer::~SVM_Optimizer()
01360 {
01361 if (solver != NULL)
01362 {
01363 delete solver;
01364 solver = NULL;
01365 }
01366 if (matrix != NULL)
01367 {
01368 delete matrix;
01369 matrix = NULL;
01370 }
01371 if (cache != NULL)
01372 {
01373 delete cache;
01374 cache = NULL;
01375 }
01376 }
01377
01378
01379 void SVM_Optimizer::init(Model& model)
01380 {
01381 C_SVM* csvm = dynamic_cast<C_SVM*>(&model);
01382 Epsilon_SVM* esvm = dynamic_cast<Epsilon_SVM*>(&model);
01383 OneClassSVM* OCsvm = dynamic_cast<OneClassSVM*>(&model);
01384 RegularizationNetwork* rn = dynamic_cast<RegularizationNetwork*>(&model);
01385 GaussianProcess* gaussproc = dynamic_cast<GaussianProcess*>(&model);
01386 AllInOneMcSVM* aio = dynamic_cast<AllInOneMcSVM*>(&model);
01387 CrammerSingerMcSVM* cs = dynamic_cast<CrammerSingerMcSVM*>(&model);
01388 OVAMcSVM* ova = dynamic_cast<OVAMcSVM*>(&model);
01389 OCCMcSVM* bc = dynamic_cast<OCCMcSVM*>(&model);
01390
01391 if (csvm != NULL)
01392 {
01393 if (csvm->is2norm()) mode = eC2;
01394 else mode = eC1;
01395 Cplus = csvm->get_Cplus();
01396 Cminus = csvm->get_Cminus();
01397 }
01398 else if (esvm != NULL)
01399 {
01400 mode = eEpsilon;
01401 C = esvm->get_C();
01402 epsilon = esvm->get_epsilon();
01403 }
01404 else if (OCsvm != NULL)
01405 {
01406 mode = e1Class;
01407 fractionOfOutliers = OCsvm->getNu();
01408 }
01409 else if (rn != NULL)
01410 {
01411 mode = eRegularizationNetwork;
01412 gamma = rn->get_gamma();
01413 }
01414 else if (gaussproc != NULL)
01415 {
01416 mode = eGaussianProcess;
01417 }
01418 else if (aio != NULL)
01419 {
01420 mode = eAllInOne;
01421 C = aio->get_C();
01422 }
01423 else if (cs != NULL)
01424 {
01425 mode = eCrammerSinger;
01426 beta = cs->get_beta();
01427 }
01428 else if (ova != NULL)
01429 {
01430 mode = eOVA;
01431 C = ova->get_C();
01432 }
01433 else if (bc != NULL)
01434 {
01435 mode = eOCC;
01436 C = bc->get_C();
01437 }
01438 else throw SHARKEXCEPTION("[SVM_Optimizer::init] The model is not a valid support vector machine meta model.");
01439
01440 if (solver != NULL)
01441 {
01442 delete solver;
01443 solver = NULL;
01444 }
01445 if (matrix != NULL)
01446 {
01447 delete matrix;
01448 matrix = NULL;
01449 }
01450 if (cache != NULL)
01451 {
01452 delete cache;
01453 cache = NULL;
01454 }
01455 }
01456
01457 double SVM_Optimizer::optimize(Model& model, ErrorFunction& error, const Array<double>& input, const Array<double>& target)
01458 {
01459 switch (mode)
01460 {
01461 case eC1:
01462 case eC2:
01463 case eEpsilon:
01464 case eNu:
01465 case eRegularizationNetwork:
01466 case e1Class:
01467 {
01468 SVM* svm = dynamic_cast<SVM*>(&model);
01469 if (svm == NULL)
01470 {
01471 MetaSVM* meta = dynamic_cast<MetaSVM*>(&model);;
01472 if (meta != NULL) svm = meta->getSVM();
01473 }
01474 if (svm == NULL) throw SHARKEXCEPTION("[SVM_Optimizer::optimize] The model is not a valid SVM or SVM meta model.");
01475
01476 return optimize(*svm, input, target);
01477 }
01478
01479 case eGaussianProcess:
01480 {
01481 GaussianProcess* gaussproc = dynamic_cast<GaussianProcess*>(&model);
01482 gaussproc->train(input, target);
01483 return 0.0;
01484 }
01485
01486 case eAllInOne:
01487 case eCrammerSinger:
01488 case eOVA:
01489 case eOCC:
01490 {
01491 MultiClassSVM* svm = dynamic_cast<MultiClassSVM*>(&model);
01492 if (svm == NULL)
01493 {
01494 MetaSVM* meta = dynamic_cast<MetaSVM*>(&model);;
01495 if (meta != NULL) svm = meta->getMultiClassSVM();
01496 }
01497 if (svm == NULL) throw SHARKEXCEPTION("[SVM_Optimizer::optimize] The model is not a valid MultiClassSVM or SVM meta model.");
01498
01499 optimize(*svm, input, target);
01500 return 0.0;
01501 }
01502
01503 default:
01504 {
01505 throw SHARKEXCEPTION("[SVM_Optimizer::optimize] call init(...) before optimize(...)");
01506 return 0.0;
01507 }
01508 }
01509 }
01510
01511 double SVM_Optimizer::optimize(SVM& model, const Array<double>& input, const Array<double>& target, bool copy)
01512 {
01513 if (solver != NULL)
01514 {
01515 delete solver;
01516 solver = NULL;
01517 }
01518 if (matrix != NULL)
01519 {
01520 delete matrix;
01521 matrix = NULL;
01522 }
01523 if (cache != NULL)
01524 {
01525 delete cache;
01526 cache = NULL;
01527 }
01528
01529 unsigned int e, examples = input.dim(0);
01530
01531 model.SetTrainingData(input, copy);
01532 KernelFunction* kernel = model.getKernel();
01533
01534 Array<double> alpha(examples);
01535 double b = 0.0;
01536 double ret = 0.0;
01537
01538 if (mode == eC1)
01539 {
01540
01541 Array<double> linear(examples);
01542 Array<double> lower(examples);
01543 Array<double> upper(examples);
01544 for (e = 0; e < examples; e++)
01545 {
01546 alpha(e) = model.getParameter(e);
01547 linear(e) = target(e, 0);
01548 if (target(e, 0) > 0.0)
01549 {
01550 lower(e) = 0.0;
01551 upper(e) = Cplus;
01552 }
01553 else
01554 {
01555 lower(e) = -Cminus;
01556 upper(e) = 0.0;
01557 }
01558 }
01559
01560 matrix = new KernelMatrix(kernel, input);
01561 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01562
01563 QpSvmDecomp* solver = new QpSvmDecomp(*cache);
01564 this->solver = solver;
01565 solver->setVerbose(printInfo);
01566 solver->setMaxIterations(maxIter);
01567 solver->setMaxSeconds(maxSeconds);
01568
01569 ret = solver->Solve(linear, lower, upper, alpha, accuracy);
01570
01571
01572 Array<double> gradient;
01573 solver->getGradient(gradient);
01574 double lowerBound = -1e100;
01575 double upperBound = 1e100;
01576 double sum = 0.0;
01577 unsigned int freeVars = 0;
01578 double value;
01579 for (e = 0; e < examples; e++)
01580 {
01581 value = gradient(e);
01582 if (alpha(e) == lower(e))
01583 {
01584 if (value > lowerBound) lowerBound = value;
01585 }
01586 else if (alpha(e) == upper(e))
01587 {
01588 if (value < upperBound) upperBound = value;
01589 }
01590 else
01591 {
01592 sum += value;
01593 freeVars++;
01594 }
01595 }
01596
01597 if (freeVars > 0)
01598 b = sum / freeVars;
01599 else
01600 b = 0.5 * (lowerBound + upperBound);
01601 }
01602 else if (mode == eC2)
01603 {
01604
01605 Array<double> linear(examples);
01606 Array<double> diag(examples);
01607 Array<double> lower(examples);
01608 Array<double> upper(examples);
01609 for (e = 0; e < examples; e++)
01610 {
01611 alpha(e) = model.getParameter(e);
01612 linear(e) = target(e, 0);
01613 if (target(e, 0) > 0.0)
01614 {
01615 diag(e) = 1.0 / Cplus;
01616 lower(e) = 0.0;
01617 upper(e) = 1e100;
01618 }
01619 else
01620 {
01621 diag(e) = 1.0 / Cminus;
01622 lower(e) = -1e100;
01623 upper(e) = 0.0;
01624 }
01625 }
01626
01627 matrix = new RegularizedKernelMatrix(kernel, input, diag);
01628 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01629
01630 QpSvmDecomp* solver = new QpSvmDecomp(*cache);
01631 this->solver = solver;
01632 solver->setVerbose(printInfo);
01633 solver->setMaxIterations(maxIter);
01634 solver->setMaxSeconds(maxSeconds);
01635
01636 ret = solver->Solve(linear, lower, upper, alpha, accuracy);
01637
01638
01639 Array<double> gradient;
01640 solver->getGradient(gradient);
01641 double lowerBound = -1e100;
01642 double upperBound = 1e100;
01643 double sum = 0.0;
01644 unsigned int freeVars = 0;
01645 double value;
01646 for (e = 0; e < examples; e++)
01647 {
01648 value = gradient(e);
01649 if (alpha(e) == lower(e))
01650 {
01651 if (value > lowerBound) lowerBound = value;
01652 }
01653 else if (alpha(e) == upper(e))
01654 {
01655 if (value < upperBound) upperBound = value;
01656 }
01657 else
01658 {
01659 sum += value;
01660 freeVars++;
01661 }
01662 }
01663
01664 if (freeVars > 0)
01665 b = sum / freeVars;
01666 else
01667 b = 0.5 * (lowerBound + upperBound);
01668 }
01669 else if (mode == eEpsilon)
01670 {
01671
01672 Array<double> solution(2*examples);
01673 Array<double> linear(2*examples);
01674 Array<double> lower(2*examples);
01675 Array<double> upper(2*examples);
01676 for (e = 0; e < examples; e++)
01677 {
01678 double p = model.getParameter(e);
01679 if (p >= 0.0)
01680 {
01681 solution(e) = p;
01682 solution(e + examples) = 0.0;
01683 }
01684 else
01685 {
01686 solution(e) = 0.0;
01687 solution(e + examples) = -p;
01688 }
01689 linear(e) = target(e, 0) - epsilon;
01690 linear(e + examples) = target(e, 0) + epsilon;
01691 lower(e) = 0.0;
01692 lower(e + examples) = -C;
01693 upper(e) = C;
01694 upper(e + examples) = 0.0;
01695 }
01696
01697 KernelMatrix* kernelmatrix = new KernelMatrix(kernel, input);
01698 matrix = new QPMatrix2(kernelmatrix);
01699 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01700
01701 QpSvmDecomp* solver = new QpSvmDecomp(*cache);
01702 this->solver = solver;
01703 solver->setVerbose(printInfo);
01704 solver->setMaxIterations(maxIter);
01705 solver->setMaxSeconds(maxSeconds);
01706
01707 ret = solver->Solve(linear, lower, upper, solution);
01708 for (e = 0; e < examples; e++)
01709 {
01710 alpha(e) = solution(e) + solution(e + examples);
01711 }
01712
01713
01714 Array<double> gradient;
01715 solver->getGradient(gradient);
01716 double lowerBound = -1e100;
01717 double upperBound = 1e100;
01718 double sum = 0.0;
01719 unsigned int freeVars = 0;
01720 double value;
01721 for (e = 0; e < examples; e++)
01722 {
01723 if (solution(e) > 0.0)
01724 {
01725 value = gradient(e);
01726 if (solution(e) < C)
01727 {
01728 sum += value;
01729 freeVars++;
01730 }
01731 else
01732 {
01733 if (value > lowerBound) lowerBound = value;
01734 }
01735 }
01736 if (solution(e + examples) < 0.0)
01737 {
01738 value = gradient(e + examples);
01739 if (solution(e + examples) > -C)
01740 {
01741 sum += value;
01742 freeVars++;
01743 }
01744 else
01745 {
01746 if (value < upperBound) upperBound = value;
01747 }
01748 }
01749 }
01750
01751 if (freeVars > 0)
01752 b = sum / freeVars;
01753 else
01754 b = 0.5 * (lowerBound + upperBound);
01755 }
01756 else if (mode == e1Class)
01757 {
01758 Array<double> linear(examples);
01759 Array<double> lower(examples);
01760 Array<double> upper(examples);
01761
01762 unsigned int NrInitialSVs = (unsigned int)(examples * fractionOfOutliers);
01763 double sumAlpha = 0;
01764 double upperBox;
01765
01766
01767
01768
01769
01770 upperBox = 1.0;
01771
01772
01773 for (e = 0; e < examples; e++)
01774 {
01775
01776 linear(e) = 0.0;
01777
01778
01779 lower(e) = 0.0;
01780 upper(e) = upperBox;
01781
01782
01783 alpha(e) = upperBox;
01784 }
01785
01786
01787 if (NrInitialSVs != examples)
01788 {
01789 int index;
01790 int diff = examples - NrInitialSVs;
01791
01792 for (int s = 0; s < diff; s++)
01793 {
01794
01795 index = Rng::discrete(0, examples - 1);
01796
01797 while (alpha(index) == 0)
01798 {
01799
01800 index = Rng::discrete(0, examples - 1);
01801 }
01802
01803 alpha(index) = 0;
01804 }
01805
01806
01807 sumAlpha = 0.0;
01808 for (unsigned int e = 0; e < examples; e++)
01809 sumAlpha += alpha(e);
01810
01811 if (sumAlpha < (examples * fractionOfOutliers))
01812 {
01813
01814 index = Rng::discrete(0, examples - 1);
01815 while (alpha(index) != 0)
01816 {
01817
01818 index = Rng::discrete(0, examples - 1);
01819 }
01820
01821 alpha(index) = (examples * fractionOfOutliers) - sumAlpha;
01822 }
01823 }
01824
01825 matrix = new KernelMatrix(kernel, input);
01826 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01827
01828 QpSvmDecomp* solver = new QpSvmDecomp(*cache);
01829 this->solver = solver;
01830 solver->setVerbose(printInfo);
01831 solver->setMaxIterations(maxIter);
01832 solver->setMaxSeconds(maxSeconds);
01833
01834
01835 ret = solver->Solve(linear, lower, upper, alpha, accuracy);
01836
01837
01838 Array<double> gradient;
01839 solver->getGradient(gradient);
01840 double lowerBound = -1e100;
01841 double upperBound = 1e100;
01842 double sum = 0.0;
01843 unsigned int freeVars = 0;
01844 double value;
01845
01846 for (e = 0; e < examples; e++)
01847 {
01848 value = gradient(e);
01849 if (alpha(e) == lower(e))
01850 {
01851 if (value > lowerBound) lowerBound = value;
01852 }
01853 else if (alpha(e) == upper(e))
01854 {
01855 if (value < upperBound) upperBound = value;
01856 }
01857 else
01858 {
01859 sum += value;
01860 freeVars++;
01861 }
01862 }
01863
01864 if (freeVars > 0)
01865 b = sum / freeVars;
01866 else
01867 b = 0.5 * (lowerBound + upperBound);
01868 }
01869 else if (mode == eRegularizationNetwork)
01870 {
01871 unsigned int f;
01872 Array2D<double> K(examples, examples);
01873 Array2D<double> invK(examples, examples);
01874 for (e = 0; e < examples; e++)
01875 {
01876 for (f = 0; f < e; f++)
01877 {
01878 double k = kernel->eval(input[e], input[f]);
01879 K(e, f) = K(f, e) = k;
01880 }
01881 double k = kernel->eval(input[e], input[e]);
01882 K(e, e) = k + gamma;
01883 }
01884 invertSymm(invK, K);
01885 matColVec(alpha, invK, target, 0);
01886
01887 b = 0.0;
01888 ret = 0.0;
01889 }
01890
01891 for (e = 0; e < examples; e++) model.setParameter(e, alpha(e));
01892 model.setParameter(examples, b);
01893
01894 model.MakeSparse();
01895
01896 return ret;
01897 }
01898
01899 void SVM_Optimizer::optimize(MultiClassSVM& model, const Array<double>& input, const Array<double>& target, bool copy)
01900 {
01901 if (solver != NULL)
01902 {
01903 delete solver;
01904 solver = NULL;
01905 }
01906 if (matrix != NULL)
01907 {
01908 delete matrix;
01909 matrix = NULL;
01910 }
01911 if (cache != NULL)
01912 {
01913 delete cache;
01914 cache = NULL;
01915 }
01916
01917 unsigned int i;
01918 unsigned int examples = input.dim(0);
01919 unsigned int classes = model.getClasses();
01920 unsigned int variables = examples * classes;
01921
01922 model.SetTrainingData(input, copy);
01923 KernelFunction* kernel = model.getKernel();
01924
01925 if (mode == eAllInOne)
01926 {
01927 Array<double> alpha(variables);
01928 for (i = 0; i < variables; i++) alpha(i) = model.getParameter(i);
01929
01930 matrix = new KernelMatrix(kernel, input);
01931 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01932 Array<double> prototypes(Matrix::unitmatrix(classes));
01933
01934 QpBoxAllInOneDecomp* solver = new QpBoxAllInOneDecomp(*cache);
01935 this->solver = solver;
01936 solver->setMaxIterations(maxIter);
01937 solver->Solve(classes, target, prototypes, C, alpha, accuracy);
01938
01939 i = 0;
01940 unsigned int e, c, p, m;
01941 for (e = 0; e < examples; e++)
01942 {
01943 double sum = 0.0;
01944 p = (unsigned int)target(e, 0);
01945 for (c = 0; c < classes; c++)
01946 {
01947 if (c == p)
01948 {
01949 i++;
01950 continue;
01951 }
01952 double len2 = 0.0;
01953 for (m = 0; m < classes; m++)
01954 {
01955 double diff = prototypes(p, m) - prototypes(c, m);
01956 len2 += diff * diff;
01957 }
01958 double value = 0.5 * alpha(i) / sqrt(len2);
01959 model.setParameter(i, -value);
01960 sum += value;
01961 i++;
01962 }
01963
01964 model.setParameter(e * classes + p, sum);
01965 }
01966 optimal = solver->isOptimal();
01967
01968 }
01969 else if (mode == eCrammerSinger)
01970 {
01971 Array<double> alpha(variables);
01972 for (i = 0; i < variables; i++) alpha(i) = model.getParameter(i);
01973
01974 matrix = new KernelMatrix(kernel, input);
01975 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01976
01977 QpCrammerSingerDecomp* solver = new QpCrammerSingerDecomp(*cache, target, classes);
01978 solver->setMaxIterations(maxIter);
01979 this->solver = solver;
01980
01981
01982 solver->Solve(alpha, beta, beta / 2.0 * accuracy);
01983 optimal = solver->isOptimal();
01984
01985 for (i = 0; i < variables; i++) model.setParameter(i, alpha(i));
01986 }
01987 else if (mode == eOVA)
01988 {
01989 Array<double> alpha(examples);
01990 Array<double> linear(examples);
01991 Array<double> lower(examples);
01992 Array<double> upper(examples);
01993
01994
01995 unsigned int c, e;
01996 matrix = new KernelMatrix(kernel, input);
01997 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
01998
01999 QpBoxDecomp* solver = new QpBoxDecomp(*cache);
02000 solver->setMaxIterations(maxIter);
02001 this->solver = solver;
02002
02003 for (c = 0; c < classes; c++)
02004 {
02005 for (e = 0; e < examples; e++)
02006 {
02007 alpha(e) = model.getParameter(e * classes + c);
02008 if (target(e, 0) == c)
02009 {
02010 linear(e) = 1.0;
02011 lower(e) = 0.0;
02012 upper(e) = C;
02013 }
02014 else
02015 {
02016 linear(e) = -1.0;
02017 lower(e) = -C;
02018 upper(e) = 0.0;
02019 }
02020 }
02021 solver->Solve(linear, lower, upper, alpha, accuracy);
02022 optimal = solver->isOptimal();
02023
02024 for (e = 0; e < examples; e++)
02025 {
02026 model.setParameter(e * classes + c, alpha(e));
02027 }
02028 }
02029 }
02030 else if (mode == eOCC)
02031 {
02032 Array<double> alpha(examples);
02033 Array<double> linear(examples);
02034 Array<double> lower(examples);
02035 Array<double> upper(examples);
02036
02037 unsigned int c, e;
02038 Array<double> prototypes(Matrix::unitmatrix(classes));
02039 matrix = new InputLabelMatrix(kernel, input, target, prototypes);
02040 cache = new CachedMatrix(matrix, 1048576 * cacheMB / sizeof(float));
02041
02042 QpBoxDecomp* solver = new QpBoxDecomp(*cache);
02043 solver->setMaxIterations(maxIter);
02044 this->solver = solver;
02045
02046 for (e = 0; e < examples; e++)
02047 {
02048 c = (unsigned int)target(e, 0);
02049 alpha(e) = model.getParameter(e * classes + c);
02050 linear(e) = 1.0;
02051 lower(e) = 0.0;
02052 upper(e) = C;
02053 }
02054 solver->Solve(linear, lower, upper, alpha, accuracy);
02055 optimal = solver->isOptimal();
02056
02057 for (e = 0; e < examples; e++)
02058 {
02059 unsigned int label = (unsigned int)target(e, 0);
02060 for (c = 0; c < classes; c++)
02061 {
02062 double value = (label == c) ? alpha(e) : 0.0;
02063 model.setParameter(e * classes + c, value);
02064 }
02065 }
02066 }
02067
02068
02069 for (i = 0; i < classes; i++) model.setParameter(variables + i, 0.0);
02070
02071
02072
02073 }
02074
02075
02076 ErrorFunction& SVM_Optimizer::dummyError = * ((ErrorFunction*) NULL);
02077