Cache distance to avoid recomputation
This commit is contained in:
@@ -68,6 +68,16 @@ class Constraints
|
||||
*/
|
||||
void Impostors(arma::Mat<size_t>& outputMatrix);
|
||||
|
||||
/**
|
||||
* Calculates k differently labeled nearest neighbors & distances to
|
||||
* impostors for each datapoint and writes them back to passed matrices.
|
||||
*
|
||||
* @param outputNeighbors Coordinates matrix to store impostors.
|
||||
* @param outputDistance matrix to store distance.
|
||||
*/
|
||||
void Impostors(arma::Mat<size_t>& outputNeighbors,
|
||||
arma::mat& outputDistance);
|
||||
|
||||
/**
|
||||
* Calculates k differently labeled nearest neighbors for a batch of dataset
|
||||
* and writes them back to passed matrix.
|
||||
@@ -80,6 +90,20 @@ class Constraints
|
||||
const size_t begin,
|
||||
const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Calculates k differently labeled nearest neighbors & distances to
|
||||
* impostors for a batch of dataset and writes them back to passed matrices.
|
||||
*
|
||||
* @param outputNeighbors Coordinates matrix to store impostors.
|
||||
* @param outputDistance matrix to store distance.
|
||||
* @param begin Index of the initial point of dataset.
|
||||
* @param batchSize Number of data points to use.
|
||||
*/
|
||||
void Impostors(arma::Mat<size_t>& outputNeighbors,
|
||||
arma::mat& outputDistance,
|
||||
const size_t begin,
|
||||
const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Generate triplets {i, j, l} for each datapoint i and writes back generated
|
||||
* triplets to matrix passed.
|
||||
|
||||
@@ -143,6 +143,42 @@ void Constraints::Impostors(arma::Mat<size_t>& outputMatrix)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates k differently labeled nearest neighbors. The function
|
||||
// writes back calculated neighbors & distances to passed matrices.
|
||||
void Constraints::Impostors(arma::Mat<size_t>& outputNeighbors,
|
||||
arma::mat& outputDistance)
|
||||
{
|
||||
size_t N = dataset.n_cols;
|
||||
|
||||
// Perform pre-calculation, if necessary.
|
||||
Precalculate();
|
||||
|
||||
outputNeighbors = arma::Mat<size_t>(k, N, arma::fill::zeros);
|
||||
outputDistance = arma::mat(k, N, arma::fill::zeros);
|
||||
|
||||
// KNN instance.
|
||||
neighbor::KNN knn;
|
||||
|
||||
arma::Mat<size_t> neighbors;
|
||||
arma::mat distances;
|
||||
|
||||
for (size_t i = 0; i < uniqueLabels.n_cols; i++)
|
||||
{
|
||||
// Perform KNN search with differently labeled points as reference
|
||||
// set and same class points as query set.
|
||||
knn.Train(dataset.cols(indexDiff[i]));
|
||||
knn.Search(dataset.cols(indexSame[i]), k, neighbors, distances);
|
||||
|
||||
// Re-map neighbors to their index.
|
||||
for (size_t j = 0; j < neighbors.n_elem; j++)
|
||||
neighbors(j) = indexDiff[i].at(neighbors(j));
|
||||
|
||||
// Store impostors.
|
||||
outputNeighbors.cols(indexSame[i]) = neighbors;
|
||||
outputDistance.cols(indexSame[i]) = distances;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates k differently labeled nearest neighbors on a
|
||||
// batch of data points.
|
||||
void Constraints::Impostors(arma::Mat<size_t>& outputMatrix,
|
||||
@@ -183,6 +219,48 @@ void Constraints::Impostors(arma::Mat<size_t>& outputMatrix,
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates k differently labeled nearest neighbors & distances on a
|
||||
// batch of data points.
|
||||
void Constraints::Impostors(arma::Mat<size_t>& outputNeighbors,
|
||||
arma::mat& outputDistance,
|
||||
const size_t begin,
|
||||
const size_t batchSize)
|
||||
{
|
||||
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
|
||||
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
|
||||
|
||||
// Perform pre-calculation, if necessary.
|
||||
Precalculate();
|
||||
|
||||
// KNN instance.
|
||||
neighbor::KNN knn;
|
||||
|
||||
arma::Mat<size_t> neighbors;
|
||||
arma::mat distances;
|
||||
|
||||
// Vectors to store indices.
|
||||
arma::uvec subIndexSame;
|
||||
|
||||
for (size_t i = 0; i < uniqueLabels.n_cols; i++)
|
||||
{
|
||||
// Calculate impostors.
|
||||
subIndexSame = arma::find(sublabels == uniqueLabels[i]);
|
||||
|
||||
// Perform KNN search with differently labeled points as reference
|
||||
// set and same class points as query set.
|
||||
knn.Train(dataset.cols(indexDiff[i]));
|
||||
knn.Search(subDataset.cols(subIndexSame), k, neighbors, distances);
|
||||
|
||||
// Re-map neighbors to their index.
|
||||
for (size_t j = 0; j < neighbors.n_elem; j++)
|
||||
neighbors(j) = indexDiff[i].at(neighbors(j));
|
||||
|
||||
// Store impostors.
|
||||
outputNeighbors.cols(begin + subIndexSame) = neighbors;
|
||||
outputDistance.cols(begin + subIndexSame) = distances;
|
||||
}
|
||||
}
|
||||
|
||||
// Generates {data point, target neighbors, impostors} triplets using
|
||||
// TargetNeighbors() and Impostors().
|
||||
void Constraints::Triplets(arma::Mat<size_t>& outputMatrix)
|
||||
|
||||
@@ -76,11 +76,12 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& coordinates)
|
||||
// Apply metric over dataset.
|
||||
transformedDataset = coordinates * dataset;
|
||||
|
||||
arma::mat distance = arma::mat(k, dataset.n_cols, arma::fill::zeros);
|
||||
if (iteration++ % range == 0)
|
||||
{
|
||||
// Re-calculate impostors on transformed dataset.
|
||||
Constraints constraint(transformedDataset, labels, k);
|
||||
constraint.Impostors(impostors);
|
||||
constraint.Impostors(impostors, distance);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dataset.n_cols; i++)
|
||||
@@ -99,12 +100,17 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& coordinates)
|
||||
// breaking point.
|
||||
for (size_t l = 0, bp = k; l < bp ; l++)
|
||||
{
|
||||
// Calculate cost due to data point, target neighbors, impostors
|
||||
// Check if we already have distance between impostor & data point
|
||||
// stored.
|
||||
double distImp = distance(l, i) > 0 ? distance(l, i) :
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
|
||||
// Calculate cost due to {data point, target neighbors, impostors}
|
||||
// triplets.
|
||||
double eval = metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(targetNeighbors(j, i))) -
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
distImp;
|
||||
|
||||
// Check bounding condition.
|
||||
if (eval < -1)
|
||||
@@ -133,11 +139,12 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& coordinates,
|
||||
// Apply metric over dataset.
|
||||
transformedDataset = coordinates * dataset;
|
||||
|
||||
arma::mat distance = arma::mat(k, dataset.n_cols, arma::fill::zeros);
|
||||
if (iteration++ % range == 0)
|
||||
{
|
||||
// Re-calculate impostors on transformed dataset.
|
||||
Constraints constraint(transformedDataset, labels, k);
|
||||
constraint.Impostors(impostors, begin, batchSize);
|
||||
constraint.Impostors(impostors, distance, begin, batchSize);
|
||||
}
|
||||
|
||||
for (size_t i = begin; i < begin + batchSize; i++)
|
||||
@@ -155,12 +162,17 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& coordinates,
|
||||
// Bound constraints to avoid uneccesary computation.
|
||||
for (size_t l = 0, bp = k; l < bp ; l++)
|
||||
{
|
||||
// Calculate cost due to data point, target neighbors, impostors
|
||||
// Check if we already have distance between impostor & data point
|
||||
// stored.
|
||||
double distImp = distance(l, i) > 0 ? distance(l, i) :
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
|
||||
// Calculate cost due to {data point, target neighbors, impostors}
|
||||
// triplets.
|
||||
double eval = metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(targetNeighbors(j, i))) -
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
distImp;
|
||||
|
||||
// Check bounding condition.
|
||||
if (eval < -1)
|
||||
@@ -295,11 +307,12 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
|
||||
// Apply metric over dataset.
|
||||
transformedDataset = coordinates * dataset;
|
||||
|
||||
arma::mat distance = arma::mat(k, dataset.n_cols, arma::fill::zeros);
|
||||
if (iteration++ % range == 0)
|
||||
{
|
||||
// Re-calculate impostors on transformed dataset.
|
||||
Constraints constraint(transformedDataset, labels, k);
|
||||
constraint.Impostors(impostors);
|
||||
constraint.Impostors(impostors, distance);
|
||||
}
|
||||
|
||||
gradient.zeros(coordinates.n_rows, coordinates.n_cols);
|
||||
@@ -326,12 +339,17 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
|
||||
// Bound constraints to avoid uneccesary computation.
|
||||
for (size_t l = 0, bp = k; l < bp ; l++)
|
||||
{
|
||||
// Check if we already have distance between impostor & data point
|
||||
// stored.
|
||||
double distImp = distance(l, i) > 0 ? distance(l, i) :
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
|
||||
// Calculate cost due to {data point, target neighbors, impostors}
|
||||
// triplets.
|
||||
double eval = metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(targetNeighbors(j, i))) -
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
distImp;
|
||||
|
||||
// Check bounding condition.
|
||||
if (eval < -1)
|
||||
@@ -373,11 +391,12 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
|
||||
// Apply metric over dataset.
|
||||
transformedDataset = coordinates * dataset;
|
||||
|
||||
arma::mat distance = arma::mat(k, dataset.n_cols, arma::fill::zeros);
|
||||
if (iteration++ % range == 0)
|
||||
{
|
||||
// Re-calculate impostors on transformed dataset.
|
||||
Constraints constraint(transformedDataset, labels, k);
|
||||
constraint.Impostors(impostors, begin, batchSize);
|
||||
constraint.Impostors(impostors, distance, begin, batchSize);
|
||||
}
|
||||
|
||||
gradient.zeros(coordinates.n_rows, coordinates.n_cols);
|
||||
@@ -404,12 +423,17 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
|
||||
// Bound constraints to avoid uneccesary computation.
|
||||
for (size_t l = 0, bp = k; l < bp ; l++)
|
||||
{
|
||||
// Check if we already have distance between impostor & data point
|
||||
// stored.
|
||||
double distImp = distance(l, i) > 0 ? distance(l, i) :
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
|
||||
// Calculate cost due to {data point, target neighbors, impostors}
|
||||
// triplets.
|
||||
double eval = metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(targetNeighbors(j, i))) -
|
||||
metric.Evaluate(transformedDataset.col(i),
|
||||
transformedDataset.col(impostors(l, i)));
|
||||
distImp;
|
||||
|
||||
// Check bounding condition.
|
||||
if (eval < -1)
|
||||
|
||||
Reference in New Issue
Block a user