make constraint member of the LMNN function class
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
Reference in New Issue
Block a user