make constraint member of the LMNN function class

This commit is contained in:
Manish
2018-06-23 11:06:26 +05:30
parent 4321cb7f10
commit 18aba9b8bd
4 changed files with 118 additions and 49 deletions
+43 -13
View File
@@ -51,28 +51,40 @@ class Constraints
* passed matrix.
*
* @param outputMatrix Coordinates matrix to store target neighbors.
* @param dataset Input dataset.
* @param labels Input dataset labels.
*/
void TargetNeighbors(arma::Mat<size_t>& outputMatrix);
void TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels);
/**
* Calculates k similar labeled nearest neighbors for a batch of dataset and
* stores them into the passed matrix.
*
* @param outputMatrix Coordinates matrix to store target neighbors.
* @param dataset Input dataset.
* @param labels Input dataset labels.
* @param begin Index of the initial point of dataset.
* @param batchSize Number of data points to use.
*/
void TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const size_t begin,
const size_t batchSize);
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize);
/**
* Calculates k differently labeled nearest neighbors for each datapoint and
* writes them back to passed matrix.
*
* @param outputMatrix Coordinates matrix to store impostors.
* @param dataset Input dataset.
* @param labels Input dataset labels.
*/
void Impostors(arma::Mat<size_t>& outputMatrix);
void Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels);
/**
* Calculates k differently labeled nearest neighbors & distances to
@@ -80,19 +92,27 @@ class Constraints
*
* @param outputNeighbors Coordinates matrix to store impostors.
* @param outputDistance matrix to store distance.
* @param dataset Input dataset.
* @param labels Input dataset labels.
*/
void Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance);
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels);
/**
* Calculates k differently labeled nearest neighbors for a batch of dataset
* and writes them back to passed matrix.
*
* @param outputMatrix Coordinates matrix to store impostors.
* @param dataset Input dataset.
* @param labels Input dataset labels.
* @param begin Index of the initial point of dataset.
* @param batchSize Number of data points to use.
*/
void Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize);
@@ -102,11 +122,15 @@ class Constraints
*
* @param outputNeighbors Coordinates matrix to store impostors.
* @param outputDistance matrix to store distance.
* @param dataset Input dataset.
* @param labels Input dataset labels.
* @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 arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize);
@@ -115,21 +139,24 @@ class Constraints
* triplets to matrix passed.
*
* @param outputMatrix Coordinates matrix to store triplets.
* @param dataset Input dataset.
* @param labels Input dataset labels.
*/
void Triplets(arma::Mat<size_t>& outputMatrix);
void Triplets(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels);
//! Access the value of k.
const size_t& K() const { return k; }
//! Modify the value of k.
size_t& K() { return k; }
//! Access the boolean value of precalculated.
const bool& PreCalulated() const { return precalculated; }
//! Modify the value of precalculated.
bool& PreCalulated() { return precalculated; }
private:
//! An alias of dataset.
arma::mat dataset;
//! An alias of Labels.
arma::Row<size_t> labels;
//! Number of target neighbors & impostors to calulate.
size_t k;
@@ -142,11 +169,14 @@ class Constraints
//! Store indices of data points having different label.
std::vector<arma::uvec> indexDiff;
//! False if nothing has ever been precalculated.
bool precalculated;
/**
* Precalculate the unique labels, and indices of similar
* and different datapoints on the basis of labels.
*/
void Precalculate();
inline void Precalculate(const arma::Row<size_t>& labels);
};
} // namespace lmnn
+58 -21
View File
@@ -20,12 +20,11 @@ namespace lmnn {
template<typename MetricType>
Constraints<MetricType>::Constraints(
const arma::mat& dataset,
const arma::mat& /* dataset */,
const arma::Row<size_t>& labels,
size_t k) :
dataset(math::MakeAlias(const_cast<arma::mat&>(dataset), false)),
labels(math::MakeAlias(const_cast<arma::Row<size_t>&>(labels), false)),
k(k)
k(k),
precalculated(false)
{
// Ensure a valid k is passed.
size_t minCount = arma::min(arma::histc(labels, arma::unique(labels)));
@@ -36,15 +35,17 @@ Constraints<MetricType>::Constraints(
<< minCount << " instances, but value of k is " << k << " "
<< "(k should be < " << minCount << ")!" << std::endl;
}
// Perform pre-calculation.
Precalculate();
}
// Calculates k similar labeled nearest neighbors.
template<typename MetricType>
void Constraints<MetricType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix)
void Constraints<MetricType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
// KNN instance.
KNN knn;
@@ -71,9 +72,14 @@ void Constraints<MetricType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix)
// batch of data points.
template<typename MetricType>
void Constraints<MetricType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const size_t begin,
const size_t batchSize)
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
@@ -107,8 +113,13 @@ void Constraints<MetricType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
// Calculates k differently labeled nearest neighbors.
template<typename MetricType>
void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputMatrix)
void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
// KNN instance.
KNN knn;
@@ -135,8 +146,13 @@ void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputMatrix)
// writes back calculated neighbors & distances to passed matrices.
template<typename MetricType>
void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance)
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
// KNN instance.
KNN knn;
@@ -164,9 +180,14 @@ void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// batch of data points.
template<typename MetricType>
void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputMatrix,
const size_t begin,
const size_t batchSize)
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
@@ -202,10 +223,15 @@ void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputMatrix,
// batch of data points.
template<typename MetricType>
void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const size_t begin,
const size_t batchSize)
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
@@ -241,15 +267,20 @@ void Constraints<MetricType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// Generates {data point, target neighbors, impostors} triplets using
// TargetNeighbors() and Impostors().
template<typename MetricType>
void Constraints<MetricType>::Triplets(arma::Mat<size_t>& outputMatrix)
void Constraints<MetricType>::Triplets(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
size_t N = dataset.n_cols;
arma::Mat<size_t> impostors;
Impostors(impostors);
Impostors(impostors, dataset);
arma::Mat<size_t> targetNeighbors;
TargetNeighbors(targetNeighbors);
TargetNeighbors(targetNeighbors, dataset);
outputMatrix = arma::Mat<size_t>(3, k * k * N , arma::fill::zeros);
@@ -269,8 +300,12 @@ void Constraints<MetricType>::Triplets(arma::Mat<size_t>& outputMatrix)
}
template<typename MetricType>
void Constraints<MetricType>::Precalculate()
inline void Constraints<MetricType>::Precalculate(const arma::Row<size_t>& labels)
{
// Make sure the calculation is necessary.
if (precalculated)
return;
uniqueLabels = arma::unique(labels);
indexSame.resize(uniqueLabels.n_elem);
@@ -282,6 +317,8 @@ void Constraints<MetricType>::Precalculate()
indexSame[i] = arma::find(labels == uniqueLabels[i]);
indexDiff[i] = arma::find(labels != uniqueLabels[i]);
}
precalculated = true;
}
} // namespace lmnn
@@ -16,6 +16,8 @@
#include <mlpack/prereqs.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include "constraints.hpp"
namespace mlpack {
namespace lmnn {
@@ -187,6 +189,8 @@ class LMNNFunction
size_t iteration;
//! Range after which impostors need to be recalculated.
size_t range;
//! Constraints Object.
Constraints<MetricType> constraint;
//! Holds pre-calculated cij.
arma::mat p_cij;
/**
+13 -15
View File
@@ -13,7 +13,6 @@
#define MLPACK_METHODS_LMNN_FUNCTION_IMPL_HPP
#include "lmnn_function.hpp"
#include "constraints.hpp"
#include <mlpack/core/math/make_alias.hpp>
#include <mlpack/core/optimizers/function.hpp>
@@ -33,7 +32,8 @@ LMNNFunction<MetricType>::LMNNFunction(const arma::mat& dataset,
metric(metric),
regularization(regularization),
iteration(0),
range(1)
range(1),
constraint(dataset, labels, k)
{
// Initialize the initial learning point.
initialPoint.eye(dataset.n_rows, dataset.n_rows);
@@ -44,9 +44,9 @@ LMNNFunction<MetricType>::LMNNFunction(const arma::mat& dataset,
targetNeighbors = arma::Mat<size_t>(k, dataset.n_cols, arma::fill::zeros);
impostors = arma::Mat<size_t>(k, dataset.n_cols, arma::fill::zeros);
distance = arma::mat(k, dataset.n_cols, arma::fill::zeros);
Constraints<MetricType> constraint(dataset, labels, k);
constraint.TargetNeighbors(targetNeighbors);
constraint.Impostors(impostors);
constraint.TargetNeighbors(targetNeighbors, dataset, labels);
constraint.Impostors(impostors, dataset, labels);
// Precalculate and save the gradient due to target neighbors.
Precalculate();
@@ -68,8 +68,8 @@ void LMNNFunction<MetricType>::Shuffle()
labels = std::move(newLabels);
// Re-calculate target neighbors as indices changed.
Constraints<MetricType> constraint(dataset, labels, k);
constraint.TargetNeighbors(targetNeighbors);
constraint.PreCalulated() = false;
constraint.TargetNeighbors(targetNeighbors, dataset, labels);
}
//! Evaluate cost over whole dataset.
@@ -84,8 +84,7 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& transformation)
if (iteration % range == 0)
{
// Re-calculate impostors on transformed dataset.
Constraints<MetricType> constraint(transformedDataset, labels, k);
constraint.Impostors(impostors, distance);
constraint.Impostors(impostors, distance, transformedDataset, labels);
}
for (size_t i = 0; i < dataset.n_cols; i++)
@@ -151,8 +150,8 @@ double LMNNFunction<MetricType>::Evaluate(const arma::mat& transformation,
if (iteration % range == 0)
{
// Re-calculate impostors on transformed dataset.
Constraints<MetricType> constraint(transformedDataset, labels, k);
constraint.Impostors(impostors, distance, begin, batchSize);
constraint.Impostors(impostors, distance, transformedDataset, labels,
begin, batchSize);
}
for (size_t i = begin; i < begin + batchSize; i++)
@@ -322,8 +321,7 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
if (iteration % range == 0)
{
// Re-calculate impostors on transformed dataset.
Constraints<MetricType> constraint(transformedDataset, labels, k);
constraint.Impostors(impostors, distance);
constraint.Impostors(impostors, distance, transformedDataset, labels);
}
gradient.zeros(transformation.n_rows, transformation.n_cols);
@@ -409,8 +407,8 @@ double LMNNFunction<MetricType>::EvaluateWithGradient(
if (iteration % range == 0)
{
// Re-calculate impostors on transformed dataset.
Constraints<MetricType> constraint(transformedDataset, labels, k);
constraint.Impostors(impostors, distance, begin, batchSize);
constraint.Impostors(impostors, distance, transformedDataset, labels,
begin, batchSize);
}
gradient.zeros(transformation.n_rows, transformation.n_cols);