Commit a5ec5963 authored by Davis King's avatar Davis King

Cleaned up the empirical_kernel_map more. I moved some functionality out of the object and

into a new projection_function class.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403322
parent 707c3705
......@@ -164,21 +164,17 @@ namespace dlib
return distance_function<kernel_type>(trans(weights)*vect, dot(vect,vect), kernel, vector_to_matrix(basis));
}
template <typename EXP>
void premultiply_projections_by (
const matrix_exp<EXP>& mat
)
const projection_function<kernel_type> get_projection_function (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(out_vector_size() != 0 && mat.nc() == out_vector_size(),
"\t void empirical_kernel_map::premultiply_projections_by()"
<< "\n\t Invalid inputs to this function."
<< "\n\t out_vector_size(): " << out_vector_size()
<< "\n\t mat.nc(): " << mat.nc()
DLIB_ASSERT(out_vector_size() != 0,
"\tconst projection_function empirical_kernel_map::get_projection_function()"
<< "\n\t You have to load this object with data before you can call this function"
<< "\n\t this: " << this
);
weights = mat*weights;
return projection_function<kernel_type>(weights, kernel, vector_to_matrix(basis));
}
const matrix<scalar_type,0,1,mem_manager_type>& project (
......@@ -192,11 +188,7 @@ namespace dlib
<< "\n\t this: " << this
);
temp1.set_size(basis.size());
for (unsigned long i = 0; i < basis.size(); ++i)
{
temp1(i) = kernel(samp, basis[i]);
}
temp1 = kernel_matrix(kernel, basis, samp);
temp2 = weights*temp1;
return temp2;
}
......@@ -252,6 +244,32 @@ namespace dlib
empirical_kernel_map<kernel_type>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <typename kernel_type, typename EXP>
const decision_function<kernel_type> convert_to_decision_function (
const projection_function<kernel_type>& project_funct,
const matrix<EXP>& vect
)
{
// make sure requires clause is not broken
DLIB_ASSERT(project_funct.out_vector_size() > 0 && is_vector(vect) &&
project_funct.out_vector_size() == vect.size() && project_funct.weights.nc() == project_funct.basis_vectors.size(),
"\t const decision_function convert_to_decision_function()"
<< "\n\t Invalid inputs to this function."
<< "\n\t project_funct.out_vector_size(): " << project_funct.out_vector_size()
<< "\n\t project_funct.weights.nc(): " << project_funct.weights.nc()
<< "\n\t project_funct.basis_vectors.size(): " << project_funct.basis_vectors.size()
<< "\n\t is_vector(vect): " << is_vector(vect)
<< "\n\t vect.size(): " << vect.size()
);
return decision_function<kernel_type>(trans(project_funct.weights)*vect,
0,
project_funct.kernel_function,
project_funct.basis_vectors);
}
// ----------------------------------------------------------------------------------------
}
......
......@@ -99,7 +99,7 @@ namespace dlib
ensures
- performs load(kernel,vector_to_matrix(basis_samples)). I.e. This function
does the exact same thing as the above load() function but lets you use
a std::vector of basis samples in addition to a row/column matrix of basis samples.
a std::vector of basis samples instead of a row/column matrix of basis samples.
!*/
const kernel_type get_kernel (
......@@ -115,27 +115,12 @@ namespace dlib
) const;
/*!
ensures
- if (this object has been loaded with sample basis functions) then
- returns the dimensionality of the space the kernel map projects
new data samples into via the project() function.
- if (this object has been loaded with basis samples) then
- returns the dimensionality of the vectors output by the project() function.
- else
- returns 0
!*/
template <typename EXP>
void premultiply_projections_by (
const matrix_exp<EXP>& mat
);
/*!
requires
- out_vector_size() != 0
- mat.nc() == out_vector_size()
ensures
- #out_vector_size() == mat.nr()
- TODO explain what this does. introduce functions to get the
weights and basis vectors and relate it to those.
!*/
const matrix<scalar_type,0,1,mem_manager_type>& project (
const sample_type& sample
) const;
......@@ -173,7 +158,8 @@ namespace dlib
function, DF, that represents the given vector in the following sense:
- for all possible sample_type objects, S, it is the case that DF(S) == dot(project(S), vect)
(i.e. the returned decision function computes dot products, in kernel feature space,
between vect and any argument you give it. )
between vect and any argument you give it. Note also that this equality is exact, even
for sample_type objects not in the span of the basis samples.)
- DF.kernel_function == get_kernel()
- DF.b == 0
- DF.basis_vectors == these will be the basis samples given to the previous call to load(). Note
......@@ -189,20 +175,37 @@ namespace dlib
- is_vector(vect) == true
- vect.size() == out_vector_size()
- out_vector_size() != 0
- TODO premultiply_projections_by() hasn't been called
ensures
- This function interprets the given vector as a point in the kernel feature space defined
by this empirical_kernel_map. The return value of this function is a distance
function, DF, that represents the given vector in the following sense:
- for all possible sample_type objects, S, it is the case that DF(S) == length(project(S) - vect)
(i.e. the returned distance function computes distances, in kernel feature space,
between vect and any argument you give it. )
- for any sample_type object S, the following equality is approximately true:
- DF(S) == length(project(S) - vect)
(i.e. the returned distance function computes distances, in kernel feature space,
between vect and any argument you give it. )
- The approximation error in the above equality will be zero (within rounding error)
if both sample_type objects involved are within the span of the set of basis
samples given to the load() function. If they are not then there will be some
approximation error. Note that all the basis samples are always within their
own span. So the equality is always exact for the samples given to the load()
function.
- DF.kernel_function == get_kernel()
- DF.b == dot(vect,vect)
- DF.basis_vectors == these will be the basis samples given to the previous call to load(). Note
that it is possible for there to be fewer basis_vectors than basis samples given to load().
!*/
const projection_function<kernel_type> get_projection_function (
) const;
/*!
requires
- out_vector_size() != 0
ensures
- returns a projection_function, PF, that computes the same projection as project().
That is, calling PF() on any sample will produce the same output vector as calling
this->project() on that sample.
!*/
void swap (
empirical_kernel_map& item
);
......@@ -248,6 +251,35 @@ namespace dlib
provides serialization support for empirical_kernel_map objects
!*/
// ----------------------------------------------------------------------------------------
template <
typename kernel_type,
typename EXP
>
const decision_function<kernel_type> convert_to_decision_function (
const projection_function<kernel_type>& project_funct,
const matrix<EXP>& vect
);
/*!
requires
- is_vector(vect) == true
- vect.size() == project_funct.out_vector_size()
- project_funct.out_vector_size() > 0
- project_funct.weights.nc() == project_funct.basis_vectors.size()
ensures
- This function interprets the given vector as a point in the kernel feature space defined
by the given projection function. The return value of this function is a decision
function, DF, that represents the given vector in the following sense:
- for all possible sample_type objects, S, it is the case that DF(S) == dot(project_funct(S), vect)
(i.e. the returned decision function computes dot products, in kernel feature space,
between vect and any argument you give it. Note also that this equality is exact, even
for sample_type objects not in the span of the basis_vectors.)
- DF.kernel_function == project_funct.kernel_function
- DF.b == 0
- DF.basis_vectors == project_funct.basis_vectors.
!*/
// ----------------------------------------------------------------------------------------
}
......
......@@ -12,6 +12,7 @@
#include "../serialize.h"
#include "../rand.h"
#include "../statistics.h"
#include "kernel_matrix.h"
namespace dlib
{
......@@ -101,7 +102,7 @@ namespace dlib
serialize(item.kernel_function, out);
serialize(item.basis_vectors, out);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while serializing object of type decision_function");
}
......@@ -122,7 +123,7 @@ namespace dlib
deserialize(item.kernel_function, in);
deserialize(item.basis_vectors, in);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while deserializing object of type decision_function");
}
......@@ -333,7 +334,7 @@ namespace dlib
serialize(item.kernel_function, out);
serialize(item.basis_vectors, out);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while serializing object of type distance_function");
}
......@@ -354,7 +355,7 @@ namespace dlib
deserialize(item.kernel_function, in);
deserialize(item.basis_vectors, in);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while deserializing object of type distance_function");
}
......@@ -410,7 +411,7 @@ namespace dlib
serialize(item.normalizer, out);
serialize(item.function, out);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while serializing object of type normalized_function");
}
......@@ -430,7 +431,7 @@ namespace dlib
deserialize(item.normalizer, in);
deserialize(item.function, in);
}
catch (serialization_error e)
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while deserializing object of type normalized_function");
}
......@@ -438,6 +439,100 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename K
>
struct projection_function
{
typedef K kernel_type;
typedef typename K::scalar_type scalar_type;
typedef typename K::sample_type sample_type;
typedef typename K::mem_manager_type mem_manager_type;
typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;
typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;
scalar_matrix_type weights;
K kernel_function;
sample_vector_type basis_vectors;
projection_function (
) {}
projection_function (
const projection_function& f
) : weights(f.weights), kernel_function(f.kernel_function), basis_vectors(f.basis_vectors) {}
projection_function (
const scalar_matrix_type& weights_,
const K& kernel_function_,
const sample_vector_type& basis_vectors_
) : weights(weights_), kernel_function(kernel_function_), basis_vectors(basis_vectors_) {}
long out_vector_size (
) const { return weights.nr(); }
const scalar_vector_type& operator() (
const sample_type& x
) const
{
// Run the x sample through all the basis functions we have and then
// multiply it by the weights matrix and return the result. Note that
// the temp vectors are here to avoid reallocating their memory every
// time this function is called.
temp1 = kernel_matrix(kernel_function, basis_vectors, x);
temp2 = weights*temp1;
return temp2;
}
private:
mutable scalar_vector_type temp1, temp2;
};
template <
typename K
>
void serialize (
const projection_function<K>& item,
std::ostream& out
)
{
try
{
serialize(item.weights, out);
serialize(item.kernel_function, out);
serialize(item.basis_vectors, out);
}
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while serializing object of type projection_function");
}
}
template <
typename K
>
void deserialize (
projection_function<K>& item,
std::istream& in
)
{
try
{
deserialize(item.weights, in);
deserialize(item.kernel_function, in);
deserialize(item.basis_vectors, in);
}
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while deserializing object of type projection_function");
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_SVm_FUNCTION
......
......@@ -461,6 +461,129 @@ namespace dlib
provides serialization support for normalized_function
!*/
// ----------------------------------------------------------------------------------------
template <
typename K
>
struct projection_function
{
/*!
REQUIREMENTS ON K
K must be a kernel function object type as defined at the
top of dlib/svm/kernel_abstract.h
WHAT THIS OBJECT REPRESENTS
This object represents a function that takes a data sample and projects
it into kernel feature space. The result is a real valued column vector that
represents a point in a kernel feature space.
!*/
typedef K kernel_type;
typedef typename K::scalar_type scalar_type;
typedef typename K::sample_type sample_type;
typedef typename K::mem_manager_type mem_manager_type;
typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;
typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;
scalar_matrix_type weights;
K kernel_function;
sample_vector_type basis_vectors;
projection_function (
);
/*!
ensures
- #weights.size() == 0
- #basis_vectors.size() == 0
!*/
projection_function (
const projection_function& f
);
/*!
ensures
- #*this is a copy of f
!*/
projection_function (
const scalar_matrix_type& weights_,
const K& kernel_function_,
const sample_vector_type& basis_vectors_
) : weights(weights_), kernel_function(kernel_function_), basis_vectors(basis_vectors_) {}
/*!
ensures
- populates the projection function with the given basis vectors, weights,
and kernel function.
!*/
projection_function& operator= (
const projection_function& d
);
/*!
ensures
- #*this is identical to d
- returns *this
!*/
long out_vector_size (
) const;
/*!
ensures
- returns weights.nr()
(i.e. returns the dimensionality of the vectors output by this projection_function.)
!*/
const scalar_vector_type& operator() (
const sample_type& x
) const
/*!
requires
- weights.nc() == basis_vectors.size()
- out_vector_size() > 0
ensures
- Takes the given x sample and projects it onto part of the kernel feature
space spanned by the basis_vectors. The exact projection arithmetic is
defined below.
!*/
{
// Run the x sample through all the basis functions we have and then
// multiply it by the weights matrix and return the result. Note that
// the temp vectors are here to avoid reallocating their memory every
// time this function is called.
temp1 = kernel_matrix(kernel_function, basis_vectors, x);
temp2 = weights*temp1;
return temp2;
}
private:
mutable scalar_vector_type temp1, temp2;
};
template <
typename K
>
void serialize (
const projection_function<K>& item,
std::ostream& out
);
/*!
provides serialization support for projection_function
!*/
template <
typename K
>
void deserialize (
projection_function<K>& item,
std::istream& in
);
/*!
provides serialization support for projection_function
!*/
// ----------------------------------------------------------------------------------------
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment