Skip to content
This repository has been archived by the owner on Nov 19, 2020. It is now read-only.

Commit

Permalink
GH-397: Add an Example for OneclassSupportVectorLearning(TModel, TKer…
Browse files Browse the repository at this point in the history
…nel, TInput) Class.
  • Loading branch information
cesarsouza committed Jan 27, 2017
1 parent 1f34143 commit 9a21f61
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,24 @@ namespace Accord.MachineLearning.VectorMachines.Learning
using System.Threading;

/// <summary>
/// One-class Support Vector Machine Learning Algorithm.
/// One-class Support Vector Machine learning algorithm.
/// </summary>
///
/// <example>
/// <para>The following example shows how to use an one-class SVM.</para>
/// <code source="Unit Tests\Accord.Tests.MachineLearning\VectorMachines\OneclassSupportVectorLearningTest.cs" region="doc_learn" />
/// </example>
///
/// <seealso cref="SupportVectorMachine"/>
/// <seealso cref="KernelSupportVectorMachine"/>
///
/// <seealso cref="ProbabilisticOutputCalibration"/>
/// <seealso cref="MulticlassSupportVectorLearning"/>
///
#pragma warning disable 0618
[Obsolete("Please use OneclassSupportVectorLearning<TKernel> instead.")]
public class OneclassSupportVectorLearning
: OneclassSupportVectorLearning<KernelSupportVectorMachine, IKernel<double[]>, double[]>
: BaseOneclassSupportVectorLearning<ISupportVectorMachine<double[]>, IKernel<double[]>, double[]>
{
/// <summary>
/// Obsolete.
Expand All @@ -54,61 +65,165 @@ public OneclassSupportVectorLearning()
{

}

/// <summary>
/// Creates an instance of the model to be learned. Inheritors
/// of this abstract class must define this method so new models
/// can be created from the training data.
/// </summary>
protected override ISupportVectorMachine<double[]> Create(int inputs, IKernel<double[]> kernel)
{
if (kernel is Linear)
return new SupportVectorMachine(inputs) { Kernel = (Linear)kernel };
return new SupportVectorMachine<IKernel<double[]>>(inputs, kernel);
}
}
#pragma warning restore 0618


/// <summary>
/// One-class Support Vector Machine learning algorithm.
/// </summary>
///
/// <example>
/// <para>The following example shows how to use an one-class SVM.</para>
/// <code source="Unit Tests\Accord.Tests.MachineLearning\VectorMachines\OneclassSupportVectorLearningTest.cs" region="doc_learn" />
/// </example>
///
/// <seealso cref="SupportVectorMachine"/>
/// <seealso cref="KernelSupportVectorMachine"/>
///
/// <seealso cref="ProbabilisticOutputCalibration"/>
/// <seealso cref="MulticlassSupportVectorLearning"/>
///
public class OneclassSupportVectorLearning<TKernel>
: BaseOneclassSupportVectorLearning<SupportVectorMachine<TKernel>, TKernel, double[]>
where TKernel : IKernel<double[]>
{
/// <summary>
/// Creates an instance of the model to be learned. Inheritors
/// of this abstract class must define this method so new models
/// can be created from the training data.
/// </summary>
protected override SupportVectorMachine<TKernel> Create(int inputs, TKernel kernel)
{
return new SupportVectorMachine<TKernel>(inputs, kernel);
}
}

/// <summary>
/// One-class Support Vector Machine Learning Algorithm.
/// One-class Support Vector Machine learning algorithm.
/// </summary>
///
/// <example>
/// <para>The following example shows how to use an one-class SVM.</para>
/// <code source="Unit Tests\Accord.Tests.MachineLearning\VectorMachines\OneclassSupportVectorLearningTest.cs" region="doc_learn" />
/// </example>
///
/// <seealso cref="SupportVectorMachine"/>
/// <seealso cref="KernelSupportVectorMachine"/>
///
/// <seealso cref="ProbabilisticOutputCalibration"/>
/// <seealso cref="MulticlassSupportVectorLearning"/>
///
public class OneclassSupportVectorLearning<TKernel, TInput>
: OneclassSupportVectorLearning<SupportVectorMachine<TKernel, TInput>, TKernel, TInput>
: BaseOneclassSupportVectorLearning<SupportVectorMachine<TKernel, TInput>, TKernel, TInput>
where TKernel : IKernel<TInput>
where TInput : ICloneable
{
/// <summary>
/// Creates an instance of the model to be learned. Inheritors
/// of this abstract class must define this method so new models
/// can be created from the training data.
/// </summary>
protected override SupportVectorMachine<TKernel, TInput> Create(int inputs, TKernel kernel)
{
return new SupportVectorMachine<TKernel, TInput>(inputs, kernel);
}
}

