Commit 577ef82d authored by Davis King's avatar Davis King

Made this function capable of accepting anything that can be converted to

a matrix via vector_to_matrix()

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403891
parent 0d1e82e7
...@@ -45,150 +45,174 @@ namespace dlib ...@@ -45,150 +45,174 @@ namespace dlib
// Build the inverse matrix. This is basically a pseudo-inverse. // Build the inverse matrix. This is basically a pseudo-inverse.
return make_symmetric(eig.get_pseudo_v()*diagm(reciprocal(vals))*trans(eig.get_pseudo_v())); return make_symmetric(eig.get_pseudo_v()*diagm(reciprocal(vals))*trans(eig.get_pseudo_v()));
} }
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename kernel_type, typename kernel_type,
typename vect1_type, typename vect1_type,
typename vect2_type, typename vect2_type,
typename vect3_type typename vect3_type
> >
const std::vector<typename kernel_type::sample_type> sort_basis_vectors ( const std::vector<typename kernel_type::sample_type> sort_basis_vectors_impl (
const kernel_type& kern, const kernel_type& kern,
const vect1_type& samples, const vect1_type& samples,
const vect2_type& labels, const vect2_type& labels,
const vect3_type& basis, const vect3_type& basis,
double eps = 0.99 double eps
) )
{
DLIB_ASSERT(is_binary_classification_problem(samples, labels) &&
0 < eps && eps <= 1,
"\t void sort_basis_vectors()"
<< "\n\t Invalid arguments were given to this function."
<< "\n\t is_binary_classification_problem(samples, labels): " << is_binary_classification_problem(samples, labels)
<< "\n\t eps: " << eps
);
typedef typename kernel_type::sample_type sample_type;
typedef typename kernel_type::scalar_type scalar_type;
typedef typename kernel_type::mem_manager_type mm_type;
typedef matrix<scalar_type,0,1,mm_type> col_matrix;
typedef matrix<scalar_type,0,0,mm_type> gen_matrix;
col_matrix c1_mean, c2_mean, temp, delta;
col_matrix weights;
running_covariance<gen_matrix> cov;
// compute the covariance matrix and the means of the two classes.
for (unsigned long i = 0; i < samples.size(); ++i)
{ {
temp = kernel_matrix(kern, basis, samples[i]); DLIB_ASSERT(is_binary_classification_problem(samples, labels) &&
cov.add(temp); 0 < eps && eps <= 1,
if (labels[i] > 0) "\t void sort_basis_vectors()"
c1_mean += temp; << "\n\t Invalid arguments were given to this function."
else << "\n\t is_binary_classification_problem(samples, labels): " << is_binary_classification_problem(samples, labels)
c2_mean += temp; << "\n\t eps: " << eps
} );
c1_mean /= sum(vector_to_matrix(labels) > 0); typedef typename kernel_type::sample_type sample_type;
c2_mean /= sum(vector_to_matrix(labels) < 0); typedef typename kernel_type::scalar_type scalar_type;
typedef typename kernel_type::mem_manager_type mm_type;
delta = c1_mean - c2_mean; typedef matrix<scalar_type,0,1,mm_type> col_matrix;
typedef matrix<scalar_type,0,0,mm_type> gen_matrix;
gen_matrix cov_inv = bs_impl::invert(cov.covariance()); col_matrix c1_mean, c2_mean, temp, delta;
matrix<long,0,1,mm_type> total_perm = trans(range(0, delta.size()-1)); col_matrix weights;
matrix<long,0,1,mm_type> perm = total_perm;
std::vector<std::pair<scalar_type,long> > sorted_feats(delta.size()); running_covariance<gen_matrix> cov;
long best_size = delta.size(); // compute the covariance matrix and the means of the two classes.
long misses = 0; for (unsigned long i = 0; i < samples.size(); ++i)
matrix<long,0,1,mm_type> best_total_perm; {
temp = kernel_matrix(kern, basis, samples(i));
cov.add(temp);
if (labels(i) > 0)
c1_mean += temp;
else
c2_mean += temp;
}
// Now we basically find fisher's linear discriminant over and over. Each c1_mean /= sum(labels > 0);
// time sorting the features so that the most important ones pile up together. c2_mean /= sum(labels < 0);
weights = trans(chol(cov_inv))*delta;
while (true)
{
for (unsigned long i = 0; i < sorted_feats.size(); ++i) delta = c1_mean - c2_mean;
sorted_feats[i] = make_pair(std::abs(weights(i)), i);
std::sort(sorted_feats.begin(), sorted_feats.end()); gen_matrix cov_inv = bs_impl::invert(cov.covariance());
// make a permutation vector according to the sorting
for (long i = 0; i < perm.size(); ++i)
perm(i) = sorted_feats[i].second;
matrix<long,0,1,mm_type> total_perm = trans(range(0, delta.size()-1));
matrix<long,0,1,mm_type> perm = total_perm;
// Apply the permutation. Doing this gives the same result as permuting all the std::vector<std::pair<scalar_type,long> > sorted_feats(delta.size());
// features and then recomputing the delta and cov_inv from scratch.
cov_inv = subm(cov_inv,perm,perm);
delta = rowm(delta,perm);
// Record all the permutations we have done so we will know how the final long best_size = delta.size();
// weights match up with the original basis vectors when we are done. long misses = 0;
total_perm = rowm(total_perm, perm); matrix<long,0,1,mm_type> best_total_perm;
// compute new Fisher weights for sorted features. // Now we basically find fisher's linear discriminant over and over. Each
// time sorting the features so that the most important ones pile up together.
weights = trans(chol(cov_inv))*delta; weights = trans(chol(cov_inv))*delta;
while (true)
// Measure how many features it takes to account for eps% of the weights vector.
const scalar_type total_weight = length_squared(weights);
scalar_type weight_accum = 0;
long size = 0;
// figure out how to get eps% of the weights
for (long i = weights.size()-1; i >= 0; --i)
{ {
++size;
weight_accum += weights(i)*weights(i);
if (weight_accum/total_weight > eps)
break;
}
// loop until the best_size stops dropping for (unsigned long i = 0; i < sorted_feats.size(); ++i)
if (size < best_size) sorted_feats[i] = make_pair(std::abs(weights(i)), i);
{
misses = 0; std::sort(sorted_feats.begin(), sorted_feats.end());
best_size = size;
best_total_perm = total_perm; // make a permutation vector according to the sorting
} for (long i = 0; i < perm.size(); ++i)
else perm(i) = sorted_feats[i].second;
{
++misses;
// Apply the permutation. Doing this gives the same result as permuting all the
// features and then recomputing the delta and cov_inv from scratch.
cov_inv = subm(cov_inv,perm,perm);
delta = rowm(delta,perm);
// Record all the permutations we have done so we will know how the final
// weights match up with the original basis vectors when we are done.
total_perm = rowm(total_perm, perm);
// compute new Fisher weights for sorted features.
weights = trans(chol(cov_inv))*delta;
// Measure how many features it takes to account for eps% of the weights vector.
const scalar_type total_weight = length_squared(weights);
scalar_type weight_accum = 0;
long size = 0;
// figure out how to get eps% of the weights
for (long i = weights.size()-1; i >= 0; --i)
{
++size;
weight_accum += weights(i)*weights(i);
if (weight_accum/total_weight > eps)
break;
}
// loop until the best_size stops dropping
if (size < best_size)
{
misses = 0;
best_size = size;
best_total_perm = total_perm;
}
else
{
++misses;
// Give up once we have had 10 rounds where we didn't find a weights vector with
// a smaller concentration of good features.
if (misses >= 10)
break;
}
// Give up once we have had 10 rounds where we didn't find a weights vector with
// a smaller concentration of good features.
if (misses >= 10)
break;
} }
} // make sure best_size isn't zero
if (best_size == 0)
best_size = 1;
// make sure best_size isn't zero std::vector<typename kernel_type::sample_type> sorted_basis;
if (best_size == 0)
best_size = 1;
std::vector<typename kernel_type::sample_type> sorted_basis; // permute the basis so that it matches up with the contents of the best weights
sorted_basis.resize(best_size);
for (unsigned long i = 0; i < sorted_basis.size(); ++i)
{
// Note that we load sorted_basis backwards so that the most important
// basis elements come first.
sorted_basis[i] = basis(best_total_perm(basis.size()-i-1));
}
// permute the basis so that it matches up with the contents of the best weights return sorted_basis;
sorted_basis.resize(best_size);
for (unsigned long i = 0; i < sorted_basis.size(); ++i)
{
// Note that we load sorted_basis backwards so that the most important
// basis elements come first.
sorted_basis[i] = vector_to_matrix(basis)(best_total_perm(basis.size()-i-1));
} }
return sorted_basis; }
// ----------------------------------------------------------------------------------------
template <
typename kernel_type,
typename vect1_type,
typename vect2_type,
typename vect3_type
>
const std::vector<typename kernel_type::sample_type> sort_basis_vectors (
const kernel_type& kern,
const vect1_type& samples,
const vect2_type& labels,
const vect3_type& basis,
double eps = 0.99
)
{
return bs_impl::sort_basis_vectors_impl(kern,
vector_to_matrix(samples),
vector_to_matrix(labels),
vector_to_matrix(basis),
eps);
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
......
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