lda.h 5.11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/**
 * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
 * @author Andre Anjos <andre.anjos@idiap.ch>
 * @date Sat Jun 4 21:38:59 2011 +0200
 *
 * @brief Implements a multi-class Fisher/LDA linear machine Training using
 * Singular Value Decomposition (SVD). For more information on Linear Machines
 * and associated methods, please consult Bishop, Machine Learning and Pattern
 * Recognition chapter 4.
 *
 * Copyright (C) Idiap Research Institute, Martigny, Switzerland
 */

#ifndef BOB_LEARN_LINEAR_FISHER_H
#define BOB_LEARN_LINEAR_FISHER_H

#include <vector>
#include "machine.h"

namespace bob { namespace learn { namespace linear {

  /**
   * @brief Sets a linear machine to perform the Fisher/LDA decomposition.\n
   *
   * References:\n
   * 1. Bishop, Machine Learning and Pattern Recognition chapter 4.\n
   * 2. http://en.wikipedia.org/wiki/Linear_discriminant_analysis
   */
  class FisherLDATrainer {
    public: //api

      /**
       * @brief Initializes a new Fisher/LDA trainer. The training stage will
       * place the resulting fisher components in the linear machine and set it
       * up to extract the variable means automatically.
       *
       * @param strip_to_rank Specifies what is the final size of the prepared
       * LinearMachine. The default setting (<code>true</code>), makes the
       * trainer return only the K-1 eigen-values/vectors limiting the output
       * to the rank of Sw^1 Sb. If you set this value to <code>false</code>,
       * the it returns all eigen-values/vectors of Sw^1 Sb, including the ones
       * that are supposed to be zero.
       *
       * @param use_pinv If set (to <code>true</code>), then use the
       * pseudo-inverse to compute Sw^-1 and then a generalized eigen-value
       * decomposition instead of using the default (more stable) version of
       * the eigen-value decomposition, starting from Sb and Sw.
       */
      FisherLDATrainer(bool use_pinv = false, bool strip_to_rank = true);

      /**
       * @brief Destructor
       */
      virtual ~FisherLDATrainer();

      /**
       * @brief Copy constructor.
       */
      FisherLDATrainer(const FisherLDATrainer& other);

      /**
       * @brief Assignment operator
       */
      FisherLDATrainer& operator=(const FisherLDATrainer& other);

      /**
       * @brief Equal to
       */
      bool operator==(const FisherLDATrainer& other) const;

      /**
       * @brief Not equal to
       */
      bool operator!=(const FisherLDATrainer& other) const;

      /**
       * @brief Similar to
       */
      bool is_similar_to(const FisherLDATrainer& other,
          const double r_epsilon=1e-5, const double a_epsilon=1e-8) const;

      /**
       * @brief Gets the pseudo-inverse flag
       */
      bool getUsePseudoInverse () const { return m_use_pinv; }

      /**
       * @brief Sets the pseudo-inverse flag
       */
      void setUsePseudoInverse (bool v) { m_use_pinv = v; }

      /**
       * @brief Gets the strip-to-rank flag
       */
      bool getStripToRank () const { return m_strip_to_rank; }

      /**
       * @brief Sets the strip-to-rank flag
       */
      void setStripToRank (bool v) { m_strip_to_rank = v; }

      /**
       * @brief Trains the LinearMachine to perform Fisher/LDA discrimination.
       * The resulting machine will have the eigen-vectors of the
       * Sigma-1 * Sigma_b product, arranged by decreasing energy.
       *
       * Each input arrayset represents data from a given input class.
       *
       * Note we set only the N-1 eigen vectors in the linear machine since the
       * last eigen value should be zero anyway. You can compress the machine
       * output further using resize() if necessary.
       */
      void train(Machine& machine,
          const std::vector<blitz::Array<double,2> >& X) const;

      /**
       * @brief Trains the LinearMachine to perform Fisher/LDA discrimination.
       * The resulting machine will have the eigen-vectors of the
       * Sigma-1 * Sigma_b product, arranged by decreasing energy. You don't
       * need to sort the results. Also returns the eigen values of the
       * covariance matrix product so you can use that to choose which
       * components to keep.
       *
       * Each input arrayset represents data from a given input class.
       *
       * Note we set only the N-1 eigen vectors in the linear machine since the
       * last eigen value should be zero anyway. You can compress the machine
       * output further using resize() if necessary.
       */
      void train(Machine& machine, blitz::Array<double,1>& eigen_values,
          const std::vector<blitz::Array<double,2> >& X) const;

      /**
       * @brief Returns the expected size of the output given the data.
       *
       * This number could be either K-1 (K = number of classes) or the number
       * of columns (features) in X, depending on the seetting of
       * <code>strip_to_rank</code>.
       */
      size_t output_size(const std::vector<blitz::Array<double,2> >& X) const;

    private:
      bool m_use_pinv; ///< use the 'pinv' method for LDA
      bool m_strip_to_rank; ///< return rank or full matrix
  };

}}}

#endif /* BOB_LEARN_LINEAR_FISHER_H */