001/* 002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.tribuo.common.libsvm; 018 019import org.tribuo.Output; 020import libsvm.svm_parameter; 021 022import java.io.Serializable; 023import java.util.Arrays; 024import java.util.logging.Logger; 025 026/** 027 * A container for SVM parameters and the kernel. 028 */ 029public class SVMParameters<T extends Output<T>> implements Serializable { 030 private static final long serialVersionUID = 1L; 031 032 private static final Logger logger = Logger.getLogger(SVMParameters.class.getName()); 033 034 /** 035 * The type of the SVM. 036 */ 037 protected final SVMType<T> svmType; 038 039 /** 040 * The kernel. 041 */ 042 protected final KernelType kernelType; 043 044 /** 045 * The libSVM format parameters. 046 */ 047 protected final svm_parameter parameters = new svm_parameter(); 048 049 /** 050 * Constructs the default SVMParameters using the specified SVMType and KernelType. 051 * @param svmType The SVM algorithm. 052 * @param kernelType The kernel. 053 */ 054 public SVMParameters(SVMType<T> svmType, KernelType kernelType) { 055 this.svmType = svmType; 056 this.kernelType = kernelType; 057 parameters.svm_type = svmType.getNativeType(); 058 parameters.kernel_type = kernelType.getNativeType(); 059 // 060 // These are defaults, which are only compatible with SVM type 061 // C_SVC and kernel type RBF 062 parameters.degree = 3; 063 parameters.gamma = 0; // 1/num_features 064 parameters.coef0 = 0; 065 parameters.nu = 0.5; 066 parameters.cache_size = 500; 067 parameters.C = 1; 068 parameters.eps = 1e-3; 069 parameters.p = 0.1; 070 parameters.shrinking = 1; 071 parameters.probability = 0; 072 parameters.nr_weight = 0; 073 parameters.weight_label = new int[0]; 074 parameters.weight = new double[0]; 075 } 076 077 /** 078 * Gets the SVM type. 079 * @return The SVM type. 080 */ 081 public SVMType<T> getSvmType() { 082 return svmType; 083 } 084 085 /** 086 * Gets the kernel type. 087 * @return The kernel type. 088 */ 089 public KernelType getKernelType() { 090 return kernelType; 091 } 092 093 /** 094 * Gets the underlying SVM parameter object. 095 * @return The SVM parameters. 096 */ 097 public svm_parameter getParameters() { 098 return parameters; 099 } 100 101 @Override 102 public String toString() { 103 return svmParamsToString(parameters); 104 } 105 106 /** 107 * Makes the model that is built provide probability estimates. 108 */ 109 public void setProbability() { 110 parameters.probability = 1; 111 } 112 113 /** 114 * Sets the cost for C_SVC. 115 * @param c The cost. 116 */ 117 public void setCost(double c) { 118 if(svmType.isNu() || !svmType.isClassification()) { 119 logger.warning(String.format("Setting cost %f for non-C_SVC model", c)); 120 } 121 parameters.C = c; 122 } 123 124 /** 125 * Sets the value of nu for NU_SVM. 126 * @param nu The nu. 127 */ 128 public void setNu(double nu) { 129 if(!svmType.isNu()) { 130 logger.warning(String.format("Setting nu %f for non-NU_SVM model", nu)); 131 } 132 parameters.nu = nu; 133 } 134 135 /** 136 * Sets the coefficient. 137 * @param coeff The coefficient. 138 */ 139 public void setCoeff(double coeff) { 140 parameters.coef0 = coeff; 141 } 142 143 /** 144 * Sets the termination closeness. 145 * @param epsilon The termination criterion. 146 */ 147 public void setEpsilon(double epsilon) { 148 parameters.p = epsilon; 149 } 150 151 /** 152 * Sets the degree of the polynomial kernel. 153 * @param degree The polynomial degree. 154 */ 155 public void setDegree(int degree) { 156 parameters.degree = degree; 157 } 158 159 /** 160 * Sets gamma in the RBF kernel. 161 * @param gamma The gamma. 162 */ 163 public void setGamma(double gamma) { 164 parameters.gamma = gamma; 165 } 166 167 /** 168 * Gets the gamma value. 169 * @return The gamma value. 170 */ 171 public double getGamma() { 172 return parameters.gamma; 173 } 174 175 /** 176 * Sets the cache size. 177 * @param cacheMB The cache size. 178 */ 179 public void setCacheSize(double cacheMB) { 180 if(cacheMB <= 0) { 181 throw new IllegalArgumentException("Cache must be larger than 0MB"); 182 } 183 parameters.cache_size = cacheMB; 184 } 185 186 /** 187 * Deep copy of the svm_parameters including the arrays. 188 * @param input The parameters to copy. 189 * @return A copy of the svm_parameters. 190 */ 191 public static svm_parameter copyParameters(svm_parameter input) { 192 svm_parameter copy = new svm_parameter(); 193 copy.svm_type = input.svm_type; 194 copy.kernel_type = input.kernel_type; 195 copy.degree = input.degree; 196 copy.gamma = input.gamma; 197 copy.coef0 = input.coef0; 198 copy.cache_size = input.cache_size; 199 copy.eps = input.eps; 200 copy.C = input.C; 201 copy.nr_weight = input.nr_weight; 202 copy.nu = input.nu; 203 copy.p = input.p; 204 copy.shrinking = input.shrinking; 205 copy.probability = input.probability; 206 copy.weight_label = input.weight_label != null ? Arrays.copyOf(input.weight_label,input.weight_label.length) : null; 207 copy.weight = input.weight != null ? Arrays.copyOf(input.weight,input.weight.length) : null; 208 return copy; 209 } 210 211 /** 212 * A sensible toString for svm_parameter. 213 * @param param The parameters. 214 * @return A String describing the parameters. 215 */ 216 public static String svmParamsToString(svm_parameter param) { 217 StringBuilder sb = new StringBuilder(); 218 sb.append("svm_parameter(svm_type="); 219 sb.append(param.svm_type); 220 sb.append(", kernel_type="); 221 sb.append(param.kernel_type); 222 sb.append(", degree="); 223 sb.append(param.degree); 224 sb.append(", gamma="); 225 sb.append(param.gamma); 226 sb.append(", coef0="); 227 sb.append(param.coef0); 228 sb.append(", cache_size="); 229 sb.append(param.coef0); 230 sb.append(", eps="); 231 sb.append(param.eps); 232 sb.append(", C="); 233 sb.append(param.C); 234 sb.append(", nr_weight="); 235 sb.append(param.nr_weight); 236 if (param.weight_label != null) { 237 sb.append(", weight_label="); 238 sb.append(Arrays.toString(param.weight_label)); 239 } 240 if (param.weight != null) { 241 sb.append(", weight="); 242 sb.append(Arrays.toString(param.weight)); 243 } 244 sb.append(", nu="); 245 sb.append(param.nu); 246 sb.append(", p="); 247 sb.append(param.p); 248 sb.append(", shrinking="); 249 sb.append(param.shrinking); 250 sb.append(", probability="); 251 sb.append(param.probability); 252 sb.append(')'); 253 return sb.toString(); 254 } 255}