255 lines
7.8 KiB
C++
255 lines
7.8 KiB
C++
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_ASSIGNMENT_FuNCTION_Hh_
|
|
#define DLIB_ASSIGNMENT_FuNCTION_Hh_
|
|
|
|
#include "assignment_function_abstract.h"
|
|
#include "../matrix.h"
|
|
#include <vector>
|
|
#include "../optimization/max_cost_assignment.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename feature_extractor
|
|
>
|
|
class assignment_function
|
|
{
|
|
public:
|
|
|
|
typedef typename feature_extractor::lhs_element lhs_element;
|
|
typedef typename feature_extractor::rhs_element rhs_element;
|
|
|
|
|
|
typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;
|
|
|
|
typedef std::vector<long> label_type;
|
|
typedef label_type result_type;
|
|
|
|
assignment_function()
|
|
{
|
|
weights.set_size(fe.num_features());
|
|
weights = 0;
|
|
bias = 0;
|
|
force_assignment = false;
|
|
}
|
|
|
|
explicit assignment_function(
|
|
const matrix<double,0,1>& weights_,
|
|
double bias_
|
|
) :
|
|
weights(weights_),
|
|
bias(bias_),
|
|
force_assignment(false)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(fe.num_features() == static_cast<unsigned long>(weights_.size()),
|
|
"\t assignment_function::assignment_function(weights_)"
|
|
<< "\n\t These sizes should match"
|
|
<< "\n\t fe.num_features(): " << fe.num_features()
|
|
<< "\n\t weights_.size(): " << weights_.size()
|
|
<< "\n\t this: " << this
|
|
);
|
|
|
|
}
|
|
|
|
assignment_function(
|
|
const matrix<double,0,1>& weights_,
|
|
double bias_,
|
|
const feature_extractor& fe_
|
|
) :
|
|
fe(fe_),
|
|
weights(weights_),
|
|
bias(bias_),
|
|
force_assignment(false)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(fe_.num_features() == static_cast<unsigned long>(weights_.size()),
|
|
"\t assignment_function::assignment_function(weights_,fe_)"
|
|
<< "\n\t These sizes should match"
|
|
<< "\n\t fe_.num_features(): " << fe_.num_features()
|
|
<< "\n\t weights_.size(): " << weights_.size()
|
|
<< "\n\t this: " << this
|
|
);
|
|
}
|
|
|
|
assignment_function(
|
|
const matrix<double,0,1>& weights_,
|
|
double bias_,
|
|
const feature_extractor& fe_,
|
|
bool force_assignment_
|
|
) :
|
|
fe(fe_),
|
|
weights(weights_),
|
|
bias(bias_),
|
|
force_assignment(force_assignment_)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(fe_.num_features() == static_cast<unsigned long>(weights_.size()),
|
|
"\t assignment_function::assignment_function(weights_,fe_,force_assignment_)"
|
|
<< "\n\t These sizes should match"
|
|
<< "\n\t fe_.num_features(): " << fe_.num_features()
|
|
<< "\n\t weights_.size(): " << weights_.size()
|
|
<< "\n\t this: " << this
|
|
);
|
|
}
|
|
|
|
const feature_extractor& get_feature_extractor (
|
|
) const { return fe; }
|
|
|
|
const matrix<double,0,1>& get_weights (
|
|
) const { return weights; }
|
|
|
|
double get_bias (
|
|
) const { return bias; }
|
|
|
|
bool forces_assignment (
|
|
) const { return force_assignment; }
|
|
|
|
void predict_assignments (
|
|
const std::vector<lhs_element>& lhs,
|
|
const std::vector<rhs_element>& rhs,
|
|
result_type& assignment
|
|
) const
|
|
{
|
|
assignment.clear();
|
|
|
|
matrix<double> cost;
|
|
unsigned long size;
|
|
if (force_assignment)
|
|
{
|
|
size = std::max(lhs.size(), rhs.size());
|
|
}
|
|
else
|
|
{
|
|
size = rhs.size() + lhs.size();
|
|
}
|
|
cost.set_size(size, size);
|
|
|
|
typedef typename feature_extractor::feature_vector_type feature_vector_type;
|
|
feature_vector_type feats;
|
|
|
|
// now fill out the cost assignment matrix
|
|
for (long r = 0; r < cost.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < cost.nc(); ++c)
|
|
{
|
|
if (r < (long)lhs.size() && c < (long)rhs.size())
|
|
{
|
|
fe.get_features(lhs[r], rhs[c], feats);
|
|
cost(r,c) = dot(weights, feats) + bias;
|
|
}
|
|
else
|
|
{
|
|
cost(r,c) = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (cost.size() != 0)
|
|
{
|
|
// max_cost_assignment() only works with integer matrices, so convert from
|
|
// double to integer.
|
|
const double scale = (std::numeric_limits<dlib::int64>::max()/1000)/max(abs(cost));
|
|
matrix<dlib::int64> int_cost = matrix_cast<dlib::int64>(round(cost*scale));
|
|
assignment = max_cost_assignment(int_cost);
|
|
assignment.resize(lhs.size());
|
|
}
|
|
|
|
// adjust assignment so that non-assignments have a value of -1
|
|
for (unsigned long i = 0; i < assignment.size(); ++i)
|
|
{
|
|
if (assignment[i] >= (long)rhs.size())
|
|
assignment[i] = -1;
|
|
}
|
|
}
|
|
|
|
void predict_assignments (
|
|
const sample_type& item,
|
|
result_type& assignment
|
|
) const
|
|
{
|
|
predict_assignments(item.first, item.second, assignment);
|
|
}
|
|
|
|
result_type operator()(
|
|
const std::vector<lhs_element>& lhs,
|
|
const std::vector<rhs_element>& rhs
|
|
) const
|
|
{
|
|
result_type temp;
|
|
predict_assignments(lhs,rhs,temp);
|
|
return temp;
|
|
}
|
|
|
|
result_type operator() (
|
|
const sample_type& item
|
|
) const
|
|
{
|
|
return (*this)(item.first, item.second);
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
feature_extractor fe;
|
|
matrix<double,0,1> weights;
|
|
double bias;
|
|
bool force_assignment;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename feature_extractor
|
|
>
|
|
void serialize (
|
|
const assignment_function<feature_extractor>& item,
|
|
std::ostream& out
|
|
)
|
|
{
|
|
int version = 2;
|
|
serialize(version, out);
|
|
serialize(item.get_feature_extractor(), out);
|
|
serialize(item.get_weights(), out);
|
|
serialize(item.get_bias(), out);
|
|
serialize(item.forces_assignment(), out);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename feature_extractor
|
|
>
|
|
void deserialize (
|
|
assignment_function<feature_extractor>& item,
|
|
std::istream& in
|
|
)
|
|
{
|
|
feature_extractor fe;
|
|
matrix<double,0,1> weights;
|
|
double bias;
|
|
bool force_assignment;
|
|
int version = 0;
|
|
deserialize(version, in);
|
|
if (version != 2)
|
|
throw serialization_error("Unexpected version found while deserializing dlib::assignment_function.");
|
|
|
|
deserialize(fe, in);
|
|
deserialize(weights, in);
|
|
deserialize(bias, in);
|
|
deserialize(force_assignment, in);
|
|
|
|
item = assignment_function<feature_extractor>(weights, bias, fe, force_assignment);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_ASSIGNMENT_FuNCTION_Hh_
|
|
|