/*
* SVM.NET Library
* Copyright (C) 2008 Matthew Johnson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using System;
using System.IO;
using System.Threading;
using System.Globalization;
namespace SVM.BotSharp.MachineLearning
{
///
/// Encapsulates an SVM Model.
///
[Serializable]
public class Model
{
internal Model()
{
}
///
/// Parameter object.
///
public Parameter Parameter{get;set;}
///
/// Number of classes in the model.
///
public int NumberOfClasses{get;set;}
///
/// Total number of support vectors.
///
public int SupportVectorCount { get; set; }
///
/// The support vectors.
///
public Node[][] SupportVectors{get;set;}
///
/// The coefficients for the support vectors.
///
public double[][] SupportVectorCoefficients{get;set;}
///
/// Values in [1,...,num_training_data] to indicate SVs in the training set
///
public int[] SupportVectorIndices { get; set; }
///
/// Constants in decision functions
///
public double[] Rho{get;set;}
///
/// First pairwise probability.
///
public double[] PairwiseProbabilityA{get;set;}
///
/// Second pairwise probability.
///
public double[] PairwiseProbabilityB{get;set;}
// for classification only
///
/// Class labels.
///
public int[] ClassLabels{get;set;}
///
/// Number of support vectors per class.
///
public int[] NumberOfSVPerClass{get;set;}
public override bool Equals(object obj)
{
Model test = obj as Model;
if (test == null)
return false;
bool same = ClassLabels.IsEqual(test.ClassLabels);
same = same && NumberOfClasses == test.NumberOfClasses;
same = same && NumberOfSVPerClass.IsEqual(test.NumberOfSVPerClass);
if(PairwiseProbabilityA != null)
same = same && PairwiseProbabilityA.IsEqual(test.PairwiseProbabilityA);
if(PairwiseProbabilityB != null)
same = same && PairwiseProbabilityB.IsEqual(test.PairwiseProbabilityB);
same = same && Parameter.Equals(test.Parameter);
same = same && Rho.IsEqual(test.Rho);
same = same && SupportVectorCoefficients.IsEqual(test.SupportVectorCoefficients);
same = same && SupportVectorCount == test.SupportVectorCount;
same = same && SupportVectors.IsEqual(test.SupportVectors);
return same;
}
public override int GetHashCode()
{
return ClassLabels.ComputeHashcode() +
NumberOfClasses.GetHashCode() +
NumberOfSVPerClass.ComputeHashcode() +
PairwiseProbabilityA.ComputeHashcode() +
PairwiseProbabilityB.ComputeHashcode() +
Parameter.GetHashCode() +
Rho.ComputeHashcode() +
SupportVectorCoefficients.ComputeHashcode() +
SupportVectorCount.GetHashCode() +
SupportVectors.ComputeHashcode();
}
///
/// Reads a Model from the provided file.
///
/// The name of the file containing the Model
/// the Model
public static Model Read(string filename)
{
FileStream input = File.OpenRead(filename);
try
{
return Read(input);
}
finally
{
input.Close();
}
}
///
/// Reads a Model from the provided stream.
///
/// The stream from which to read the Model.
/// the Model
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":
if (arg == "polynomial")
arg = "poly";
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
/// Writes a model to the provided filename. This will overwrite any previous data in the file.
///
/// The desired file
/// The Model to write
public static void Write(string filename, Model model)
{
FileStream stream = File.Open(filename, FileMode.Create);
try
{
Write(stream, model);
}
finally
{
stream.Close();
}
}
///
/// Writes a model to the provided stream.
///
/// The output stream
/// The model to write
public static void Write(Stream stream, Model model)
{
TemporaryCulture.Start();
StreamWriter output = new StreamWriter(stream);
Parameter param = model.Parameter;
output.Write("svm_type {0}\n", param.SvmType);
output.Write("kernel_type {0}\n", param.KernelType);
if (param.KernelType == KernelType.POLY)
output.Write("degree {0}\n", param.Degree);
if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.RBF || param.KernelType == KernelType.SIGMOID)
output.Write("gamma {0:0.000000}\n", param.Gamma);
if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.SIGMOID)
output.Write("coef0 {0:0.000000}\n", param.Coefficient0);
int nr_class = model.NumberOfClasses;
int l = model.SupportVectorCount;
output.Write("nr_class {0}\n", nr_class);
output.Write("total_sv {0}\n", l);
{
output.Write("rho");
for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
output.Write(" {0:0.000000}", model.Rho[i]);
output.Write("\n");
}
if (model.ClassLabels != null)
{
output.Write("label");
for (int i = 0; i < nr_class; i++)
output.Write(" {0}", 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(" {0:0.000000}", 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(" {0:0.000000}", model.PairwiseProbabilityB[i]);
output.Write("\n");
}
if (model.NumberOfSVPerClass != null)
{
output.Write("nr_sv");
for (int i = 0; i < nr_class; i++)
output.Write(" {0}", 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("{0:0.000000} ", sv_coef[j][i]);
Node[] p = SV[i];
if (p.Length == 0)
{
output.Write("\n");
continue;
}
if (param.KernelType == KernelType.PRECOMPUTED)
output.Write("0:{0:0.000000}", (int)p[0].Value);
else
{
output.Write("{0}:{1:0.000000}", p[0].Index, p[0].Value);
for (int j = 1; j < p.Length; j++)
output.Write(" {0}:{1:0.000000}", p[j].Index, p[j].Value);
}
output.Write("\n");
}
output.Flush();
TemporaryCulture.Stop();
}
}
}