Commit bf2edbec authored by Davis King's avatar Davis King

Added dpca_matrix_of_size() to discriminant_pca. It allows the user

to easily get a transformation matrix of a particular size.
parent d9746486
......@@ -239,6 +239,25 @@ namespace dlib
return dpca_mat;
}
const general_matrix dpca_matrix_of_size (
const long num_rows
)
{
// make sure requires clause is not broken
DLIB_ASSERT(0 < num_rows && num_rows <= in_vector_size(),
"\t general_matrix discriminant_pca::dpca_matrix_of_size()"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t num_rows: " << num_rows
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t this: " << this
);
general_matrix dpca_mat;
general_matrix eigenvalues;
dpca_matrix_of_size(dpca_mat, eigenvalues, num_rows);
return dpca_mat;
}
void dpca_matrix (
general_matrix& dpca_mat,
general_matrix& eigenvalues,
......@@ -254,53 +273,25 @@ namespace dlib
<< "\n\t this: " << this
);
general_matrix cov;
// now combine the three measures of variance into a single matrix by using the
// within_weight and between_weight weights.
cov = get_total_covariance_matrix();
if (within_count != 0)
cov -= within_weight*within_cov/within_count;
if (between_count != 0)
cov += between_weight*between_cov/between_count;
eigenvalue_decomposition<general_matrix> eig(make_symmetric(cov));
eigenvalues = eig.get_real_eigenvalues();
dpca_mat = eig.get_pseudo_v();
// sort the eigenvalues and eigenvectors so that the biggest eigenvalues come first
rsort_columns(dpca_mat, eigenvalues);
// Some of the eigenvalues might be negative. So first lets zero those out
// so they won't get considered.
eigenvalues = pointwise_multiply(eigenvalues > 0, eigenvalues);
// figure out how many eigenvectors we want in our dpca matrix
const double thresh = sum(eigenvalues)*eps;
long num_vectors = 0;
double total = 0;
for (long r = 0; r < eigenvalues.size() && total < thresh; ++r)
{
// Don't even think about looking at eigenvalues that are 0. If we go this
// far then we have all we need.
if (eigenvalues(r) == 0)
break;
++num_vectors;
total += eigenvalues(r);
}
if (num_vectors == 0)
throw discriminant_pca_error("While performing discriminant_pca, all eigenvalues were negative or 0");
// So now we know we want to use num_vectors of the first eigenvectors. So
// pull those out and discard the rest.
dpca_mat = trans(colm(dpca_mat,range(0,num_vectors-1)));
compute_dpca_matrix(dpca_mat, eigenvalues, eps, 0);
}
// also clip off the eigenvalues we aren't using
eigenvalues = rowm(eigenvalues, range(0,num_vectors-1));
void dpca_matrix_of_size (
general_matrix& dpca_mat,
general_matrix& eigenvalues,
const long num_rows
)
{
// make sure requires clause is not broken
DLIB_ASSERT(0 < num_rows && num_rows <= in_vector_size(),
"\t general_matrix discriminant_pca::dpca_matrix_of_size()"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t num_rows: " << num_rows
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t this: " << this
);
compute_dpca_matrix(dpca_mat, eigenvalues, 1, num_rows);
}
void swap (
......@@ -419,6 +410,70 @@ namespace dlib
private:
void compute_dpca_matrix (
general_matrix& dpca_mat,
general_matrix& eigenvalues,
const double eps,
long num_rows
) const
{
general_matrix cov;
// now combine the three measures of variance into a single matrix by using the
// within_weight and between_weight weights.
cov = get_total_covariance_matrix();
if (within_count != 0)
cov -= within_weight*within_cov/within_count;
if (between_count != 0)
cov += between_weight*between_cov/between_count;
eigenvalue_decomposition<general_matrix> eig(make_symmetric(cov));
eigenvalues = eig.get_real_eigenvalues();
dpca_mat = eig.get_pseudo_v();
// sort the eigenvalues and eigenvectors so that the biggest eigenvalues come first
rsort_columns(dpca_mat, eigenvalues);
long num_vectors = 0;
if (num_rows == 0)
{
// Some of the eigenvalues might be negative. So first lets zero those out
// so they won't get considered.
eigenvalues = pointwise_multiply(eigenvalues > 0, eigenvalues);
// figure out how many eigenvectors we want in our dpca matrix
const double thresh = sum(eigenvalues)*eps;
double total = 0;
for (long r = 0; r < eigenvalues.size() && total < thresh; ++r)
{
// Don't even think about looking at eigenvalues that are 0. If we go this
// far then we have all we need.
if (eigenvalues(r) == 0)
break;
++num_vectors;
total += eigenvalues(r);
}
if (num_vectors == 0)
throw discriminant_pca_error("While performing discriminant_pca, all eigenvalues were negative or 0");
}
else
{
num_vectors = num_rows;
}
// So now we know we want to use num_vectors of the first eigenvectors. So
// pull those out and discard the rest.
dpca_mat = trans(colm(dpca_mat,range(0,num_vectors-1)));
// also clip off the eigenvalues we aren't using
eigenvalues = rowm(eigenvalues, range(0,num_vectors-1));
}
general_matrix get_total_covariance_matrix (
) const
/*!
......
......@@ -240,6 +240,47 @@ namespace dlib
that prevents this algorithm from working properly.
!*/
const general_matrix dpca_matrix_of_size (
const long num_rows
);
/*!
requires
- 0 < num_rows <= in_vector_size()
ensures
- computes and returns the matrix MAT given by dpca_matrix_of_size(MAT,eigen,num_rows).
That is, this function returns the dpca_matrix computed by the function
defined below.
- Note that MAT is the desired linear transformation matrix. That is,
multiplying a vector by MAT performs the desired linear dimensionality
reduction to num_rows dimensions.
!*/
void dpca_matrix_of_size (
general_matrix& dpca_mat,
general_matrix& eigenvalues,
const long num_rows
);
/*!
requires
- 0 < num_rows <= in_vector_size()
ensures
- is_col_vector(#eigenvalues) == true
- #dpca_mat.nr() == eigenvalues.size()
- #dpca_mat.nr() == num_rows
- #dpca_mat.nc() == in_vector_size()
- rowm(#dpca_mat,i) represents the ith eigenvector of the S matrix described
in the class description and its eigenvalue is given by eigenvalues(i).
- The values in #eigenvalues might be positive or negative. Additionally, the
eigenvalues are in sorted order with the largest eigenvalue stored at
eigenvalues(0).
- (#dpca_mat)*trans(#dpca_mat) == identity_matrix.
(i.e. the rows of the dpca_matrix are all unit length vectors and are mutually
orthogonal)
- Note that #dpca_mat is the desired linear transformation matrix. That is,
multiplying a vector by #dpca_mat performs the desired linear dimensionality
reduction to num_rows dimensions.
!*/
const discriminant_pca operator+ (
const discriminant_pca& item
) const;
......
......@@ -80,6 +80,15 @@ namespace
DLIB_TEST(last >= eig(i));
}
{
matrix<double> mat = dpca.dpca_matrix_of_size(4);
DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(4)));
}
{
matrix<double> mat = dpca.dpca_matrix_of_size(3);
DLIB_TEST(equal(mat*trans(mat), identity_matrix<double>(3)));
}
dpca.set_within_class_weight(5);
dpca.set_between_class_weight(6);
......
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