/// <summary>
/// One-class Support Vector Machine Learning Algorithm.
/// </summary>
///
public class OneclassSupportVectorLearning<TModel, TKernel, TInput>
public abstract class BaseOneclassSupportVectorLearning<TModel, TKernel, TInput>
: IUnsupervisedLearning<TModel, TInput, bool>
where TKernel : IKernel<TInput>
where TModel : SupportVectorMachine<TKernel, TInput>
where TInput : ICloneable
where TModel : ISupportVectorMachine<TInput>
// TODO: after a few releases, the TModel constraint should be changed to:
// where TModel : SupportVectorMachine<TKernel, TInput>, ISupportVectorMachine<TInput>
{
[NonSerialized]
CancellationToken token = new CancellationToken();

private bool useKernelEstimation = false;

private double[] alpha;
private TInput[] inputs;
private double nu = 0.5;

TModel machine;
TKernel kernel;

double eps = 0.001;
bool shrinking = true;

// TODO: Remove this field after a few releases. It exists
// only to provide compatibility with previous releases of
// the framework.
private ISupportVectorMachine<TInput> machine;



/// <summary>
/// Gets or sets the classifier being learned.
/// </summary>
///
public TModel Model { get; set; }

/// <summary>
/// Gets or sets the kernel function use to create a
/// kernel Support Vector Machine. If this property
/// is set, <see cref="UseKernelEstimation"/> will be
/// set to false.
/// </summary>
///
public TKernel Kernel
{
get { return kernel; }
set
{
this.kernel = value;
this.useKernelEstimation = false;
}
}

/// <summary>
/// Gets or sets whether initial values for some kernel parameters
/// should be estimated from the data, if possible. Default is true.
/// </summary>
///
public bool UseKernelEstimation
{
get { return useKernelEstimation; }
set { useKernelEstimation = value; }
}


/// <summary>
/// Constructs a new one-class support vector learning algorithm.
/// </summary>
///
/// <param name="machine">A support vector machine.</param>
///
public OneclassSupportVectorLearning(TModel machine)
public BaseOneclassSupportVectorLearning(TModel machine)
{
this.machine = machine;
this.Model = machine;
}

/// <summary>
/// Constructs a new one-class support vector learning algorithm.
/// </summary>
///
public OneclassSupportVectorLearning()
public BaseOneclassSupportVectorLearning()
{

}
Expand Down Expand Up @@ -177,6 +292,14 @@ public double Nu
set { nu = value; }
}

/// <summary>
/// Creates an instance of the model to be learned. Inheritors
/// of this abstract class must define this method so new models
/// can be created from the training data.
/// </summary>
///
protected abstract TModel Create(int inputs, TKernel kernel);


