From 8ce078a5df1b9c22c7d4cabdabfe6602b8c8470e Mon Sep 17 00:00:00 2001 From: Julien Nioche Date: Wed, 9 Feb 2011 19:07:23 +0000 Subject: [PATCH] Issue 5: Upgrade to version 3.0 of libsvm --- CHANGES.txt | 3 +- lib/libsvm-3.0.jar | Bin 0 -> 49782 bytes libLinear.copyright.txt | 4 +- libSVM.copyright.txt | 2 +- .../libsvm/LibSVMModelCreator.java | 34 +- src/java/libsvm/svm.java | 2811 ----------------- src/java/libsvm/svm_model.java | 55 - src/java/libsvm/svm_node.java | 6 - src/java/libsvm/svm_parameter.java | 47 - src/java/libsvm/svm_problem.java | 11 - src/java/libsvm/svm_problem_impl.java | 35 - 11 files changed, 20 insertions(+), 2988 deletions(-) create mode 100644 lib/libsvm-3.0.jar delete mode 100644 src/java/libsvm/svm.java delete mode 100644 src/java/libsvm/svm_model.java delete mode 100644 src/java/libsvm/svm_node.java delete mode 100644 src/java/libsvm/svm_parameter.java delete mode 100644 src/java/libsvm/svm_problem.java delete mode 100644 src/java/libsvm/svm_problem_impl.java diff --git a/CHANGES.txt b/CHANGES.txt index 5bee6c2..99e0c3a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 1.4.1-SNAPSHOT -- updated to liblinear 1.7 +- upgraded lisvm 3.0 + rely on external lib instead of modified code +- upgraded liblinear 1.7 - can specify weighting schemes per field - added TestWeightingSchemes - can remap the attribute numbers before generating the vector file diff --git a/lib/libsvm-3.0.jar b/lib/libsvm-3.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..6ed1a2515a9f28c582681eb26f3a40a1b68ff5f4 GIT binary patch literal 49782 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 H{rCR>VvI=} literal 0 HcmV?d00001 diff --git a/libLinear.copyright.txt b/libLinear.copyright.txt index 65ad0ec..c319013 100644 --- a/libLinear.copyright.txt +++ b/libLinear.copyright.txt @@ -1,5 +1,4 @@ - -Copyright (c) 2007-2008 The LIBLINEAR Project. +Copyright (c) 2007-2010 The LIBLINEAR Project. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,3 +28,4 @@ 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. + diff --git a/libSVM.copyright.txt b/libSVM.copyright.txt index 5af6ebb..58a2d82 100644 --- a/libSVM.copyright.txt +++ b/libSVM.copyright.txt @@ -1,4 +1,4 @@ -Copyright (c) 2000-2006 Chih-Chung Chang and Chih-Jen Lin +Copyright (c) 2000-2010 Chih-Chung Chang and Chih-Jen Lin All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/java/com/digitalpebble/classification/libsvm/LibSVMModelCreator.java b/src/java/com/digitalpebble/classification/libsvm/LibSVMModelCreator.java index a015555..c364cc7 100755 --- a/src/java/com/digitalpebble/classification/libsvm/LibSVMModelCreator.java +++ b/src/java/com/digitalpebble/classification/libsvm/LibSVMModelCreator.java @@ -29,7 +29,6 @@ import libsvm.svm_node; import libsvm.svm_parameter; import libsvm.svm_problem; -import libsvm.svm_problem_impl; import com.digitalpebble.classification.Document; import com.digitalpebble.classification.Learner; @@ -94,12 +93,6 @@ public void internal_learn() throws Exception { } else { model = svm.svm_train(prob, param); svm.svm_save_model(model_file_name, model); - // dump linear weights in lexicon - try { - double[] weights = model.getLinearWeights(); - this.lexicon.setLinearWeight(weights); - } catch (Exception e) { - } } } @@ -221,12 +214,15 @@ private void read_problem(File learningFile) throws IOException { max_index = Math.max(max_index, x[m - 1].index); vx.addElement(x); } - prob = new svm_problem_impl(vy.size()); - for (int i = 0; i < prob.size(); i++) - prob.setNodes(i, (svm_node[]) vx.elementAt(i)); - for (int i = 0; i < prob.size(); i++) { + prob = new svm_problem(); + prob.l=vy.size(); + prob.y = new double[prob.l]; + prob.x = new svm_node[prob.l][]; + for (int i = 0; i < prob.l; i++) + prob.x[i]= (svm_node[]) vx.elementAt(i); + for (int i = 0; i < prob.l; i++) { double labell = Double.parseDouble((String) vy.elementAt(i)); - prob.setLabel(i, labell); + prob.y[i]= labell; } if (param.gamma == 0) param.gamma = 1.0 / max_index; @@ -246,13 +242,13 @@ private void do_cross_validation() { int total_correct = 0; double total_error = 0; double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; - double size = prob.size(); - double[] target = new double[prob.size()]; + double size = prob.l; + double[] target = new double[prob.l]; svm.svm_cross_validation(prob, param, this.nfold, target); if (param.svm_type == svm_parameter.EPSILON_SVR || param.svm_type == svm_parameter.NU_SVR) { - for (i = 0; i < prob.size(); i++) { - double y = prob.getLabel(i); + for (i = 0; i < prob.l; i++) { + double y = prob.y[i]; double v = target[i]; total_error += (v - y) * (v - y); sumv += v; @@ -274,7 +270,7 @@ private void do_cross_validation() { int numclasses = lexicon.getLabelNum(); double[][] confMatrix = new double[numclasses][numclasses]; for (i = 0; i < size; i++) { - double expected = prob.getLabel(i); + double expected = prob.y[i]; if (target[i] == expected) ++total_correct; confMatrix[(int) target[i]][(int) expected]++; @@ -328,13 +324,13 @@ private void do_cross_validation() { Map inverted = lexicon.getInvertedIndex(); for (i = 0; i < size; i++) { StringBuffer sb = new StringBuffer(); - double expected = prob.getLabel(i); + double expected = prob.y[i]; if (target[i] == expected) continue; sb.append("expected: ").append(lexicon.getLabel((int) expected)) .append("\tfound:").append( lexicon.getLabel((int) target[i])); - svm_node[] nodes = prob.getNodes(i); + svm_node[] nodes = prob.x[i]; for (svm_node node : nodes) { String attLabel = inverted.get(new Integer(node.index)); if (attLabel == null) diff --git a/src/java/libsvm/svm.java b/src/java/libsvm/svm.java deleted file mode 100644 index 3434ac9..0000000 --- a/src/java/libsvm/svm.java +++ /dev/null @@ -1,2811 +0,0 @@ -package libsvm; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.util.StringTokenizer; - -// -// 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 int 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_, int 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 float[] 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 float[] 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; - } - - private static double tanh(double x) - { - double e = Math.exp(x); - return 1.0-2.0/(e*e+1); - } - - 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 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; - } - - final 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 tanh(param.gamma*dot(x,y)+param.coef0); - case svm_parameter.PRECOMPUTED: - return x[(int)(y[0].value)].value; - default: - return 0; // java - } - } -} - -// Generalized SMO+SVMlight algorithm -// Solves: -// -// min 0.5(\alpha^T Q \alpha) + b^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, b, y, Cp, Cn, and an initial feasible point \alpha -// l is the size of vectors and matrices -// eps is the stopping criterion -// -// 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; - float[] QD; - double eps; - double Cp,Cn; - double[] b; - int[] active_set; - double[] G_bar; // gradient, if we treat free variables as 0 - int l; - boolean unshrinked; // 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 _=b[i]; b[i]=b[j]; b[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; - for(i=active_size;i 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 = Q_i[i]+Q_j[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= 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=Q_i[i]+QD[j]-2*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=Q_i[i]+QD[j]+2*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) - return 1; - - working_set[0] = Gmax_idx; - working_set[1] = Gmin_idx; - return 0; - } - - // return 1 if already optimal, return 0 otherwise - int max_violating_pair(int[] working_set) - { - // return i,j which maximize -grad(f)^T d , under constraint - // if alpha_i == C, d != +1 - // if alpha_i == 0, d != -1 - - double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) } - int Gmax1_idx = -1; - - int Gmax2_idx = -1; - double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) } - - for(int i=0;i= Gmax1) - { - Gmax1 = -G[i]; - Gmax1_idx = i; - } - } - if(!is_lower_bound(i)) // d = -1 - { - if(G[i] >= Gmax2) - { - Gmax2 = G[i]; - Gmax2_idx = i; - } - } - } - else // y = -1 - { - if(!is_upper_bound(i)) // d = +1 - { - if(-G[i] >= Gmax2) - { - Gmax2 = -G[i]; - Gmax2_idx = i; - } - } - if(!is_lower_bound(i)) // d = -1 - { - if(G[i] >= Gmax1) - { - Gmax1 = G[i]; - Gmax1_idx = i; - } - } - } - } - - if(Gmax1+Gmax2 < eps) - return 1; - - working_set[0] = Gmax1_idx; - working_set[1] = Gmax2_idx; - return 0; - } - - void do_shrinking() - { - int i,j,k; - int[] working_set = new int[2]; - if(max_violating_pair(working_set)!=0) return; - i = working_set[0]; - j = working_set[1]; - double Gm1 = -y[j]*G[j]; - double Gm2 = y[i]*G[i]; - - // shrink - - for(k=0;k= Gm1) continue; - } - else if(-G[k] >= Gm2) continue; - } - else if(is_upper_bound(k)) - { - if(y[k]==+1) - { - if(G[k] >= Gm2) continue; - } - else if(G[k] >= Gm1) continue; - } - else continue; - - --active_size; - swap_index(k,active_size); - --k; // look at the newcomer - } - - // unshrink, check all variables again before final iterations - - if(unshrinked || -(Gm1 + Gm2) > eps*10) return; - - unshrinked = true; - reconstruct_gradient(); - - for(k=l-1;k>=active_size;k--) - { - if(is_lower_bound(k)) - { - if(y[k]==+1) - { - if(-G[k] < Gm1) continue; - } - else if(-G[k] < Gm2) continue; - } - else if(is_upper_bound(k)) - { - if(y[k]==+1) - { - if(G[k] < Gm2) continue; - } - else if(G[k] < Gm1) continue; - } - else continue; - - swap_index(k,active_size); - active_size++; - ++k; // look at the newcomer - } - } - - 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[] b, byte[] y, - double[] alpha, double Cp, double Cn, double eps, - SolutionInfo si, int shrinking) - { - this.si = si; - super.Solve(l,Q,b,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 = Q_ip[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 = Q_in[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) - 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; - } - - 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 k; - for(k=0;k Gmax1) Gmax1 = -G[k]; - } - else if(-G[k] > Gmax3) Gmax3 = -G[k]; - } - if(!is_lower_bound(k)) - { - if(y[k]==+1) - { - if(G[k] > Gmax2) Gmax2 = G[k]; - } - else if(G[k] > Gmax4) Gmax4 = G[k]; - } - } - - // shrinking - - double Gm1 = -Gmax2; - double Gm2 = -Gmax1; - double Gm3 = -Gmax4; - double Gm4 = -Gmax3; - - for(k=0;k= Gm1) continue; - } - else if(-G[k] >= Gm3) continue; - } - else if(is_upper_bound(k)) - { - if(y[k]==+1) - { - if(G[k] >= Gm2) continue; - } - else if(G[k] >= Gm4) continue; - } - else continue; - - --active_size; - swap_index(k,active_size); - --k; // look at the newcomer - } - - // unshrink, check all variables again before final iterations - - if(unshrinked || Math.max(-(Gm1+Gm2),-(Gm3+Gm4)) > eps*10) return; - - unshrinked = true; - reconstruct_gradient(); - - for(k=l-1;k>=active_size;k--) - { - if(is_lower_bound(k)) - { - if(y[k]==+1) - { - if(-G[k] < Gm1) continue; - } - else if(-G[k] < Gm3) continue; - } - else if(is_upper_bound(k)) - { - if(y[k]==+1) - { - if(G[k] < Gm2) continue; - } - else if(G[k] < Gm4) continue; - } - else continue; - - swap_index(k,active_size); - active_size++; - ++k; // look at the newcomer - } - } - - 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 float[] QD; - - SVC_Q(svm_problem prob, svm_parameter param, byte[] y_) - { - super(prob.size(), prob.getMatrix(), param); - y = (byte[])y_.clone(); - cache = new Cache(prob.size(),(int)(param.cache_size*(1<<20))); - QD = new float[prob.size()]; - 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.getLabel(i) > 0) - { - if(Math.abs(alpha[i]) >= si.upper_bound_p) - ++nBSV; - } - else - { - if(Math.abs(alpha[i]) >= si.upper_bound_n) - ++nBSV; - } - } - } - - // System.out.print("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-3; // 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) - System.err.print("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) - System.err.print("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.size()]; - double[] dec_values = new double[prob.size()]; - - // 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.size()-count); - System.err.print("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.size(); - 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]; - int j = 0; - for(i=0;i 0) - { - model.SV[j] = prob.getNodes(i); - model.sv_coef[0][j] = f.alpha[i]; - ++j; - } - } - else - { - // classification - int l = prob.size(); - 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]; - 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[] label = tmp_label[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 res[0]; - } - else - { - 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); - - int[] vote = new int[nr_class]; - for(i=0;i 0) - ++vote[i]; - else - ++vote[j]; - } - - 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_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 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.size(); - 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; - } -} diff --git a/src/java/libsvm/svm_model.java b/src/java/libsvm/svm_model.java deleted file mode 100644 index 49028a6..0000000 --- a/src/java/libsvm/svm_model.java +++ /dev/null @@ -1,55 +0,0 @@ -// -// svm_model -// -package libsvm; - -public class svm_model implements java.io.Serializable { - svm_parameter param; // parameter - int nr_class; // number of classes, = 2 in regression/one class svm - int l; // total #SV - svm_node[][] SV; // SVs (SV[l]) - double[][] sv_coef; // coefficients for SVs in decision functions - // (sv_coef[n-1][l]) - double[] rho; // constants in decision functions (rho[n*(n-1)/2]) - double[] probA; // pariwise probability information - double[] probB; - // for classification only - int[] label; // label of each class (label[n]) - int[] nSV; // number of SVs for each class (nSV[n]) - - // nSV[0] + nSV[1] + ... + nSV[n-1] = l - double[] linWeights; - - - // returns the weights for each attribute in a linear model - public double[] getLinearWeights() throws Exception { - if(l == 0) throw new Exception("Model not trained"); - if(param.kernel_type != svm_parameter.LINEAR) throw new Exception("Model is not a linear kernel"); - if(nr_class != 2) throw new Exception("Model is not binary"); - return _getLinearWeights(); - } - - private double[] _getLinearWeights() { - if(this.linWeights != null) return this.linWeights; - int highestIndex = 0; - // find the highest index in the SVs - for(int i = 0; i < SV.length; i++) { - svm_node[] currentnodes = SV[i]; - for(int j = 0; j < currentnodes.length; j++) { - if (highestIndex