📄 smo.c
字号:
/* -------------------------------------------------------------------- [Alpha,bias,nsv,kercnt,trnerr,margin]= smo(data,labels,ker,arg,C,eps,tol,Alpha,bias ) Sequential Minimal Optimizer for Support Vector Machines. Make executable file by command 'mex smo.c kernel.c'. mandatory inputs: data [D x N ] matrix of N training D-dimensional patterns. labels [1 x N] pattern labels (1 for 1st class, 2 for 2nd class ). ker [string] kernel identifier: 'linear', 'poly', 'rbf'. arg [real] kernel argument. C [real] or [2 x real] one trade-off constant for both the classes or two constants for the first and the second class. optional inputs: eps [real] tolerance of KKT-conditions fulfilment (default 0.001). tol [real] minimal change of optimized Lagrangeians (default 0.001). Alpha [1xL] initial values of optimized Lagrangeians. If not given then SMO starts up from Alpha = zeros(1,L). bias [real] initial value of the threshold. If not given then SMO starts from bias = 0. mandatory outputs: Alpha [1 x N] found Lagrangeian multipliers. bias [real] found bias. optional outputs: nsv [real] number of Support Vectors (number of Alpha > ZERO_LIM). kercnt [int] number of kernel evaluations. trnerr [real] classification error on training data. margin [real] margin between classes and the found hyperplane. Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac (c) Czech Technical University Prague, http://cmp.felk.cvut.cz Modifications: 23-october-2001, V.Franc 16-October-2001, V.Franc 27-september-2001, V.Franc, roundig of a2 in takeStep removed. 23-September-2001, V.Franc, different trade-off C1 and C2. 22-September-2001, V.Franc, kernel.c used. 19-September-2001, V.Franc, computation of nsv and nerr added. 17-September-2001, V.Franc, created. -------------------------------------------------------------------- */#include "mex.h"#include "matrix.h"#include <math.h>#include <stdlib.h>#include <string.h>#include "kernel.h"/* case insensitive string comparision */#ifdef __BORLANDC__ #define STR_COMPARE(A,B,C) strncmpi(A,B,C) /* Borland */#else #define STR_COMPARE(A,B,C) strncmp(A,B,C) /* Linux gcc */#endif/* if RANDOM is defined then a random element is used within optimization procedure as originally suggested. */#define RANDOM#define ZERO_LIM 1e-9 /* patterns with alpha > ZERO_LIM are SV */#define MAX(A,B) (((A) > (B)) ? (A) : (B) )#define MIN(A,B) (((A) < (B)) ? (A) : (B) )#define C(arg) (target[arg] > 0 ? C1 : C2)/* --- Global variables ---------------------------------------------- */long N = 0; /* number of training patterns */double C1=1; /* trade-off constant for the 1st class */double C2=1; /* trade-off constant for the 2nd class */double tolerance=0.001; /* tolerance in KKT fulfilment */double eps=0.001; /* minimal Lagrangeian change */double *data; /* pointer at patterns */double *target; /* pointer at labels */double *error_cache; /* error cache */double *alpha; /* Lagrange multipliers */double *b; /* Bias (threshold) *//* ============================================================== Implementation of Sequential Minimal Optimizer (SMO)============================================================== *//* -------------------------------------------------------------- Computes value of the learned function for k-th pattern.-------------------------------------------------------------- */double learned_func( long k ){ double s = 0.; long i; for( i = 0; i < N; i++ ) { if( alpha[i] > 0 ) s += alpha[i]*target[i]*kernel(i,k); } s -= *b; return( s );}/* -------------------------------------------------------------- Optimizes objective function for i1-th and i2-th pattern.-------------------------------------------------------------- */long takeStep( long i1, long i2 ) { double y1, y2, s; long i; double alpha1, alpha2; double a1, a2; double E1, E2, L, H, k11, k22, k12, eta, Lobj, Hobj; double gamma; double c1, c2; double t; double b1, b2, bnew; double delta_b; double t1, t2; if( i1 == i2 ) return( 0 ); alpha1 = alpha[i1]; y1 = target[i1]; if( alpha1 > 0 && alpha1 < C(i1) ) E1 = error_cache[i1]; else E1 = learned_func(i1) - y1; alpha2 = alpha[i2]; y2 = target[i2]; if( alpha2 > 0 && alpha2 < C(i2) ) E2 = error_cache[i2]; else E2 = learned_func(i2) - y2; s = y1 * y2; if(s < 0) {
L = MAX(0, alpha2 - alpha1);
H = MIN(C(i2), C(i1) + alpha2 - alpha1);
}
else
{
L = MAX(0, alpha2 + alpha1 - C(i1) );
H = MIN(C(i2), alpha2 + alpha1);
}
if( L == H ) return( 0 ); k11 = kernel(i1,i1); k12 = kernel(i1,i2); k22 = kernel(i2,i2); eta = 2 * k12 - k11 - k22; if( eta < 0 ) { a2 = alpha2 + y2 * (E2 - E1) / eta; if( a2 < L ) a2 = L; else if( a2 > H ) a2 = H; } else { c1 = eta/2; c2 = y2 * (E1-E2)- eta * alpha2; Lobj = c1 * L * L + c2 * L; Hobj = c1 * H * H + c2 * H; if( Lobj > Hobj+eps ) a2 = L; else if( Lobj < Hobj-eps ) a2 = H; else a2 = alpha2; } if( fabs(a2-alpha2) < eps*(a2+alpha2+eps )) return( 0 ); a1 = alpha1 - s * (a2 - alpha2 ); if( a1 < 0 ) { a2 += s * a1; a1 = 0; } else if( a1 > C(i1) ) { t = a1-C(i1); a2 += s * t; a1 = C(i1); } if( a1 > 0 && a1 < C(i1) ) bnew = *b + E1 + y1 * (a1 - alpha1) * k11 + y2 * (a2 - alpha2) * k12; else { if( a2 > 0 && a2 < C(i2) ) bnew = *b + E2 + y1 *(a1 - alpha1)*k12 + y2*(a2 - alpha2) * k22; else { b1 = *b + E1 + y1 * (a1 - alpha1) * k11 + y2 * (a2 - alpha2) * k12; b2 = *b + E2 + y1 * (a1 - alpha1) * k12 + y2 * (a2 - alpha2) * k22; bnew = (b1 + b2) / 2; } } delta_b = bnew - *b; *b = bnew; t1 = y1 * (a1-alpha1); t2 = y2 * (a2-alpha2); for( i = 0; i < N; i++ ) { if (0 < alpha[i] && alpha[i] < C(i)) { error_cache[i] += t1 * kernel(i1,i) + t2 * kernel(i2,i) - delta_b; } } error_cache[i1] = 0; error_cache[i2] = 0; alpha[i1] = a1; /* Store a1 in the alpha array.*/ alpha[i2] = a2; /* Store a2 in the alpha array.*/ return( 1 );}/* -------------------------------------------------------------- Finds the second Lagrange multiplayer to be optimize.-------------------------------------------------------------- */long examineExample( long i1 ){ double y1, alpha1, E1, r1; double tmax; double E2, temp; long k, i2; long k0; y1 = target[i1]; alpha1 = alpha[i1]; if( alpha1 > 0 && alpha1 < C(i1) ) E1 = error_cache[i1]; else E1 = learned_func(i1) - y1; r1 = y1 * E1; if(( r1 < -tolerance && alpha1 < C(i1) ) || (r1 > tolerance && alpha1 > 0)) { /* Try i2 by three ways; if successful, then immediately return 1; */ for( i2 = (-1), tmax = 0, k = 0; k < N; k++ ) { if( alpha[k] > 0 && alpha[k] < C(k) ) { E2 = error_cache[k]; temp = fabs(E1 - E2); if( temp > tmax ) { tmax = temp; i2 = k; } } } if( i2 >= 0 ) { if( takeStep(i1,i2) ) return( 1 ); }#ifdef RANDOM for( k0 = rand(), k = k0; k < N + k0; k++ ) { i2 = k % N;#else for( k = 0; k < N; k++) { i2 = k;#endif if( alpha[i2] > 0 && alpha[i2] < C(i2) ) { if( takeStep(i1,i2) ) return( 1 ); } }#ifdef RANDOM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -