// Copyright (C) 2013 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #undef DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_ #ifdef DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_ #include "../matrix.h" namespace dlib { // ---------------------------------------------------------------------------------------- template < typename matrix_type > struct frobmetric_training_sample { /*! WHAT THIS OBJECT REPRESENTS This object represents a training data sample for the vector_normalizer_frobmetric object. It defines a set of training triplets relative to a single anchor_vect vector. That is, it specifies that the learned distance metric should satisfy num_triples() constraints which are, for all valid i and j: length(T*anchor_vect-T*near_vects[i]) + 1 < length(T*anchor_vect - T*far_vects[j]) for some appropriate linear transformation T which will be learned by vector_normalizer_frobmetric. !*/ matrix_type anchor_vect; std::vector<matrix_type> near_vects; std::vector<matrix_type> far_vects; unsigned long num_triples ( ) const { return near_vects.size() * far_vects.size(); } /*! ensures - returns the number of training triplets defined by this object. !*/ void clear() /*! ensures - #near_vects.size() == 0 - #far_vects.size() == 0 !*/ }; template < typename matrix_type > void serialize(const frobmetric_training_sample<matrix_type>& item, std::ostream& out) template < typename matrix_type > void deserialize(frobmetric_training_sample<matrix_type>& item, std::istream& in) /*! provides serialisation support. !*/ // ---------------------------------------------------------------------------------------- template < typename matrix_type > class vector_normalizer_frobmetric { /*! REQUIREMENTS ON matrix_type - must be a dlib::matrix object capable of representing column vectors INITIAL VALUE - in_vector_size() == 0 - out_vector_size() == 0 - get_epsilon() == 0.1 - get_c() == 1 - get_max_iterations() == 5000 - This object is not verbose - uses_identity_matrix_prior() == false WHAT THIS OBJECT REPRESENTS This object is a tool for performing the FrobMetric distance metric learning algorithm described in the following paper: A Scalable Dual Approach to Semidefinite Metric Learning By Chunhua Shen, Junae Kim, Lei Wang, in CVPR 2011 Therefore, this object is a tool that takes as input training triplets (anchor_vect, near, far) of vectors and attempts to learn a linear transformation T such that: length(T*anchor_vect-T*near) + 1 < length(T*anchor_vect - T*far) That is, you give a bunch of anchor_vect vectors and for each anchor_vect you specify some vectors which should be near to it and some that should be far form it. This object then tries to find a transformation matrix that makes the "near" vectors close to their anchors while the "far" vectors are farther away. THREAD SAFETY Note that this object contains a cached matrix object it uses to store intermediate results for normalization. This avoids needing to reallocate it every time this object performs normalization but also makes it non-thread safe. So make sure you don't share instances of this object between threads. !*/ public: typedef typename matrix_type::mem_manager_type mem_manager_type; typedef typename matrix_type::type scalar_type; typedef matrix_type result_type; vector_normalizer_frobmetric ( ); /*! ensures - this object is properly initialized !*/ bool uses_identity_matrix_prior ( ) const; /*! ensures - Normally this object will try and find a matrix transform() that minimizes sum(squared(transform())) but also fits the training data. However, if #uses_identity_matrix_prior() == true then it will instead try to find the transformation matrix that minimizes sum(squared(identity_matrix()-transform())). That is, it will try to find the matrix most similar to the identity matrix that best fits the training data. !*/ void set_uses_identity_matrix_prior ( bool use_prior ); /*! ensures - #uses_identity_matrix_prior() == use_prior !*/ void be_verbose( ); /*! ensures - This object will print status messages to standard out so the user can observe the progress of the train() routine. !*/ void be_quiet ( ); /*! ensures - this object will not print anything to standard out. !*/ void set_epsilon ( double eps ); /*! requires - eps > 0 ensures - #get_epsilon() == eps !*/ double get_epsilon ( ) const; /*! ensures - returns the error epsilon that determines when training should stop. Smaller values may result in a more accurate solution but take longer to execute. !*/ void set_c ( double C ); /*! requires - C > 0 ensures - #set_c() == C !*/ double get_c ( ) const; /*! ensures - returns the regularization parameter. It is the parameter that determines the trade-off between trying to fit the training data exactly or allowing more errors but hopefully improving the generalization of the resulting distance metric. Larger values encourage exact fitting while smaller values of C may encourage better generalization. !*/ void set_max_iterations ( unsigned long max_iterations ); /*! ensures - #get_max_iterations() == max_iterations !*/ unsigned long get_max_iterations ( ) const; /*! ensures - The train() routine uses an iterative numerical solver to find the best distance metric. This function returns the maximum allowable number of iterations it will use before terminating. Note that typically the solver terminates prior to the max iteration count limit due to the error dropping below get_epsilon(). !*/ void train ( const std::vector<frobmetric_training_sample<matrix_type> >& samples ); /*! requires - samples.size() != 0 - All matrices inside samples (i.e. anchors and elements of near_vects and far_vects) are column vectors with the same non-zero dimension. - All the vectors in samples contain finite values. - All elements of samples contain data, specifically, for all valid i: - samples[i].num_triples() != 0 ensures - learns a distance metric from the given training samples. After train finishes you can use this object's operator() to transform vectors according to the learned distance metric. In particular, we will have: - #transform() == The linear transformation learned by the FrobMetric learning procedure. - #in_vector_size() == samples[0].anchor_vect.size() - You can call (*this)(x) to transform a vector according to the learned distance metric. That is, it should generally be the case that: - length((*this)(anchor_vect) - (*this)(near)) + 1 < length((*this)(anchor_vect) - (*this)(far)) for the anchor_vect, near, and far vectors in the training data. - #transformed_means() == the mean of the input anchor_vect vectors after being transformed by #transform() !*/ long in_vector_size ( ) const; /*! ensures - returns the number of rows that input vectors are required to contain if they are to be normalized by this object. !*/ long out_vector_size ( ) const; /*! ensures - returns the number of rows in the normalized vectors that come out of this object. - The value returned is always in_vector_size(). So out_vector_size() is just provided to maintain interface consistency with other vector normalizer objects. That is, the transformations applied by this object do not change the dimensionality of the vectors. !*/ const matrix<scalar_type,0,1,mem_manager_type>& transformed_means ( ) const; /*! ensures - returns a column vector V such that: - V.size() == in_vector_size() - V is a vector such that subtracting it from transformed vectors results in them having an expected value of 0. Therefore, it is equal to transform() times the mean of the input anchor_vect vectors given to train(). !*/ const matrix<scalar_type,0,0,mem_manager_type>& transform ( ) const; /*! ensures - returns a copy of the transformation matrix we learned during the last call to train(). - The returned matrix is square and has in_vector_size() by in_vector_size() dimensions. !*/ const result_type& operator() ( const matrix_type& x ) const; /*! requires - in_vector_size() != 0 - in_vector_size() == x.size() - is_col_vector(x) == true ensures - returns a normalized version of x, call it Z, that has the following properties: - Z == The result of applying the linear transform we learned during train() to the input vector x. - Z == transform()*x-transformed_means() - is_col_vector(Z) == true - Z.size() == x.size() - The expected value of each element of Z is 0. !*/ }; // ---------------------------------------------------------------------------------------- template < typename matrix_type > void serialize ( const vector_normalizer_frobmetric<matrix_type>& item, std::ostream& out ); /*! provides serialization support !*/ // ---------------------------------------------------------------------------------------- template < typename matrix_type > void deserialize ( vector_normalizer_frobmetric<matrix_type>& item, std::istream& in ); /*! provides deserialization support !*/ // ---------------------------------------------------------------------------------------- } #endif // DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_