Added the get_transformation_to() function to the empirical_kernel_map. I also changed the

epsilon value used to tell if something is essentially zero to a more reasonable value.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403369
This commit is contained in:
Davis King 2010-01-08 00:29:27 +00:00
parent a5e6f0a714
commit 8f26951cc8
3 changed files with 135 additions and 2 deletions

View File

@ -95,7 +95,7 @@ namespace dlib
// find out the value of the largest norm of the elements in basis_samples.
const scalar_type max_norm = max(diag(kernel_matrix(kernel, basis_samples)));
// we will consider anything less than or equal to this number to be 0
const scalar_type eps = max_norm*std::numeric_limits<scalar_type>::epsilon();
const scalar_type eps = max_norm*100*std::numeric_limits<scalar_type>::epsilon();
// Copy all the basis_samples into basis but make sure we don't copy any samples
// that have length 0
@ -218,6 +218,25 @@ namespace dlib
return projection_function<kernel_type>(weights, kernel, vector_to_matrix(basis));
}
const matrix<scalar_type,0,0,mem_manager_type> get_transformation_to (
const empirical_kernel_map& target
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(out_vector_size() != 0 &&
target.out_vector_size() != 0 &&
get_kernel() == target.get_kernel(),
"\t const matrix empirical_kernel_map::get_transformation_to(target)"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t out_vector_size(): " << out_vector_size()
<< "\n\t target.out_vector_size(): " << target.out_vector_size()
<< "\n\t get_kernel()==target.get_kernel(): " << (get_kernel()==target.get_kernel())
<< "\n\t this: " << this
);
return target.weights * kernel_matrix(target.get_kernel(),target.basis, basis)*trans(weights);
}
const matrix<scalar_type,0,1,mem_manager_type>& project (
const sample_type& samp
) const

View File

@ -256,6 +256,37 @@ namespace dlib
this->project() on that sample.
!*/
const matrix<scalar_type,0,0,mem_manager_type> get_transformation_to (
const empirical_kernel_map& target
) const;
/*!
requires
- get_kernel() == target.get_kernel()
- out_vector_size() != 0
- target.out_vector_size() != 0
ensures
- A point in the kernel feature space defined by the kernel get_kernel() typically
has different representations with respect to different empirical_kernel_maps.
This function lets you obtain a transformation matrix that will allow you
to map between these different representations. That is, this function returns
a matrix M with the following properties:
- M maps vectors represented according to *this into the representation used by target.
- M.nr() == target.out_vector_size()
- M.nc() == this->out_vector_size()
- Let V be a vector of this->out_vector_size() length. Then define two distance_functions
DF1 = this->convert_to_distance_function(V)
DF2 = target.convert_to_distance_function(M*V)
Then DF1(DF2) == 0 // i.e. the distance between these two points should be 0
That is, DF1 and DF2 both represent the same point in kernel feature space. Note
that the above equality is only approximate. If the vector V represents a point in
kernel space that isn't in the span of the basis samples used by target then the
equality is approximate. However, if it is in their span then the equality will
be exact. For example, if target's basis samples are a superset of the basis samples
used by *this then the equality will always be exact (within rounding error).
!*/
void swap (
empirical_kernel_map& item
);

View File

@ -96,7 +96,7 @@ namespace
// make sure the distances match
const double dist_error = abs(length(proj_samples[idx1] - proj_samples[idx2]) - dist_funct(samples[idx2]));
DLIB_TEST_MSG( dist_error < 1e-7, dist_error);
DLIB_TEST_MSG( dist_error < 1e-6, dist_error);
// make sure the dot products match
DLIB_TEST(abs(dot(proj_samples[idx1],proj_samples[idx2]) - dec_funct(samples[idx2])) < 1e-10);
@ -160,6 +160,87 @@ namespace
}
}
for (int j = 1; j <= 20; ++j)
{
dlog << LTRACE << "j: " << j;
sample_type samp, samp2;
std::vector<sample_type> samples1;
std::vector<sample_type> samples2;
print_spinner();
// make some random samples. At the end samples1 will be a subset of samples2
for (int i = 0; i < 5*j; ++i)
{
samples1.push_back(randm(10,1,rnd));
samples2.push_back(samples1.back());
}
for (int i = 0; i < 5*j; ++i)
{
samples2.push_back(randm(10,1,rnd));
}
// add on a little bit to make sure there is at least one non-zero sample. If all the
// samples are zero then empirical_kernel_map_error will be thrown and we don't want that.
samples1.front()(0) += 0.001;
samples2.front()(0) += 0.001;
ekm.load(kern, samples1);
ekm2.load(kern, samples2);
dlog << LTRACE << "ekm.out_vector_size(): " << ekm.out_vector_size();
dlog << LTRACE << "ekm2.out_vector_size(): " << ekm2.out_vector_size();
const double eps = 1e-6;
matrix<double> transform;
// Make sure transformations back to yourself work right. Note that we can't just
// check that transform is the identity matrix since it might be an identity transform
// for only a subspace of vectors (this happens if the ekm maps points into a subspace of
// all possible ekm.out_vector_size() vectors).
transform = ekm.get_transformation_to(ekm);
DLIB_TEST(transform.nr() == ekm.out_vector_size());
DLIB_TEST(transform.nc() == ekm.out_vector_size());
for (unsigned long i = 0; i < samples1.size(); ++i)
{
samp = ekm.project(samples1[i]);
DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
samp = ekm.project((samples1[0] + samples1[i])/2);
DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
}
transform = ekm2.get_transformation_to(ekm2);
DLIB_TEST(transform.nr() == ekm2.out_vector_size());
DLIB_TEST(transform.nc() == ekm2.out_vector_size());
for (unsigned long i = 0; i < samples2.size(); ++i)
{
samp = ekm2.project(samples2[i]);
DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
samp = ekm2.project((samples2[0] + samples2[i])/2);
DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp));
//dlog << LTRACE << "mapping error: " << length(samp - transform*samp);
}
// now test the transform from ekm to ekm2
transform = ekm.get_transformation_to(ekm2);
DLIB_TEST(transform.nr() == ekm2.out_vector_size());
DLIB_TEST(transform.nc() == ekm.out_vector_size());
for (unsigned long i = 0; i < samples1.size(); ++i)
{
samp = ekm.project(samples1[i]);
distance_function<kernel_type> df1 = ekm.convert_to_distance_function(samp);
distance_function<kernel_type> df2 = ekm2.convert_to_distance_function(transform*samp);
DLIB_TEST_MSG(df1(df2) < eps, df1(df2));
//dlog << LTRACE << "mapping error: " << df1(df2);
samp = ekm.project((samples1[0] + samples1[i])/2);
df1 = ekm.convert_to_distance_function(samp);
df2 = ekm2.convert_to_distance_function(transform*samp);
DLIB_TEST_MSG(df1(df2) < eps, df1(df2));
}
}
}
@ -172,8 +253,10 @@ namespace
rnd.set_seed(cast_to_string(thetime));
print_spinner();
dlog << LINFO << "test with linear kernel";
test_with_kernel(linear_kernel<sample_type>());
print_spinner();
dlog << LINFO << "test with rbf kernel";
test_with_kernel(radial_basis_kernel<sample_type>(0.2));
print_spinner();
}