/// <summary> /// Writes a model to the provided stream. /// </summary> /// <param name="stream">The output stream</param> /// <param name="model">The model to write</param> public static void Write(Stream stream, Model model) { TemporaryCulture.Start(); StreamWriter output = new StreamWriter(stream); Parameter param = model.Parameter; output.Write("svm_type " + param.SvmType + "\n"); output.Write("kernel_type " + param.KernelType + "\n"); if (param.KernelType == KernelType.POLY) output.Write("degree " + param.Degree + "\n"); if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.RBF || param.KernelType == KernelType.SIGMOID) output.Write("gamma " + param.Gamma + "\n"); if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.SIGMOID) output.Write("coef0 " + param.Coefficient0 + "\n"); int nr_class = model.NumberOfClasses; int l = model.SupportVectorCount; output.Write("nr_class " + nr_class + "\n"); output.Write("total_sv " + l + "\n"); { output.Write("rho"); for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++) output.Write(" " + model.Rho[i]); output.Write("\n"); } if (model.ClassLabels != null) { output.Write("label"); for (int i = 0; i < nr_class; i++) output.Write(" " + model.ClassLabels[i]); output.Write("\n"); } if (model.PairwiseProbabilityA != null) // regression has probA only { output.Write("probA"); for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++) output.Write(" " + model.PairwiseProbabilityA[i]); output.Write("\n"); } if (model.PairwiseProbabilityB != null) { output.Write("probB"); for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++) output.Write(" " + model.PairwiseProbabilityB[i]); output.Write("\n"); } if (model.NumberOfSVPerClass != null) { output.Write("nr_sv"); for (int i = 0; i < nr_class; i++) output.Write(" " + model.NumberOfSVPerClass[i]); output.Write("\n"); } output.Write("SV\n"); double[][] sv_coef = model.SupportVectorCoefficients; Node[][] SV = model.SupportVectors; for (int i = 0; i < l; i++) { for (int j = 0; j < nr_class - 1; j++) output.Write(sv_coef[j][i] + " "); Node[] p = SV[i]; if (p.Length == 0) { output.WriteLine(); continue; } if (param.KernelType == KernelType.PRECOMPUTED) output.Write("0:{0}", (int)p[0].Value); else { output.Write("{0}:{1}", p[0].Index, p[0].Value); for (int j = 1; j < p.Length; j++) output.Write(" {0}:{1}", p[j].Index, p[j].Value); } output.WriteLine(); } output.Flush(); TemporaryCulture.Stop(); }
/// <summary> /// Writes a model to the provided filename. This will overwrite any previous data in the file. /// </summary> /// <param name="filename">The desired file</param> /// <param name="model">The Model to write</param> public static void Write(string filename, Model model) { FileStream stream = File.Open(filename, FileMode.Create); try { Write(stream, model); } finally { stream.Close(); } }
/// <summary> /// Reads a Model from the provided stream. /// </summary> /// <param name="stream">The stream from which to read the Model.</param> /// <returns>the Model</returns> public static Model Read(Stream stream) { TemporaryCulture.Start(); StreamReader input = new StreamReader(stream); // read parameters Model model = new Model(); Parameter param = new Parameter(); model.Parameter = param; model.Rho = null; model.PairwiseProbabilityA = null; model.PairwiseProbabilityB = null; model.ClassLabels = null; model.NumberOfSVPerClass = null; bool headerFinished = false; while (!headerFinished) { string line = input.ReadLine(); string cmd, arg; int splitIndex = line.IndexOf(' '); if (splitIndex >= 0) { cmd = line.Substring(0, splitIndex); arg = line.Substring(splitIndex + 1); } else { cmd = line; arg = ""; } arg = arg.ToLower(); int i, n; switch (cmd) { case "svm_type": param.SvmType = (SvmType)Enum.Parse(typeof(SvmType), arg.ToUpper()); break; case "kernel_type": param.KernelType = (KernelType)Enum.Parse(typeof(KernelType), arg.ToUpper()); break; case "degree": param.Degree = int.Parse(arg); break; case "gamma": param.Gamma = double.Parse(arg); break; case "coef0": param.Coefficient0 = double.Parse(arg); break; case "nr_class": model.NumberOfClasses = int.Parse(arg); break; case "total_sv": model.SupportVectorCount = int.Parse(arg); break; case "rho": n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2; model.Rho = new double[n]; string[] rhoParts = arg.Split(); for (i = 0; i < n; i++) model.Rho[i] = double.Parse(rhoParts[i]); break; case "label": n = model.NumberOfClasses; model.ClassLabels = new int[n]; string[] labelParts = arg.Split(); for (i = 0; i < n; i++) model.ClassLabels[i] = int.Parse(labelParts[i]); break; case "probA": n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2; model.PairwiseProbabilityA = new double[n]; string[] probAParts = arg.Split(); for (i = 0; i < n; i++) model.PairwiseProbabilityA[i] = double.Parse(probAParts[i]); break; case "probB": n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2; model.PairwiseProbabilityB = new double[n]; string[] probBParts = arg.Split(); for (i = 0; i < n; i++) model.PairwiseProbabilityB[i] = double.Parse(probBParts[i]); break; case "nr_sv": n = model.NumberOfClasses; model.NumberOfSVPerClass = new int[n]; string[] nrsvParts = arg.Split(); for (i = 0; i < n; i++) model.NumberOfSVPerClass[i] = int.Parse(nrsvParts[i]); break; case "SV": headerFinished = true; break; default: throw new Exception("Unknown text in model file"); } } // read sv_coef and SV int m = model.NumberOfClasses - 1; int l = model.SupportVectorCount; model.SupportVectorCoefficients = new double[m][]; for (int i = 0; i < m; i++) { model.SupportVectorCoefficients[i] = new double[l]; } model.SupportVectors = new Node[l][]; for (int i = 0; i < l; i++) { string[] parts = input.ReadLine().Trim().Split(); for (int k = 0; k < m; k++) model.SupportVectorCoefficients[k][i] = double.Parse(parts[k]); int n = parts.Length - m; model.SupportVectors[i] = new Node[n]; for (int j = 0; j < n; j++) { string[] nodeParts = parts[m + j].Split(':'); model.SupportVectors[i][j] = new Node(); model.SupportVectors[i][j].Index = int.Parse(nodeParts[0]); model.SupportVectors[i][j].Value = double.Parse(nodeParts[1]); } } TemporaryCulture.Stop(); return model; }
/// <summary> /// Predicts the class memberships of all the vectors in the problem. /// </summary> /// <param name="problem">The SVM Problem to solve</param> /// <param name="outputFile">File for result output</param> /// <param name="model">The Model to use</param> /// <param name="predict_probability">Whether to output a distribution over the classes</param> /// <returns>Percentage correctly labelled</returns> public static double Predict( Problem problem, string outputFile, Model model, bool predict_probability) { int correct = 0; int total = 0; double error = 0; double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; StreamWriter output = outputFile != null ? new StreamWriter(outputFile) : null; SvmType svm_type = Procedures.svm_get_svm_type(model); int nr_class = Procedures.svm_get_nr_class(model); int[] labels = new int[nr_class]; double[] prob_estimates = null; if (predict_probability) { if (svm_type == SvmType.EPSILON_SVR || svm_type == SvmType.NU_SVR) { Console.WriteLine("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + Procedures.svm_get_svr_probability(model)); } else { Procedures.svm_get_labels(model, labels); prob_estimates = new double[nr_class]; if (output != null) { output.Write("labels"); for (int j = 0; j < nr_class; j++) { output.Write(" " + labels[j]); } output.Write("\n"); } } } else { Procedures.svm_get_labels(model, labels); if (output != null) { output.Write("labels"); for (int j = 0; j < nr_class; j++) { output.Write(" " + labels[j]); } output.Write("\n"); } } for (int i = 0; i < problem.Count; i++) { double target = problem.Y[i]; Node[] x = problem.X[i]; double v; if (predict_probability && (svm_type == SvmType.C_SVC || svm_type == SvmType.NU_SVC)) { v = Procedures.svm_predict_probability(model, x, prob_estimates); if (output != null) { output.Write(target + " " + v + " "); for (int j = 0; j < nr_class; j++) { output.Write(prob_estimates[j] + " "); } output.Write("\n"); } } else { v = Procedures.svm_predict(model, x); if (output != null) output.Write(target + " " + v + "\n"); } if (v == target) ++correct; error += (v - target) * (v - target); sumv += v; sumy += target; sumvv += v * v; sumyy += target * target; sumvy += v * target; ++total; } if (output != null) output.Close(); return (double)correct / total; }
/// <summary> /// Predicts a class distribution for the single input vector. /// </summary> /// <param name="model">Model to use for prediction</param> /// <param name="x">The vector for which to predict the class distribution</param> /// <returns>A probability distribtion over classes</returns> public static double[] PredictProbability(Model model, Node[] x) { SvmType svm_type = Procedures.svm_get_svm_type(model); if (svm_type != SvmType.C_SVC && svm_type != SvmType.NU_SVC) throw new Exception("Model type " + svm_type + " unable to predict probabilities."); int nr_class = Procedures.svm_get_nr_class(model); double[] probEstimates = new double[nr_class]; Procedures.svm_predict_probability(model, x, probEstimates); return probEstimates; }
/// <summary> /// Predict the class for a single input vector. /// </summary> /// <param name="model">The Model to use for prediction</param> /// <param name="x">The vector for which to predict class</param> /// <returns>The result</returns> public static double Predict(Model model, Node[] x) { return Procedures.svm_predict(model, x); }