Commit 801f07ef authored by Davis King's avatar Davis King

Fixed a bug in the linearly_independent_subset_finder object. Also

added a way to set a minimum tolerance.  This also breaks backwards
compatibility with the previous serialization format for the object.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402517
parent 8c98c050
...@@ -31,6 +31,7 @@ namespace dlib ...@@ -31,6 +31,7 @@ namespace dlib
CONVENTION CONVENTION
- max_dictionary_size() == my_max_dictionary_size - max_dictionary_size() == my_max_dictionary_size
- get_kernel() == kernel - get_kernel() == kernel
- minimum_tolerance() == min_tolerance
- dictionary_size() == dictionary.size() - dictionary_size() == dictionary.size()
- get_dictionary() == vector_to_matrix(dictionary) - get_dictionary() == vector_to_matrix(dictionary)
- K.nr() == dictionary.size() - K.nr() == dictionary.size()
...@@ -56,11 +57,20 @@ namespace dlib ...@@ -56,11 +57,20 @@ namespace dlib
linearly_independent_subset_finder ( linearly_independent_subset_finder (
const kernel_type& kernel_, const kernel_type& kernel_,
unsigned long max_dictionary_size_ unsigned long max_dictionary_size_,
scalar_type min_tolerance_ = 0.001
) : ) :
kernel(kernel_), kernel(kernel_),
my_max_dictionary_size(max_dictionary_size_) my_max_dictionary_size(max_dictionary_size_),
min_tolerance(min_tolerance_)
{ {
// make sure requires clause is not broken
DLIB_ASSERT(min_tolerance_ > 0,
"\tlinearly_independent_subset_finder()"
<< "\n\tinvalid argument to constructor"
<< "\n\tmin_tolerance_: " << min_tolerance_
<< "\n\tthis: " << this
);
clear_dictionary(); clear_dictionary();
} }
...@@ -75,6 +85,12 @@ namespace dlib ...@@ -75,6 +85,12 @@ namespace dlib
return kernel; return kernel;
} }
scalar_type minimum_tolerance(
) const
{
return min_tolerance;
}
void clear_dictionary () void clear_dictionary ()
{ {
dictionary.clear(); dictionary.clear();
...@@ -115,15 +131,17 @@ namespace dlib ...@@ -115,15 +131,17 @@ namespace dlib
// if this new vector is approximately linearly independent of the vectors // if this new vector is approximately linearly independent of the vectors
// in our dictionary. Or if our dictionary just isn't full yet. // in our dictionary. Or if our dictionary just isn't full yet.
if (delta > min_strength || dictionary.size() < my_max_dictionary_size) if (delta > min_strength && delta > min_tolerance)
{ {
if (dictionary.size() == my_max_dictionary_size) if (dictionary.size() == my_max_dictionary_size)
{ {
const long i = min_vect_idx; const long i = min_vect_idx;
// replace the min strength vector with x // replace the min strength vector with x. Put the new vector onto the end of
dictionary[i] = x; // dictionary and remove the vector at position i.
dictionary.erase(dictionary.begin()+i);
dictionary.push_back(x);
// compute reduced K_inv. // compute reduced K_inv.
// Remove the i'th vector from the inverse kernel matrix. This formula is basically // Remove the i'th vector from the inverse kernel matrix. This formula is basically
...@@ -147,23 +165,14 @@ namespace dlib ...@@ -147,23 +165,14 @@ namespace dlib
K_inv(temp.nr(), temp.nc()) = 1/delta; K_inv(temp.nr(), temp.nc()) = 1/delta;
// now update the kernel matrix K // now update the kernel matrix K
for (long r = 0; r < K.nr(); ++r) set_subm(K,get_rect(temp)) = removerc(K, i,i);
{ set_subm(K, 0, K.nr()-1,K.nr()-1,1) = k2;
if (r < i) // update the bottom row of the matrix
{ set_subm(K, K.nr()-1, 0, 1, K.nr()-1) = trans(k2);
K(r,i) = k2(r); K(K.nr()-1, K.nc()-1) = kx;
K(i,r) = k2(r);
} // now we have to recompute the min_strength in this case
else if (r == i) recompute_min_strength();
{
K(i,i) = kx;
}
else
{
K(r,i) = k2(r-1);
K(i,r) = k2(r-1);
}
}
} }
else else
{ {
...@@ -197,13 +206,6 @@ namespace dlib ...@@ -197,13 +206,6 @@ namespace dlib
dictionary.push_back(x); dictionary.push_back(x);
} }
// now we have to recompute the min_strength in this case
if (dictionary.size() == my_max_dictionary_size)
{
recompute_min_strength();
}
} }
} }
} }
...@@ -219,6 +221,7 @@ namespace dlib ...@@ -219,6 +221,7 @@ namespace dlib
K_inv.swap(item.K_inv); K_inv.swap(item.K_inv);
K.swap(item.K); K.swap(item.K);
exchange(my_max_dictionary_size, item.my_max_dictionary_size); exchange(my_max_dictionary_size, item.my_max_dictionary_size);
exchange(min_tolerance, item.min_tolerance);
// non-state temp members // non-state temp members
a.swap(item.a); a.swap(item.a);
...@@ -246,6 +249,7 @@ namespace dlib ...@@ -246,6 +249,7 @@ namespace dlib
serialize(item.K_inv, out); serialize(item.K_inv, out);
serialize(item.K, out); serialize(item.K, out);
serialize(item.my_max_dictionary_size, out); serialize(item.my_max_dictionary_size, out);
serialize(item.min_tolerance, out);
} }
friend void deserialize(linearly_independent_subset_finder& item, std::istream& in) friend void deserialize(linearly_independent_subset_finder& item, std::istream& in)
...@@ -257,6 +261,7 @@ namespace dlib ...@@ -257,6 +261,7 @@ namespace dlib
deserialize(item.K_inv, in); deserialize(item.K_inv, in);
deserialize(item.K, in); deserialize(item.K, in);
deserialize(item.my_max_dictionary_size, in); deserialize(item.my_max_dictionary_size, in);
deserialize(item.min_tolerance, in);
} }
const sample_type& operator[] ( const sample_type& operator[] (
...@@ -310,6 +315,7 @@ namespace dlib ...@@ -310,6 +315,7 @@ namespace dlib
matrix<scalar_type,0,0,mem_manager_type> K; matrix<scalar_type,0,0,mem_manager_type> K;
unsigned long my_max_dictionary_size; unsigned long my_max_dictionary_size;
scalar_type min_tolerance;
// temp variables here just so we don't have to reconstruct them over and over. Thus, // temp variables here just so we don't have to reconstruct them over and over. Thus,
// they aren't really part of the state of this object. // they aren't really part of the state of this object.
......
...@@ -47,10 +47,14 @@ namespace dlib ...@@ -47,10 +47,14 @@ namespace dlib
linearly_independent_subset_finder ( linearly_independent_subset_finder (
const kernel_type& kernel_, const kernel_type& kernel_,
unsigned long max_dictionary_size unsigned long max_dictionary_size,
scalar_type min_tolerance = 0.001
); );
/*! /*!
requires
- min_tolerance > 0
ensures ensures
- #minimum_tolerance() == min_tolerance
- this object is properly initialized - this object is properly initialized
- #get_kernel() == kernel_ - #get_kernel() == kernel_
- #max_dictionary_size() == max_dictionary_size_ - #max_dictionary_size() == max_dictionary_size_
...@@ -72,6 +76,18 @@ namespace dlib ...@@ -72,6 +76,18 @@ namespace dlib
greater than max_dictionary_size(). greater than max_dictionary_size().
!*/ !*/
scalar_type minimum_tolerance(
) const;
/*!
ensures
- returns the minimum tolerance to use for the approximately linearly dependent
test used for dictionary vector selection (see KRLS paper for ALD details).
In other words, this is the minimum threshold for how linearly independent
a sample must be for it to even be considered for addition to the dictionary.
Moreover, bigger values of this field will make the algorithm run faster but
might give less accurate results.
!*/
void clear_dictionary ( void clear_dictionary (
); );
/*! /*!
......
...@@ -75,7 +75,7 @@ namespace dlib ...@@ -75,7 +75,7 @@ namespace dlib
) const; ) const;
/*! /*!
ensures ensures
- returns the number of centers (a.k.a. support_vectors in the - returns the maximum number of centers (a.k.a. support_vectors in the
trained decision_function) you will get when you train this object on data. trained decision_function) you will get when you train this object on data.
!*/ !*/
......
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