libsvm-3.21+ds/0000755000175000017500000000000012654255166012647 5ustar ctsai12ctsai12libsvm-3.21+ds/svm.cpp0000644000175000017500000017650412633544336014172 0ustar ctsai12ctsai12#include #include #include #include #include #include #include #include #include #include "svm.h" int libsvm_version = LIBSVM_VERSION; typedef float Qfloat; typedef signed char schar; #ifndef min template static inline T min(T x,T y) { return (x static inline T max(T x,T y) { return (x>y)?x:y; } #endif template static inline void swap(T& x, T& y) { T t=x; x=y; y=t; } template static inline void clone(T*& dst, S* src, int n) { dst = new T[n]; memcpy((void *)dst,(void *)src,sizeof(T)*n); } static inline double powi(double base, int times) { double tmp = base, ret = 1.0; for(int t=times; t>0; t/=2) { if(t%2==1) ret*=tmp; tmp = tmp * tmp; } return ret; } #define INF HUGE_VAL #define TAU 1e-12 #define Malloc(type,n) (type *)malloc((n)*sizeof(type)) static void print_string_stdout(const char *s) { fputs(s,stdout); fflush(stdout); } static void (*svm_print_string) (const char *) = &print_string_stdout; #if 1 static void info(const char *fmt,...) { char buf[BUFSIZ]; va_list ap; va_start(ap,fmt); vsprintf(buf,fmt,ap); va_end(ap); (*svm_print_string)(buf); } #else static void info(const char *fmt,...) {} #endif // // Kernel Cache // // l is the number of total data items // size is the cache size limit in bytes // class Cache { public: Cache(int l,long int size); ~Cache(); // request data [0,len) // return some position p where [p,len) need to be filled // (p >= len if nothing needs to be filled) int get_data(const int index, Qfloat **data, int len); void swap_index(int i, int j); private: int l; long int size; struct head_t { head_t *prev, *next; // a circular list Qfloat *data; int len; // data[0,len) is cached in this entry }; head_t *head; head_t lru_head; void lru_delete(head_t *h); void lru_insert(head_t *h); }; Cache::Cache(int l_,long int size_):l(l_),size(size_) { head = (head_t *)calloc(l,sizeof(head_t)); // initialized to 0 size /= sizeof(Qfloat); size -= l * sizeof(head_t) / sizeof(Qfloat); size = max(size, 2 * (long int) l); // cache must be large enough for two columns lru_head.next = lru_head.prev = &lru_head; } Cache::~Cache() { for(head_t *h = lru_head.next; h != &lru_head; h=h->next) free(h->data); free(head); } void Cache::lru_delete(head_t *h) { // delete from current location h->prev->next = h->next; h->next->prev = h->prev; } void Cache::lru_insert(head_t *h) { // insert to last position h->next = &lru_head; h->prev = lru_head.prev; h->prev->next = h; h->next->prev = h; } int Cache::get_data(const int index, Qfloat **data, int len) { head_t *h = &head[index]; if(h->len) lru_delete(h); int more = len - h->len; if(more > 0) { // free old space while(size < more) { head_t *old = lru_head.next; lru_delete(old); free(old->data); size += old->len; old->data = 0; old->len = 0; } // allocate new space h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len); size -= more; swap(h->len,len); } lru_insert(h); *data = h->data; return len; } void Cache::swap_index(int i, int j) { if(i==j) return; if(head[i].len) lru_delete(&head[i]); if(head[j].len) lru_delete(&head[j]); swap(head[i].data,head[j].data); swap(head[i].len,head[j].len); if(head[i].len) lru_insert(&head[i]); if(head[j].len) lru_insert(&head[j]); if(i>j) swap(i,j); for(head_t *h = lru_head.next; h!=&lru_head; h=h->next) { if(h->len > i) { if(h->len > j) swap(h->data[i],h->data[j]); else { // give up lru_delete(h); free(h->data); size += h->len; h->data = 0; h->len = 0; } } } } // // Kernel evaluation // // the static method k_function is for doing single kernel evaluation // the constructor of Kernel prepares to calculate the l*l kernel matrix // the member function get_Q is for getting one column from the Q Matrix // class QMatrix { public: virtual Qfloat *get_Q(int column, int len) const = 0; virtual double *get_QD() const = 0; virtual void swap_index(int i, int j) const = 0; virtual ~QMatrix() {} }; class Kernel: public QMatrix { public: Kernel(int l, svm_node * const * x, const svm_parameter& param); virtual ~Kernel(); static double k_function(const svm_node *x, const svm_node *y, const svm_parameter& param); virtual Qfloat *get_Q(int column, int len) const = 0; virtual double *get_QD() const = 0; virtual void swap_index(int i, int j) const // no so const... { swap(x[i],x[j]); if(x_square) swap(x_square[i],x_square[j]); } protected: double (Kernel::*kernel_function)(int i, int j) const; private: const svm_node **x; double *x_square; // svm_parameter const int kernel_type; const int degree; const double gamma; const double coef0; static double dot(const svm_node *px, const svm_node *py); double kernel_linear(int i, int j) const { return dot(x[i],x[j]); } double kernel_poly(int i, int j) const { return powi(gamma*dot(x[i],x[j])+coef0,degree); } double kernel_rbf(int i, int j) const { return exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); } double kernel_sigmoid(int i, int j) const { return tanh(gamma*dot(x[i],x[j])+coef0); } double kernel_precomputed(int i, int j) const { return x[i][(int)(x[j][0].value)].value; } }; Kernel::Kernel(int l, svm_node * const * x_, const svm_parameter& param) :kernel_type(param.kernel_type), degree(param.degree), gamma(param.gamma), coef0(param.coef0) { switch(kernel_type) { case LINEAR: kernel_function = &Kernel::kernel_linear; break; case POLY: kernel_function = &Kernel::kernel_poly; break; case RBF: kernel_function = &Kernel::kernel_rbf; break; case SIGMOID: kernel_function = &Kernel::kernel_sigmoid; break; case PRECOMPUTED: kernel_function = &Kernel::kernel_precomputed; break; } clone(x,x_,l); if(kernel_type == RBF) { x_square = new double[l]; for(int i=0;iindex != -1 && py->index != -1) { if(px->index == py->index) { sum += px->value * py->value; ++px; ++py; } else { if(px->index > py->index) ++py; else ++px; } } return sum; } double Kernel::k_function(const svm_node *x, const svm_node *y, const svm_parameter& param) { switch(param.kernel_type) { case LINEAR: return dot(x,y); case POLY: return powi(param.gamma*dot(x,y)+param.coef0,param.degree); case RBF: { double sum = 0; while(x->index != -1 && y->index !=-1) { if(x->index == y->index) { double d = x->value - y->value; sum += d*d; ++x; ++y; } else { if(x->index > y->index) { sum += y->value * y->value; ++y; } else { sum += x->value * x->value; ++x; } } } while(x->index != -1) { sum += x->value * x->value; ++x; } while(y->index != -1) { sum += y->value * y->value; ++y; } return exp(-param.gamma*sum); } case SIGMOID: return tanh(param.gamma*dot(x,y)+param.coef0); case PRECOMPUTED: //x: test (validation), y: SV return x[(int)(y->value)].value; default: return 0; // Unreachable } } // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918 // Solves: // // min 0.5(\alpha^T Q \alpha) + p^T \alpha // // y^T \alpha = \delta // y_i = +1 or -1 // 0 <= alpha_i <= Cp for y_i = 1 // 0 <= alpha_i <= Cn for y_i = -1 // // Given: // // Q, p, y, Cp, Cn, and an initial feasible point \alpha // l is the size of vectors and matrices // eps is the stopping tolerance // // solution will be put in \alpha, objective value will be put in obj // class Solver { public: Solver() {}; virtual ~Solver() {}; struct SolutionInfo { double obj; double rho; double upper_bound_p; double upper_bound_n; double r; // for Solver_NU }; void Solve(int l, const QMatrix& Q, const double *p_, const schar *y_, double *alpha_, double Cp, double Cn, double eps, SolutionInfo* si, int shrinking); protected: int active_size; schar *y; double *G; // gradient of objective function enum { LOWER_BOUND, UPPER_BOUND, FREE }; char *alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE double *alpha; const QMatrix *Q; const double *QD; double eps; double Cp,Cn; double *p; int *active_set; double *G_bar; // gradient, if we treat free variables as 0 int l; bool unshrink; // XXX double get_C(int i) { return (y[i] > 0)? Cp : Cn; } void update_alpha_status(int i) { if(alpha[i] >= get_C(i)) alpha_status[i] = UPPER_BOUND; else if(alpha[i] <= 0) alpha_status[i] = LOWER_BOUND; else alpha_status[i] = FREE; } bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; } bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; } bool is_free(int i) { return alpha_status[i] == FREE; } void swap_index(int i, int j); void reconstruct_gradient(); virtual int select_working_set(int &i, int &j); virtual double calculate_rho(); virtual void do_shrinking(); private: bool be_shrunk(int i, double Gmax1, double Gmax2); }; void Solver::swap_index(int i, int j) { Q->swap_index(i,j); swap(y[i],y[j]); swap(G[i],G[j]); swap(alpha_status[i],alpha_status[j]); swap(alpha[i],alpha[j]); swap(p[i],p[j]); swap(active_set[i],active_set[j]); swap(G_bar[i],G_bar[j]); } void Solver::reconstruct_gradient() { // reconstruct inactive elements of G from G_bar and free variables if(active_size == l) return; int i,j; int nr_free = 0; for(j=active_size;j 2*active_size*(l-active_size)) { for(i=active_size;iget_Q(i,active_size); for(j=0;jget_Q(i,l); double alpha_i = alpha[i]; for(j=active_size;jl = l; this->Q = &Q; QD=Q.get_QD(); clone(p, p_,l); clone(y, y_,l); clone(alpha,alpha_,l); this->Cp = Cp; this->Cn = Cn; this->eps = eps; unshrink = false; // initialize alpha_status { alpha_status = new char[l]; for(int i=0;iINT_MAX/100 ? INT_MAX : 100*l); int counter = min(l,1000)+1; while(iter < max_iter) { // show progress and do shrinking if(--counter == 0) { counter = min(l,1000); if(shrinking) do_shrinking(); info("."); } int i,j; if(select_working_set(i,j)!=0) { // reconstruct the whole gradient reconstruct_gradient(); // reset active set size and check active_size = l; info("*"); if(select_working_set(i,j)!=0) break; else counter = 1; // do shrinking next iteration } ++iter; // update alpha[i] and alpha[j], handle bounds carefully const Qfloat *Q_i = Q.get_Q(i,active_size); const Qfloat *Q_j = Q.get_Q(j,active_size); double C_i = get_C(i); double C_j = get_C(j); double old_alpha_i = alpha[i]; double old_alpha_j = alpha[j]; if(y[i]!=y[j]) { double quad_coef = QD[i]+QD[j]+2*Q_i[j]; if (quad_coef <= 0) quad_coef = TAU; double delta = (-G[i]-G[j])/quad_coef; double diff = alpha[i] - alpha[j]; alpha[i] += delta; alpha[j] += delta; if(diff > 0) { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = diff; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = -diff; } } if(diff > C_i - C_j) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = C_i - diff; } } else { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = C_j + diff; } } } else { double quad_coef = QD[i]+QD[j]-2*Q_i[j]; if (quad_coef <= 0) quad_coef = TAU; double delta = (G[i]-G[j])/quad_coef; double sum = alpha[i] + alpha[j]; alpha[i] -= delta; alpha[j] += delta; if(sum > C_i) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = sum - C_i; } } else { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = sum; } } if(sum > C_j) { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = sum - C_j; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = sum; } } } // update G double delta_alpha_i = alpha[i] - old_alpha_i; double delta_alpha_j = alpha[j] - old_alpha_j; for(int k=0;k= max_iter) { if(active_size < l) { // reconstruct the whole gradient to calculate objective value reconstruct_gradient(); active_size = l; info("*"); } fprintf(stderr,"\nWARNING: reaching max number of iterations\n"); } // calculate rho si->rho = calculate_rho(); // calculate objective value { double v = 0; int i; for(i=0;iobj = v/2; } // put back the solution { for(int i=0;iupper_bound_p = Cp; si->upper_bound_n = Cn; info("\noptimization finished, #iter = %d\n",iter); delete[] p; delete[] y; delete[] alpha; delete[] alpha_status; delete[] active_set; delete[] G; delete[] G_bar; } // return 1 if already optimal, return 0 otherwise int Solver::select_working_set(int &out_i, int &out_j) { // return i,j such that // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) // j: minimizes the decrease of obj value // (if quadratic coefficeint <= 0, replace it with tau) // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) double Gmax = -INF; double Gmax2 = -INF; int Gmax_idx = -1; int Gmin_idx = -1; double obj_diff_min = INF; for(int t=0;t= Gmax) { Gmax = -G[t]; Gmax_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmax) { Gmax = G[t]; Gmax_idx = t; } } int i = Gmax_idx; const Qfloat *Q_i = NULL; if(i != -1) // NULL Q_i not accessed: Gmax=-INF if i=-1 Q_i = Q->get_Q(i,active_size); for(int j=0;j= Gmax2) Gmax2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff= Gmax-G[j]; if (-G[j] >= Gmax2) Gmax2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(Gmax+Gmax2 < eps || Gmin_idx == -1) return 1; out_i = Gmax_idx; out_j = Gmin_idx; return 0; } bool Solver::be_shrunk(int i, double Gmax1, double Gmax2) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax2); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax1); } else return(false); } void Solver::do_shrinking() { int i; double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } // find maximal violating pair first for(i=0;i= Gmax1) Gmax1 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax2) Gmax2 = G[i]; } } else { if(!is_upper_bound(i)) { if(-G[i] >= Gmax2) Gmax2 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax1) Gmax1 = G[i]; } } } if(unshrink == false && Gmax1 + Gmax2 <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; info("*"); } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2)) { swap_index(i,active_size); break; } active_size--; } } } double Solver::calculate_rho() { double r; int nr_free = 0; double ub = INF, lb = -INF, sum_free = 0; for(int i=0;i0) r = sum_free/nr_free; else r = (ub+lb)/2; return r; } // // Solver for nu-svm classification and regression // // additional constraint: e^T \alpha = constant // class Solver_NU: public Solver { public: Solver_NU() {} void Solve(int l, const QMatrix& Q, const double *p, const schar *y, double *alpha, double Cp, double Cn, double eps, SolutionInfo* si, int shrinking) { this->si = si; Solver::Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking); } private: SolutionInfo *si; int select_working_set(int &i, int &j); double calculate_rho(); bool be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4); void do_shrinking(); }; // return 1 if already optimal, return 0 otherwise int Solver_NU::select_working_set(int &out_i, int &out_j) { // return i,j such that y_i = y_j and // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) // j: minimizes the decrease of obj value // (if quadratic coefficeint <= 0, replace it with tau) // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) double Gmaxp = -INF; double Gmaxp2 = -INF; int Gmaxp_idx = -1; double Gmaxn = -INF; double Gmaxn2 = -INF; int Gmaxn_idx = -1; int Gmin_idx = -1; double obj_diff_min = INF; for(int t=0;t= Gmaxp) { Gmaxp = -G[t]; Gmaxp_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmaxn) { Gmaxn = G[t]; Gmaxn_idx = t; } } int ip = Gmaxp_idx; int in = Gmaxn_idx; const Qfloat *Q_ip = NULL; const Qfloat *Q_in = NULL; if(ip != -1) // NULL Q_ip not accessed: Gmaxp=-INF if ip=-1 Q_ip = Q->get_Q(ip,active_size); if(in != -1) Q_in = Q->get_Q(in,active_size); for(int j=0;j= Gmaxp2) Gmaxp2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[ip]+QD[j]-2*Q_ip[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff=Gmaxn-G[j]; if (-G[j] >= Gmaxn2) Gmaxn2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[in]+QD[j]-2*Q_in[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1) return 1; if (y[Gmin_idx] == +1) out_i = Gmaxp_idx; else out_i = Gmaxn_idx; out_j = Gmin_idx; return 0; } bool Solver_NU::be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax4); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax3); } else return(false); } void Solver_NU::do_shrinking() { double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) } double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) } double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) } // find maximal violating pair first int i; for(i=0;i Gmax1) Gmax1 = -G[i]; } else if(-G[i] > Gmax4) Gmax4 = -G[i]; } if(!is_lower_bound(i)) { if(y[i]==+1) { if(G[i] > Gmax2) Gmax2 = G[i]; } else if(G[i] > Gmax3) Gmax3 = G[i]; } } if(unshrink == false && max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4)) { swap_index(i,active_size); break; } active_size--; } } } double Solver_NU::calculate_rho() { int nr_free1 = 0,nr_free2 = 0; double ub1 = INF, ub2 = INF; double lb1 = -INF, lb2 = -INF; double sum_free1 = 0, sum_free2 = 0; for(int i=0;i 0) r1 = sum_free1/nr_free1; else r1 = (ub1+lb1)/2; if(nr_free2 > 0) r2 = sum_free2/nr_free2; else r2 = (ub2+lb2)/2; si->r = (r1+r2)/2; return (r1-r2)/2; } // // Q matrices for various formulations // class SVC_Q: public Kernel { public: SVC_Q(const svm_problem& prob, const svm_parameter& param, const schar *y_) :Kernel(prob.l, prob.x, param) { clone(y,y_,prob.l); cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); QD = new double[prob.l]; for(int i=0;i*kernel_function)(i,i); } Qfloat *get_Q(int i, int len) const { Qfloat *data; int start, j; if((start = cache->get_data(i,&data,len)) < len) { for(j=start;j*kernel_function)(i,j)); } return data; } double *get_QD() const { return QD; } void swap_index(int i, int j) const { cache->swap_index(i,j); Kernel::swap_index(i,j); swap(y[i],y[j]); swap(QD[i],QD[j]); } ~SVC_Q() { delete[] y; delete cache; delete[] QD; } private: schar *y; Cache *cache; double *QD; }; class ONE_CLASS_Q: public Kernel { public: ONE_CLASS_Q(const svm_problem& prob, const svm_parameter& param) :Kernel(prob.l, prob.x, param) { cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20))); QD = new double[prob.l]; for(int i=0;i*kernel_function)(i,i); } Qfloat *get_Q(int i, int len) const { Qfloat *data; int start, j; if((start = cache->get_data(i,&data,len)) < len) { for(j=start;j*kernel_function)(i,j); } return data; } double *get_QD() const { return QD; } void swap_index(int i, int j) const { cache->swap_index(i,j); Kernel::swap_index(i,j); swap(QD[i],QD[j]); } ~ONE_CLASS_Q() { delete cache; delete[] QD; } private: Cache *cache; double *QD; }; class SVR_Q: public Kernel { public: SVR_Q(const svm_problem& prob, const svm_parameter& param) :Kernel(prob.l, prob.x, param) { l = prob.l; cache = new Cache(l,(long int)(param.cache_size*(1<<20))); QD = new double[2*l]; sign = new schar[2*l]; index = new int[2*l]; for(int k=0;k*kernel_function)(k,k); QD[k+l] = QD[k]; } buffer[0] = new Qfloat[2*l]; buffer[1] = new Qfloat[2*l]; next_buffer = 0; } void swap_index(int i, int j) const { swap(sign[i],sign[j]); swap(index[i],index[j]); swap(QD[i],QD[j]); } Qfloat *get_Q(int i, int len) const { Qfloat *data; int j, real_i = index[i]; if(cache->get_data(real_i,&data,l) < l) { for(j=0;j*kernel_function)(real_i,j); } // reorder and copy Qfloat *buf = buffer[next_buffer]; next_buffer = 1 - next_buffer; schar si = sign[i]; for(j=0;jl; double *minus_ones = new double[l]; schar *y = new schar[l]; int i; for(i=0;iy[i] > 0) y[i] = +1; else y[i] = -1; } Solver s; s.Solve(l, SVC_Q(*prob,*param,y), minus_ones, y, alpha, Cp, Cn, param->eps, si, param->shrinking); double sum_alpha=0; for(i=0;il)); for(i=0;il; double nu = param->nu; schar *y = new schar[l]; for(i=0;iy[i]>0) y[i] = +1; else y[i] = -1; double sum_pos = nu*l/2; double sum_neg = nu*l/2; for(i=0;ieps, si, param->shrinking); double r = si->r; info("C = %f\n",1/r); for(i=0;irho /= r; si->obj /= (r*r); si->upper_bound_p = 1/r; si->upper_bound_n = 1/r; delete[] y; delete[] zeros; } static void solve_one_class( const svm_problem *prob, const svm_parameter *param, double *alpha, Solver::SolutionInfo* si) { int l = prob->l; double *zeros = new double[l]; schar *ones = new schar[l]; int i; int n = (int)(param->nu*prob->l); // # of alpha's at upper bound for(i=0;il) alpha[n] = param->nu * prob->l - n; for(i=n+1;ieps, si, param->shrinking); delete[] zeros; delete[] ones; } static void solve_epsilon_svr( const svm_problem *prob, const svm_parameter *param, double *alpha, Solver::SolutionInfo* si) { int l = prob->l; double *alpha2 = new double[2*l]; double *linear_term = new double[2*l]; schar *y = new schar[2*l]; int i; for(i=0;ip - prob->y[i]; y[i] = 1; alpha2[i+l] = 0; linear_term[i+l] = param->p + prob->y[i]; y[i+l] = -1; } Solver s; s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, alpha2, param->C, param->C, param->eps, si, param->shrinking); double sum_alpha = 0; for(i=0;iC*l)); delete[] alpha2; delete[] linear_term; delete[] y; } static void solve_nu_svr( const svm_problem *prob, const svm_parameter *param, double *alpha, Solver::SolutionInfo* si) { int l = prob->l; double C = param->C; double *alpha2 = new double[2*l]; double *linear_term = new double[2*l]; schar *y = new schar[2*l]; int i; double sum = C * param->nu * l / 2; for(i=0;iy[i]; y[i] = 1; linear_term[i+l] = prob->y[i]; y[i+l] = -1; } Solver_NU s; s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y, alpha2, C, C, param->eps, si, param->shrinking); info("epsilon = %f\n",-si->r); for(i=0;il); Solver::SolutionInfo si; switch(param->svm_type) { case C_SVC: solve_c_svc(prob,param,alpha,&si,Cp,Cn); break; case NU_SVC: solve_nu_svc(prob,param,alpha,&si); break; case ONE_CLASS: solve_one_class(prob,param,alpha,&si); break; case EPSILON_SVR: solve_epsilon_svr(prob,param,alpha,&si); break; case NU_SVR: solve_nu_svr(prob,param,alpha,&si); break; } info("obj = %f, rho = %f\n",si.obj,si.rho); // output SVs int nSV = 0; int nBSV = 0; for(int i=0;il;i++) { if(fabs(alpha[i]) > 0) { ++nSV; if(prob->y[i] > 0) { if(fabs(alpha[i]) >= si.upper_bound_p) ++nBSV; } else { if(fabs(alpha[i]) >= si.upper_bound_n) ++nBSV; } } } info("nSV = %d, nBSV = %d\n",nSV,nBSV); decision_function f; f.alpha = alpha; f.rho = si.rho; return f; } // Platt's binary SVM Probablistic Output: an improvement from Lin et al. static void sigmoid_train( int l, const double *dec_values, const double *labels, double& A, double& B) { double prior1=0, prior0 = 0; int i; for (i=0;i 0) prior1+=1; else prior0+=1; int max_iter=100; // Maximal number of iterations double min_step=1e-10; // Minimal step taken in line search double sigma=1e-12; // For numerically strict PD of Hessian double eps=1e-5; double hiTarget=(prior1+1.0)/(prior1+2.0); double loTarget=1/(prior0+2.0); double *t=Malloc(double,l); double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize; double newA,newB,newf,d1,d2; int iter; // Initial Point and Initial Fun Value A=0.0; B=log((prior0+1.0)/(prior1+1.0)); double fval = 0.0; for (i=0;i0) t[i]=hiTarget; else t[i]=loTarget; fApB = dec_values[i]*A+B; if (fApB>=0) fval += t[i]*fApB + log(1+exp(-fApB)); else fval += (t[i] - 1)*fApB +log(1+exp(fApB)); } for (iter=0;iter= 0) { p=exp(-fApB)/(1.0+exp(-fApB)); q=1.0/(1.0+exp(-fApB)); } else { p=1.0/(1.0+exp(fApB)); q=exp(fApB)/(1.0+exp(fApB)); } d2=p*q; h11+=dec_values[i]*dec_values[i]*d2; h22+=d2; h21+=dec_values[i]*d2; d1=t[i]-p; g1+=dec_values[i]*d1; g2+=d1; } // Stopping Criteria if (fabs(g1)= min_step) { newA = A + stepsize * dA; newB = B + stepsize * dB; // New function value newf = 0.0; for (i=0;i= 0) newf += t[i]*fApB + log(1+exp(-fApB)); else newf += (t[i] - 1)*fApB +log(1+exp(fApB)); } // Check sufficient decrease if (newf=max_iter) info("Reaching maximal iterations in two-class probability estimates\n"); free(t); } static double sigmoid_predict(double decision_value, double A, double B) { double fApB = decision_value*A+B; // 1-p used later; avoid catastrophic cancellation if (fApB >= 0) return exp(-fApB)/(1.0+exp(-fApB)); else return 1.0/(1+exp(fApB)) ; } // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng static void multiclass_probability(int k, double **r, double *p) { int t,j; int iter = 0, max_iter=max(100,k); double **Q=Malloc(double *,k); double *Qp=Malloc(double,k); double pQp, eps=0.005/k; for (t=0;tmax_error) max_error=error; } if (max_error=max_iter) info("Exceeds max_iter in multiclass_prob\n"); for(t=0;tl); double *dec_values = Malloc(double,prob->l); // random shuffle for(i=0;il;i++) perm[i]=i; for(i=0;il;i++) { int j = i+rand()%(prob->l-i); swap(perm[i],perm[j]); } for(i=0;il/nr_fold; int end = (i+1)*prob->l/nr_fold; int j,k; struct svm_problem subprob; subprob.l = prob->l-(end-begin); subprob.x = Malloc(struct svm_node*,subprob.l); subprob.y = Malloc(double,subprob.l); k=0; for(j=0;jx[perm[j]]; subprob.y[k] = prob->y[perm[j]]; ++k; } for(j=end;jl;j++) { subprob.x[k] = prob->x[perm[j]]; subprob.y[k] = prob->y[perm[j]]; ++k; } int p_count=0,n_count=0; for(j=0;j0) p_count++; else n_count++; if(p_count==0 && n_count==0) for(j=begin;j 0 && n_count == 0) for(j=begin;j 0) for(j=begin;jx[perm[j]],&(dec_values[perm[j]])); // ensure +1 -1 order; reason not using CV subroutine dec_values[perm[j]] *= submodel->label[0]; } svm_free_and_destroy_model(&submodel); svm_destroy_param(&subparam); } free(subprob.x); free(subprob.y); } sigmoid_train(prob->l,dec_values,prob->y,probA,probB); free(dec_values); free(perm); } // Return parameter of a Laplace distribution static double svm_svr_probability( const svm_problem *prob, const svm_parameter *param) { int i; int nr_fold = 5; double *ymv = Malloc(double,prob->l); double mae = 0; svm_parameter newparam = *param; newparam.probability = 0; svm_cross_validation(prob,&newparam,nr_fold,ymv); for(i=0;il;i++) { ymv[i]=prob->y[i]-ymv[i]; mae += fabs(ymv[i]); } mae /= prob->l; double std=sqrt(2*mae*mae); int count=0; mae=0; for(i=0;il;i++) if (fabs(ymv[i]) > 5*std) count=count+1; else mae+=fabs(ymv[i]); mae /= (prob->l-count); info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma= %g\n",mae); free(ymv); return mae; } // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data // perm, length l, must be allocated before calling this subroutine static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **label_ret, int **start_ret, int **count_ret, int *perm) { int l = prob->l; int max_nr_class = 16; int nr_class = 0; int *label = Malloc(int,max_nr_class); int *count = Malloc(int,max_nr_class); int *data_label = Malloc(int,l); int i; for(i=0;iy[i]; int j; for(j=0;jparam = *param; model->free_sv = 0; // XXX if(param->svm_type == ONE_CLASS || param->svm_type == EPSILON_SVR || param->svm_type == NU_SVR) { // regression or one-class-svm model->nr_class = 2; model->label = NULL; model->nSV = NULL; model->probA = NULL; model->probB = NULL; model->sv_coef = Malloc(double *,1); if(param->probability && (param->svm_type == EPSILON_SVR || param->svm_type == NU_SVR)) { model->probA = Malloc(double,1); model->probA[0] = svm_svr_probability(prob,param); } decision_function f = svm_train_one(prob,param,0,0); model->rho = Malloc(double,1); model->rho[0] = f.rho; int nSV = 0; int i; for(i=0;il;i++) if(fabs(f.alpha[i]) > 0) ++nSV; model->l = nSV; model->SV = Malloc(svm_node *,nSV); model->sv_coef[0] = Malloc(double,nSV); model->sv_indices = Malloc(int,nSV); int j = 0; for(i=0;il;i++) if(fabs(f.alpha[i]) > 0) { model->SV[j] = prob->x[i]; model->sv_coef[0][j] = f.alpha[i]; model->sv_indices[j] = i+1; ++j; } free(f.alpha); } else { // classification int l = prob->l; int nr_class; int *label = NULL; int *start = NULL; int *count = NULL; int *perm = Malloc(int,l); // group training data of the same class svm_group_classes(prob,&nr_class,&label,&start,&count,perm); if(nr_class == 1) info("WARNING: training data in only one class. See README for details.\n"); svm_node **x = Malloc(svm_node *,l); int i; for(i=0;ix[perm[i]]; // calculate weighted C double *weighted_C = Malloc(double, nr_class); for(i=0;iC; for(i=0;inr_weight;i++) { int j; for(j=0;jweight_label[i] == label[j]) break; if(j == nr_class) fprintf(stderr,"WARNING: class label %d specified in weight is not found\n", param->weight_label[i]); else weighted_C[j] *= param->weight[i]; } // train k*(k-1)/2 models bool *nonzero = Malloc(bool,l); for(i=0;iprobability) { probA=Malloc(double,nr_class*(nr_class-1)/2); probB=Malloc(double,nr_class*(nr_class-1)/2); } int p = 0; for(i=0;iprobability) svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]); f[p] = svm_train_one(&sub_prob,param,weighted_C[i],weighted_C[j]); for(k=0;k 0) nonzero[si+k] = true; for(k=0;k 0) nonzero[sj+k] = true; free(sub_prob.x); free(sub_prob.y); ++p; } // build output model->nr_class = nr_class; model->label = Malloc(int,nr_class); for(i=0;ilabel[i] = label[i]; model->rho = Malloc(double,nr_class*(nr_class-1)/2); for(i=0;irho[i] = f[i].rho; if(param->probability) { model->probA = Malloc(double,nr_class*(nr_class-1)/2); model->probB = Malloc(double,nr_class*(nr_class-1)/2); for(i=0;iprobA[i] = probA[i]; model->probB[i] = probB[i]; } } else { model->probA=NULL; model->probB=NULL; } int total_sv = 0; int *nz_count = Malloc(int,nr_class); model->nSV = Malloc(int,nr_class); for(i=0;inSV[i] = nSV; nz_count[i] = nSV; } info("Total nSV = %d\n",total_sv); model->l = total_sv; model->SV = Malloc(svm_node *,total_sv); model->sv_indices = Malloc(int,total_sv); p = 0; for(i=0;iSV[p] = x[i]; model->sv_indices[p++] = perm[i] + 1; } int *nz_start = Malloc(int,nr_class); nz_start[0] = 0; for(i=1;isv_coef = Malloc(double *,nr_class-1); for(i=0;isv_coef[i] = Malloc(double,total_sv); p = 0; for(i=0;isv_coef[j-1][q++] = f[p].alpha[k]; q = nz_start[j]; for(k=0;ksv_coef[i][q++] = f[p].alpha[ci+k]; ++p; } free(label); free(probA); free(probB); free(count); free(perm); free(start); free(x); free(weighted_C); free(nonzero); for(i=0;il; int *perm = Malloc(int,l); int nr_class; if (nr_fold > l) { nr_fold = l; fprintf(stderr,"WARNING: # folds > # data. Will use # folds = # data instead (i.e., leave-one-out cross validation)\n"); } fold_start = Malloc(int,nr_fold+1); // stratified cv may not give leave-one-out rate // Each class to l folds -> some folds may have zero elements if((param->svm_type == C_SVC || param->svm_type == NU_SVC) && nr_fold < l) { int *start = NULL; int *label = NULL; int *count = NULL; svm_group_classes(prob,&nr_class,&label,&start,&count,perm); // random shuffle and then data grouped by fold using the array perm int *fold_count = Malloc(int,nr_fold); int c; int *index = Malloc(int,l); for(i=0;ix[perm[j]]; subprob.y[k] = prob->y[perm[j]]; ++k; } for(j=end;jx[perm[j]]; subprob.y[k] = prob->y[perm[j]]; ++k; } struct svm_model *submodel = svm_train(&subprob,param); if(param->probability && (param->svm_type == C_SVC || param->svm_type == NU_SVC)) { double *prob_estimates=Malloc(double,svm_get_nr_class(submodel)); for(j=begin;jx[perm[j]],prob_estimates); free(prob_estimates); } else for(j=begin;jx[perm[j]]); svm_free_and_destroy_model(&submodel); free(subprob.x); free(subprob.y); } free(fold_start); free(perm); } int svm_get_svm_type(const svm_model *model) { return model->param.svm_type; } int svm_get_nr_class(const svm_model *model) { return model->nr_class; } void svm_get_labels(const svm_model *model, int* label) { if (model->label != NULL) for(int i=0;inr_class;i++) label[i] = model->label[i]; } void svm_get_sv_indices(const svm_model *model, int* indices) { if (model->sv_indices != NULL) for(int i=0;il;i++) indices[i] = model->sv_indices[i]; } int svm_get_nr_sv(const svm_model *model) { return model->l; } double svm_get_svr_probability(const svm_model *model) { if ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && model->probA!=NULL) return model->probA[0]; else { fprintf(stderr,"Model doesn't contain information for SVR probability inference\n"); return 0; } } double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values) { int i; if(model->param.svm_type == ONE_CLASS || model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) { double *sv_coef = model->sv_coef[0]; double sum = 0; for(i=0;il;i++) sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); sum -= model->rho[0]; *dec_values = sum; if(model->param.svm_type == ONE_CLASS) return (sum>0)?1:-1; else return sum; } else { int nr_class = model->nr_class; int l = model->l; double *kvalue = Malloc(double,l); for(i=0;iSV[i],model->param); int *start = Malloc(int,nr_class); start[0] = 0; for(i=1;inSV[i-1]; int *vote = Malloc(int,nr_class); for(i=0;inSV[i]; int cj = model->nSV[j]; int k; double *coef1 = model->sv_coef[j-1]; double *coef2 = model->sv_coef[i]; for(k=0;krho[p]; dec_values[p] = sum; if(dec_values[p] > 0) ++vote[i]; else ++vote[j]; p++; } int vote_max_idx = 0; for(i=1;i vote[vote_max_idx]) vote_max_idx = i; free(kvalue); free(start); free(vote); return model->label[vote_max_idx]; } } double svm_predict(const svm_model *model, const svm_node *x) { int nr_class = model->nr_class; double *dec_values; if(model->param.svm_type == ONE_CLASS || model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) dec_values = Malloc(double, 1); else dec_values = Malloc(double, nr_class*(nr_class-1)/2); double pred_result = svm_predict_values(model, x, dec_values); free(dec_values); return pred_result; } double svm_predict_probability( const svm_model *model, const svm_node *x, double *prob_estimates) { if ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && model->probA!=NULL && model->probB!=NULL) { int i; int nr_class = model->nr_class; double *dec_values = Malloc(double, nr_class*(nr_class-1)/2); svm_predict_values(model, x, dec_values); double min_prob=1e-7; double **pairwise_prob=Malloc(double *,nr_class); for(i=0;iprobA[k],model->probB[k]),min_prob),1-min_prob); pairwise_prob[j][i]=1-pairwise_prob[i][j]; k++; } multiclass_probability(nr_class,pairwise_prob,prob_estimates); int prob_max_idx = 0; for(i=1;i prob_estimates[prob_max_idx]) prob_max_idx = i; for(i=0;ilabel[prob_max_idx]; } else return svm_predict(model, x); } static const char *svm_type_table[] = { "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL }; static const char *kernel_type_table[]= { "linear","polynomial","rbf","sigmoid","precomputed",NULL }; int svm_save_model(const char *model_file_name, const svm_model *model) { FILE *fp = fopen(model_file_name,"w"); if(fp==NULL) return -1; char *old_locale = setlocale(LC_ALL, NULL); if (old_locale) { old_locale = strdup(old_locale); } setlocale(LC_ALL, "C"); const svm_parameter& param = model->param; fprintf(fp,"svm_type %s\n", svm_type_table[param.svm_type]); fprintf(fp,"kernel_type %s\n", kernel_type_table[param.kernel_type]); if(param.kernel_type == POLY) fprintf(fp,"degree %d\n", param.degree); if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID) fprintf(fp,"gamma %g\n", param.gamma); if(param.kernel_type == POLY || param.kernel_type == SIGMOID) fprintf(fp,"coef0 %g\n", param.coef0); int nr_class = model->nr_class; int l = model->l; fprintf(fp, "nr_class %d\n", nr_class); fprintf(fp, "total_sv %d\n",l); { fprintf(fp, "rho"); for(int i=0;irho[i]); fprintf(fp, "\n"); } if(model->label) { fprintf(fp, "label"); for(int i=0;ilabel[i]); fprintf(fp, "\n"); } if(model->probA) // regression has probA only { fprintf(fp, "probA"); for(int i=0;iprobA[i]); fprintf(fp, "\n"); } if(model->probB) { fprintf(fp, "probB"); for(int i=0;iprobB[i]); fprintf(fp, "\n"); } if(model->nSV) { fprintf(fp, "nr_sv"); for(int i=0;inSV[i]); fprintf(fp, "\n"); } fprintf(fp, "SV\n"); const double * const *sv_coef = model->sv_coef; const svm_node * const *SV = model->SV; for(int i=0;ivalue)); else while(p->index != -1) { fprintf(fp,"%d:%.8g ",p->index,p->value); p++; } fprintf(fp, "\n"); } setlocale(LC_ALL, old_locale); free(old_locale); if (ferror(fp) != 0 || fclose(fp) != 0) return -1; else return 0; } static char *line = NULL; static int max_line_len; static char* readline(FILE *input) { int len; if(fgets(line,max_line_len,input) == NULL) return NULL; while(strrchr(line,'\n') == NULL) { max_line_len *= 2; line = (char *) realloc(line,max_line_len); len = (int) strlen(line); if(fgets(line+len,max_line_len-len,input) == NULL) break; } return line; } // // FSCANF helps to handle fscanf failures. // Its do-while block avoids the ambiguity when // if (...) // FSCANF(); // is used // #define FSCANF(_stream, _format, _var) do{ if (fscanf(_stream, _format, _var) != 1) return false; }while(0) bool read_model_header(FILE *fp, svm_model* model) { svm_parameter& param = model->param; char cmd[81]; while(1) { FSCANF(fp,"%80s",cmd); if(strcmp(cmd,"svm_type")==0) { FSCANF(fp,"%80s",cmd); int i; for(i=0;svm_type_table[i];i++) { if(strcmp(svm_type_table[i],cmd)==0) { param.svm_type=i; break; } } if(svm_type_table[i] == NULL) { fprintf(stderr,"unknown svm type.\n"); return false; } } else if(strcmp(cmd,"kernel_type")==0) { FSCANF(fp,"%80s",cmd); int i; for(i=0;kernel_type_table[i];i++) { if(strcmp(kernel_type_table[i],cmd)==0) { param.kernel_type=i; break; } } if(kernel_type_table[i] == NULL) { fprintf(stderr,"unknown kernel function.\n"); return false; } } else if(strcmp(cmd,"degree")==0) FSCANF(fp,"%d",¶m.degree); else if(strcmp(cmd,"gamma")==0) FSCANF(fp,"%lf",¶m.gamma); else if(strcmp(cmd,"coef0")==0) FSCANF(fp,"%lf",¶m.coef0); else if(strcmp(cmd,"nr_class")==0) FSCANF(fp,"%d",&model->nr_class); else if(strcmp(cmd,"total_sv")==0) FSCANF(fp,"%d",&model->l); else if(strcmp(cmd,"rho")==0) { int n = model->nr_class * (model->nr_class-1)/2; model->rho = Malloc(double,n); for(int i=0;irho[i]); } else if(strcmp(cmd,"label")==0) { int n = model->nr_class; model->label = Malloc(int,n); for(int i=0;ilabel[i]); } else if(strcmp(cmd,"probA")==0) { int n = model->nr_class * (model->nr_class-1)/2; model->probA = Malloc(double,n); for(int i=0;iprobA[i]); } else if(strcmp(cmd,"probB")==0) { int n = model->nr_class * (model->nr_class-1)/2; model->probB = Malloc(double,n); for(int i=0;iprobB[i]); } else if(strcmp(cmd,"nr_sv")==0) { int n = model->nr_class; model->nSV = Malloc(int,n); for(int i=0;inSV[i]); } else if(strcmp(cmd,"SV")==0) { while(1) { int c = getc(fp); if(c==EOF || c=='\n') break; } break; } else { fprintf(stderr,"unknown text in model file: [%s]\n",cmd); return false; } } return true; } svm_model *svm_load_model(const char *model_file_name) { FILE *fp = fopen(model_file_name,"rb"); if(fp==NULL) return NULL; char *old_locale = setlocale(LC_ALL, NULL); if (old_locale) { old_locale = strdup(old_locale); } setlocale(LC_ALL, "C"); // read parameters svm_model *model = Malloc(svm_model,1); model->rho = NULL; model->probA = NULL; model->probB = NULL; model->sv_indices = NULL; model->label = NULL; model->nSV = NULL; // read header if (!read_model_header(fp, model)) { fprintf(stderr, "ERROR: fscanf failed to read model\n"); setlocale(LC_ALL, old_locale); free(old_locale); free(model->rho); free(model->label); free(model->nSV); free(model); return NULL; } // read sv_coef and SV int elements = 0; long pos = ftell(fp); max_line_len = 1024; line = Malloc(char,max_line_len); char *p,*endptr,*idx,*val; while(readline(fp)!=NULL) { p = strtok(line,":"); while(1) { p = strtok(NULL,":"); if(p == NULL) break; ++elements; } } elements += model->l; fseek(fp,pos,SEEK_SET); int m = model->nr_class - 1; int l = model->l; model->sv_coef = Malloc(double *,m); int i; for(i=0;isv_coef[i] = Malloc(double,l); model->SV = Malloc(svm_node*,l); svm_node *x_space = NULL; if(l>0) x_space = Malloc(svm_node,elements); int j=0; for(i=0;iSV[i] = &x_space[j]; p = strtok(line, " \t"); model->sv_coef[0][i] = strtod(p,&endptr); for(int k=1;ksv_coef[k][i] = strtod(p,&endptr); } while(1) { idx = strtok(NULL, ":"); val = strtok(NULL, " \t"); if(val == NULL) break; x_space[j].index = (int) strtol(idx,&endptr,10); x_space[j].value = strtod(val,&endptr); ++j; } x_space[j++].index = -1; } free(line); setlocale(LC_ALL, old_locale); free(old_locale); if (ferror(fp) != 0 || fclose(fp) != 0) return NULL; model->free_sv = 1; // XXX return model; } void svm_free_model_content(svm_model* model_ptr) { if(model_ptr->free_sv && model_ptr->l > 0 && model_ptr->SV != NULL) free((void *)(model_ptr->SV[0])); if(model_ptr->sv_coef) { for(int i=0;inr_class-1;i++) free(model_ptr->sv_coef[i]); } free(model_ptr->SV); model_ptr->SV = NULL; free(model_ptr->sv_coef); model_ptr->sv_coef = NULL; free(model_ptr->rho); model_ptr->rho = NULL; free(model_ptr->label); model_ptr->label= NULL; free(model_ptr->probA); model_ptr->probA = NULL; free(model_ptr->probB); model_ptr->probB= NULL; free(model_ptr->sv_indices); model_ptr->sv_indices = NULL; free(model_ptr->nSV); model_ptr->nSV = NULL; } void svm_free_and_destroy_model(svm_model** model_ptr_ptr) { if(model_ptr_ptr != NULL && *model_ptr_ptr != NULL) { svm_free_model_content(*model_ptr_ptr); free(*model_ptr_ptr); *model_ptr_ptr = NULL; } } void svm_destroy_param(svm_parameter* param) { free(param->weight_label); free(param->weight); } const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *param) { // svm_type int svm_type = param->svm_type; if(svm_type != C_SVC && svm_type != NU_SVC && svm_type != ONE_CLASS && svm_type != EPSILON_SVR && svm_type != NU_SVR) return "unknown svm type"; // kernel_type, degree int kernel_type = param->kernel_type; if(kernel_type != LINEAR && kernel_type != POLY && kernel_type != RBF && kernel_type != SIGMOID && kernel_type != PRECOMPUTED) return "unknown kernel type"; if(param->gamma < 0) return "gamma < 0"; if(param->degree < 0) return "degree of polynomial kernel < 0"; // cache_size,eps,C,nu,p,shrinking if(param->cache_size <= 0) return "cache_size <= 0"; if(param->eps <= 0) return "eps <= 0"; if(svm_type == C_SVC || svm_type == EPSILON_SVR || svm_type == NU_SVR) if(param->C <= 0) return "C <= 0"; if(svm_type == NU_SVC || svm_type == ONE_CLASS || svm_type == NU_SVR) if(param->nu <= 0 || param->nu > 1) return "nu <= 0 or nu > 1"; if(svm_type == EPSILON_SVR) if(param->p < 0) return "p < 0"; if(param->shrinking != 0 && param->shrinking != 1) return "shrinking != 0 and shrinking != 1"; if(param->probability != 0 && param->probability != 1) return "probability != 0 and probability != 1"; if(param->probability == 1 && svm_type == ONE_CLASS) return "one-class SVM probability output not supported yet"; // check whether nu-svc is feasible if(svm_type == NU_SVC) { int l = prob->l; int max_nr_class = 16; int nr_class = 0; int *label = Malloc(int,max_nr_class); int *count = Malloc(int,max_nr_class); int i; for(i=0;iy[i]; int j; for(j=0;jnu*(n1+n2)/2 > min(n1,n2)) { free(label); free(count); return "specified nu is infeasible"; } } } free(label); free(count); } return NULL; } int svm_check_probability_model(const svm_model *model) { return ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) && model->probA!=NULL && model->probB!=NULL) || ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) && model->probA!=NULL); } void svm_set_print_string_function(void (*print_func)(const char *)) { if(print_func == NULL) svm_print_string = &print_string_stdout; else svm_print_string = print_func; } libsvm-3.21+ds/svm-train.c0000644000175000017500000002143212633544336014732 0ustar ctsai12ctsai12#include #include #include #include #include #include "svm.h" #define Malloc(type,n) (type *)malloc((n)*sizeof(type)) void print_null(const char *s) {} void exit_with_help() { printf( "Usage: svm-train [options] training_set_file [model_file]\n" "options:\n" "-s svm_type : set type of SVM (default 0)\n" " 0 -- C-SVC (multi-class classification)\n" " 1 -- nu-SVC (multi-class classification)\n" " 2 -- one-class SVM\n" " 3 -- epsilon-SVR (regression)\n" " 4 -- nu-SVR (regression)\n" "-t kernel_type : set type of kernel function (default 2)\n" " 0 -- linear: u'*v\n" " 1 -- polynomial: (gamma*u'*v + coef0)^degree\n" " 2 -- radial basis function: exp(-gamma*|u-v|^2)\n" " 3 -- sigmoid: tanh(gamma*u'*v + coef0)\n" " 4 -- precomputed kernel (kernel values in training_set_file)\n" "-d degree : set degree in kernel function (default 3)\n" "-g gamma : set gamma in kernel function (default 1/num_features)\n" "-r coef0 : set coef0 in kernel function (default 0)\n" "-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)\n" "-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)\n" "-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)\n" "-m cachesize : set cache memory size in MB (default 100)\n" "-e epsilon : set tolerance of termination criterion (default 0.001)\n" "-h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1)\n" "-b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)\n" "-wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1)\n" "-v n: n-fold cross validation mode\n" "-q : quiet mode (no outputs)\n" ); exit(1); } void exit_input_error(int line_num) { fprintf(stderr,"Wrong input format at line %d\n", line_num); exit(1); } void parse_command_line(int argc, char **argv, char *input_file_name, char *model_file_name); void read_problem(const char *filename); void do_cross_validation(); struct svm_parameter param; // set by parse_command_line struct svm_problem prob; // set by read_problem struct svm_model *model; struct svm_node *x_space; int cross_validation; int nr_fold; static char *line = NULL; static int max_line_len; static char* readline(FILE *input) { int len; if(fgets(line,max_line_len,input) == NULL) return NULL; while(strrchr(line,'\n') == NULL) { max_line_len *= 2; line = (char *) realloc(line,max_line_len); len = (int) strlen(line); if(fgets(line+len,max_line_len-len,input) == NULL) break; } return line; } int main(int argc, char **argv) { char input_file_name[1024]; char model_file_name[1024]; const char *error_msg; parse_command_line(argc, argv, input_file_name, model_file_name); read_problem(input_file_name); error_msg = svm_check_parameter(&prob,¶m); if(error_msg) { fprintf(stderr,"ERROR: %s\n",error_msg); exit(1); } if(cross_validation) { do_cross_validation(); } else { model = svm_train(&prob,¶m); if(svm_save_model(model_file_name,model)) { fprintf(stderr, "can't save model to file %s\n", model_file_name); exit(1); } svm_free_and_destroy_model(&model); } svm_destroy_param(¶m); free(prob.y); free(prob.x); free(x_space); free(line); return 0; } void do_cross_validation() { int i; int total_correct = 0; double total_error = 0; double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; double *target = Malloc(double,prob.l); svm_cross_validation(&prob,¶m,nr_fold,target); if(param.svm_type == EPSILON_SVR || param.svm_type == NU_SVR) { for(i=0;i=argc) exit_with_help(); switch(argv[i-1][1]) { case 's': param.svm_type = atoi(argv[i]); break; case 't': param.kernel_type = atoi(argv[i]); break; case 'd': param.degree = atoi(argv[i]); break; case 'g': param.gamma = atof(argv[i]); break; case 'r': param.coef0 = atof(argv[i]); break; case 'n': param.nu = atof(argv[i]); break; case 'm': param.cache_size = atof(argv[i]); break; case 'c': param.C = atof(argv[i]); break; case 'e': param.eps = atof(argv[i]); break; case 'p': param.p = atof(argv[i]); break; case 'h': param.shrinking = atoi(argv[i]); break; case 'b': param.probability = atoi(argv[i]); break; case 'q': print_func = &print_null; i--; break; case 'v': cross_validation = 1; nr_fold = atoi(argv[i]); if(nr_fold < 2) { fprintf(stderr,"n-fold cross validation: n must >= 2\n"); exit_with_help(); } break; case 'w': ++param.nr_weight; param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); param.weight_label[param.nr_weight-1] = atoi(&argv[i-1][2]); param.weight[param.nr_weight-1] = atof(argv[i]); break; default: fprintf(stderr,"Unknown option: -%c\n", argv[i-1][1]); exit_with_help(); } } svm_set_print_string_function(print_func); // determine filenames if(i>=argc) exit_with_help(); strcpy(input_file_name, argv[i]); if(i start from 0 readline(fp); prob.x[i] = &x_space[j]; label = strtok(line," \t\n"); if(label == NULL) // empty line exit_input_error(i+1); prob.y[i] = strtod(label,&endptr); if(endptr == label || *endptr != '\0') exit_input_error(i+1); while(1) { idx = strtok(NULL,":"); val = strtok(NULL," \t"); if(val == NULL) break; errno = 0; x_space[j].index = (int) strtol(idx,&endptr,10); if(endptr == idx || errno != 0 || *endptr != '\0' || x_space[j].index <= inst_max_index) exit_input_error(i+1); else inst_max_index = x_space[j].index; errno = 0; x_space[j].value = strtod(val,&endptr); if(endptr == val || errno != 0 || (*endptr != '\0' && !isspace(*endptr))) exit_input_error(i+1); ++j; } if(inst_max_index > max_index) max_index = inst_max_index; x_space[j++].index = -1; } if(param.gamma == 0 && max_index > 0) param.gamma = 1.0/max_index; if(param.kernel_type == PRECOMPUTED) for(i=0;i max_index) { fprintf(stderr,"Wrong input format: sample_serial_number out of range\n"); exit(1); } } fclose(fp); } libsvm-3.21+ds/java/0000755000175000017500000000000012654255155013566 5ustar ctsai12ctsai12libsvm-3.21+ds/java/svm_scale.java0000644000175000017500000002136012633544333016403 0ustar ctsai12ctsai12import libsvm.*; import java.io.*; import java.util.*; import java.text.DecimalFormat; class svm_scale { private String line = null; private double lower = -1.0; private double upper = 1.0; private double y_lower; private double y_upper; private boolean y_scaling = false; private double[] feature_max; private double[] feature_min; private double y_max = -Double.MAX_VALUE; private double y_min = Double.MAX_VALUE; private int max_index; private long num_nonzeros = 0; private long new_num_nonzeros = 0; private static void exit_with_help() { System.out.print( "Usage: svm-scale [options] data_filename\n" +"options:\n" +"-l lower : x scaling lower limit (default -1)\n" +"-u upper : x scaling upper limit (default +1)\n" +"-y y_lower y_upper : y scaling limits (default: no y scaling)\n" +"-s save_filename : save scaling parameters to save_filename\n" +"-r restore_filename : restore scaling parameters from restore_filename\n" ); System.exit(1); } private BufferedReader rewind(BufferedReader fp, String filename) throws IOException { fp.close(); return new BufferedReader(new FileReader(filename)); } private void output_target(double value) { if(y_scaling) { if(value == y_min) value = y_lower; else if(value == y_max) value = y_upper; else value = y_lower + (y_upper-y_lower) * (value-y_min) / (y_max-y_min); } System.out.print(value + " "); } private void output(int index, double value) { /* skip single-valued attribute */ if(feature_max[index] == feature_min[index]) return; if(value == feature_min[index]) value = lower; else if(value == feature_max[index]) value = upper; else value = lower + (upper-lower) * (value-feature_min[index])/ (feature_max[index]-feature_min[index]); if(value != 0) { System.out.print(index + ":" + value + " "); new_num_nonzeros++; } } private String readline(BufferedReader fp) throws IOException { line = fp.readLine(); return line; } private void run(String []argv) throws IOException { int i,index; BufferedReader fp = null, fp_restore = null; String save_filename = null; String restore_filename = null; String data_filename = null; for(i=0;i lower) || (y_scaling && !(y_upper > y_lower))) { System.err.println("inconsistent lower/upper specification"); System.exit(1); } if(restore_filename != null && save_filename != null) { System.err.println("cannot use -r and -s simultaneously"); System.exit(1); } if(argv.length != i+1) exit_with_help(); data_filename = argv[i]; try { fp = new BufferedReader(new FileReader(data_filename)); } catch (Exception e) { System.err.println("can't open file " + data_filename); System.exit(1); } /* assumption: min index of attributes is 1 */ /* pass 1: find out max index of attributes */ max_index = 0; if(restore_filename != null) { int idx, c; try { fp_restore = new BufferedReader(new FileReader(restore_filename)); } catch (Exception e) { System.err.println("can't open file " + restore_filename); System.exit(1); } if((c = fp_restore.read()) == 'y') { fp_restore.readLine(); fp_restore.readLine(); fp_restore.readLine(); } fp_restore.readLine(); fp_restore.readLine(); String restore_line = null; while((restore_line = fp_restore.readLine())!=null) { StringTokenizer st2 = new StringTokenizer(restore_line); idx = Integer.parseInt(st2.nextToken()); max_index = Math.max(max_index, idx); } fp_restore = rewind(fp_restore, restore_filename); } while (readline(fp) != null) { StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); st.nextToken(); while(st.hasMoreTokens()) { index = Integer.parseInt(st.nextToken()); max_index = Math.max(max_index, index); st.nextToken(); num_nonzeros++; } } try { feature_max = new double[(max_index+1)]; feature_min = new double[(max_index+1)]; } catch(OutOfMemoryError e) { System.err.println("can't allocate enough memory"); System.exit(1); } for(i=0;i<=max_index;i++) { feature_max[i] = -Double.MAX_VALUE; feature_min[i] = Double.MAX_VALUE; } fp = rewind(fp, data_filename); /* pass 2: find out min/max value */ while(readline(fp) != null) { int next_index = 1; double target; double value; StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); target = Double.parseDouble(st.nextToken()); y_max = Math.max(y_max, target); y_min = Math.min(y_min, target); while (st.hasMoreTokens()) { index = Integer.parseInt(st.nextToken()); value = Double.parseDouble(st.nextToken()); for (i = next_index; i num_nonzeros) System.err.print( "WARNING: original #nonzeros " + num_nonzeros+"\n" +" new #nonzeros " + new_num_nonzeros+"\n" +"Use -l 0 if many original feature values are zeros\n"); fp.close(); } public static void main(String argv[]) throws IOException { svm_scale s = new svm_scale(); s.run(argv); } } libsvm-3.21+ds/java/Makefile0000644000175000017500000000116012633544331015216 0ustar ctsai12ctsai12.SUFFIXES: .class .java FILES = libsvm/svm.class libsvm/svm_model.class libsvm/svm_node.class \ libsvm/svm_parameter.class libsvm/svm_problem.class \ libsvm/svm_print_interface.class \ svm_train.class svm_predict.class svm_toy.class svm_scale.class #JAVAC = jikes JAVAC_FLAGS = -target 1.5 -source 1.5 JAVAC = javac # JAVAC_FLAGS = all: $(FILES) jar cvf libsvm.jar *.class libsvm/*.class .java.class: $(JAVAC) $(JAVAC_FLAGS) $< libsvm/svm.java: libsvm/svm.m4 m4 libsvm/svm.m4 > libsvm/svm.java clean: rm -f libsvm/*.class *.class *.jar libsvm/*~ *~ libsvm/svm.java dist: clean all rm *.class libsvm/*.class libsvm-3.21+ds/java/svm_predict.java0000644000175000017500000001152612633544333016751 0ustar ctsai12ctsai12import libsvm.*; import java.io.*; import java.util.*; class svm_predict { private static svm_print_interface svm_print_null = new svm_print_interface() { public void print(String s) {} }; private static svm_print_interface svm_print_stdout = new svm_print_interface() { public void print(String s) { System.out.print(s); } }; private static svm_print_interface svm_print_string = svm_print_stdout; static void info(String s) { svm_print_string.print(s); } private static double atof(String s) { return Double.valueOf(s).doubleValue(); } private static int atoi(String s) { return Integer.parseInt(s); } private static void predict(BufferedReader input, DataOutputStream output, svm_model model, int predict_probability) throws IOException { int correct = 0; int total = 0; double error = 0; double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; int svm_type=svm.svm_get_svm_type(model); int nr_class=svm.svm_get_nr_class(model); double[] prob_estimates=null; if(predict_probability == 1) { if(svm_type == svm_parameter.EPSILON_SVR || svm_type == svm_parameter.NU_SVR) { svm_predict.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="+svm.svm_get_svr_probability(model)+"\n"); } else { int[] labels=new int[nr_class]; svm.svm_get_labels(model,labels); prob_estimates = new double[nr_class]; output.writeBytes("labels"); for(int j=0;j=argv.length-2) exit_with_help(); try { BufferedReader input = new BufferedReader(new FileReader(argv[i])); DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(argv[i+2]))); svm_model model = svm.svm_load_model(argv[i+1]); if (model == null) { System.err.print("can't open model file "+argv[i+1]+"\n"); System.exit(1); } if(predict_probability == 1) { if(svm.svm_check_probability_model(model)==0) { System.err.print("Model does not support probabiliy estimates\n"); System.exit(1); } } else { if(svm.svm_check_probability_model(model)!=0) { svm_predict.info("Model supports probability estimates, but disabled in prediction.\n"); } } predict(input,output,model,predict_probability); input.close(); output.close(); } catch(FileNotFoundException e) { exit_with_help(); } catch(ArrayIndexOutOfBoundsException e) { exit_with_help(); } } } libsvm-3.21+ds/java/libsvm/0000755000175000017500000000000012633544372015061 5ustar ctsai12ctsai12libsvm-3.21+ds/java/libsvm/svm.java0000644000175000017500000017453712633544357016555 0ustar ctsai12ctsai12 package libsvm; import java.io.*; import java.util.*; // // Kernel Cache // // l is the number of total data items // size is the cache size limit in bytes // class Cache { private final int l; private long size; private final class head_t { head_t prev, next; // a cicular list float[] data; int len; // data[0,len) is cached in this entry } private final head_t[] head; private head_t lru_head; Cache(int l_, long size_) { l = l_; size = size_; head = new head_t[l]; for(int i=0;i= len if nothing needs to be filled) // java: simulate pointer using single-element array int get_data(int index, float[][] data, int len) { head_t h = head[index]; if(h.len > 0) lru_delete(h); int more = len - h.len; if(more > 0) { // free old space while(size < more) { head_t old = lru_head.next; lru_delete(old); size += old.len; old.data = null; old.len = 0; } // allocate new space float[] new_data = new float[len]; if(h.data != null) System.arraycopy(h.data,0,new_data,0,h.len); h.data = new_data; size -= more; do {int _=h.len; h.len=len; len=_;} while(false); } lru_insert(h); data[0] = h.data; return len; } void swap_index(int i, int j) { if(i==j) return; if(head[i].len > 0) lru_delete(head[i]); if(head[j].len > 0) lru_delete(head[j]); do {float[] _=head[i].data; head[i].data=head[j].data; head[j].data=_;} while(false); do {int _=head[i].len; head[i].len=head[j].len; head[j].len=_;} while(false); if(head[i].len > 0) lru_insert(head[i]); if(head[j].len > 0) lru_insert(head[j]); if(i>j) do {int _=i; i=j; j=_;} while(false); for(head_t h = lru_head.next; h!=lru_head; h=h.next) { if(h.len > i) { if(h.len > j) do {float _=h.data[i]; h.data[i]=h.data[j]; h.data[j]=_;} while(false); else { // give up lru_delete(h); size += h.len; h.data = null; h.len = 0; } } } } } // // Kernel evaluation // // the static method k_function is for doing single kernel evaluation // the constructor of Kernel prepares to calculate the l*l kernel matrix // the member function get_Q is for getting one column from the Q Matrix // abstract class QMatrix { abstract float[] get_Q(int column, int len); abstract double[] get_QD(); abstract void swap_index(int i, int j); }; abstract class Kernel extends QMatrix { private svm_node[][] x; private final double[] x_square; // svm_parameter private final int kernel_type; private final int degree; private final double gamma; private final double coef0; abstract float[] get_Q(int column, int len); abstract double[] get_QD(); void swap_index(int i, int j) { do {svm_node[] _=x[i]; x[i]=x[j]; x[j]=_;} while(false); if(x_square != null) do {double _=x_square[i]; x_square[i]=x_square[j]; x_square[j]=_;} while(false); } private static double powi(double base, int times) { double tmp = base, ret = 1.0; for(int t=times; t>0; t/=2) { if(t%2==1) ret*=tmp; tmp = tmp * tmp; } return ret; } double kernel_function(int i, int j) { switch(kernel_type) { case svm_parameter.LINEAR: return dot(x[i],x[j]); case svm_parameter.POLY: return powi(gamma*dot(x[i],x[j])+coef0,degree); case svm_parameter.RBF: return Math.exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); case svm_parameter.SIGMOID: return Math.tanh(gamma*dot(x[i],x[j])+coef0); case svm_parameter.PRECOMPUTED: return x[i][(int)(x[j][0].value)].value; default: return 0; // java } } Kernel(int l, svm_node[][] x_, svm_parameter param) { this.kernel_type = param.kernel_type; this.degree = param.degree; this.gamma = param.gamma; this.coef0 = param.coef0; x = (svm_node[][])x_.clone(); if(kernel_type == svm_parameter.RBF) { x_square = new double[l]; for(int i=0;i y[j].index) ++j; else ++i; } } return sum; } static double k_function(svm_node[] x, svm_node[] y, svm_parameter param) { switch(param.kernel_type) { case svm_parameter.LINEAR: return dot(x,y); case svm_parameter.POLY: return powi(param.gamma*dot(x,y)+param.coef0,param.degree); case svm_parameter.RBF: { double sum = 0; int xlen = x.length; int ylen = y.length; int i = 0; int j = 0; while(i < xlen && j < ylen) { if(x[i].index == y[j].index) { double d = x[i++].value - y[j++].value; sum += d*d; } else if(x[i].index > y[j].index) { sum += y[j].value * y[j].value; ++j; } else { sum += x[i].value * x[i].value; ++i; } } while(i < xlen) { sum += x[i].value * x[i].value; ++i; } while(j < ylen) { sum += y[j].value * y[j].value; ++j; } return Math.exp(-param.gamma*sum); } case svm_parameter.SIGMOID: return Math.tanh(param.gamma*dot(x,y)+param.coef0); case svm_parameter.PRECOMPUTED: return x[(int)(y[0].value)].value; default: return 0; // java } } } // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918 // Solves: // // min 0.5(\alpha^T Q \alpha) + p^T \alpha // // y^T \alpha = \delta // y_i = +1 or -1 // 0 <= alpha_i <= Cp for y_i = 1 // 0 <= alpha_i <= Cn for y_i = -1 // // Given: // // Q, p, y, Cp, Cn, and an initial feasible point \alpha // l is the size of vectors and matrices // eps is the stopping tolerance // // solution will be put in \alpha, objective value will be put in obj // class Solver { int active_size; byte[] y; double[] G; // gradient of objective function static final byte LOWER_BOUND = 0; static final byte UPPER_BOUND = 1; static final byte FREE = 2; byte[] alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE double[] alpha; QMatrix Q; double[] QD; double eps; double Cp,Cn; double[] p; int[] active_set; double[] G_bar; // gradient, if we treat free variables as 0 int l; boolean unshrink; // XXX static final double INF = java.lang.Double.POSITIVE_INFINITY; double get_C(int i) { return (y[i] > 0)? Cp : Cn; } void update_alpha_status(int i) { if(alpha[i] >= get_C(i)) alpha_status[i] = UPPER_BOUND; else if(alpha[i] <= 0) alpha_status[i] = LOWER_BOUND; else alpha_status[i] = FREE; } boolean is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; } boolean is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; } boolean is_free(int i) { return alpha_status[i] == FREE; } // java: information about solution except alpha, // because we cannot return multiple values otherwise... static class SolutionInfo { double obj; double rho; double upper_bound_p; double upper_bound_n; double r; // for Solver_NU } void swap_index(int i, int j) { Q.swap_index(i,j); do {byte _=y[i]; y[i]=y[j]; y[j]=_;} while(false); do {double _=G[i]; G[i]=G[j]; G[j]=_;} while(false); do {byte _=alpha_status[i]; alpha_status[i]=alpha_status[j]; alpha_status[j]=_;} while(false); do {double _=alpha[i]; alpha[i]=alpha[j]; alpha[j]=_;} while(false); do {double _=p[i]; p[i]=p[j]; p[j]=_;} while(false); do {int _=active_set[i]; active_set[i]=active_set[j]; active_set[j]=_;} while(false); do {double _=G_bar[i]; G_bar[i]=G_bar[j]; G_bar[j]=_;} while(false); } void reconstruct_gradient() { // reconstruct inactive elements of G from G_bar and free variables if(active_size == l) return; int i,j; int nr_free = 0; for(j=active_size;j 2*active_size*(l-active_size)) { for(i=active_size;iInteger.MAX_VALUE/100 ? Integer.MAX_VALUE : 100*l); int counter = Math.min(l,1000)+1; int[] working_set = new int[2]; while(iter < max_iter) { // show progress and do shrinking if(--counter == 0) { counter = Math.min(l,1000); if(shrinking!=0) do_shrinking(); svm.info("."); } if(select_working_set(working_set)!=0) { // reconstruct the whole gradient reconstruct_gradient(); // reset active set size and check active_size = l; svm.info("*"); if(select_working_set(working_set)!=0) break; else counter = 1; // do shrinking next iteration } int i = working_set[0]; int j = working_set[1]; ++iter; // update alpha[i] and alpha[j], handle bounds carefully float[] Q_i = Q.get_Q(i,active_size); float[] Q_j = Q.get_Q(j,active_size); double C_i = get_C(i); double C_j = get_C(j); double old_alpha_i = alpha[i]; double old_alpha_j = alpha[j]; if(y[i]!=y[j]) { double quad_coef = QD[i]+QD[j]+2*Q_i[j]; if (quad_coef <= 0) quad_coef = 1e-12; double delta = (-G[i]-G[j])/quad_coef; double diff = alpha[i] - alpha[j]; alpha[i] += delta; alpha[j] += delta; if(diff > 0) { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = diff; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = -diff; } } if(diff > C_i - C_j) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = C_i - diff; } } else { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = C_j + diff; } } } else { double quad_coef = QD[i]+QD[j]-2*Q_i[j]; if (quad_coef <= 0) quad_coef = 1e-12; double delta = (G[i]-G[j])/quad_coef; double sum = alpha[i] + alpha[j]; alpha[i] -= delta; alpha[j] += delta; if(sum > C_i) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = sum - C_i; } } else { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = sum; } } if(sum > C_j) { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = sum - C_j; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = sum; } } } // update G double delta_alpha_i = alpha[i] - old_alpha_i; double delta_alpha_j = alpha[j] - old_alpha_j; for(int k=0;k= max_iter) { if(active_size < l) { // reconstruct the whole gradient to calculate objective value reconstruct_gradient(); active_size = l; svm.info("*"); } System.err.print("\nWARNING: reaching max number of iterations\n"); } // calculate rho si.rho = calculate_rho(); // calculate objective value { double v = 0; int i; for(i=0;i= Gmax) { Gmax = -G[t]; Gmax_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmax) { Gmax = G[t]; Gmax_idx = t; } } int i = Gmax_idx; float[] Q_i = null; if(i != -1) // null Q_i not accessed: Gmax=-INF if i=-1 Q_i = Q.get_Q(i,active_size); for(int j=0;j= Gmax2) Gmax2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/1e-12; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff= Gmax-G[j]; if (-G[j] >= Gmax2) Gmax2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/1e-12; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(Gmax+Gmax2 < eps || Gmin_idx == -1) return 1; working_set[0] = Gmax_idx; working_set[1] = Gmin_idx; return 0; } private boolean be_shrunk(int i, double Gmax1, double Gmax2) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax2); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax1); } else return(false); } void do_shrinking() { int i; double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } // find maximal violating pair first for(i=0;i= Gmax1) Gmax1 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax2) Gmax2 = G[i]; } } else { if(!is_upper_bound(i)) { if(-G[i] >= Gmax2) Gmax2 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax1) Gmax1 = G[i]; } } } if(unshrink == false && Gmax1 + Gmax2 <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2)) { swap_index(i,active_size); break; } active_size--; } } } double calculate_rho() { double r; int nr_free = 0; double ub = INF, lb = -INF, sum_free = 0; for(int i=0;i 0) ub = Math.min(ub,yG); else lb = Math.max(lb,yG); } else if(is_upper_bound(i)) { if(y[i] < 0) ub = Math.min(ub,yG); else lb = Math.max(lb,yG); } else { ++nr_free; sum_free += yG; } } if(nr_free>0) r = sum_free/nr_free; else r = (ub+lb)/2; return r; } } // // Solver for nu-svm classification and regression // // additional constraint: e^T \alpha = constant // final class Solver_NU extends Solver { private SolutionInfo si; void Solve(int l, QMatrix Q, double[] p, byte[] y, double[] alpha, double Cp, double Cn, double eps, SolutionInfo si, int shrinking) { this.si = si; super.Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking); } // return 1 if already optimal, return 0 otherwise int select_working_set(int[] working_set) { // return i,j such that y_i = y_j and // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) // j: minimizes the decrease of obj value // (if quadratic coefficeint <= 0, replace it with tau) // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) double Gmaxp = -INF; double Gmaxp2 = -INF; int Gmaxp_idx = -1; double Gmaxn = -INF; double Gmaxn2 = -INF; int Gmaxn_idx = -1; int Gmin_idx = -1; double obj_diff_min = INF; for(int t=0;t= Gmaxp) { Gmaxp = -G[t]; Gmaxp_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmaxn) { Gmaxn = G[t]; Gmaxn_idx = t; } } int ip = Gmaxp_idx; int in = Gmaxn_idx; float[] Q_ip = null; float[] Q_in = null; if(ip != -1) // null Q_ip not accessed: Gmaxp=-INF if ip=-1 Q_ip = Q.get_Q(ip,active_size); if(in != -1) Q_in = Q.get_Q(in,active_size); for(int j=0;j= Gmaxp2) Gmaxp2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[ip]+QD[j]-2*Q_ip[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/1e-12; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff=Gmaxn-G[j]; if (-G[j] >= Gmaxn2) Gmaxn2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[in]+QD[j]-2*Q_in[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/1e-12; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(Math.max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1) return 1; if(y[Gmin_idx] == +1) working_set[0] = Gmaxp_idx; else working_set[0] = Gmaxn_idx; working_set[1] = Gmin_idx; return 0; } private boolean be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax4); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax3); } else return(false); } void do_shrinking() { double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) } double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) } double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) } // find maximal violating pair first int i; for(i=0;i Gmax1) Gmax1 = -G[i]; } else if(-G[i] > Gmax4) Gmax4 = -G[i]; } if(!is_lower_bound(i)) { if(y[i]==+1) { if(G[i] > Gmax2) Gmax2 = G[i]; } else if(G[i] > Gmax3) Gmax3 = G[i]; } } if(unshrink == false && Math.max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4)) { swap_index(i,active_size); break; } active_size--; } } } double calculate_rho() { int nr_free1 = 0,nr_free2 = 0; double ub1 = INF, ub2 = INF; double lb1 = -INF, lb2 = -INF; double sum_free1 = 0, sum_free2 = 0; for(int i=0;i 0) r1 = sum_free1/nr_free1; else r1 = (ub1+lb1)/2; if(nr_free2 > 0) r2 = sum_free2/nr_free2; else r2 = (ub2+lb2)/2; si.r = (r1+r2)/2; return (r1-r2)/2; } } // // Q matrices for various formulations // class SVC_Q extends Kernel { private final byte[] y; private final Cache cache; private final double[] QD; SVC_Q(svm_problem prob, svm_parameter param, byte[] y_) { super(prob.l, prob.x, param); y = (byte[])y_.clone(); cache = new Cache(prob.l,(long)(param.cache_size*(1<<20))); QD = new double[prob.l]; for(int i=0;i 0) y[i] = +1; else y[i] = -1; } Solver s = new Solver(); s.Solve(l, new SVC_Q(prob,param,y), minus_ones, y, alpha, Cp, Cn, param.eps, si, param.shrinking); double sum_alpha=0; for(i=0;i0) y[i] = +1; else y[i] = -1; double sum_pos = nu*l/2; double sum_neg = nu*l/2; for(i=0;i 0) { ++nSV; if(prob.y[i] > 0) { if(Math.abs(alpha[i]) >= si.upper_bound_p) ++nBSV; } else { if(Math.abs(alpha[i]) >= si.upper_bound_n) ++nBSV; } } } svm.info("nSV = "+nSV+", nBSV = "+nBSV+"\n"); decision_function f = new decision_function(); f.alpha = alpha; f.rho = si.rho; return f; } // Platt's binary SVM Probablistic Output: an improvement from Lin et al. private static void sigmoid_train(int l, double[] dec_values, double[] labels, double[] probAB) { double A, B; double prior1=0, prior0 = 0; int i; for (i=0;i 0) prior1+=1; else prior0+=1; int max_iter=100; // Maximal number of iterations double min_step=1e-10; // Minimal step taken in line search double sigma=1e-12; // For numerically strict PD of Hessian double eps=1e-5; double hiTarget=(prior1+1.0)/(prior1+2.0); double loTarget=1/(prior0+2.0); double[] t= new double[l]; double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize; double newA,newB,newf,d1,d2; int iter; // Initial Point and Initial Fun Value A=0.0; B=Math.log((prior0+1.0)/(prior1+1.0)); double fval = 0.0; for (i=0;i0) t[i]=hiTarget; else t[i]=loTarget; fApB = dec_values[i]*A+B; if (fApB>=0) fval += t[i]*fApB + Math.log(1+Math.exp(-fApB)); else fval += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB)); } for (iter=0;iter= 0) { p=Math.exp(-fApB)/(1.0+Math.exp(-fApB)); q=1.0/(1.0+Math.exp(-fApB)); } else { p=1.0/(1.0+Math.exp(fApB)); q=Math.exp(fApB)/(1.0+Math.exp(fApB)); } d2=p*q; h11+=dec_values[i]*dec_values[i]*d2; h22+=d2; h21+=dec_values[i]*d2; d1=t[i]-p; g1+=dec_values[i]*d1; g2+=d1; } // Stopping Criteria if (Math.abs(g1)= min_step) { newA = A + stepsize * dA; newB = B + stepsize * dB; // New function value newf = 0.0; for (i=0;i= 0) newf += t[i]*fApB + Math.log(1+Math.exp(-fApB)); else newf += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB)); } // Check sufficient decrease if (newf=max_iter) svm.info("Reaching maximal iterations in two-class probability estimates\n"); probAB[0]=A;probAB[1]=B; } private static double sigmoid_predict(double decision_value, double A, double B) { double fApB = decision_value*A+B; if (fApB >= 0) return Math.exp(-fApB)/(1.0+Math.exp(-fApB)); else return 1.0/(1+Math.exp(fApB)) ; } // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng private static void multiclass_probability(int k, double[][] r, double[] p) { int t,j; int iter = 0, max_iter=Math.max(100,k); double[][] Q=new double[k][k]; double[] Qp=new double[k]; double pQp, eps=0.005/k; for (t=0;tmax_error) max_error=error; } if (max_error=max_iter) svm.info("Exceeds max_iter in multiclass_prob\n"); } // Cross-validation decision values for probability estimates private static void svm_binary_svc_probability(svm_problem prob, svm_parameter param, double Cp, double Cn, double[] probAB) { int i; int nr_fold = 5; int[] perm = new int[prob.l]; double[] dec_values = new double[prob.l]; // random shuffle for(i=0;i0) p_count++; else n_count++; if(p_count==0 && n_count==0) for(j=begin;j 0 && n_count == 0) for(j=begin;j 0) for(j=begin;j 5*std) count=count+1; else mae+=Math.abs(ymv[i]); mae /= (prob.l-count); svm.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="+mae+"\n"); return mae; } // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data // perm, length l, must be allocated before calling this subroutine private static void svm_group_classes(svm_problem prob, int[] nr_class_ret, int[][] label_ret, int[][] start_ret, int[][] count_ret, int[] perm) { int l = prob.l; int max_nr_class = 16; int nr_class = 0; int[] label = new int[max_nr_class]; int[] count = new int[max_nr_class]; int[] data_label = new int[l]; int i; for(i=0;i 0) ++nSV; model.l = nSV; model.SV = new svm_node[nSV][]; model.sv_coef[0] = new double[nSV]; model.sv_indices = new int[nSV]; int j = 0; for(i=0;i 0) { model.SV[j] = prob.x[i]; model.sv_coef[0][j] = f.alpha[i]; model.sv_indices[j] = i+1; ++j; } } else { // classification int l = prob.l; int[] tmp_nr_class = new int[1]; int[][] tmp_label = new int[1][]; int[][] tmp_start = new int[1][]; int[][] tmp_count = new int[1][]; int[] perm = new int[l]; // group training data of the same class svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm); int nr_class = tmp_nr_class[0]; int[] label = tmp_label[0]; int[] start = tmp_start[0]; int[] count = tmp_count[0]; if(nr_class == 1) svm.info("WARNING: training data in only one class. See README for details.\n"); svm_node[][] x = new svm_node[l][]; int i; for(i=0;i 0) nonzero[si+k] = true; for(k=0;k 0) nonzero[sj+k] = true; ++p; } // build output model.nr_class = nr_class; model.label = new int[nr_class]; for(i=0;i some folds may have zero elements if((param.svm_type == svm_parameter.C_SVC || param.svm_type == svm_parameter.NU_SVC) && nr_fold < l) { int[] tmp_nr_class = new int[1]; int[][] tmp_label = new int[1][]; int[][] tmp_start = new int[1][]; int[][] tmp_count = new int[1][]; svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm); int nr_class = tmp_nr_class[0]; int[] start = tmp_start[0]; int[] count = tmp_count[0]; // random shuffle and then data grouped by fold using the array perm int[] fold_count = new int[nr_fold]; int c; int[] index = new int[l]; for(i=0;i0)?1:-1; else return sum; } else { int nr_class = model.nr_class; int l = model.l; double[] kvalue = new double[l]; for(i=0;i 0) ++vote[i]; else ++vote[j]; p++; } int vote_max_idx = 0; for(i=1;i vote[vote_max_idx]) vote_max_idx = i; return model.label[vote_max_idx]; } } public static double svm_predict(svm_model model, svm_node[] x) { int nr_class = model.nr_class; double[] dec_values; if(model.param.svm_type == svm_parameter.ONE_CLASS || model.param.svm_type == svm_parameter.EPSILON_SVR || model.param.svm_type == svm_parameter.NU_SVR) dec_values = new double[1]; else dec_values = new double[nr_class*(nr_class-1)/2]; double pred_result = svm_predict_values(model, x, dec_values); return pred_result; } public static double svm_predict_probability(svm_model model, svm_node[] x, double[] prob_estimates) { if ((model.param.svm_type == svm_parameter.C_SVC || model.param.svm_type == svm_parameter.NU_SVC) && model.probA!=null && model.probB!=null) { int i; int nr_class = model.nr_class; double[] dec_values = new double[nr_class*(nr_class-1)/2]; svm_predict_values(model, x, dec_values); double min_prob=1e-7; double[][] pairwise_prob=new double[nr_class][nr_class]; int k=0; for(i=0;i prob_estimates[prob_max_idx]) prob_max_idx = i; return model.label[prob_max_idx]; } else return svm_predict(model, x); } static final String svm_type_table[] = { "c_svc","nu_svc","one_class","epsilon_svr","nu_svr", }; static final String kernel_type_table[]= { "linear","polynomial","rbf","sigmoid","precomputed" }; public static void svm_save_model(String model_file_name, svm_model model) throws IOException { DataOutputStream fp = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(model_file_name))); svm_parameter param = model.param; fp.writeBytes("svm_type "+svm_type_table[param.svm_type]+"\n"); fp.writeBytes("kernel_type "+kernel_type_table[param.kernel_type]+"\n"); if(param.kernel_type == svm_parameter.POLY) fp.writeBytes("degree "+param.degree+"\n"); if(param.kernel_type == svm_parameter.POLY || param.kernel_type == svm_parameter.RBF || param.kernel_type == svm_parameter.SIGMOID) fp.writeBytes("gamma "+param.gamma+"\n"); if(param.kernel_type == svm_parameter.POLY || param.kernel_type == svm_parameter.SIGMOID) fp.writeBytes("coef0 "+param.coef0+"\n"); int nr_class = model.nr_class; int l = model.l; fp.writeBytes("nr_class "+nr_class+"\n"); fp.writeBytes("total_sv "+l+"\n"); { fp.writeBytes("rho"); for(int i=0;i 1) return "nu <= 0 or nu > 1"; if(svm_type == svm_parameter.EPSILON_SVR) if(param.p < 0) return "p < 0"; if(param.shrinking != 0 && param.shrinking != 1) return "shrinking != 0 and shrinking != 1"; if(param.probability != 0 && param.probability != 1) return "probability != 0 and probability != 1"; if(param.probability == 1 && svm_type == svm_parameter.ONE_CLASS) return "one-class SVM probability output not supported yet"; // check whether nu-svc is feasible if(svm_type == svm_parameter.NU_SVC) { int l = prob.l; int max_nr_class = 16; int nr_class = 0; int[] label = new int[max_nr_class]; int[] count = new int[max_nr_class]; int i; for(i=0;i Math.min(n1,n2)) return "specified nu is infeasible"; } } } return null; } public static int svm_check_probability_model(svm_model model) { if (((model.param.svm_type == svm_parameter.C_SVC || model.param.svm_type == svm_parameter.NU_SVC) && model.probA!=null && model.probB!=null) || ((model.param.svm_type == svm_parameter.EPSILON_SVR || model.param.svm_type == svm_parameter.NU_SVR) && model.probA!=null)) return 1; else return 0; } public static void svm_set_print_string_function(svm_print_interface print_func) { if (print_func == null) svm_print_string = svm_print_stdout; else svm_print_string = print_func; } } libsvm-3.21+ds/java/libsvm/svm_node.java0000644000175000017500000000016312633544332017532 0ustar ctsai12ctsai12package libsvm; public class svm_node implements java.io.Serializable { public int index; public double value; } libsvm-3.21+ds/java/libsvm/svm.m40000644000175000017500000017323412633544332016136 0ustar ctsai12ctsai12define(`swap',`do {$1 _=$2; $2=$3; $3=_;} while(false)') define(`Qfloat',`float') define(`SIZE_OF_QFLOAT',4) define(`TAU',1e-12) changecom(`//',`') package libsvm; import java.io.*; import java.util.*; // // Kernel Cache // // l is the number of total data items // size is the cache size limit in bytes // class Cache { private final int l; private long size; private final class head_t { head_t prev, next; // a cicular list Qfloat[] data; int len; // data[0,len) is cached in this entry } private final head_t[] head; private head_t lru_head; Cache(int l_, long size_) { l = l_; size = size_; head = new head_t[l]; for(int i=0;i= len if nothing needs to be filled) // java: simulate pointer using single-element array int get_data(int index, Qfloat[][] data, int len) { head_t h = head[index]; if(h.len > 0) lru_delete(h); int more = len - h.len; if(more > 0) { // free old space while(size < more) { head_t old = lru_head.next; lru_delete(old); size += old.len; old.data = null; old.len = 0; } // allocate new space Qfloat[] new_data = new Qfloat[len]; if(h.data != null) System.arraycopy(h.data,0,new_data,0,h.len); h.data = new_data; size -= more; swap(int,h.len,len); } lru_insert(h); data[0] = h.data; return len; } void swap_index(int i, int j) { if(i==j) return; if(head[i].len > 0) lru_delete(head[i]); if(head[j].len > 0) lru_delete(head[j]); swap(Qfloat[],head[i].data,head[j].data); swap(int,head[i].len,head[j].len); if(head[i].len > 0) lru_insert(head[i]); if(head[j].len > 0) lru_insert(head[j]); if(i>j) swap(int,i,j); for(head_t h = lru_head.next; h!=lru_head; h=h.next) { if(h.len > i) { if(h.len > j) swap(Qfloat,h.data[i],h.data[j]); else { // give up lru_delete(h); size += h.len; h.data = null; h.len = 0; } } } } } // // Kernel evaluation // // the static method k_function is for doing single kernel evaluation // the constructor of Kernel prepares to calculate the l*l kernel matrix // the member function get_Q is for getting one column from the Q Matrix // abstract class QMatrix { abstract Qfloat[] get_Q(int column, int len); abstract double[] get_QD(); abstract void swap_index(int i, int j); }; abstract class Kernel extends QMatrix { private svm_node[][] x; private final double[] x_square; // svm_parameter private final int kernel_type; private final int degree; private final double gamma; private final double coef0; abstract Qfloat[] get_Q(int column, int len); abstract double[] get_QD(); void swap_index(int i, int j) { swap(svm_node[],x[i],x[j]); if(x_square != null) swap(double,x_square[i],x_square[j]); } private static double powi(double base, int times) { double tmp = base, ret = 1.0; for(int t=times; t>0; t/=2) { if(t%2==1) ret*=tmp; tmp = tmp * tmp; } return ret; } double kernel_function(int i, int j) { switch(kernel_type) { case svm_parameter.LINEAR: return dot(x[i],x[j]); case svm_parameter.POLY: return powi(gamma*dot(x[i],x[j])+coef0,degree); case svm_parameter.RBF: return Math.exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); case svm_parameter.SIGMOID: return Math.tanh(gamma*dot(x[i],x[j])+coef0); case svm_parameter.PRECOMPUTED: return x[i][(int)(x[j][0].value)].value; default: return 0; // java } } Kernel(int l, svm_node[][] x_, svm_parameter param) { this.kernel_type = param.kernel_type; this.degree = param.degree; this.gamma = param.gamma; this.coef0 = param.coef0; x = (svm_node[][])x_.clone(); if(kernel_type == svm_parameter.RBF) { x_square = new double[l]; for(int i=0;i y[j].index) ++j; else ++i; } } return sum; } static double k_function(svm_node[] x, svm_node[] y, svm_parameter param) { switch(param.kernel_type) { case svm_parameter.LINEAR: return dot(x,y); case svm_parameter.POLY: return powi(param.gamma*dot(x,y)+param.coef0,param.degree); case svm_parameter.RBF: { double sum = 0; int xlen = x.length; int ylen = y.length; int i = 0; int j = 0; while(i < xlen && j < ylen) { if(x[i].index == y[j].index) { double d = x[i++].value - y[j++].value; sum += d*d; } else if(x[i].index > y[j].index) { sum += y[j].value * y[j].value; ++j; } else { sum += x[i].value * x[i].value; ++i; } } while(i < xlen) { sum += x[i].value * x[i].value; ++i; } while(j < ylen) { sum += y[j].value * y[j].value; ++j; } return Math.exp(-param.gamma*sum); } case svm_parameter.SIGMOID: return Math.tanh(param.gamma*dot(x,y)+param.coef0); case svm_parameter.PRECOMPUTED: return x[(int)(y[0].value)].value; default: return 0; // java } } } // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918 // Solves: // // min 0.5(\alpha^T Q \alpha) + p^T \alpha // // y^T \alpha = \delta // y_i = +1 or -1 // 0 <= alpha_i <= Cp for y_i = 1 // 0 <= alpha_i <= Cn for y_i = -1 // // Given: // // Q, p, y, Cp, Cn, and an initial feasible point \alpha // l is the size of vectors and matrices // eps is the stopping tolerance // // solution will be put in \alpha, objective value will be put in obj // class Solver { int active_size; byte[] y; double[] G; // gradient of objective function static final byte LOWER_BOUND = 0; static final byte UPPER_BOUND = 1; static final byte FREE = 2; byte[] alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE double[] alpha; QMatrix Q; double[] QD; double eps; double Cp,Cn; double[] p; int[] active_set; double[] G_bar; // gradient, if we treat free variables as 0 int l; boolean unshrink; // XXX static final double INF = java.lang.Double.POSITIVE_INFINITY; double get_C(int i) { return (y[i] > 0)? Cp : Cn; } void update_alpha_status(int i) { if(alpha[i] >= get_C(i)) alpha_status[i] = UPPER_BOUND; else if(alpha[i] <= 0) alpha_status[i] = LOWER_BOUND; else alpha_status[i] = FREE; } boolean is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; } boolean is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; } boolean is_free(int i) { return alpha_status[i] == FREE; } // java: information about solution except alpha, // because we cannot return multiple values otherwise... static class SolutionInfo { double obj; double rho; double upper_bound_p; double upper_bound_n; double r; // for Solver_NU } void swap_index(int i, int j) { Q.swap_index(i,j); swap(byte, y[i],y[j]); swap(double, G[i],G[j]); swap(byte, alpha_status[i],alpha_status[j]); swap(double, alpha[i],alpha[j]); swap(double, p[i],p[j]); swap(int, active_set[i],active_set[j]); swap(double, G_bar[i],G_bar[j]); } void reconstruct_gradient() { // reconstruct inactive elements of G from G_bar and free variables if(active_size == l) return; int i,j; int nr_free = 0; for(j=active_size;j 2*active_size*(l-active_size)) { for(i=active_size;iInteger.MAX_VALUE/100 ? Integer.MAX_VALUE : 100*l); int counter = Math.min(l,1000)+1; int[] working_set = new int[2]; while(iter < max_iter) { // show progress and do shrinking if(--counter == 0) { counter = Math.min(l,1000); if(shrinking!=0) do_shrinking(); svm.info("."); } if(select_working_set(working_set)!=0) { // reconstruct the whole gradient reconstruct_gradient(); // reset active set size and check active_size = l; svm.info("*"); if(select_working_set(working_set)!=0) break; else counter = 1; // do shrinking next iteration } int i = working_set[0]; int j = working_set[1]; ++iter; // update alpha[i] and alpha[j], handle bounds carefully Qfloat[] Q_i = Q.get_Q(i,active_size); Qfloat[] Q_j = Q.get_Q(j,active_size); double C_i = get_C(i); double C_j = get_C(j); double old_alpha_i = alpha[i]; double old_alpha_j = alpha[j]; if(y[i]!=y[j]) { double quad_coef = QD[i]+QD[j]+2*Q_i[j]; if (quad_coef <= 0) quad_coef = TAU; double delta = (-G[i]-G[j])/quad_coef; double diff = alpha[i] - alpha[j]; alpha[i] += delta; alpha[j] += delta; if(diff > 0) { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = diff; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = -diff; } } if(diff > C_i - C_j) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = C_i - diff; } } else { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = C_j + diff; } } } else { double quad_coef = QD[i]+QD[j]-2*Q_i[j]; if (quad_coef <= 0) quad_coef = TAU; double delta = (G[i]-G[j])/quad_coef; double sum = alpha[i] + alpha[j]; alpha[i] -= delta; alpha[j] += delta; if(sum > C_i) { if(alpha[i] > C_i) { alpha[i] = C_i; alpha[j] = sum - C_i; } } else { if(alpha[j] < 0) { alpha[j] = 0; alpha[i] = sum; } } if(sum > C_j) { if(alpha[j] > C_j) { alpha[j] = C_j; alpha[i] = sum - C_j; } } else { if(alpha[i] < 0) { alpha[i] = 0; alpha[j] = sum; } } } // update G double delta_alpha_i = alpha[i] - old_alpha_i; double delta_alpha_j = alpha[j] - old_alpha_j; for(int k=0;k= max_iter) { if(active_size < l) { // reconstruct the whole gradient to calculate objective value reconstruct_gradient(); active_size = l; svm.info("*"); } System.err.print("\nWARNING: reaching max number of iterations\n"); } // calculate rho si.rho = calculate_rho(); // calculate objective value { double v = 0; int i; for(i=0;i= Gmax) { Gmax = -G[t]; Gmax_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmax) { Gmax = G[t]; Gmax_idx = t; } } int i = Gmax_idx; Qfloat[] Q_i = null; if(i != -1) // null Q_i not accessed: Gmax=-INF if i=-1 Q_i = Q.get_Q(i,active_size); for(int j=0;j= Gmax2) Gmax2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff= Gmax-G[j]; if (-G[j] >= Gmax2) Gmax2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(Gmax+Gmax2 < eps || Gmin_idx == -1) return 1; working_set[0] = Gmax_idx; working_set[1] = Gmin_idx; return 0; } private boolean be_shrunk(int i, double Gmax1, double Gmax2) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax2); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax1); } else return(false); } void do_shrinking() { int i; double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } // find maximal violating pair first for(i=0;i= Gmax1) Gmax1 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax2) Gmax2 = G[i]; } } else { if(!is_upper_bound(i)) { if(-G[i] >= Gmax2) Gmax2 = -G[i]; } if(!is_lower_bound(i)) { if(G[i] >= Gmax1) Gmax1 = G[i]; } } } if(unshrink == false && Gmax1 + Gmax2 <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2)) { swap_index(i,active_size); break; } active_size--; } } } double calculate_rho() { double r; int nr_free = 0; double ub = INF, lb = -INF, sum_free = 0; for(int i=0;i 0) ub = Math.min(ub,yG); else lb = Math.max(lb,yG); } else if(is_upper_bound(i)) { if(y[i] < 0) ub = Math.min(ub,yG); else lb = Math.max(lb,yG); } else { ++nr_free; sum_free += yG; } } if(nr_free>0) r = sum_free/nr_free; else r = (ub+lb)/2; return r; } } // // Solver for nu-svm classification and regression // // additional constraint: e^T \alpha = constant // final class Solver_NU extends Solver { private SolutionInfo si; void Solve(int l, QMatrix Q, double[] p, byte[] y, double[] alpha, double Cp, double Cn, double eps, SolutionInfo si, int shrinking) { this.si = si; super.Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking); } // return 1 if already optimal, return 0 otherwise int select_working_set(int[] working_set) { // return i,j such that y_i = y_j and // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha) // j: minimizes the decrease of obj value // (if quadratic coefficeint <= 0, replace it with tau) // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha) double Gmaxp = -INF; double Gmaxp2 = -INF; int Gmaxp_idx = -1; double Gmaxn = -INF; double Gmaxn2 = -INF; int Gmaxn_idx = -1; int Gmin_idx = -1; double obj_diff_min = INF; for(int t=0;t= Gmaxp) { Gmaxp = -G[t]; Gmaxp_idx = t; } } else { if(!is_lower_bound(t)) if(G[t] >= Gmaxn) { Gmaxn = G[t]; Gmaxn_idx = t; } } int ip = Gmaxp_idx; int in = Gmaxn_idx; Qfloat[] Q_ip = null; Qfloat[] Q_in = null; if(ip != -1) // null Q_ip not accessed: Gmaxp=-INF if ip=-1 Q_ip = Q.get_Q(ip,active_size); if(in != -1) Q_in = Q.get_Q(in,active_size); for(int j=0;j= Gmaxp2) Gmaxp2 = G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[ip]+QD[j]-2*Q_ip[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } else { if (!is_upper_bound(j)) { double grad_diff=Gmaxn-G[j]; if (-G[j] >= Gmaxn2) Gmaxn2 = -G[j]; if (grad_diff > 0) { double obj_diff; double quad_coef = QD[in]+QD[j]-2*Q_in[j]; if (quad_coef > 0) obj_diff = -(grad_diff*grad_diff)/quad_coef; else obj_diff = -(grad_diff*grad_diff)/TAU; if (obj_diff <= obj_diff_min) { Gmin_idx=j; obj_diff_min = obj_diff; } } } } } if(Math.max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1) return 1; if(y[Gmin_idx] == +1) working_set[0] = Gmaxp_idx; else working_set[0] = Gmaxn_idx; working_set[1] = Gmin_idx; return 0; } private boolean be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4) { if(is_upper_bound(i)) { if(y[i]==+1) return(-G[i] > Gmax1); else return(-G[i] > Gmax4); } else if(is_lower_bound(i)) { if(y[i]==+1) return(G[i] > Gmax2); else return(G[i] > Gmax3); } else return(false); } void do_shrinking() { double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) } double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) } double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) } double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) } // find maximal violating pair first int i; for(i=0;i Gmax1) Gmax1 = -G[i]; } else if(-G[i] > Gmax4) Gmax4 = -G[i]; } if(!is_lower_bound(i)) { if(y[i]==+1) { if(G[i] > Gmax2) Gmax2 = G[i]; } else if(G[i] > Gmax3) Gmax3 = G[i]; } } if(unshrink == false && Math.max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10) { unshrink = true; reconstruct_gradient(); active_size = l; } for(i=0;i i) { if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4)) { swap_index(i,active_size); break; } active_size--; } } } double calculate_rho() { int nr_free1 = 0,nr_free2 = 0; double ub1 = INF, ub2 = INF; double lb1 = -INF, lb2 = -INF; double sum_free1 = 0, sum_free2 = 0; for(int i=0;i 0) r1 = sum_free1/nr_free1; else r1 = (ub1+lb1)/2; if(nr_free2 > 0) r2 = sum_free2/nr_free2; else r2 = (ub2+lb2)/2; si.r = (r1+r2)/2; return (r1-r2)/2; } } // // Q matrices for various formulations // class SVC_Q extends Kernel { private final byte[] y; private final Cache cache; private final double[] QD; SVC_Q(svm_problem prob, svm_parameter param, byte[] y_) { super(prob.l, prob.x, param); y = (byte[])y_.clone(); cache = new Cache(prob.l,(long)(param.cache_size*(1<<20))); QD = new double[prob.l]; for(int i=0;i 0) y[i] = +1; else y[i] = -1; } Solver s = new Solver(); s.Solve(l, new SVC_Q(prob,param,y), minus_ones, y, alpha, Cp, Cn, param.eps, si, param.shrinking); double sum_alpha=0; for(i=0;i0) y[i] = +1; else y[i] = -1; double sum_pos = nu*l/2; double sum_neg = nu*l/2; for(i=0;i 0) { ++nSV; if(prob.y[i] > 0) { if(Math.abs(alpha[i]) >= si.upper_bound_p) ++nBSV; } else { if(Math.abs(alpha[i]) >= si.upper_bound_n) ++nBSV; } } } svm.info("nSV = "+nSV+", nBSV = "+nBSV+"\n"); decision_function f = new decision_function(); f.alpha = alpha; f.rho = si.rho; return f; } // Platt's binary SVM Probablistic Output: an improvement from Lin et al. private static void sigmoid_train(int l, double[] dec_values, double[] labels, double[] probAB) { double A, B; double prior1=0, prior0 = 0; int i; for (i=0;i 0) prior1+=1; else prior0+=1; int max_iter=100; // Maximal number of iterations double min_step=1e-10; // Minimal step taken in line search double sigma=1e-12; // For numerically strict PD of Hessian double eps=1e-5; double hiTarget=(prior1+1.0)/(prior1+2.0); double loTarget=1/(prior0+2.0); double[] t= new double[l]; double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize; double newA,newB,newf,d1,d2; int iter; // Initial Point and Initial Fun Value A=0.0; B=Math.log((prior0+1.0)/(prior1+1.0)); double fval = 0.0; for (i=0;i0) t[i]=hiTarget; else t[i]=loTarget; fApB = dec_values[i]*A+B; if (fApB>=0) fval += t[i]*fApB + Math.log(1+Math.exp(-fApB)); else fval += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB)); } for (iter=0;iter= 0) { p=Math.exp(-fApB)/(1.0+Math.exp(-fApB)); q=1.0/(1.0+Math.exp(-fApB)); } else { p=1.0/(1.0+Math.exp(fApB)); q=Math.exp(fApB)/(1.0+Math.exp(fApB)); } d2=p*q; h11+=dec_values[i]*dec_values[i]*d2; h22+=d2; h21+=dec_values[i]*d2; d1=t[i]-p; g1+=dec_values[i]*d1; g2+=d1; } // Stopping Criteria if (Math.abs(g1)= min_step) { newA = A + stepsize * dA; newB = B + stepsize * dB; // New function value newf = 0.0; for (i=0;i= 0) newf += t[i]*fApB + Math.log(1+Math.exp(-fApB)); else newf += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB)); } // Check sufficient decrease if (newf=max_iter) svm.info("Reaching maximal iterations in two-class probability estimates\n"); probAB[0]=A;probAB[1]=B; } private static double sigmoid_predict(double decision_value, double A, double B) { double fApB = decision_value*A+B; if (fApB >= 0) return Math.exp(-fApB)/(1.0+Math.exp(-fApB)); else return 1.0/(1+Math.exp(fApB)) ; } // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng private static void multiclass_probability(int k, double[][] r, double[] p) { int t,j; int iter = 0, max_iter=Math.max(100,k); double[][] Q=new double[k][k]; double[] Qp=new double[k]; double pQp, eps=0.005/k; for (t=0;tmax_error) max_error=error; } if (max_error=max_iter) svm.info("Exceeds max_iter in multiclass_prob\n"); } // Cross-validation decision values for probability estimates private static void svm_binary_svc_probability(svm_problem prob, svm_parameter param, double Cp, double Cn, double[] probAB) { int i; int nr_fold = 5; int[] perm = new int[prob.l]; double[] dec_values = new double[prob.l]; // random shuffle for(i=0;i0) p_count++; else n_count++; if(p_count==0 && n_count==0) for(j=begin;j 0 && n_count == 0) for(j=begin;j 0) for(j=begin;j 5*std) count=count+1; else mae+=Math.abs(ymv[i]); mae /= (prob.l-count); svm.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="+mae+"\n"); return mae; } // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data // perm, length l, must be allocated before calling this subroutine private static void svm_group_classes(svm_problem prob, int[] nr_class_ret, int[][] label_ret, int[][] start_ret, int[][] count_ret, int[] perm) { int l = prob.l; int max_nr_class = 16; int nr_class = 0; int[] label = new int[max_nr_class]; int[] count = new int[max_nr_class]; int[] data_label = new int[l]; int i; for(i=0;i 0) ++nSV; model.l = nSV; model.SV = new svm_node[nSV][]; model.sv_coef[0] = new double[nSV]; model.sv_indices = new int[nSV]; int j = 0; for(i=0;i 0) { model.SV[j] = prob.x[i]; model.sv_coef[0][j] = f.alpha[i]; model.sv_indices[j] = i+1; ++j; } } else { // classification int l = prob.l; int[] tmp_nr_class = new int[1]; int[][] tmp_label = new int[1][]; int[][] tmp_start = new int[1][]; int[][] tmp_count = new int[1][]; int[] perm = new int[l]; // group training data of the same class svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm); int nr_class = tmp_nr_class[0]; int[] label = tmp_label[0]; int[] start = tmp_start[0]; int[] count = tmp_count[0]; if(nr_class == 1) svm.info("WARNING: training data in only one class. See README for details.\n"); svm_node[][] x = new svm_node[l][]; int i; for(i=0;i 0) nonzero[si+k] = true; for(k=0;k 0) nonzero[sj+k] = true; ++p; } // build output model.nr_class = nr_class; model.label = new int[nr_class]; for(i=0;i some folds may have zero elements if((param.svm_type == svm_parameter.C_SVC || param.svm_type == svm_parameter.NU_SVC) && nr_fold < l) { int[] tmp_nr_class = new int[1]; int[][] tmp_label = new int[1][]; int[][] tmp_start = new int[1][]; int[][] tmp_count = new int[1][]; svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm); int nr_class = tmp_nr_class[0]; int[] start = tmp_start[0]; int[] count = tmp_count[0]; // random shuffle and then data grouped by fold using the array perm int[] fold_count = new int[nr_fold]; int c; int[] index = new int[l]; for(i=0;i0)?1:-1; else return sum; } else { int nr_class = model.nr_class; int l = model.l; double[] kvalue = new double[l]; for(i=0;i 0) ++vote[i]; else ++vote[j]; p++; } int vote_max_idx = 0; for(i=1;i vote[vote_max_idx]) vote_max_idx = i; return model.label[vote_max_idx]; } } public static double svm_predict(svm_model model, svm_node[] x) { int nr_class = model.nr_class; double[] dec_values; if(model.param.svm_type == svm_parameter.ONE_CLASS || model.param.svm_type == svm_parameter.EPSILON_SVR || model.param.svm_type == svm_parameter.NU_SVR) dec_values = new double[1]; else dec_values = new double[nr_class*(nr_class-1)/2]; double pred_result = svm_predict_values(model, x, dec_values); return pred_result; } public static double svm_predict_probability(svm_model model, svm_node[] x, double[] prob_estimates) { if ((model.param.svm_type == svm_parameter.C_SVC || model.param.svm_type == svm_parameter.NU_SVC) && model.probA!=null && model.probB!=null) { int i; int nr_class = model.nr_class; double[] dec_values = new double[nr_class*(nr_class-1)/2]; svm_predict_values(model, x, dec_values); double min_prob=1e-7; double[][] pairwise_prob=new double[nr_class][nr_class]; int k=0; for(i=0;i prob_estimates[prob_max_idx]) prob_max_idx = i; return model.label[prob_max_idx]; } else return svm_predict(model, x); } static final String svm_type_table[] = { "c_svc","nu_svc","one_class","epsilon_svr","nu_svr", }; static final String kernel_type_table[]= { "linear","polynomial","rbf","sigmoid","precomputed" }; public static void svm_save_model(String model_file_name, svm_model model) throws IOException { DataOutputStream fp = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(model_file_name))); svm_parameter param = model.param; fp.writeBytes("svm_type "+svm_type_table[param.svm_type]+"\n"); fp.writeBytes("kernel_type "+kernel_type_table[param.kernel_type]+"\n"); if(param.kernel_type == svm_parameter.POLY) fp.writeBytes("degree "+param.degree+"\n"); if(param.kernel_type == svm_parameter.POLY || param.kernel_type == svm_parameter.RBF || param.kernel_type == svm_parameter.SIGMOID) fp.writeBytes("gamma "+param.gamma+"\n"); if(param.kernel_type == svm_parameter.POLY || param.kernel_type == svm_parameter.SIGMOID) fp.writeBytes("coef0 "+param.coef0+"\n"); int nr_class = model.nr_class; int l = model.l; fp.writeBytes("nr_class "+nr_class+"\n"); fp.writeBytes("total_sv "+l+"\n"); { fp.writeBytes("rho"); for(int i=0;i 1) return "nu <= 0 or nu > 1"; if(svm_type == svm_parameter.EPSILON_SVR) if(param.p < 0) return "p < 0"; if(param.shrinking != 0 && param.shrinking != 1) return "shrinking != 0 and shrinking != 1"; if(param.probability != 0 && param.probability != 1) return "probability != 0 and probability != 1"; if(param.probability == 1 && svm_type == svm_parameter.ONE_CLASS) return "one-class SVM probability output not supported yet"; // check whether nu-svc is feasible if(svm_type == svm_parameter.NU_SVC) { int l = prob.l; int max_nr_class = 16; int nr_class = 0; int[] label = new int[max_nr_class]; int[] count = new int[max_nr_class]; int i; for(i=0;i Math.min(n1,n2)) return "specified nu is infeasible"; } } } return null; } public static int svm_check_probability_model(svm_model model) { if (((model.param.svm_type == svm_parameter.C_SVC || model.param.svm_type == svm_parameter.NU_SVC) && model.probA!=null && model.probB!=null) || ((model.param.svm_type == svm_parameter.EPSILON_SVR || model.param.svm_type == svm_parameter.NU_SVR) && model.probA!=null)) return 1; else return 0; } public static void svm_set_print_string_function(svm_print_interface print_func) { if (print_func == null) svm_print_string = svm_print_stdout; else svm_print_string = print_func; } } libsvm-3.21+ds/java/libsvm/svm_model.java0000644000175000017500000000154412633544332017711 0ustar ctsai12ctsai12// // svm_model // package libsvm; public class svm_model implements java.io.Serializable { public svm_parameter param; // parameter public int nr_class; // number of classes, = 2 in regression/one class svm public int l; // total #SV public svm_node[][] SV; // SVs (SV[l]) public double[][] sv_coef; // coefficients for SVs in decision functions (sv_coef[k-1][l]) public double[] rho; // constants in decision functions (rho[k*(k-1)/2]) public double[] probA; // pariwise probability information public double[] probB; public int[] sv_indices; // sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set // for classification only public int[] label; // label of each class (label[k]) public int[] nSV; // number of SVs for each class (nSV[k]) // nSV[0] + nSV[1] + ... + nSV[k-1] = l }; libsvm-3.21+ds/java/libsvm/svm_problem.java0000644000175000017500000000021012633544332020236 0ustar ctsai12ctsai12package libsvm; public class svm_problem implements java.io.Serializable { public int l; public double[] y; public svm_node[][] x; } libsvm-3.21+ds/java/libsvm/svm_parameter.java0000644000175000017500000000241012633544332020562 0ustar ctsai12ctsai12package libsvm; public class svm_parameter implements Cloneable,java.io.Serializable { /* svm_type */ public static final int C_SVC = 0; public static final int NU_SVC = 1; public static final int ONE_CLASS = 2; public static final int EPSILON_SVR = 3; public static final int NU_SVR = 4; /* kernel_type */ public static final int LINEAR = 0; public static final int POLY = 1; public static final int RBF = 2; public static final int SIGMOID = 3; public static final int PRECOMPUTED = 4; public int svm_type; public int kernel_type; public int degree; // for poly public double gamma; // for poly/rbf/sigmoid public double coef0; // for poly/sigmoid // these are for training only public double cache_size; // in MB public double eps; // stopping criteria public double C; // for C_SVC, EPSILON_SVR and NU_SVR public int nr_weight; // for C_SVC public int[] weight_label; // for C_SVC public double[] weight; // for C_SVC public double nu; // for NU_SVC, ONE_CLASS, and NU_SVR public double p; // for EPSILON_SVR public int shrinking; // use the shrinking heuristics public int probability; // do probability estimates public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } } } libsvm-3.21+ds/java/libsvm/svm_print_interface.java0000644000175000017500000000012712633544332021761 0ustar ctsai12ctsai12package libsvm; public interface svm_print_interface { public void print(String s); } libsvm-3.21+ds/java/svm_toy.java0000644000175000017500000002775512633544333016145 0ustar ctsai12ctsai12import libsvm.*; import java.applet.*; import java.awt.*; import java.util.*; import java.awt.event.*; import java.io.*; public class svm_toy extends Applet { static final String DEFAULT_PARAM="-t 2 -c 100"; int XLEN; int YLEN; // off-screen buffer Image buffer; Graphics buffer_gc; // pre-allocated colors final static Color colors[] = { new Color(0,0,0), new Color(0,120,120), new Color(120,120,0), new Color(120,0,120), new Color(0,200,200), new Color(200,200,0), new Color(200,0,200) }; class point { point(double x, double y, byte value) { this.x = x; this.y = y; this.value = value; } double x, y; byte value; } Vector point_list = new Vector(); byte current_value = 1; public void init() { setSize(getSize()); final Button button_change = new Button("Change"); Button button_run = new Button("Run"); Button button_clear = new Button("Clear"); Button button_save = new Button("Save"); Button button_load = new Button("Load"); final TextField input_line = new TextField(DEFAULT_PARAM); BorderLayout layout = new BorderLayout(); this.setLayout(layout); Panel p = new Panel(); GridBagLayout gridbag = new GridBagLayout(); p.setLayout(gridbag); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; c.gridwidth = 1; gridbag.setConstraints(button_change,c); gridbag.setConstraints(button_run,c); gridbag.setConstraints(button_clear,c); gridbag.setConstraints(button_save,c); gridbag.setConstraints(button_load,c); c.weightx = 5; c.gridwidth = 5; gridbag.setConstraints(input_line,c); button_change.setBackground(colors[current_value]); p.add(button_change); p.add(button_run); p.add(button_clear); p.add(button_save); p.add(button_load); p.add(input_line); this.add(p,BorderLayout.SOUTH); button_change.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_change_clicked(); button_change.setBackground(colors[current_value]); }}); button_run.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_run_clicked(input_line.getText()); }}); button_clear.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_clear_clicked(); }}); button_save.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_save_clicked(input_line.getText()); }}); button_load.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_load_clicked(); }}); input_line.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { button_run_clicked(input_line.getText()); }}); this.enableEvents(AWTEvent.MOUSE_EVENT_MASK); } void draw_point(point p) { Color c = colors[p.value+3]; Graphics window_gc = getGraphics(); buffer_gc.setColor(c); buffer_gc.fillRect((int)(p.x*XLEN),(int)(p.y*YLEN),4,4); window_gc.setColor(c); window_gc.fillRect((int)(p.x*XLEN),(int)(p.y*YLEN),4,4); } void clear_all() { point_list.removeAllElements(); if(buffer != null) { buffer_gc.setColor(colors[0]); buffer_gc.fillRect(0,0,XLEN,YLEN); } repaint(); } void draw_all_points() { int n = point_list.size(); for(int i=0;i 3) current_value = 1; } private static double atof(String s) { return Double.valueOf(s).doubleValue(); } private static int atoi(String s) { return Integer.parseInt(s); } void button_run_clicked(String args) { // guard if(point_list.isEmpty()) return; svm_parameter param = new svm_parameter(); // default values param.svm_type = svm_parameter.C_SVC; param.kernel_type = svm_parameter.RBF; param.degree = 3; param.gamma = 0; param.coef0 = 0; param.nu = 0.5; param.cache_size = 40; param.C = 1; param.eps = 1e-3; param.p = 0.1; param.shrinking = 1; param.probability = 0; param.nr_weight = 0; param.weight_label = new int[0]; param.weight = new double[0]; // parse options StringTokenizer st = new StringTokenizer(args); String[] argv = new String[st.countTokens()]; for(int i=0;i=argv.length) { System.err.print("unknown option\n"); break; } switch(argv[i-1].charAt(1)) { case 's': param.svm_type = atoi(argv[i]); break; case 't': param.kernel_type = atoi(argv[i]); break; case 'd': param.degree = atoi(argv[i]); break; case 'g': param.gamma = atof(argv[i]); break; case 'r': param.coef0 = atof(argv[i]); break; case 'n': param.nu = atof(argv[i]); break; case 'm': param.cache_size = atof(argv[i]); break; case 'c': param.C = atof(argv[i]); break; case 'e': param.eps = atof(argv[i]); break; case 'p': param.p = atof(argv[i]); break; case 'h': param.shrinking = atoi(argv[i]); break; case 'b': param.probability = atoi(argv[i]); break; case 'w': ++param.nr_weight; { int[] old = param.weight_label; param.weight_label = new int[param.nr_weight]; System.arraycopy(old,0,param.weight_label,0,param.nr_weight-1); } { double[] old = param.weight; param.weight = new double[param.nr_weight]; System.arraycopy(old,0,param.weight,0,param.nr_weight-1); } param.weight_label[param.nr_weight-1] = atoi(argv[i-1].substring(2)); param.weight[param.nr_weight-1] = atof(argv[i]); break; default: System.err.print("unknown option\n"); } } // build problem svm_problem prob = new svm_problem(); prob.l = point_list.size(); prob.y = new double[prob.l]; if(param.kernel_type == svm_parameter.PRECOMPUTED) { } else if(param.svm_type == svm_parameter.EPSILON_SVR || param.svm_type == svm_parameter.NU_SVR) { if(param.gamma == 0) param.gamma = 1; prob.x = new svm_node[prob.l][1]; for(int i=0;i= XLEN || e.getY() >= YLEN) return; point p = new point((double)e.getX()/XLEN, (double)e.getY()/YLEN, current_value); point_list.addElement(p); draw_point(p); } } public void paint(Graphics g) { // create buffer first time if(buffer == null) { buffer = this.createImage(XLEN,YLEN); buffer_gc = buffer.getGraphics(); buffer_gc.setColor(colors[0]); buffer_gc.fillRect(0,0,XLEN,YLEN); } g.drawImage(buffer,0,0,this); } public Dimension getPreferredSize() { return new Dimension(XLEN,YLEN+50); } public void setSize(Dimension d) { setSize(d.width,d.height); } public void setSize(int w,int h) { super.setSize(w,h); XLEN = w; YLEN = h-50; clear_all(); } public static void main(String[] argv) { new AppletFrame("svm_toy",new svm_toy(),500,500+50); } } class AppletFrame extends Frame { AppletFrame(String title, Applet applet, int width, int height) { super(title); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); applet.init(); applet.setSize(width,height); applet.start(); this.add(applet); this.pack(); this.setVisible(true); } } libsvm-3.21+ds/java/svm_train.java0000644000175000017500000002024312633544333016430 0ustar ctsai12ctsai12import libsvm.*; import java.io.*; import java.util.*; class svm_train { private svm_parameter param; // set by parse_command_line private svm_problem prob; // set by read_problem private svm_model model; private String input_file_name; // set by parse_command_line private String model_file_name; // set by parse_command_line private String error_msg; private int cross_validation; private int nr_fold; private static svm_print_interface svm_print_null = new svm_print_interface() { public void print(String s) {} }; private static void exit_with_help() { System.out.print( "Usage: svm_train [options] training_set_file [model_file]\n" +"options:\n" +"-s svm_type : set type of SVM (default 0)\n" +" 0 -- C-SVC (multi-class classification)\n" +" 1 -- nu-SVC (multi-class classification)\n" +" 2 -- one-class SVM\n" +" 3 -- epsilon-SVR (regression)\n" +" 4 -- nu-SVR (regression)\n" +"-t kernel_type : set type of kernel function (default 2)\n" +" 0 -- linear: u'*v\n" +" 1 -- polynomial: (gamma*u'*v + coef0)^degree\n" +" 2 -- radial basis function: exp(-gamma*|u-v|^2)\n" +" 3 -- sigmoid: tanh(gamma*u'*v + coef0)\n" +" 4 -- precomputed kernel (kernel values in training_set_file)\n" +"-d degree : set degree in kernel function (default 3)\n" +"-g gamma : set gamma in kernel function (default 1/num_features)\n" +"-r coef0 : set coef0 in kernel function (default 0)\n" +"-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)\n" +"-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)\n" +"-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)\n" +"-m cachesize : set cache memory size in MB (default 100)\n" +"-e epsilon : set tolerance of termination criterion (default 0.001)\n" +"-h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1)\n" +"-b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)\n" +"-wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1)\n" +"-v n : n-fold cross validation mode\n" +"-q : quiet mode (no outputs)\n" ); System.exit(1); } private void do_cross_validation() { int i; int total_correct = 0; double total_error = 0; double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; double[] target = new double[prob.l]; svm.svm_cross_validation(prob,param,nr_fold,target); if(param.svm_type == svm_parameter.EPSILON_SVR || param.svm_type == svm_parameter.NU_SVR) { for(i=0;i=argv.length) exit_with_help(); switch(argv[i-1].charAt(1)) { case 's': param.svm_type = atoi(argv[i]); break; case 't': param.kernel_type = atoi(argv[i]); break; case 'd': param.degree = atoi(argv[i]); break; case 'g': param.gamma = atof(argv[i]); break; case 'r': param.coef0 = atof(argv[i]); break; case 'n': param.nu = atof(argv[i]); break; case 'm': param.cache_size = atof(argv[i]); break; case 'c': param.C = atof(argv[i]); break; case 'e': param.eps = atof(argv[i]); break; case 'p': param.p = atof(argv[i]); break; case 'h': param.shrinking = atoi(argv[i]); break; case 'b': param.probability = atoi(argv[i]); break; case 'q': print_func = svm_print_null; i--; break; case 'v': cross_validation = 1; nr_fold = atoi(argv[i]); if(nr_fold < 2) { System.err.print("n-fold cross validation: n must >= 2\n"); exit_with_help(); } break; case 'w': ++param.nr_weight; { int[] old = param.weight_label; param.weight_label = new int[param.nr_weight]; System.arraycopy(old,0,param.weight_label,0,param.nr_weight-1); } { double[] old = param.weight; param.weight = new double[param.nr_weight]; System.arraycopy(old,0,param.weight,0,param.nr_weight-1); } param.weight_label[param.nr_weight-1] = atoi(argv[i-1].substring(2)); param.weight[param.nr_weight-1] = atof(argv[i]); break; default: System.err.print("Unknown option: " + argv[i-1] + "\n"); exit_with_help(); } } svm.svm_set_print_string_function(print_func); // determine filenames if(i>=argv.length) exit_with_help(); input_file_name = argv[i]; if(i vy = new Vector(); Vector vx = new Vector(); int max_index = 0; while(true) { String line = fp.readLine(); if(line == null) break; StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); vy.addElement(atof(st.nextToken())); int m = st.countTokens()/2; svm_node[] x = new svm_node[m]; for(int j=0;j0) max_index = Math.max(max_index, x[m-1].index); vx.addElement(x); } prob = new svm_problem(); prob.l = vy.size(); prob.x = new svm_node[prob.l][]; for(int i=0;i 0) param.gamma = 1.0/max_index; if(param.kernel_type == svm_parameter.PRECOMPUTED) for(int i=0;i max_index) { System.err.print("Wrong input format: sample_serial_number out of range\n"); System.exit(1); } } fp.close(); } } libsvm-3.21+ds/java/test_applet.html0000644000175000017500000000012112633544333016766 0ustar ctsai12ctsai12 libsvm-3.21+ds/python/0000755000175000017500000000000012633544335014164 5ustar ctsai12ctsai12libsvm-3.21+ds/python/Makefile0000644000175000017500000000004012633544334015615 0ustar ctsai12ctsai12all = lib lib: make -C .. lib libsvm-3.21+ds/python/svmutil.py0000644000175000017500000002076712633544335016255 0ustar ctsai12ctsai12#!/usr/bin/env python import os import sys from svm import * from svm import __all__ as svm_all __all__ = ['evaluations', 'svm_load_model', 'svm_predict', 'svm_read_problem', 'svm_save_model', 'svm_train'] + svm_all sys.path = [os.path.dirname(os.path.abspath(__file__))] + sys.path def svm_read_problem(data_file_name): """ svm_read_problem(data_file_name) -> [y, x] Read LIBSVM-format data from data_file_name and return labels y and data instances x. """ prob_y = [] prob_x = [] for line in open(data_file_name): line = line.split(None, 1) # In case an instance with all zero features if len(line) == 1: line += [''] label, features = line xi = {} for e in features.split(): ind, val = e.split(":") xi[int(ind)] = float(val) prob_y += [float(label)] prob_x += [xi] return (prob_y, prob_x) def svm_load_model(model_file_name): """ svm_load_model(model_file_name) -> model Load a LIBSVM model from model_file_name and return. """ model = libsvm.svm_load_model(model_file_name.encode()) if not model: print("can't open model file %s" % model_file_name) return None model = toPyModel(model) return model def svm_save_model(model_file_name, model): """ svm_save_model(model_file_name, model) -> None Save a LIBSVM model to the file model_file_name. """ libsvm.svm_save_model(model_file_name.encode(), model) def evaluations(ty, pv): """ evaluations(ty, pv) -> (ACC, MSE, SCC) Calculate accuracy, mean squared error and squared correlation coefficient using the true values (ty) and predicted values (pv). """ if len(ty) != len(pv): raise ValueError("len(ty) must equal to len(pv)") total_correct = total_error = 0 sumv = sumy = sumvv = sumyy = sumvy = 0 for v, y in zip(pv, ty): if y == v: total_correct += 1 total_error += (v-y)*(v-y) sumv += v sumy += y sumvv += v*v sumyy += y*y sumvy += v*y l = len(ty) ACC = 100.0*total_correct/l MSE = total_error/l try: SCC = ((l*sumvy-sumv*sumy)*(l*sumvy-sumv*sumy))/((l*sumvv-sumv*sumv)*(l*sumyy-sumy*sumy)) except: SCC = float('nan') return (ACC, MSE, SCC) def svm_train(arg1, arg2=None, arg3=None): """ svm_train(y, x [, options]) -> model | ACC | MSE svm_train(prob [, options]) -> model | ACC | MSE svm_train(prob, param) -> model | ACC| MSE Train an SVM model from data (y, x) or an svm_problem prob using 'options' or an svm_parameter param. If '-v' is specified in 'options' (i.e., cross validation) either accuracy (ACC) or mean-squared error (MSE) is returned. options: -s svm_type : set type of SVM (default 0) 0 -- C-SVC (multi-class classification) 1 -- nu-SVC (multi-class classification) 2 -- one-class SVM 3 -- epsilon-SVR (regression) 4 -- nu-SVR (regression) -t kernel_type : set type of kernel function (default 2) 0 -- linear: u'*v 1 -- polynomial: (gamma*u'*v + coef0)^degree 2 -- radial basis function: exp(-gamma*|u-v|^2) 3 -- sigmoid: tanh(gamma*u'*v + coef0) 4 -- precomputed kernel (kernel values in training_set_file) -d degree : set degree in kernel function (default 3) -g gamma : set gamma in kernel function (default 1/num_features) -r coef0 : set coef0 in kernel function (default 0) -c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1) -n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5) -p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1) -m cachesize : set cache memory size in MB (default 100) -e epsilon : set tolerance of termination criterion (default 0.001) -h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1) -b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0) -wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1) -v n: n-fold cross validation mode -q : quiet mode (no outputs) """ prob, param = None, None if isinstance(arg1, (list, tuple)): assert isinstance(arg2, (list, tuple)) y, x, options = arg1, arg2, arg3 param = svm_parameter(options) prob = svm_problem(y, x, isKernel=(param.kernel_type == PRECOMPUTED)) elif isinstance(arg1, svm_problem): prob = arg1 if isinstance(arg2, svm_parameter): param = arg2 else: param = svm_parameter(arg2) if prob == None or param == None: raise TypeError("Wrong types for the arguments") if param.kernel_type == PRECOMPUTED: for xi in prob.x_space: idx, val = xi[0].index, xi[0].value if xi[0].index != 0: raise ValueError('Wrong input format: first column must be 0:sample_serial_number') if val <= 0 or val > prob.n: raise ValueError('Wrong input format: sample_serial_number out of range') if param.gamma == 0 and prob.n > 0: param.gamma = 1.0 / prob.n libsvm.svm_set_print_string_function(param.print_func) err_msg = libsvm.svm_check_parameter(prob, param) if err_msg: raise ValueError('Error: %s' % err_msg) if param.cross_validation: l, nr_fold = prob.l, param.nr_fold target = (c_double * l)() libsvm.svm_cross_validation(prob, param, nr_fold, target) ACC, MSE, SCC = evaluations(prob.y[:l], target[:l]) if param.svm_type in [EPSILON_SVR, NU_SVR]: print("Cross Validation Mean squared error = %g" % MSE) print("Cross Validation Squared correlation coefficient = %g" % SCC) return MSE else: print("Cross Validation Accuracy = %g%%" % ACC) return ACC else: m = libsvm.svm_train(prob, param) m = toPyModel(m) # If prob is destroyed, data including SVs pointed by m can remain. m.x_space = prob.x_space return m def svm_predict(y, x, m, options=""): """ svm_predict(y, x, m [, options]) -> (p_labels, p_acc, p_vals) Predict data (y, x) with the SVM model m. options: -b probability_estimates: whether to predict probability estimates, 0 or 1 (default 0); for one-class SVM only 0 is supported. -q : quiet mode (no outputs). The return tuple contains p_labels: a list of predicted labels p_acc: a tuple including accuracy (for classification), mean-squared error, and squared correlation coefficient (for regression). p_vals: a list of decision values or probability estimates (if '-b 1' is specified). If k is the number of classes, for decision values, each element includes results of predicting k(k-1)/2 binary-class SVMs. For probabilities, each element contains k values indicating the probability that the testing instance is in each class. Note that the order of classes here is the same as 'model.label' field in the model structure. """ def info(s): print(s) predict_probability = 0 argv = options.split() i = 0 while i < len(argv): if argv[i] == '-b': i += 1 predict_probability = int(argv[i]) elif argv[i] == '-q': info = print_null else: raise ValueError("Wrong options") i+=1 svm_type = m.get_svm_type() is_prob_model = m.is_probability_model() nr_class = m.get_nr_class() pred_labels = [] pred_values = [] if predict_probability: if not is_prob_model: raise ValueError("Model does not support probabiliy estimates") if svm_type in [NU_SVR, EPSILON_SVR]: info("Prob. model for test data: target value = predicted value + z,\n" "z: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=%g" % m.get_svr_probability()); nr_class = 0 prob_estimates = (c_double * nr_class)() for xi in x: xi, idx = gen_svm_nodearray(xi, isKernel=(m.param.kernel_type == PRECOMPUTED)) label = libsvm.svm_predict_probability(m, xi, prob_estimates) values = prob_estimates[:nr_class] pred_labels += [label] pred_values += [values] else: if is_prob_model: info("Model supports probability estimates, but disabled in predicton.") if svm_type in (ONE_CLASS, EPSILON_SVR, NU_SVC): nr_classifier = 1 else: nr_classifier = nr_class*(nr_class-1)//2 dec_values = (c_double * nr_classifier)() for xi in x: xi, idx = gen_svm_nodearray(xi, isKernel=(m.param.kernel_type == PRECOMPUTED)) label = libsvm.svm_predict_values(m, xi, dec_values) if(nr_class == 1): values = [1] else: values = dec_values[:nr_classifier] pred_labels += [label] pred_values += [values] ACC, MSE, SCC = evaluations(y, pred_labels) l = len(y) if svm_type in [EPSILON_SVR, NU_SVR]: info("Mean squared error = %g (regression)" % MSE) info("Squared correlation coefficient = %g (regression)" % SCC) else: info("Accuracy = %g%% (%d/%d) (classification)" % (ACC, int(l*ACC/100), l)) return pred_labels, (ACC, MSE, SCC), pred_values libsvm-3.21+ds/python/README0000644000175000017500000002720412633544334015050 0ustar ctsai12ctsai12---------------------------------- --- Python interface of LIBSVM --- ---------------------------------- Table of Contents ================= - Introduction - Installation - Quick Start - Design Description - Data Structures - Utility Functions - Additional Information Introduction ============ Python (http://www.python.org/) is a programming language suitable for rapid development. This tool provides a simple Python interface to LIBSVM, a library for support vector machines (http://www.csie.ntu.edu.tw/~cjlin/libsvm). The interface is very easy to use as the usage is the same as that of LIBSVM. The interface is developed with the built-in Python library "ctypes." Installation ============ On Unix systems, type > make The interface needs only LIBSVM shared library, which is generated by the above command. We assume that the shared library is on the LIBSVM main directory or in the system path. For windows, the shared library libsvm.dll for 32-bit python is ready in the directory `..\windows'. You can also copy it to the system directory (e.g., `C:\WINDOWS\system32\' for Windows XP). To regenerate the shared library, please follow the instruction of building windows binaries in LIBSVM README. Quick Start =========== There are two levels of usage. The high-level one uses utility functions in svmutil.py and the usage is the same as the LIBSVM MATLAB interface. >>> from svmutil import * # Read data in LIBSVM format >>> y, x = svm_read_problem('../heart_scale') >>> m = svm_train(y[:200], x[:200], '-c 4') >>> p_label, p_acc, p_val = svm_predict(y[200:], x[200:], m) # Construct problem in python format # Dense data >>> y, x = [1,-1], [[1,0,1], [-1,0,-1]] # Sparse data >>> y, x = [1,-1], [{1:1, 3:1}, {1:-1,3:-1}] >>> prob = svm_problem(y, x) >>> param = svm_parameter('-t 0 -c 4 -b 1') >>> m = svm_train(prob, param) # Precomputed kernel data (-t 4) # Dense data >>> y, x = [1,-1], [[1, 2, -2], [2, -2, 2]] # Sparse data >>> y, x = [1,-1], [{0:1, 1:2, 2:-2}, {0:2, 1:-2, 2:2}] # isKernel=True must be set for precomputer kernel >>> prob = svm_problem(y, x, isKernel=True) >>> param = svm_parameter('-t 4 -c 4 -b 1') >>> m = svm_train(prob, param) # For the format of precomputed kernel, please read LIBSVM README. # Other utility functions >>> svm_save_model('heart_scale.model', m) >>> m = svm_load_model('heart_scale.model') >>> p_label, p_acc, p_val = svm_predict(y, x, m, '-b 1') >>> ACC, MSE, SCC = evaluations(y, p_label) # Getting online help >>> help(svm_train) The low-level use directly calls C interfaces imported by svm.py. Note that all arguments and return values are in ctypes format. You need to handle them carefully. >>> from svm import * >>> prob = svm_problem([1,-1], [{1:1, 3:1}, {1:-1,3:-1}]) >>> param = svm_parameter('-c 4') >>> m = libsvm.svm_train(prob, param) # m is a ctype pointer to an svm_model # Convert a Python-format instance to svm_nodearray, a ctypes structure >>> x0, max_idx = gen_svm_nodearray({1:1, 3:1}) >>> label = libsvm.svm_predict(m, x0) Design Description ================== There are two files svm.py and svmutil.py, which respectively correspond to low-level and high-level use of the interface. In svm.py, we adopt the Python built-in library "ctypes," so that Python can directly access C structures and interface functions defined in svm.h. While advanced users can use structures/functions in svm.py, to avoid handling ctypes structures, in svmutil.py we provide some easy-to-use functions. The usage is similar to LIBSVM MATLAB interface. Data Structures =============== Four data structures derived from svm.h are svm_node, svm_problem, svm_parameter, and svm_model. They all contain fields with the same names in svm.h. Access these fields carefully because you directly use a C structure instead of a Python object. For svm_model, accessing the field directly is not recommanded. Programmers should use the interface functions or methods of svm_model class in Python to get the values. The following description introduces additional fields and methods. Before using the data structures, execute the following command to load the LIBSVM shared library: >>> from svm import * - class svm_node: Construct an svm_node. >>> node = svm_node(idx, val) idx: an integer indicates the feature index. val: a float indicates the feature value. Show the index and the value of a node. >>> print(node) - Function: gen_svm_nodearray(xi [,feature_max=None [,isKernel=False]]) Generate a feature vector from a Python list/tuple or a dictionary: >>> xi, max_idx = gen_svm_nodearray({1:1, 3:1, 5:-2}) xi: the returned svm_nodearray (a ctypes structure) max_idx: the maximal feature index of xi feature_max: if feature_max is assigned, features with indices larger than feature_max are removed. isKernel: if isKernel == True, the list index starts from 0 for precomputed kernel. Otherwise, the list index starts from 1. The default value is False. - class svm_problem: Construct an svm_problem instance >>> prob = svm_problem(y, x) y: a Python list/tuple of l labels (type must be int/double). x: a Python list/tuple of l data instances. Each element of x must be an instance of list/tuple/dictionary type. Note that if your x contains sparse data (i.e., dictionary), the internal ctypes data format is still sparse. For pre-computed kernel, the isKernel flag should be set to True: >>> prob = svm_problem(y, x, isKernel=True) Please read LIBSVM README for more details of pre-computed kernel. - class svm_parameter: Construct an svm_parameter instance >>> param = svm_parameter('training_options') If 'training_options' is empty, LIBSVM default values are applied. Set param to LIBSVM default values. >>> param.set_to_default_values() Parse a string of options. >>> param.parse_options('training_options') Show values of parameters. >>> print(param) - class svm_model: There are two ways to obtain an instance of svm_model: >>> model = svm_train(y, x) >>> model = svm_load_model('model_file_name') Note that the returned structure of interface functions libsvm.svm_train and libsvm.svm_load_model is a ctypes pointer of svm_model, which is different from the svm_model object returned by svm_train and svm_load_model in svmutil.py. We provide a function toPyModel for the conversion: >>> model_ptr = libsvm.svm_train(prob, param) >>> model = toPyModel(model_ptr) If you obtain a model in a way other than the above approaches, handle it carefully to avoid memory leak or segmentation fault. Some interface functions to access LIBSVM models are wrapped as members of the class svm_model: >>> svm_type = model.get_svm_type() >>> nr_class = model.get_nr_class() >>> svr_probability = model.get_svr_probability() >>> class_labels = model.get_labels() >>> sv_indices = model.get_sv_indices() >>> nr_sv = model.get_nr_sv() >>> is_prob_model = model.is_probability_model() >>> support_vector_coefficients = model.get_sv_coef() >>> support_vectors = model.get_SV() Utility Functions ================= To use utility functions, type >>> from svmutil import * The above command loads svm_train() : train an SVM model svm_predict() : predict testing data svm_read_problem() : read the data from a LIBSVM-format file. svm_load_model() : load a LIBSVM model. svm_save_model() : save model to a file. evaluations() : evaluate prediction results. - Function: svm_train There are three ways to call svm_train() >>> model = svm_train(y, x [, 'training_options']) >>> model = svm_train(prob [, 'training_options']) >>> model = svm_train(prob, param) y: a list/tuple of l training labels (type must be int/double). x: a list/tuple of l training instances. The feature vector of each training instance is an instance of list/tuple or dictionary. training_options: a string in the same form as that for LIBSVM command mode. prob: an svm_problem instance generated by calling svm_problem(y, x). For pre-computed kernel, you should use svm_problem(y, x, isKernel=True) param: an svm_parameter instance generated by calling svm_parameter('training_options') model: the returned svm_model instance. See svm.h for details of this structure. If '-v' is specified, cross validation is conducted and the returned model is just a scalar: cross-validation accuracy for classification and mean-squared error for regression. To train the same data many times with different parameters, the second and the third ways should be faster.. Examples: >>> y, x = svm_read_problem('../heart_scale') >>> prob = svm_problem(y, x) >>> param = svm_parameter('-s 3 -c 5 -h 0') >>> m = svm_train(y, x, '-c 5') >>> m = svm_train(prob, '-t 2 -c 5') >>> m = svm_train(prob, param) >>> CV_ACC = svm_train(y, x, '-v 3') - Function: svm_predict To predict testing data with a model, use >>> p_labs, p_acc, p_vals = svm_predict(y, x, model [,'predicting_options']) y: a list/tuple of l true labels (type must be int/double). It is used for calculating the accuracy. Use [0]*len(x) if true labels are unavailable. x: a list/tuple of l predicting instances. The feature vector of each predicting instance is an instance of list/tuple or dictionary. predicting_options: a string of predicting options in the same format as that of LIBSVM. model: an svm_model instance. p_labels: a list of predicted labels p_acc: a tuple including accuracy (for classification), mean squared error, and squared correlation coefficient (for regression). p_vals: a list of decision values or probability estimates (if '-b 1' is specified). If k is the number of classes in training data, for decision values, each element includes results of predicting k(k-1)/2 binary-class SVMs. For classification, k = 1 is a special case. Decision value [+1] is returned for each testing instance, instead of an empty list. For probabilities, each element contains k values indicating the probability that the testing instance is in each class. Note that the order of classes is the same as the 'model.label' field in the model structure. Example: >>> m = svm_train(y, x, '-c 5') >>> p_labels, p_acc, p_vals = svm_predict(y, x, m) - Functions: svm_read_problem/svm_load_model/svm_save_model See the usage by examples: >>> y, x = svm_read_problem('data.txt') >>> m = svm_load_model('model_file') >>> svm_save_model('model_file', m) - Function: evaluations Calculate some evaluations using the true values (ty) and predicted values (pv): >>> (ACC, MSE, SCC) = evaluations(ty, pv) ty: a list of true values. pv: a list of predict values. ACC: accuracy. MSE: mean squared error. SCC: squared correlation coefficient. Additional Information ====================== This interface was written by Hsiang-Fu Yu from Department of Computer Science, National Taiwan University. If you find this tool useful, please cite LIBSVM as follows Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines. ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm For any question, please contact Chih-Jen Lin , or check the FAQ page: http://www.csie.ntu.edu.tw/~cjlin/libsvm/faq.html libsvm-3.21+ds/python/svm.py0000644000175000017500000002260312633544335015346 0ustar ctsai12ctsai12#!/usr/bin/env python from ctypes import * from ctypes.util import find_library from os import path import sys if sys.version_info[0] >= 3: xrange = range __all__ = ['libsvm', 'svm_problem', 'svm_parameter', 'toPyModel', 'gen_svm_nodearray', 'print_null', 'svm_node', 'C_SVC', 'EPSILON_SVR', 'LINEAR', 'NU_SVC', 'NU_SVR', 'ONE_CLASS', 'POLY', 'PRECOMPUTED', 'PRINT_STRING_FUN', 'RBF', 'SIGMOID', 'c_double', 'svm_model'] try: dirname = path.dirname(path.abspath(__file__)) if sys.platform == 'win32': libsvm = CDLL(path.join(dirname, r'..\windows\libsvm.dll')) else: libsvm = CDLL(path.join(dirname, '../libsvm.so.2')) except: # For unix the prefix 'lib' is not considered. if find_library('svm'): libsvm = CDLL(find_library('svm')) elif find_library('libsvm'): libsvm = CDLL(find_library('libsvm')) else: raise Exception('LIBSVM library not found.') C_SVC = 0 NU_SVC = 1 ONE_CLASS = 2 EPSILON_SVR = 3 NU_SVR = 4 LINEAR = 0 POLY = 1 RBF = 2 SIGMOID = 3 PRECOMPUTED = 4 PRINT_STRING_FUN = CFUNCTYPE(None, c_char_p) def print_null(s): return def genFields(names, types): return list(zip(names, types)) def fillprototype(f, restype, argtypes): f.restype = restype f.argtypes = argtypes class svm_node(Structure): _names = ["index", "value"] _types = [c_int, c_double] _fields_ = genFields(_names, _types) def __str__(self): return '%d:%g' % (self.index, self.value) def gen_svm_nodearray(xi, feature_max=None, isKernel=None): if isinstance(xi, dict): index_range = xi.keys() elif isinstance(xi, (list, tuple)): if not isKernel: xi = [0] + xi # idx should start from 1 index_range = range(len(xi)) else: raise TypeError('xi should be a dictionary, list or tuple') if feature_max: assert(isinstance(feature_max, int)) index_range = filter(lambda j: j <= feature_max, index_range) if not isKernel: index_range = filter(lambda j:xi[j] != 0, index_range) index_range = sorted(index_range) ret = (svm_node * (len(index_range)+1))() ret[-1].index = -1 for idx, j in enumerate(index_range): ret[idx].index = j ret[idx].value = xi[j] max_idx = 0 if index_range: max_idx = index_range[-1] return ret, max_idx class svm_problem(Structure): _names = ["l", "y", "x"] _types = [c_int, POINTER(c_double), POINTER(POINTER(svm_node))] _fields_ = genFields(_names, _types) def __init__(self, y, x, isKernel=None): if len(y) != len(x): raise ValueError("len(y) != len(x)") self.l = l = len(y) max_idx = 0 x_space = self.x_space = [] for i, xi in enumerate(x): tmp_xi, tmp_idx = gen_svm_nodearray(xi,isKernel=isKernel) x_space += [tmp_xi] max_idx = max(max_idx, tmp_idx) self.n = max_idx self.y = (c_double * l)() for i, yi in enumerate(y): self.y[i] = yi self.x = (POINTER(svm_node) * l)() for i, xi in enumerate(self.x_space): self.x[i] = xi class svm_parameter(Structure): _names = ["svm_type", "kernel_type", "degree", "gamma", "coef0", "cache_size", "eps", "C", "nr_weight", "weight_label", "weight", "nu", "p", "shrinking", "probability"] _types = [c_int, c_int, c_int, c_double, c_double, c_double, c_double, c_double, c_int, POINTER(c_int), POINTER(c_double), c_double, c_double, c_int, c_int] _fields_ = genFields(_names, _types) def __init__(self, options = None): if options == None: options = '' self.parse_options(options) def __str__(self): s = '' attrs = svm_parameter._names + list(self.__dict__.keys()) values = map(lambda attr: getattr(self, attr), attrs) for attr, val in zip(attrs, values): s += (' %s: %s\n' % (attr, val)) s = s.strip() return s def set_to_default_values(self): self.svm_type = C_SVC; self.kernel_type = RBF self.degree = 3 self.gamma = 0 self.coef0 = 0 self.nu = 0.5 self.cache_size = 100 self.C = 1 self.eps = 0.001 self.p = 0.1 self.shrinking = 1 self.probability = 0 self.nr_weight = 0 self.weight_label = None self.weight = None self.cross_validation = False self.nr_fold = 0 self.print_func = cast(None, PRINT_STRING_FUN) def parse_options(self, options): if isinstance(options, list): argv = options elif isinstance(options, str): argv = options.split() else: raise TypeError("arg 1 should be a list or a str.") self.set_to_default_values() self.print_func = cast(None, PRINT_STRING_FUN) weight_label = [] weight = [] i = 0 while i < len(argv): if argv[i] == "-s": i = i + 1 self.svm_type = int(argv[i]) elif argv[i] == "-t": i = i + 1 self.kernel_type = int(argv[i]) elif argv[i] == "-d": i = i + 1 self.degree = int(argv[i]) elif argv[i] == "-g": i = i + 1 self.gamma = float(argv[i]) elif argv[i] == "-r": i = i + 1 self.coef0 = float(argv[i]) elif argv[i] == "-n": i = i + 1 self.nu = float(argv[i]) elif argv[i] == "-m": i = i + 1 self.cache_size = float(argv[i]) elif argv[i] == "-c": i = i + 1 self.C = float(argv[i]) elif argv[i] == "-e": i = i + 1 self.eps = float(argv[i]) elif argv[i] == "-p": i = i + 1 self.p = float(argv[i]) elif argv[i] == "-h": i = i + 1 self.shrinking = int(argv[i]) elif argv[i] == "-b": i = i + 1 self.probability = int(argv[i]) elif argv[i] == "-q": self.print_func = PRINT_STRING_FUN(print_null) elif argv[i] == "-v": i = i + 1 self.cross_validation = 1 self.nr_fold = int(argv[i]) if self.nr_fold < 2: raise ValueError("n-fold cross validation: n must >= 2") elif argv[i].startswith("-w"): i = i + 1 self.nr_weight += 1 weight_label += [int(argv[i-1][2:])] weight += [float(argv[i])] else: raise ValueError("Wrong options") i += 1 libsvm.svm_set_print_string_function(self.print_func) self.weight_label = (c_int*self.nr_weight)() self.weight = (c_double*self.nr_weight)() for i in range(self.nr_weight): self.weight[i] = weight[i] self.weight_label[i] = weight_label[i] class svm_model(Structure): _names = ['param', 'nr_class', 'l', 'SV', 'sv_coef', 'rho', 'probA', 'probB', 'sv_indices', 'label', 'nSV', 'free_sv'] _types = [svm_parameter, c_int, c_int, POINTER(POINTER(svm_node)), POINTER(POINTER(c_double)), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_int), POINTER(c_int), POINTER(c_int), c_int] _fields_ = genFields(_names, _types) def __init__(self): self.__createfrom__ = 'python' def __del__(self): # free memory created by C to avoid memory leak if hasattr(self, '__createfrom__') and self.__createfrom__ == 'C': libsvm.svm_free_and_destroy_model(pointer(self)) def get_svm_type(self): return libsvm.svm_get_svm_type(self) def get_nr_class(self): return libsvm.svm_get_nr_class(self) def get_svr_probability(self): return libsvm.svm_get_svr_probability(self) def get_labels(self): nr_class = self.get_nr_class() labels = (c_int * nr_class)() libsvm.svm_get_labels(self, labels) return labels[:nr_class] def get_sv_indices(self): total_sv = self.get_nr_sv() sv_indices = (c_int * total_sv)() libsvm.svm_get_sv_indices(self, sv_indices) return sv_indices[:total_sv] def get_nr_sv(self): return libsvm.svm_get_nr_sv(self) def is_probability_model(self): return (libsvm.svm_check_probability_model(self) == 1) def get_sv_coef(self): return [tuple(self.sv_coef[j][i] for j in xrange(self.nr_class - 1)) for i in xrange(self.l)] def get_SV(self): result = [] for sparse_sv in self.SV[:self.l]: row = dict() i = 0 while True: row[sparse_sv[i].index] = sparse_sv[i].value if sparse_sv[i].index == -1: break i += 1 result.append(row) return result def toPyModel(model_ptr): """ toPyModel(model_ptr) -> svm_model Convert a ctypes POINTER(svm_model) to a Python svm_model """ if bool(model_ptr) == False: raise ValueError("Null pointer") m = model_ptr.contents m.__createfrom__ = 'C' return m fillprototype(libsvm.svm_train, POINTER(svm_model), [POINTER(svm_problem), POINTER(svm_parameter)]) fillprototype(libsvm.svm_cross_validation, None, [POINTER(svm_problem), POINTER(svm_parameter), c_int, POINTER(c_double)]) fillprototype(libsvm.svm_save_model, c_int, [c_char_p, POINTER(svm_model)]) fillprototype(libsvm.svm_load_model, POINTER(svm_model), [c_char_p]) fillprototype(libsvm.svm_get_svm_type, c_int, [POINTER(svm_model)]) fillprototype(libsvm.svm_get_nr_class, c_int, [POINTER(svm_model)]) fillprototype(libsvm.svm_get_labels, None, [POINTER(svm_model), POINTER(c_int)]) fillprototype(libsvm.svm_get_sv_indices, None, [POINTER(svm_model), POINTER(c_int)]) fillprototype(libsvm.svm_get_nr_sv, c_int, [POINTER(svm_model)]) fillprototype(libsvm.svm_get_svr_probability, c_double, [POINTER(svm_model)]) fillprototype(libsvm.svm_predict_values, c_double, [POINTER(svm_model), POINTER(svm_node), POINTER(c_double)]) fillprototype(libsvm.svm_predict, c_double, [POINTER(svm_model), POINTER(svm_node)]) fillprototype(libsvm.svm_predict_probability, c_double, [POINTER(svm_model), POINTER(svm_node), POINTER(c_double)]) fillprototype(libsvm.svm_free_model_content, None, [POINTER(svm_model)]) fillprototype(libsvm.svm_free_and_destroy_model, None, [POINTER(POINTER(svm_model))]) fillprototype(libsvm.svm_destroy_param, None, [POINTER(svm_parameter)]) fillprototype(libsvm.svm_check_parameter, c_char_p, [POINTER(svm_problem), POINTER(svm_parameter)]) fillprototype(libsvm.svm_check_probability_model, c_int, [POINTER(svm_model)]) fillprototype(libsvm.svm_set_print_string_function, None, [PRINT_STRING_FUN]) libsvm-3.21+ds/svm-predict.c0000644000175000017500000001264012633544335015247 0ustar ctsai12ctsai12#include #include #include #include #include #include "svm.h" int print_null(const char *s,...) {return 0;} static int (*info)(const char *fmt,...) = &printf; struct svm_node *x; int max_nr_attr = 64; struct svm_model* model; int predict_probability=0; static char *line = NULL; static int max_line_len; static char* readline(FILE *input) { int len; if(fgets(line,max_line_len,input) == NULL) return NULL; while(strrchr(line,'\n') == NULL) { max_line_len *= 2; line = (char *) realloc(line,max_line_len); len = (int) strlen(line); if(fgets(line+len,max_line_len-len,input) == NULL) break; } return line; } void exit_input_error(int line_num) { fprintf(stderr,"Wrong input format at line %d\n", line_num); exit(1); } void predict(FILE *input, FILE *output) { int correct = 0; int total = 0; double error = 0; double sump = 0, sumt = 0, sumpp = 0, sumtt = 0, sumpt = 0; int svm_type=svm_get_svm_type(model); int nr_class=svm_get_nr_class(model); double *prob_estimates=NULL; int j; if(predict_probability) { if (svm_type==NU_SVR || svm_type==EPSILON_SVR) info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=%g\n",svm_get_svr_probability(model)); else { int *labels=(int *) malloc(nr_class*sizeof(int)); svm_get_labels(model,labels); prob_estimates = (double *) malloc(nr_class*sizeof(double)); fprintf(output,"labels"); for(j=0;j start from 0 label = strtok(line," \t\n"); if(label == NULL) // empty line exit_input_error(total+1); target_label = strtod(label,&endptr); if(endptr == label || *endptr != '\0') exit_input_error(total+1); while(1) { if(i>=max_nr_attr-1) // need one more for index = -1 { max_nr_attr *= 2; x = (struct svm_node *) realloc(x,max_nr_attr*sizeof(struct svm_node)); } idx = strtok(NULL,":"); val = strtok(NULL," \t"); if(val == NULL) break; errno = 0; x[i].index = (int) strtol(idx,&endptr,10); if(endptr == idx || errno != 0 || *endptr != '\0' || x[i].index <= inst_max_index) exit_input_error(total+1); else inst_max_index = x[i].index; errno = 0; x[i].value = strtod(val,&endptr); if(endptr == val || errno != 0 || (*endptr != '\0' && !isspace(*endptr))) exit_input_error(total+1); ++i; } x[i].index = -1; if (predict_probability && (svm_type==C_SVC || svm_type==NU_SVC)) { predict_label = svm_predict_probability(model,x,prob_estimates); fprintf(output,"%g",predict_label); for(j=0;j=argc-2) exit_with_help(); input = fopen(argv[i],"r"); if(input == NULL) { fprintf(stderr,"can't open input file %s\n",argv[i]); exit(1); } output = fopen(argv[i+2],"w"); if(output == NULL) { fprintf(stderr,"can't open output file %s\n",argv[i+2]); exit(1); } if((model=svm_load_model(argv[i+1]))==0) { fprintf(stderr,"can't open model file %s\n",argv[i+1]); exit(1); } x = (struct svm_node *) malloc(max_nr_attr*sizeof(struct svm_node)); if(predict_probability) { if(svm_check_probability_model(model)==0) { fprintf(stderr,"Model does not support probabiliy estimates\n"); exit(1); } } else { if(svm_check_probability_model(model)!=0) info("Model supports probability estimates, but disabled in prediction.\n"); } predict(input,output); svm_free_and_destroy_model(&model); free(x); free(line); fclose(input); fclose(output); return 0; } libsvm-3.21+ds/svm.h0000644000175000017500000000646612633544337013637 0ustar ctsai12ctsai12#ifndef _LIBSVM_H #define _LIBSVM_H #define LIBSVM_VERSION 321 #ifdef __cplusplus extern "C" { #endif extern int libsvm_version; struct svm_node { int index; double value; }; struct svm_problem { int l; double *y; struct svm_node **x; }; enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; /* svm_type */ enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */ struct svm_parameter { int svm_type; int kernel_type; int degree; /* for poly */ double gamma; /* for poly/rbf/sigmoid */ double coef0; /* for poly/sigmoid */ /* these are for training only */ double cache_size; /* in MB */ double eps; /* stopping criteria */ double C; /* for C_SVC, EPSILON_SVR and NU_SVR */ int nr_weight; /* for C_SVC */ int *weight_label; /* for C_SVC */ double* weight; /* for C_SVC */ double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */ double p; /* for EPSILON_SVR */ int shrinking; /* use the shrinking heuristics */ int probability; /* do probability estimates */ }; // // svm_model // struct svm_model { struct svm_parameter param; /* parameter */ int nr_class; /* number of classes, = 2 in regression/one class svm */ int l; /* total #SV */ struct svm_node **SV; /* SVs (SV[l]) */ double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */ double *probA; /* pariwise probability information */ double *probB; int *sv_indices; /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */ /* for classification only */ int *label; /* label of each class (label[k]) */ int *nSV; /* number of SVs for each class (nSV[k]) */ /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ /* XXX */ int free_sv; /* 1 if svm_model is created by svm_load_model*/ /* 0 if svm_model is created by svm_train */ }; struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target); int svm_save_model(const char *model_file_name, const struct svm_model *model); struct svm_model *svm_load_model(const char *model_file_name); int svm_get_svm_type(const struct svm_model *model); int svm_get_nr_class(const struct svm_model *model); void svm_get_labels(const struct svm_model *model, int *label); void svm_get_sv_indices(const struct svm_model *model, int *sv_indices); int svm_get_nr_sv(const struct svm_model *model); double svm_get_svr_probability(const struct svm_model *model); double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values); double svm_predict(const struct svm_model *model, const struct svm_node *x); double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates); void svm_free_model_content(struct svm_model *model_ptr); void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr); void svm_destroy_param(struct svm_parameter *param); const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param); int svm_check_probability_model(const struct svm_model *model); void svm_set_print_string_function(void (*print_func)(const char *)); #ifdef __cplusplus } #endif #endif /* _LIBSVM_H */ libsvm-3.21+ds/Makefile0000644000175000017500000000133412633544330014277 0ustar ctsai12ctsai12CXX ?= g++ CFLAGS = -Wall -Wconversion -O3 -fPIC SHVER = 2 OS = $(shell uname) all: svm-train svm-predict svm-scale lib: svm.o if [ "$(OS)" = "Darwin" ]; then \ SHARED_LIB_FLAG="-dynamiclib -Wl,-install_name,libsvm.so.$(SHVER)"; \ else \ SHARED_LIB_FLAG="-shared -Wl,-soname,libsvm.so.$(SHVER)"; \ fi; \ $(CXX) $${SHARED_LIB_FLAG} svm.o -o libsvm.so.$(SHVER) svm-predict: svm-predict.c svm.o $(CXX) $(CFLAGS) svm-predict.c svm.o -o svm-predict -lm svm-train: svm-train.c svm.o $(CXX) $(CFLAGS) svm-train.c svm.o -o svm-train -lm svm-scale: svm-scale.c $(CXX) $(CFLAGS) svm-scale.c -o svm-scale svm.o: svm.cpp svm.h $(CXX) $(CFLAGS) -c svm.cpp clean: rm -f *~ svm.o svm-train svm-predict svm-scale libsvm.so.$(SHVER) libsvm-3.21+ds/COPYRIGHT0000644000175000017500000000273112633544330014134 0ustar ctsai12ctsai12 Copyright (c) 2000-2014 Chih-Chung Chang and Chih-Jen Lin All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither name of copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libsvm-3.21+ds/svm-toy/0000755000175000017500000000000012633544336014262 5ustar ctsai12ctsai12libsvm-3.21+ds/svm-toy/gtk/0000755000175000017500000000000012633544336015047 5ustar ctsai12ctsai12libsvm-3.21+ds/svm-toy/gtk/main.c0000644000175000017500000000061612633544336016142 0ustar ctsai12ctsai12/* * Initial main.c file generated by Glade. Edit as required. * Glade will not overwrite this file. */ #include #include "interface.h" void svm_toy_initialize(); int main (int argc, char *argv[]) { GtkWidget *window; gtk_set_locale (); gtk_init (&argc, &argv); window = create_window (); gtk_widget_show (window); svm_toy_initialize(); gtk_main (); return 0; } libsvm-3.21+ds/svm-toy/gtk/Makefile0000644000175000017500000000107512633544335016511 0ustar ctsai12ctsai12CC? = gcc CXX? = g++ CFLAGS = -Wall -O3 -g `pkg-config --cflags gtk+-2.0` LIBS = `pkg-config --libs gtk+-2.0` svm-toy: main.o interface.o callbacks.o ../../svm.o $(CXX) $(CFLAGS) main.o interface.o callbacks.o ../../svm.o -o svm-toy $(LIBS) main.o: main.c $(CC) $(CFLAGS) -c main.c interface.o: interface.c interface.h $(CC) $(CFLAGS) -c interface.c callbacks.o: callbacks.cpp callbacks.h $(CXX) $(CFLAGS) -c callbacks.cpp ../../svm.o: ../../svm.cpp ../../svm.h make -C ../.. svm.o clean: rm -f *~ callbacks.o svm-toy main.o interface.o callbacks.o ../../svm.o libsvm-3.21+ds/svm-toy/gtk/callbacks.h0000644000175000017500000000334512633544335017143 0ustar ctsai12ctsai12#include #ifdef __cplusplus extern "C" { #endif void on_window1_destroy (GtkObject *object, gpointer user_data); gboolean on_draw_main_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); gboolean on_draw_main_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); void on_button_change_clicked (GtkButton *button, gpointer user_data); void on_button_run_clicked (GtkButton *button, gpointer user_data); void on_button_clear_clicked (GtkButton *button, gpointer user_data); void on_button_save_clicked (GtkButton *button, gpointer user_data); void on_button_load_clicked (GtkButton *button, gpointer user_data); void on_fileselection_destroy (GtkObject *object, gpointer user_data); void on_filesel_ok_clicked (GtkButton *button, gpointer user_data); void on_filesel_cancel_clicked (GtkButton *button, gpointer user_data); #ifdef __cplusplus } #endif libsvm-3.21+ds/svm-toy/gtk/interface.h0000644000175000017500000000031312633544335017154 0ustar ctsai12ctsai12/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef __cplusplus extern "C" { #endif GtkWidget* create_window (void); GtkWidget* create_fileselection (void); #ifdef __cplusplus } #endif libsvm-3.21+ds/svm-toy/gtk/interface.c0000644000175000017500000001447112633544335017161 0ustar ctsai12ctsai12/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #include #include #include #include #include #include #include "callbacks.h" #include "interface.h" GtkWidget* create_window (void) { GtkWidget *window; GtkWidget *vbox1; extern GtkWidget *draw_main; GtkWidget *hbox1; GtkWidget *button_change; GtkWidget *button_run; GtkWidget *button_clear; GtkWidget *button_save; GtkWidget *button_load; extern GtkWidget *entry_option; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_object_set_data (GTK_OBJECT (window), "window", window); gtk_window_set_title (GTK_WINDOW (window), "SVM Toy"); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_ref (vbox1); gtk_object_set_data_full (GTK_OBJECT (window), "vbox1", vbox1, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (window), vbox1); draw_main = gtk_drawing_area_new (); gtk_widget_ref (draw_main); gtk_object_set_data_full (GTK_OBJECT (window), "draw_main", draw_main, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (draw_main); gtk_box_pack_start (GTK_BOX (vbox1), draw_main, TRUE, TRUE, 0); gtk_widget_set_usize (draw_main, 500, 500); gtk_widget_set_events (draw_main, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_ref (hbox1); gtk_object_set_data_full (GTK_OBJECT (window), "hbox1", hbox1, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (hbox1); gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0); button_change = gtk_button_new_with_label ("Change"); gtk_widget_ref (button_change); gtk_object_set_data_full (GTK_OBJECT (window), "button_change", button_change, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (button_change); gtk_box_pack_start (GTK_BOX (hbox1), button_change, FALSE, FALSE, 0); button_run = gtk_button_new_with_label ("Run"); gtk_widget_ref (button_run); gtk_object_set_data_full (GTK_OBJECT (window), "button_run", button_run, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (button_run); gtk_box_pack_start (GTK_BOX (hbox1), button_run, FALSE, FALSE, 0); button_clear = gtk_button_new_with_label ("Clear"); gtk_widget_ref (button_clear); gtk_object_set_data_full (GTK_OBJECT (window), "button_clear", button_clear, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (button_clear); gtk_box_pack_start (GTK_BOX (hbox1), button_clear, FALSE, FALSE, 0); button_save = gtk_button_new_with_label ("Save"); gtk_widget_ref (button_save); gtk_object_set_data_full (GTK_OBJECT (window), "button_save", button_save, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (button_save); gtk_box_pack_start (GTK_BOX (hbox1), button_save, FALSE, FALSE, 0); button_load = gtk_button_new_with_label ("Load"); gtk_widget_ref (button_load); gtk_object_set_data_full (GTK_OBJECT (window), "button_load", button_load, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (button_load); gtk_box_pack_start (GTK_BOX (hbox1), button_load, FALSE, FALSE, 0); entry_option = gtk_entry_new (); gtk_widget_ref (entry_option); gtk_object_set_data_full (GTK_OBJECT (window), "entry_option", entry_option, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (entry_option); gtk_box_pack_start (GTK_BOX (hbox1), entry_option, TRUE, TRUE, 0); gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (on_window1_destroy), NULL); gtk_signal_connect (GTK_OBJECT (draw_main), "button_press_event", GTK_SIGNAL_FUNC (on_draw_main_button_press_event), NULL); gtk_signal_connect (GTK_OBJECT (draw_main), "expose_event", GTK_SIGNAL_FUNC (on_draw_main_expose_event), NULL); gtk_signal_connect (GTK_OBJECT (button_change), "clicked", GTK_SIGNAL_FUNC (on_button_change_clicked), NULL); gtk_signal_connect (GTK_OBJECT (button_run), "clicked", GTK_SIGNAL_FUNC (on_button_run_clicked), NULL); gtk_signal_connect (GTK_OBJECT (button_clear), "clicked", GTK_SIGNAL_FUNC (on_button_clear_clicked), NULL); gtk_signal_connect (GTK_OBJECT (button_save), "clicked", GTK_SIGNAL_FUNC (on_button_save_clicked), NULL); gtk_signal_connect (GTK_OBJECT (button_load), "clicked", GTK_SIGNAL_FUNC (on_button_load_clicked), NULL); gtk_signal_connect (GTK_OBJECT (entry_option), "activate", GTK_SIGNAL_FUNC (on_button_run_clicked), NULL); return window; } GtkWidget* create_fileselection (void) { GtkWidget *fileselection; GtkWidget *filesel_ok; GtkWidget *filesel_cancel; fileselection = gtk_file_selection_new ("Select File"); gtk_object_set_data (GTK_OBJECT (fileselection), "fileselection", fileselection); gtk_container_set_border_width (GTK_CONTAINER (fileselection), 10); gtk_window_set_modal (GTK_WINDOW (fileselection), TRUE); filesel_ok = GTK_FILE_SELECTION (fileselection)->ok_button; gtk_object_set_data (GTK_OBJECT (fileselection), "filesel_ok", filesel_ok); gtk_widget_show (filesel_ok); GTK_WIDGET_SET_FLAGS (filesel_ok, GTK_CAN_DEFAULT); filesel_cancel = GTK_FILE_SELECTION (fileselection)->cancel_button; gtk_object_set_data (GTK_OBJECT (fileselection), "filesel_cancel", filesel_cancel); gtk_widget_show (filesel_cancel); GTK_WIDGET_SET_FLAGS (filesel_cancel, GTK_CAN_DEFAULT); gtk_signal_connect (GTK_OBJECT (fileselection), "destroy", GTK_SIGNAL_FUNC (on_fileselection_destroy), NULL); gtk_signal_connect (GTK_OBJECT (filesel_ok), "clicked", GTK_SIGNAL_FUNC (on_filesel_ok_clicked), NULL); gtk_signal_connect (GTK_OBJECT (filesel_cancel), "clicked", GTK_SIGNAL_FUNC (on_filesel_cancel_clicked), NULL); return fileselection; } libsvm-3.21+ds/svm-toy/gtk/svm-toy.glade0000644000175000017500000001440212633544336017464 0ustar ctsai12ctsai12 svm-toy svm-toy src pixmaps C False False False True True True False interface.c interface.h callbacks.c callbacks.h support.c support.h GtkWindow window destroy on_window1_destroy Sun, 16 Apr 2000 09:47:10 GMT SVM Toy GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox1 False 0 GtkDrawingArea draw_main 500 500 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK button_press_event on_draw_main_button_press_event Sun, 16 Apr 2000 13:02:05 GMT expose_event on_draw_main_expose_event Sun, 16 Apr 2000 14:27:05 GMT 0 True True GtkHBox hbox1 False 0 0 False False GtkButton button_change True clicked on_button_change_clicked Sun, 16 Apr 2000 09:40:18 GMT 0 False False GtkButton button_run True clicked on_button_run_clicked Sun, 16 Apr 2000 09:40:37 GMT 0 False False GtkButton button_clear True clicked on_button_clear_clicked Sun, 16 Apr 2000 09:40:44 GMT 0 False False GtkButton button_save True clicked on_button_save_clicked Fri, 16 Jun 2000 18:23:46 GMT 0 False False GtkButton button_load True clicked on_button_load_clicked Fri, 16 Jun 2000 18:23:56 GMT 0 False False GtkEntry entry_option True activate on_button_run_clicked Sun, 16 Apr 2000 09:42:46 GMT True True 0 0 True True GtkFileSelection fileselection 10 destroy on_fileselection_destroy Fri, 16 Jun 2000 18:11:28 GMT Select File GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE True False True False True GtkButton FileSel:ok_button filesel_ok True True clicked on_filesel_ok_clicked Fri, 16 Jun 2000 18:09:56 GMT GtkButton FileSel:cancel_button filesel_cancel True True clicked on_filesel_cancel_clicked Fri, 16 Jun 2000 18:09:46 GMT libsvm-3.21+ds/svm-toy/gtk/callbacks.cpp0000644000175000017500000002410412633544335017472 0ustar ctsai12ctsai12#include #include #include #include #include #include #include "callbacks.h" #include "interface.h" #include "../../svm.h" using namespace std; #define DEFAULT_PARAM "-t 2 -c 100" #define XLEN 500 #define YLEN 500 GdkColor colors[] = { {0,0,0,0}, {0,0,120<<8,120<<8}, {0,120<<8,120<<8,0}, {0,120<<8,0,120<<8}, {0,0,200<<8,200<<8}, {0,200<<8,200<<8,0}, {0,200<<8,0,200<<8}, }; GdkGC *gc; GdkPixmap *pixmap; extern "C" GtkWidget *draw_main; GtkWidget *draw_main; extern "C" GtkWidget *entry_option; GtkWidget *entry_option; typedef struct { double x, y; signed char value; } point; list point_list; int current_value = 1; extern "C" void svm_toy_initialize() { gboolean success[7]; gdk_colormap_alloc_colors( gdk_colormap_get_system(), colors, 7, FALSE, TRUE, success); gc = gdk_gc_new(draw_main->window); pixmap = gdk_pixmap_new(draw_main->window,XLEN,YLEN,-1); gdk_gc_set_foreground(gc,&colors[0]); gdk_draw_rectangle(pixmap,gc,TRUE,0,0,XLEN,YLEN); gtk_entry_set_text(GTK_ENTRY(entry_option),DEFAULT_PARAM); } void redraw_area(GtkWidget* widget, int x, int y, int w, int h) { gdk_draw_pixmap(widget->window, gc, pixmap, x,y,x,y,w,h); } void draw_point(const point& p) { gdk_gc_set_foreground(gc,&colors[p.value+3]); gdk_draw_rectangle(pixmap, gc, TRUE,int(p.x*XLEN),int(p.y*YLEN),4,4); gdk_draw_rectangle(draw_main->window, gc, TRUE,int(p.x*XLEN),int(p.y*YLEN),4,4); } void draw_all_points() { for(list::iterator p = point_list.begin(); p != point_list.end();p++) draw_point(*p); } void clear_all() { point_list.clear(); gdk_gc_set_foreground(gc,&colors[0]); gdk_draw_rectangle(pixmap,gc,TRUE,0,0,XLEN,YLEN); redraw_area(draw_main,0,0,XLEN,YLEN); } void on_button_change_clicked (GtkButton *button, gpointer user_data) { ++current_value; if(current_value > 3) current_value = 1; } void on_button_run_clicked (GtkButton *button, gpointer user_data) { // guard if(point_list.empty()) return; svm_parameter param; int i,j; // default values param.svm_type = C_SVC; param.kernel_type = RBF; param.degree = 3; param.gamma = 0; param.coef0 = 0; param.nu = 0.5; param.cache_size = 100; param.C = 1; param.eps = 1e-3; param.p = 0.1; param.shrinking = 1; param.probability = 0; param.nr_weight = 0; param.weight_label = NULL; param.weight = NULL; // parse options const char *p = gtk_entry_get_text(GTK_ENTRY(entry_option)); while (1) { while (*p && *p != '-') p++; if (*p == '\0') break; p++; switch (*p++) { case 's': param.svm_type = atoi(p); break; case 't': param.kernel_type = atoi(p); break; case 'd': param.degree = atoi(p); break; case 'g': param.gamma = atof(p); break; case 'r': param.coef0 = atof(p); break; case 'n': param.nu = atof(p); break; case 'm': param.cache_size = atof(p); break; case 'c': param.C = atof(p); break; case 'e': param.eps = atof(p); break; case 'p': param.p = atof(p); break; case 'h': param.shrinking = atoi(p); break; case 'b': param.probability = atoi(p); break; case 'w': ++param.nr_weight; param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); param.weight_label[param.nr_weight-1] = atoi(p); while(*p && !isspace(*p)) ++p; param.weight[param.nr_weight-1] = atof(p); break; } } // build problem svm_problem prob; prob.l = point_list.size(); prob.y = new double[prob.l]; if(param.kernel_type == PRECOMPUTED) { } else if(param.svm_type == EPSILON_SVR || param.svm_type == NU_SVR) { if(param.gamma == 0) param.gamma = 1; svm_node *x_space = new svm_node[2 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[2 * i].index = 1; x_space[2 * i].value = q->x; x_space[2 * i + 1].index = -1; prob.x[i] = &x_space[2 * i]; prob.y[i] = q->y; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[2]; x[0].index = 1; x[1].index = -1; int *j = new int[XLEN]; for (i = 0; i < XLEN; i++) { x[0].value = (double) i / XLEN; j[i] = (int)(YLEN*svm_predict(model, x)); } gdk_gc_set_foreground(gc,&colors[0]); gdk_draw_line(pixmap,gc,0,0,0,YLEN-1); gdk_draw_line(draw_main->window,gc,0,0,0,YLEN-1); int p = (int)(param.p * YLEN); for(i = 1; i < XLEN; i++) { gdk_gc_set_foreground(gc,&colors[0]); gdk_draw_line(pixmap,gc,i,0,i,YLEN-1); gdk_draw_line(draw_main->window,gc,i,0,i,YLEN-1); gdk_gc_set_foreground(gc,&colors[5]); gdk_draw_line(pixmap,gc,i-1,j[i-1],i,j[i]); gdk_draw_line(draw_main->window,gc,i-1,j[i-1],i,j[i]); if(param.svm_type == EPSILON_SVR) { gdk_gc_set_foreground(gc,&colors[2]); gdk_draw_line(pixmap,gc,i-1,j[i-1]+p,i,j[i]+p); gdk_draw_line(draw_main->window,gc,i-1,j[i-1]+p,i,j[i]+p); gdk_gc_set_foreground(gc,&colors[2]); gdk_draw_line(pixmap,gc,i-1,j[i-1]-p,i,j[i]-p); gdk_draw_line(draw_main->window,gc,i-1,j[i-1]-p,i,j[i]-p); } } svm_free_and_destroy_model(&model); delete[] j; delete[] x_space; delete[] prob.x; delete[] prob.y; } else { if(param.gamma == 0) param.gamma = 0.5; svm_node *x_space = new svm_node[3 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[3 * i].index = 1; x_space[3 * i].value = q->x; x_space[3 * i + 1].index = 2; x_space[3 * i + 1].value = q->y; x_space[3 * i + 2].index = -1; prob.x[i] = &x_space[3 * i]; prob.y[i] = q->value; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[3]; x[0].index = 1; x[1].index = 2; x[2].index = -1; for (i = 0; i < XLEN; i++) for (j = 0; j < YLEN; j++) { x[0].value = (double) i / XLEN; x[1].value = (double) j / YLEN; double d = svm_predict(model, x); if (param.svm_type == ONE_CLASS && d<0) d=2; gdk_gc_set_foreground(gc,&colors[(int)d]); gdk_draw_point(pixmap,gc,i,j); gdk_draw_point(draw_main->window,gc,i,j); } svm_free_and_destroy_model(&model); delete[] x_space; delete[] prob.x; delete[] prob.y; } free(param.weight_label); free(param.weight); draw_all_points(); } void on_button_clear_clicked (GtkButton *button, gpointer user_data) { clear_all(); } void on_window1_destroy (GtkObject *object, gpointer user_data) { gtk_exit(0); } gboolean on_draw_main_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { point p = {(double)event->x/XLEN, (double)event->y/YLEN, current_value}; point_list.push_back(p); draw_point(p); return FALSE; } gboolean on_draw_main_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { redraw_area(widget, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } GtkWidget *fileselection; static enum { SAVE, LOAD } fileselection_flag; void show_fileselection() { fileselection = create_fileselection(); gtk_signal_connect_object( GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->ok_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) fileselection); gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fileselection)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) fileselection); gtk_widget_show(fileselection); } void on_button_save_clicked (GtkButton *button, gpointer user_data) { fileselection_flag = SAVE; show_fileselection(); } void on_button_load_clicked (GtkButton *button, gpointer user_data) { fileselection_flag = LOAD; show_fileselection(); } void on_filesel_ok_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide(fileselection); const char *filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)); if(fileselection_flag == SAVE) { FILE *fp = fopen(filename,"w"); const char *p = gtk_entry_get_text(GTK_ENTRY(entry_option)); const char* svm_type_str = strstr(p, "-s "); int svm_type = C_SVC; if(svm_type_str != NULL) sscanf(svm_type_str, "-s %d", &svm_type); if(fp) { if(svm_type == EPSILON_SVR || svm_type == NU_SVR) { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%f 1:%f\n", p->y, p->x); } else { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%d 1:%f 2:%f\n", p->value, p->x, p->y); } fclose(fp); } } else if(fileselection_flag == LOAD) { FILE *fp = fopen(filename,"r"); if(fp) { clear_all(); char buf[4096]; while(fgets(buf,sizeof(buf),fp)) { int v; double x,y; if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)==3) { point p = {x,y,v}; point_list.push_back(p); } else if(sscanf(buf,"%lf%*d:%lf",&y,&x)==2) { point p = {x,y,current_value}; point_list.push_back(p); } else break; } fclose(fp); draw_all_points(); } } } void on_fileselection_destroy (GtkObject *object, gpointer user_data) { } void on_filesel_cancel_clicked (GtkButton *button, gpointer user_data) { } libsvm-3.21+ds/svm-toy/windows/0000755000175000017500000000000012633544336015754 5ustar ctsai12ctsai12libsvm-3.21+ds/svm-toy/windows/svm-toy.cpp0000644000175000017500000002635712633544336020113 0ustar ctsai12ctsai12#include #include #include #include #include #include #include "../../svm.h" using namespace std; #define DEFAULT_PARAM "-t 2 -c 100" #define XLEN 500 #define YLEN 500 #define DrawLine(dc,x1,y1,x2,y2,c) \ do { \ HPEN hpen = CreatePen(PS_SOLID,0,c); \ HPEN horig = SelectPen(dc,hpen); \ MoveToEx(dc,x1,y1,NULL); \ LineTo(dc,x2,y2); \ SelectPen(dc,horig); \ DeletePen(hpen); \ } while(0) using namespace std; COLORREF colors[] = { RGB(0,0,0), RGB(0,120,120), RGB(120,120,0), RGB(120,0,120), RGB(0,200,200), RGB(200,200,0), RGB(200,0,200) }; HWND main_window; HBITMAP buffer; HDC window_dc; HDC buffer_dc; HBRUSH brush1, brush2, brush3; HWND edit; enum { ID_BUTTON_CHANGE, ID_BUTTON_RUN, ID_BUTTON_CLEAR, ID_BUTTON_LOAD, ID_BUTTON_SAVE, ID_EDIT }; struct point { double x, y; signed char value; }; list point_list; int current_value = 1; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "SvmToy"; MSG msg; WNDCLASSEX wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wndclass); main_window = CreateWindow(szAppName, // window class name "SVM Toy", // window caption WS_OVERLAPPEDWINDOW,// window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position XLEN, // initial x size YLEN+52, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(main_window, iCmdShow); UpdateWindow(main_window); CreateWindow("button", "Change", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_CHANGE, hInstance, NULL); CreateWindow("button", "Run", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 50, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_RUN, hInstance, NULL); CreateWindow("button", "Clear", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 100, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_CLEAR, hInstance, NULL); CreateWindow("button", "Save", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 150, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_SAVE, hInstance, NULL); CreateWindow("button", "Load", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 200, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_LOAD, hInstance, NULL); edit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE, 250, YLEN, 250, 25, main_window, (HMENU) ID_EDIT, hInstance, NULL); Edit_SetText(edit,DEFAULT_PARAM); brush1 = CreateSolidBrush(colors[4]); brush2 = CreateSolidBrush(colors[5]); brush3 = CreateSolidBrush(colors[6]); window_dc = GetDC(main_window); buffer = CreateCompatibleBitmap(window_dc, XLEN, YLEN); buffer_dc = CreateCompatibleDC(window_dc); SelectObject(buffer_dc, buffer); PatBlt(buffer_dc, 0, 0, XLEN, YLEN, BLACKNESS); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } int getfilename( HWND hWnd , char *filename, int len, int save) { OPENFILENAME OpenFileName; memset(&OpenFileName,0,sizeof(OpenFileName)); filename[0]='\0'; OpenFileName.lStructSize = sizeof(OPENFILENAME); OpenFileName.hwndOwner = hWnd; OpenFileName.lpstrFile = filename; OpenFileName.nMaxFile = len; OpenFileName.Flags = 0; return save?GetSaveFileName(&OpenFileName):GetOpenFileName(&OpenFileName); } void clear_all() { point_list.clear(); PatBlt(buffer_dc, 0, 0, XLEN, YLEN, BLACKNESS); InvalidateRect(main_window, 0, 0); } HBRUSH choose_brush(int v) { if(v==1) return brush1; else if(v==2) return brush2; else return brush3; } void draw_point(const point & p) { RECT rect; rect.left = int(p.x*XLEN); rect.top = int(p.y*YLEN); rect.right = int(p.x*XLEN) + 3; rect.bottom = int(p.y*YLEN) + 3; FillRect(window_dc, &rect, choose_brush(p.value)); FillRect(buffer_dc, &rect, choose_brush(p.value)); } void draw_all_points() { for(list::iterator p = point_list.begin(); p != point_list.end(); p++) draw_point(*p); } void button_run_clicked() { // guard if(point_list.empty()) return; svm_parameter param; int i,j; // default values param.svm_type = C_SVC; param.kernel_type = RBF; param.degree = 3; param.gamma = 0; param.coef0 = 0; param.nu = 0.5; param.cache_size = 100; param.C = 1; param.eps = 1e-3; param.p = 0.1; param.shrinking = 1; param.probability = 0; param.nr_weight = 0; param.weight_label = NULL; param.weight = NULL; // parse options char str[1024]; Edit_GetLine(edit, 0, str, sizeof(str)); const char *p = str; while (1) { while (*p && *p != '-') p++; if (*p == '\0') break; p++; switch (*p++) { case 's': param.svm_type = atoi(p); break; case 't': param.kernel_type = atoi(p); break; case 'd': param.degree = atoi(p); break; case 'g': param.gamma = atof(p); break; case 'r': param.coef0 = atof(p); break; case 'n': param.nu = atof(p); break; case 'm': param.cache_size = atof(p); break; case 'c': param.C = atof(p); break; case 'e': param.eps = atof(p); break; case 'p': param.p = atof(p); break; case 'h': param.shrinking = atoi(p); break; case 'b': param.probability = atoi(p); break; case 'w': ++param.nr_weight; param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); param.weight_label[param.nr_weight-1] = atoi(p); while(*p && !isspace(*p)) ++p; param.weight[param.nr_weight-1] = atof(p); break; } } // build problem svm_problem prob; prob.l = point_list.size(); prob.y = new double[prob.l]; if(param.kernel_type == PRECOMPUTED) { } else if(param.svm_type == EPSILON_SVR || param.svm_type == NU_SVR) { if(param.gamma == 0) param.gamma = 1; svm_node *x_space = new svm_node[2 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[2 * i].index = 1; x_space[2 * i].value = q->x; x_space[2 * i + 1].index = -1; prob.x[i] = &x_space[2 * i]; prob.y[i] = q->y; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[2]; x[0].index = 1; x[1].index = -1; int *j = new int[XLEN]; for (i = 0; i < XLEN; i++) { x[0].value = (double) i / XLEN; j[i] = (int)(YLEN*svm_predict(model, x)); } DrawLine(buffer_dc,0,0,0,YLEN,colors[0]); DrawLine(window_dc,0,0,0,YLEN,colors[0]); int p = (int)(param.p * YLEN); for(int i=1; i < XLEN; i++) { DrawLine(buffer_dc,i,0,i,YLEN,colors[0]); DrawLine(window_dc,i,0,i,YLEN,colors[0]); DrawLine(buffer_dc,i-1,j[i-1],i,j[i],colors[5]); DrawLine(window_dc,i-1,j[i-1],i,j[i],colors[5]); if(param.svm_type == EPSILON_SVR) { DrawLine(buffer_dc,i-1,j[i-1]+p,i,j[i]+p,colors[2]); DrawLine(window_dc,i-1,j[i-1]+p,i,j[i]+p,colors[2]); DrawLine(buffer_dc,i-1,j[i-1]-p,i,j[i]-p,colors[2]); DrawLine(window_dc,i-1,j[i-1]-p,i,j[i]-p,colors[2]); } } svm_free_and_destroy_model(&model); delete[] j; delete[] x_space; delete[] prob.x; delete[] prob.y; } else { if(param.gamma == 0) param.gamma = 0.5; svm_node *x_space = new svm_node[3 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[3 * i].index = 1; x_space[3 * i].value = q->x; x_space[3 * i + 1].index = 2; x_space[3 * i + 1].value = q->y; x_space[3 * i + 2].index = -1; prob.x[i] = &x_space[3 * i]; prob.y[i] = q->value; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[3]; x[0].index = 1; x[1].index = 2; x[2].index = -1; for (i = 0; i < XLEN; i++) for (j = 0; j < YLEN; j++) { x[0].value = (double) i / XLEN; x[1].value = (double) j / YLEN; double d = svm_predict(model, x); if (param.svm_type == ONE_CLASS && d<0) d=2; SetPixel(window_dc, i, j, colors[(int)d]); SetPixel(buffer_dc, i, j, colors[(int)d]); } svm_free_and_destroy_model(&model); delete[] x_space; delete[] prob.x; delete[] prob.y; } free(param.weight_label); free(param.weight); draw_all_points(); } LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (iMsg) { case WM_LBUTTONDOWN: { int x = LOWORD(lParam); int y = HIWORD(lParam); point p = {(double)x/XLEN, (double)y/YLEN, current_value}; point_list.push_back(p); draw_point(p); } return 0; case WM_PAINT: { hdc = BeginPaint(hwnd, &ps); BitBlt(hdc, 0, 0, XLEN, YLEN, buffer_dc, 0, 0, SRCCOPY); EndPaint(hwnd, &ps); } return 0; case WM_COMMAND: { int id = LOWORD(wParam); switch (id) { case ID_BUTTON_CHANGE: ++current_value; if(current_value > 3) current_value = 1; break; case ID_BUTTON_RUN: button_run_clicked(); break; case ID_BUTTON_CLEAR: clear_all(); break; case ID_BUTTON_SAVE: { char filename[1024]; if(getfilename(hwnd,filename,1024,1)) { FILE *fp = fopen(filename,"w"); char str[1024]; Edit_GetLine(edit, 0, str, sizeof(str)); const char *p = str; const char* svm_type_str = strstr(p, "-s "); int svm_type = C_SVC; if(svm_type_str != NULL) sscanf(svm_type_str, "-s %d", &svm_type); if(fp) { if(svm_type == EPSILON_SVR || svm_type == NU_SVR) { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%f 1:%f\n", p->y, p->x); } else { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%d 1:%f 2:%f\n", p->value, p->x, p->y); } fclose(fp); } } } break; case ID_BUTTON_LOAD: { char filename[1024]; if(getfilename(hwnd,filename,1024,0)) { FILE *fp = fopen(filename,"r"); if(fp) { clear_all(); char buf[4096]; while(fgets(buf,sizeof(buf),fp)) { int v; double x,y; if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)==3) { point p = {x,y,v}; point_list.push_back(p); } else if(sscanf(buf,"%lf%*d:%lf",&y,&x)==2) { point p = {x,y,current_value}; point_list.push_back(p); } else break; } fclose(fp); draw_all_points(); } } } break; } } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } libsvm-3.21+ds/svm-toy/qt/0000755000175000017500000000000012633544336014706 5ustar ctsai12ctsai12libsvm-3.21+ds/svm-toy/qt/Makefile0000644000175000017500000000066212633544336016352 0ustar ctsai12ctsai12CXX? = g++ INCLUDE = /usr/include/qt4 CFLAGS = -Wall -O3 -I$(INCLUDE) -I$(INCLUDE)/QtGui -I$(INCLUDE)/QtCore LIB = -lQtGui -lQtCore MOC = /usr/bin/moc-qt4 svm-toy: svm-toy.cpp svm-toy.moc ../../svm.o $(CXX) $(CFLAGS) svm-toy.cpp ../../svm.o -o svm-toy $(LIB) svm-toy.moc: svm-toy.cpp $(MOC) svm-toy.cpp -o svm-toy.moc ../../svm.o: ../../svm.cpp ../../svm.h make -C ../.. svm.o clean: rm -f *~ svm-toy svm-toy.moc ../../svm.o libsvm-3.21+ds/svm-toy/qt/svm-toy.cpp0000644000175000017500000002302012633544336017025 0ustar ctsai12ctsai12#include #include #include #include #include #include #include "../../svm.h" using namespace std; #define DEFAULT_PARAM "-t 2 -c 100" #define XLEN 500 #define YLEN 500 QRgb colors[] = { qRgb(0,0,0), qRgb(0,120,120), qRgb(120,120,0), qRgb(120,0,120), qRgb(0,200,200), qRgb(200,200,0), qRgb(200,0,200) }; class SvmToyWindow : public QWidget { Q_OBJECT public: SvmToyWindow(); ~SvmToyWindow(); protected: virtual void mousePressEvent( QMouseEvent* ); virtual void paintEvent( QPaintEvent* ); private: QPixmap buffer; QPixmap icon1; QPixmap icon2; QPixmap icon3; QPushButton button_change_icon; QPushButton button_run; QPushButton button_clear; QPushButton button_save; QPushButton button_load; QLineEdit input_line; QPainter buffer_painter; struct point { double x, y; signed char value; }; list point_list; int current_value; const QPixmap& choose_icon(int v) { if(v==1) return icon1; else if(v==2) return icon2; else return icon3; } void clear_all() { point_list.clear(); buffer.fill(Qt::black); repaint(); } void draw_point(const point& p) { const QPixmap& icon = choose_icon(p.value); buffer_painter.drawPixmap((int)(p.x*XLEN),(int)(p.y*YLEN),icon); repaint(); } void draw_all_points() { for(list::iterator p = point_list.begin(); p != point_list.end();p++) draw_point(*p); } private slots: void button_change_icon_clicked() { ++current_value; if(current_value > 3) current_value = 1; button_change_icon.setIcon(choose_icon(current_value)); } void button_run_clicked() { // guard if(point_list.empty()) return; svm_parameter param; int i,j; // default values param.svm_type = C_SVC; param.kernel_type = RBF; param.degree = 3; param.gamma = 0; param.coef0 = 0; param.nu = 0.5; param.cache_size = 100; param.C = 1; param.eps = 1e-3; param.p = 0.1; param.shrinking = 1; param.probability = 0; param.nr_weight = 0; param.weight_label = NULL; param.weight = NULL; // parse options const char *p = input_line.text().toAscii().constData(); while (1) { while (*p && *p != '-') p++; if (*p == '\0') break; p++; switch (*p++) { case 's': param.svm_type = atoi(p); break; case 't': param.kernel_type = atoi(p); break; case 'd': param.degree = atoi(p); break; case 'g': param.gamma = atof(p); break; case 'r': param.coef0 = atof(p); break; case 'n': param.nu = atof(p); break; case 'm': param.cache_size = atof(p); break; case 'c': param.C = atof(p); break; case 'e': param.eps = atof(p); break; case 'p': param.p = atof(p); break; case 'h': param.shrinking = atoi(p); break; case 'b': param.probability = atoi(p); break; case 'w': ++param.nr_weight; param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); param.weight_label[param.nr_weight-1] = atoi(p); while(*p && !isspace(*p)) ++p; param.weight[param.nr_weight-1] = atof(p); break; } } // build problem svm_problem prob; prob.l = point_list.size(); prob.y = new double[prob.l]; if(param.kernel_type == PRECOMPUTED) { } else if(param.svm_type == EPSILON_SVR || param.svm_type == NU_SVR) { if(param.gamma == 0) param.gamma = 1; svm_node *x_space = new svm_node[2 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[2 * i].index = 1; x_space[2 * i].value = q->x; x_space[2 * i + 1].index = -1; prob.x[i] = &x_space[2 * i]; prob.y[i] = q->y; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[2]; x[0].index = 1; x[1].index = -1; int *j = new int[XLEN]; for (i = 0; i < XLEN; i++) { x[0].value = (double) i / XLEN; j[i] = (int)(YLEN*svm_predict(model, x)); } buffer_painter.setPen(colors[0]); buffer_painter.drawLine(0,0,0,YLEN-1); int p = (int)(param.p * YLEN); for(i = 1; i < XLEN; i++) { buffer_painter.setPen(colors[0]); buffer_painter.drawLine(i,0,i,YLEN-1); buffer_painter.setPen(colors[5]); buffer_painter.drawLine(i-1,j[i-1],i,j[i]); if(param.svm_type == EPSILON_SVR) { buffer_painter.setPen(colors[2]); buffer_painter.drawLine(i-1,j[i-1]+p,i,j[i]+p); buffer_painter.setPen(colors[2]); buffer_painter.drawLine(i-1,j[i-1]-p,i,j[i]-p); } } svm_free_and_destroy_model(&model); delete[] j; delete[] x_space; delete[] prob.x; delete[] prob.y; } else { if(param.gamma == 0) param.gamma = 0.5; svm_node *x_space = new svm_node[3 * prob.l]; prob.x = new svm_node *[prob.l]; i = 0; for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) { x_space[3 * i].index = 1; x_space[3 * i].value = q->x; x_space[3 * i + 1].index = 2; x_space[3 * i + 1].value = q->y; x_space[3 * i + 2].index = -1; prob.x[i] = &x_space[3 * i]; prob.y[i] = q->value; } // build model & classify svm_model *model = svm_train(&prob, ¶m); svm_node x[3]; x[0].index = 1; x[1].index = 2; x[2].index = -1; for (i = 0; i < XLEN; i++) for (j = 0; j < YLEN ; j++) { x[0].value = (double) i / XLEN; x[1].value = (double) j / YLEN; double d = svm_predict(model, x); if (param.svm_type == ONE_CLASS && d<0) d=2; buffer_painter.setPen(colors[(int)d]); buffer_painter.drawPoint(i,j); } svm_free_and_destroy_model(&model); delete[] x_space; delete[] prob.x; delete[] prob.y; } free(param.weight_label); free(param.weight); draw_all_points(); } void button_clear_clicked() { clear_all(); } void button_save_clicked() { QString filename = QFileDialog::getSaveFileName(); if(!filename.isNull()) { FILE *fp = fopen(filename.toAscii().constData(),"w"); const char *p = input_line.text().toAscii().constData(); const char* svm_type_str = strstr(p, "-s "); int svm_type = C_SVC; if(svm_type_str != NULL) sscanf(svm_type_str, "-s %d", &svm_type); if(fp) { if(svm_type == EPSILON_SVR || svm_type == NU_SVR) { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%f 1:%f\n", p->y, p->x); } else { for(list::iterator p = point_list.begin(); p != point_list.end();p++) fprintf(fp,"%d 1:%f 2:%f\n", p->value, p->x, p->y); } fclose(fp); } } } void button_load_clicked() { QString filename = QFileDialog::getOpenFileName(); if(!filename.isNull()) { FILE *fp = fopen(filename.toAscii().constData(),"r"); if(fp) { clear_all(); char buf[4096]; while(fgets(buf,sizeof(buf),fp)) { int v; double x,y; if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)==3) { point p = {x,y,v}; point_list.push_back(p); } else if(sscanf(buf,"%lf%*d:%lf",&y,&x)==2) { point p = {x,y,current_value}; point_list.push_back(p); } else break; } fclose(fp); draw_all_points(); } } } }; #include "svm-toy.moc" SvmToyWindow::SvmToyWindow() :button_change_icon(this) ,button_run("Run",this) ,button_clear("Clear",this) ,button_save("Save",this) ,button_load("Load",this) ,input_line(this) ,current_value(1) { buffer = QPixmap(XLEN,YLEN); buffer.fill(Qt::black); buffer_painter.begin(&buffer); QObject::connect(&button_change_icon, SIGNAL(clicked()), this, SLOT(button_change_icon_clicked())); QObject::connect(&button_run, SIGNAL(clicked()), this, SLOT(button_run_clicked())); QObject::connect(&button_clear, SIGNAL(clicked()), this, SLOT(button_clear_clicked())); QObject::connect(&button_save, SIGNAL(clicked()), this, SLOT(button_save_clicked())); QObject::connect(&button_load, SIGNAL(clicked()), this, SLOT(button_load_clicked())); QObject::connect(&input_line, SIGNAL(returnPressed()), this, SLOT(button_run_clicked())); // don't blank the window before repainting setAttribute(Qt::WA_NoBackground); icon1 = QPixmap(4,4); icon2 = QPixmap(4,4); icon3 = QPixmap(4,4); QPainter painter; painter.begin(&icon1); painter.fillRect(0,0,4,4,QBrush(colors[4])); painter.end(); painter.begin(&icon2); painter.fillRect(0,0,4,4,QBrush(colors[5])); painter.end(); painter.begin(&icon3); painter.fillRect(0,0,4,4,QBrush(colors[6])); painter.end(); button_change_icon.setGeometry( 0, YLEN, 50, 25 ); button_run.setGeometry( 50, YLEN, 50, 25 ); button_clear.setGeometry( 100, YLEN, 50, 25 ); button_save.setGeometry( 150, YLEN, 50, 25); button_load.setGeometry( 200, YLEN, 50, 25); input_line.setGeometry( 250, YLEN, 250, 25); input_line.setText(DEFAULT_PARAM); button_change_icon.setIcon(icon1); } SvmToyWindow::~SvmToyWindow() { buffer_painter.end(); } void SvmToyWindow::mousePressEvent( QMouseEvent* event ) { point p = {(double)event->x()/XLEN, (double)event->y()/YLEN, current_value}; point_list.push_back(p); draw_point(p); } void SvmToyWindow::paintEvent( QPaintEvent* ) { // copy the image from the buffer pixmap to the window QPainter p(this); p.drawPixmap(0, 0, buffer); } int main( int argc, char* argv[] ) { QApplication myapp( argc, argv ); SvmToyWindow* mywidget = new SvmToyWindow(); mywidget->setGeometry( 100, 100, XLEN, YLEN+25 ); mywidget->show(); return myapp.exec(); } libsvm-3.21+ds/Makefile.win0000644000175000017500000000216012633544331015072 0ustar ctsai12ctsai12#You must ensure nmake.exe, cl.exe, link.exe are in system path. #VCVARS64.bat #Under dosbox prompt #nmake -f Makefile.win ########################################## CXX = cl.exe CFLAGS = /nologo /O2 /EHsc /I. /D _WIN64 /D _CRT_SECURE_NO_DEPRECATE TARGET = windows all: $(TARGET)\svm-train.exe $(TARGET)\svm-predict.exe $(TARGET)\svm-scale.exe $(TARGET)\svm-toy.exe lib $(TARGET)\svm-predict.exe: svm.h svm-predict.c svm.obj $(CXX) $(CFLAGS) svm-predict.c svm.obj -Fe$(TARGET)\svm-predict.exe $(TARGET)\svm-train.exe: svm.h svm-train.c svm.obj $(CXX) $(CFLAGS) svm-train.c svm.obj -Fe$(TARGET)\svm-train.exe $(TARGET)\svm-scale.exe: svm.h svm-scale.c $(CXX) $(CFLAGS) svm-scale.c -Fe$(TARGET)\svm-scale.exe $(TARGET)\svm-toy.exe: svm.h svm.obj svm-toy\windows\svm-toy.cpp $(CXX) $(CFLAGS) svm-toy\windows\svm-toy.cpp svm.obj user32.lib gdi32.lib comdlg32.lib -Fe$(TARGET)\svm-toy.exe svm.obj: svm.cpp svm.h $(CXX) $(CFLAGS) -c svm.cpp lib: svm.cpp svm.h svm.def $(CXX) $(CFLAGS) -LD svm.cpp -Fe$(TARGET)\libsvm -link -DEF:svm.def clean: -erase /Q *.obj $(TARGET)\*.exe $(TARGET)\*.dll $(TARGET)\*.exp $(TARGET)\*.lib libsvm-3.21+ds/svm.def0000644000175000017500000000073512633544336014136 0ustar ctsai12ctsai12LIBRARY libsvm EXPORTS svm_train @1 svm_cross_validation @2 svm_save_model @3 svm_load_model @4 svm_get_svm_type @5 svm_get_nr_class @6 svm_get_labels @7 svm_get_svr_probability @8 svm_predict_values @9 svm_predict @10 svm_predict_probability @11 svm_free_model_content @12 svm_free_and_destroy_model @13 svm_destroy_param @14 svm_check_parameter @15 svm_check_probability_model @16 svm_set_print_string_function @17 svm_get_sv_indices @18 svm_get_nr_sv @19 libsvm-3.21+ds/README0000644000175000017500000007000712633544331013523 0ustar ctsai12ctsai12Libsvm is a simple, easy-to-use, and efficient software for SVM classification and regression. It solves C-SVM classification, nu-SVM classification, one-class-SVM, epsilon-SVM regression, and nu-SVM regression. It also provides an automatic model selection tool for C-SVM classification. This document explains the use of libsvm. Libsvm is available at http://www.csie.ntu.edu.tw/~cjlin/libsvm Please read the COPYRIGHT file before using libsvm. Table of Contents ================= - Quick Start - Installation and Data Format - `svm-train' Usage - `svm-predict' Usage - `svm-scale' Usage - Tips on Practical Use - Examples - Precomputed Kernels - Library Usage - Java Version - Building Windows Binaries - Additional Tools: Sub-sampling, Parameter Selection, Format checking, etc. - MATLAB/OCTAVE Interface - Python Interface - Additional Information Quick Start =========== If you are new to SVM and if the data is not large, please go to `tools' directory and use easy.py after installation. It does everything automatic -- from data scaling to parameter selection. Usage: easy.py training_file [testing_file] More information about parameter selection can be found in `tools/README.' Installation and Data Format ============================ On Unix systems, type `make' to build the `svm-train' and `svm-predict' programs. Run them without arguments to show the usages of them. On other systems, consult `Makefile' to build them (e.g., see 'Building Windows binaries' in this file) or use the pre-built binaries (Windows binaries are in the directory `windows'). The format of training and testing data file is: