/** * @file MAPMultinomialGaussianPrior.cpp * @brief MAP estimation of multinomial with gaussian prior * @author Erik Rodner * @date 05/26/2008 */ #include #include #include "vislearning/optimization/mapestimation/MAPMultinomialGaussianPrior.h" using namespace OBJREC; using namespace std; // refactor-nice.pl: check this substitution // old: using namespace ice; using namespace NICE; MAPMultinomialGaussianPrior::MAPMultinomialGaussianPrior() { } MAPMultinomialGaussianPrior::~MAPMultinomialGaussianPrior() { } #undef DEBUG_OPTIMIZATION #undef DEBUG_ANALYZEOPTIMIZATION double MAPMultinomialGaussianPrior::objective ( // refactor-nice.pl: check this substitution // old: const Vector & theta, const NICE::Vector & theta, // refactor-nice.pl: check this substitution // old: const Vector & counts, const NICE::Vector & counts, // refactor-nice.pl: check this substitution // old: const Vector & mu, const NICE::Vector & mu, double sigmaq ) { // calculate - log double sum_likelihood = 0.0; for ( size_t i = 0 ; i < counts.size() ; i++ ) { double ti = (theta[i] < 10e-7) ? 10e-7 : theta[i]; sum_likelihood += counts[i] * log( ti ); } double sum_prior = 0.0; for ( size_t i = 0 ; i < counts.size() ; i++ ) { double d = (theta[i] - mu[i]); sum_prior -= d*d*0.5; } sum_prior /= sigmaq; #ifdef DEBUG_OPTIMIZATION fprintf (stderr, "log likelihood : %f\n", sum_likelihood ); fprintf (stderr, "log prior : %f\n", sum_prior ); #endif return sum_likelihood + sum_prior; } // refactor-nice.pl: check this substitution // old: void MAPMultinomialGaussianPrior::normalizeProb ( Vector & x ) void MAPMultinomialGaussianPrior::normalizeProb ( NICE::Vector & x ) { double sum = 0.0; for ( size_t i = 0 ; i < x.size() ; i++ ) sum += x[i]; for ( size_t i = 0 ; i < x.size() ; i++ ) x[i] /= sum; } double MAPMultinomialGaussianPrior::estimateLambdaNonLinear ( // refactor-nice.pl: check this substitution // old: const Vector & counts, const NICE::Vector & counts, // refactor-nice.pl: check this substitution // old: const Vector & mu, const NICE::Vector & mu, double sigmaq ) { // calculate lagrange multiplier const int maxIterations = 10000; const double eps = 10e-9; double count = 0; for ( size_t i = 0 ; i < counts.size() ; i++ ) count += counts[i]; double lambda = - count; int m = mu.size(); int iterations = 0; double diff = 0.0; do { // calculate f(\lambda) = 0.5 m \lambda \sigma^2 + \sum_l \sqrt{ g_l(\lambda) } - 0.5 double f = 0.5 * m * lambda * sigmaq - 0.5; double fabl = 0.5 * m * sigmaq; for ( size_t i = 0 ; i < mu.size() ; i++ ) { double phalf = 0.5 * (mu[i] + lambda * sigmaq); double undersqrt = phalf*phalf + sigmaq * counts[i]; assert ( undersqrt >= 0.0 ); // undersqrt = g_l(\lambda) double gabl = (mu[i] + lambda * sigmaq) * sigmaq; fabl -= gabl / sqrt(undersqrt); f += sqrt(undersqrt); } double lambdanew = lambda - f / fabl; diff = fabs(f / fabl); #ifdef DEBUG_OPTIMIZATION fprintf (stderr, "(%d) %f %f\n", iterations, lambdanew, diff ); #endif lambda = lambdanew; #ifdef DEBUG_ANALYZEOPTIMIZATION // refactor-nice.pl: check this substitution // old: Vector theta (m); NICE::Vector theta (m); // calculate theta estimation double sum = 0.0; for ( size_t i = 0 ; i < mu.size() ; i++ ) { double phalf = 0.5 * (mu[i] + lambda*sigmaq); theta[i] = phalf + sqrt( phalf*phalf + sigmaq * counts[i] ); assert ( theta[i] >= 0.0 ); sum += theta[i]; } fprintf (stderr, "OPT %f %d %f\n", sigmaq, iterations, objective ( theta, counts, mu, sigmaq ) ); #endif iterations++; } while ( (iterations < maxIterations) && (diff > eps) ); fprintf (stderr, "MAPMultinomialGaussianPrior: optimization finished (%d/%d iterations, %f last delta)\n", iterations, maxIterations, diff ); fprintf (stderr, "MAPMultinomialGaussianPrior: final lambda: %f\n", lambda ); return lambda; } double MAPMultinomialGaussianPrior::estimateLambda ( // refactor-nice.pl: check this substitution // old: const Vector & counts, const NICE::Vector & counts, // refactor-nice.pl: check this substitution // old: const Vector & mu, const NICE::Vector & mu, double sigmaq ) { // calculate lagrange multiplier const int maxIterations = 10000; //const double eps = 10e-5; const double eps = 10e-9; int m = mu.size(); double count = 0; for ( size_t i = 0 ; i < counts.size() ; i++ ) count += counts[i]; // using iterative formula, hopefully this converges double lambda = - count; double diff; int iterations = 0; do { // calculate evil sqrt sum double sqrsum = 0.0; for ( size_t i = 0 ; i < mu.size() ; i++ ) { double phalf = 0.5 * (mu[i] + lambda * sigmaq); double undersqrt = phalf*phalf + sigmaq * counts[i]; assert ( undersqrt >= 0.0 ); sqrsum += sqrt( undersqrt ); } double lambdanew = - (sqrsum - 0.5) * 2 / (sigmaq * m); diff = fabs(lambda-lambdanew); #ifdef DEBUG_OPTIMIZATION fprintf (stderr, "(%d) %f %f\n", iterations, lambdanew, diff ); #endif lambda = lambdanew; #ifdef DEBUG_ANALYZEOPTIMIZATION // refactor-nice.pl: check this substitution // old: Vector theta (m); NICE::Vector theta (m); // calculate theta estimation double sum = 0.0; for ( size_t i = 0 ; i < mu.size() ; i++ ) { double phalf = 0.5 * (mu[i] + lambda*sigmaq); theta[i] = phalf + sqrt( phalf*phalf + sigmaq * counts[i] ); assert ( theta[i] >= 0.0 ); sum += theta[i]; } fprintf (stderr, "OPT %f %d %f\n", sigmaq, iterations, objective ( theta, counts, mu, sigmaq ) ); #endif iterations++; } while ( (iterations < maxIterations) && (diff > eps) ); fprintf (stderr, "MAPMultinomialGaussianPrior: optimization finished (%d/%d iterations, %f last delta)\n", iterations, maxIterations, diff ); fprintf (stderr, "MAPMultinomialGaussianPrior: final lambda: %f\n", lambda ); return lambda; } void MAPMultinomialGaussianPrior::estimate ( // refactor-nice.pl: check this substitution // old: Vector & theta, NICE::Vector & theta, // refactor-nice.pl: check this substitution // old: const Vector & counts, const NICE::Vector & counts, // refactor-nice.pl: check this substitution // old: const Vector & mu, const NICE::Vector & mu, double sigmaq ) { theta = Vector(counts); normalizeProb ( theta ); #ifdef DEBUG_OPTIMIZATION fprintf (stderr, "objective (non informative) : %f\n", objective ( theta, counts, mu, sigmaq ) ); #endif double lambda = 1.0; if ( sigmaq < std::numeric_limits::epsilon() ) { fprintf (stderr, "MAPMultinomialGaussianPrior: skipping lambda optimization (sigmaq = 0.0)\n"); } else { //lambda = estimateLambdaNonLinear ( counts, mu, sigmaq ); lambda = estimateLambda ( counts, mu, sigmaq ); } // calculate theta estimation double sum = 0.0; for ( size_t i = 0 ; i < mu.size() ; i++ ) { double phalf = 0.5 * (mu[i] + lambda*sigmaq); theta[i] = phalf + sqrt( phalf*phalf + sigmaq * counts[i] ); assert ( theta[i] >= 0.0 ); sum += theta[i]; } #ifdef DEBUG_OPTIMIZATION fprintf (stderr, "objective (informative prior) : %f\n", objective ( theta, counts, mu, sigmaq ) ); fprintf (stderr, "Sum over theta = %f\n", sum ); #endif } // refactor-nice.pl: check this substitution // old: void MAPMultinomialGaussianPrior::estimate ( Vector & mapEstimate, void MAPMultinomialGaussianPrior::estimate ( NICE::Vector & mapEstimate, const VVector & likelihoodDistributionSamples, const VVector & priorDistributionSamples, double sigmaq ) { assert ( likelihoodDistributionSamples.size() == 1 ); // refactor-nice.pl: check this substitution // old: const Vector & mlEstimate = likelihoodDistributionSamples[0]; const NICE::Vector & mlEstimate = likelihoodDistributionSamples[0]; // refactor-nice.pl: check this substitution // old: Vector mu; NICE::Vector mu; for ( VVector::const_iterator i = priorDistributionSamples.begin(); i != priorDistributionSamples.end(); i++ ) { // refactor-nice.pl: check this substitution // old: const Vector & x = *i; const NICE::Vector & x = *i; if ( mu.size() == 0 ) mu = x; else mu = mu + x; } mu = mu * (1.0/priorDistributionSamples.size()); mapEstimate.resize(mlEstimate.size()); mapEstimate.set(0); estimate ( mapEstimate, mlEstimate, mu, sigmaq ); double sum = 0.0; for ( int i = 0 ; i < (int)mapEstimate.size() ; i++ ) sum += mapEstimate[i]; assert ( fabs(sum-1) < 10e-4 ); }