/// <summary>
/// Learns a model that can map the given inputs to the desired outputs.
Expand All @@ -189,64 +312,97 @@ public double Nu
/// </returns>
public TModel Learn(TInput[] x, double[] weights = null)
{
this.inputs = x;
double[] zeros = new double[inputs.Length];
int[] ones = Vector.Ones<int>(inputs.Length);
this.alpha = Vector.Ones<double>(inputs.Length);

var kernel = machine.Kernel;
bool initialized = false;

int l = inputs.Length;
int n = (int)(nu * l); // # of alpha's at upper bound
SupportVectorLearningHelper.CheckArgs(x);

for (int i = 0; i < n; i++)
alpha[i] = 1;
if (kernel == null)
{
kernel = SupportVectorLearningHelper.CreateKernel<TKernel, TInput>(x);
initialized = true;
}

if (n < inputs.Length)
alpha[n] = nu * l - n;
if (!initialized && useKernelEstimation)
kernel = SupportVectorLearningHelper.EstimateKernel(kernel, x);

for (int i = n + 1; i < l; i++)
alpha[i] = 0;
if (Model == null)
Model = Create(SupportVectorLearningHelper.GetNumberOfInputs(kernel, x), kernel);

Func<int, int, double> Q = (int i, int j) => kernel.Function(x[i], x[j]);
Model.Kernel = kernel;

var s = new FanChenLinQuadraticOptimization(alpha.Length, Q, zeros, ones)
try
{
Tolerance = eps,
Shrinking = this.shrinking,
Solution = alpha,
Token = Token
};
this.inputs = x;
double[] zeros = new double[inputs.Length];
int[] ones = Vector.Ones<int>(inputs.Length);
this.alpha = Vector.Ones<double>(inputs.Length);

bool success = s.Minimize();
int l = inputs.Length;
int n = (int)(nu * l); // # of alpha's at upper bound

int sv = 0;
for (int i = 0; i < alpha.Length; i++)
if (alpha[i] > 0) sv++;
for (int i = 0; i < n; i++)
alpha[i] = 1;

machine.SupportVectors = new TInput[sv];
machine.Weights = new double[sv];
if (n < inputs.Length)
alpha[n] = nu * l - n;

for (int i = 0, j = 0; i < alpha.Length; i++)
{
if (alpha[i] > 0)
for (int i = n + 1; i < l; i++)
alpha[i] = 0;

Func<int, int, double> Q = (int i, int j) => kernel.Function(x[i], x[j]);

var s = new FanChenLinQuadraticOptimization(alpha.Length, Q, zeros, ones)
{
Tolerance = eps,
Shrinking = this.shrinking,
Solution = alpha,
Token = Token
};

bool success = s.Minimize();

int sv = 0;
for (int i = 0; i < alpha.Length; i++)
if (alpha[i] > 0) sv++;

Model.SupportVectors = new TInput[sv];
Model.Weights = new double[sv];

for (int i = 0, j = 0; i < alpha.Length; i++)
{
machine.SupportVectors[j] = inputs[i];
machine.Weights[j] = alpha[i];
j++;
if (alpha[i] > 0)
{
Model.SupportVectors[j] = inputs[i];
Model.Weights[j] = alpha[i];
j++;
}
}
}

machine.Threshold = s.Rho;
Model.Threshold = s.Rho;

if (success == false)
if (success == false)
{
throw new ConvergenceException("Convergence could not be attained. " +
"Please reduce the cost of misclassification errors by reducing " +
"the complexity parameter C or try a different kernel function.");
}
}
finally
{
throw new ConvergenceException("Convergence could not be attained. " +
"Please reduce the cost of misclassification errors by reducing " +
"the complexity parameter C or try a different kernel function.");
if (machine != null)
{
// TODO: This block is only necessary to offer compatibility
// to code written using previous versions of the framework,
// and should be removed after a few releases.
machine.SupportVectors = Model.SupportVectors;
machine.Weights = Model.Weights;
machine.Threshold = Model.Threshold;
machine.Kernel = Model.Kernel;
machine.IsProbabilistic = Model.IsProbabilistic;
}
}

return machine;
return Model;
}


Expand All @@ -255,10 +411,11 @@ public TModel Learn(TInput[] x, double[] weights = null)
/// Obsolete.
/// </summary>
///
protected OneclassSupportVectorLearning(TModel model, TInput[] input)
protected BaseOneclassSupportVectorLearning(ISupportVectorMachine<TInput> model, TInput[] input)
{
this.machine = model;
this.inputs = input;
this.Kernel = (TKernel)model.Kernel;
}

/// <summary>
Expand All @@ -268,7 +425,7 @@ protected OneclassSupportVectorLearning(TModel model, TInput[] input)
public double Run()
{
Learn(inputs);
return new LogLikelihoodLoss().Loss(machine.Score(inputs));
return new LogLikelihoodLoss().Loss(Model.Score(inputs));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ public enum SelectionStrategy
///
//[Obsolete("Please use SequentialMinimalOptimization<TKernel> instead.")]
public class SequentialMinimalOptimization :
BaseSequentialMinimalOptimization<
ISupportVectorMachine<double[]>, IKernel<double[]>, double[]>,
BaseSequentialMinimalOptimization<ISupportVectorMachine<double[]>, IKernel<double[]>, double[]>,
ISupportVectorMachineLearning
{
/// <summary>
Expand Down Expand Up @@ -418,8 +417,8 @@ public abstract class BaseSequentialMinimalOptimization<TModel, TKernel, TInput>
ISupportVectorMachineLearning<TInput>
where TKernel : IKernel<TInput>
where TModel : ISupportVectorMachine<TInput>
// TODO: after a few releases, the TModel constraint should be changed to:
// where TModel : SupportVectorMachine<TKernel, TInput>, ISupportVectorMachine<TInput>
// TODO: after a few releases, the TModel constraint should be changed to:
// where TModel : SupportVectorMachine<TKernel, TInput>, ISupportVectorMachine<TInput>
{
// Learning algorithm parameters
private double tolerance = 1e-2;
Expand Down
Loading

0 comments on commit 9a21f61

Please sign in to comment.