MissingFeaturesKernelExpansion.h
Go to the documentation of this file.
1 //===========================================================================
2 /*!
3  *
4  *
5  * \brief A kernel expansion with support of missing features
6  *
7  *
8  *
9  * \author B. Li
10  * \date 2012
11  *
12  *
13  * \par Copyright 1995-2017 Shark Development Team
14  *
15  * <BR><HR>
16  * This file is part of Shark.
17  * <http://shark-ml.org/>
18  *
19  * Shark is free software: you can redistribute it and/or modify
20  * it under the terms of the GNU Lesser General Public License as published
21  * by the Free Software Foundation, either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * Shark is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU Lesser General Public License for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public License
30  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
33 //===========================================================================
34 #include <shark/Data/Dataset.h>
35 #include <shark/Data/DataView.h>
38 
39 namespace shark {
40 
41 /// Kernel expansion with missing features support
42 template<class InputType>
44 {
45 private:
47 public:
48  typedef typename Base::KernelType KernelType;
51  /// Constructors from the base class
52  ///@{
54 
55 
57  : Base(kernel)
58  {}
59 
61  : Base(kernel, basis, offset, 1u)
62  {}
63  ///@}
64 
65  /// \brief From INameable: return the class name.
66  std::string name() const
67  { return "MissingFeaturesKernelExpansion"; }
68 
69  boost::shared_ptr<State> createState()const{
70  return boost::shared_ptr<State>(new EmptyState());
71  }
72 
73  /// Override eval(...) in the base class
74  virtual void eval(BatchInputType const& patterns, BatchOutputType& outputs)const{
76  SIZE_CHECK(Base::m_alpha.size1() > 0u);
77 
78  //Todo: i am too lazy to us iterated loops in this function.
79  //so i am using a DataView to have O(1) random access lookup. but this is not needed!
80  DataView<Data<InputType> const > indexedBasis(Base::m_basis);
81 
82  ensure_size(outputs,batchSize(patterns),Base::outputShape().numElements());
83  if (Base::hasOffset())
84  noalias(outputs) = repeat(Base::m_b,batchSize(patterns));
85  else
86  outputs.clear();
87 
88  for(std::size_t p = 0; p != batchSize(patterns); ++p){
89 
90 
91  // Calculate scaling coefficient for the 'pattern'
92  const double patternNorm = computeNorm(column(Base::m_alpha, 0), m_scalingCoefficients, row(patterns,p));
93  const double patternSc = patternNorm / m_classifierNorm;
94 
95  // Do normal classification except that we use kernel which supports inputs with Missing features
96  //TODO: evaluate k for all i and replace the += with a matrix-vector operation.
97  //better: do this for all p and i and go matrix-matrix-multiplication
98  for (std::size_t i = 0; i != indexedBasis.size(); ++i){
99  const double k = evalSkipMissingFeatures(
101  indexedBasis[i],
102  row(patterns,p)) / m_scalingCoefficients[i] / patternSc;
103  noalias(row(outputs,p)) += k * row(Base::m_alpha, i);
104 
105  }
106  }
107  }
108  void eval(BatchInputType const& patterns, BatchOutputType& outputs, State & state)const{
109  eval(patterns, outputs);
110  }
111 
112  /// Calculate norm of classifier, i.e., ||w||
113  ///
114  /// formula:
115  /// \f$ \sum_{i,j=1}^{n}\alpha_i\frac{y_i}{s_i}K\left(x_i,x_j)\right)\frac{y_j}{s_j}\alpha_j \f$
116  /// where \f$ s_i \f$ is scaling coefficient, and \f$ K \f$ is kernel function,
117  /// \f$ K\left(x_i,x_j)\right) \f$ is taken only over features that are valid for both \f$ x_i \f$ and \f$ x_j \f$
118  template<class InputTypeT>
119  double computeNorm(
120  const RealVector& alpha,
121  const RealVector& scalingCoefficient,
122  InputTypeT const& missingness
123  ) const{
125  SIZE_CHECK(alpha.size() == scalingCoefficient.size());
126  SIZE_CHECK(Base::m_basis.numberOfElements() == alpha.size());
127 
128  // Calculate ||w||^2
129  double norm_sqr = 0.0;
130 
131  //Todo: i am too lazy to use iterated loops in this function.
132  //so i am using a DataView to have O(1) random access lookup. but this is not needed!
133  DataView<Data<InputType> const > indexedBasis(Base::m_basis);
134 
135  for (std::size_t i = 0; i < alpha.size(); ++i){
136  for (std::size_t j = 0; j < alpha.size(); ++j){
137  const double evalResult = evalSkipMissingFeatures(
139  indexedBasis[i],
140  indexedBasis[j],
141  missingness);
142  // Note that in Shark solver, we do axis flip by substituting \alpha with y \times \alpha
143  norm_sqr += evalResult * alpha(i) * alpha(j) / scalingCoefficient(i) / scalingCoefficient(j);
144  }
145  }
146 
147  // Return ||w||
148  return std::sqrt(norm_sqr);
149  }
150 
151  double computeNorm(
152  const RealVector& alpha,
153  const RealVector& scalingCoefficient
154  ) const{
156  SIZE_CHECK(alpha.size() == scalingCoefficient.size());
157  SIZE_CHECK(Base::m_basis.numberOfElements() == alpha.size());
158 
159  //Todo: i am too lazy to us iterated loops in this function.
160  //so i am using a DataView to have O(1) random access lookup. but this is not needed!
161  DataView<Data<InputType> const > indexedBasis(Base::m_basis);
162 
163  // Calculate ||w||^2
164  double norm_sqr = 0.0;
165 
166  for (std::size_t i = 0; i < alpha.size(); ++i){
167  for (std::size_t j = 0; j < alpha.size(); ++j){
168  const double evalResult = evalSkipMissingFeatures(
170  indexedBasis[i],
171  indexedBasis[j]);
172  // Note that in Shark solver, we do axis flip by substituting \alpha with y \times \alpha
173  norm_sqr += evalResult * alpha(i) * alpha(j) / scalingCoefficient(i) / scalingCoefficient(j);
174  }
175  }
176 
177  // Return ||w||
178  return std::sqrt(norm_sqr);
179  }
180 
181  void setScalingCoefficients(const RealVector& scalingCoefficients)
182  {
183 #if DEBUG
184  for(double v: scalingCoefficients)
185  {
186  SHARK_ASSERT(v > 0.0);
187  }
188 #endif
189  m_scalingCoefficients = scalingCoefficients;
190  }
191 
192  void setClassifierNorm(double classifierNorm)
193  {
194  SHARK_ASSERT(classifierNorm > 0.0);
195  m_classifierNorm = classifierNorm;
196  }
197 
198 protected:
199  /// The scaling coefficients
201 
202  /// The norm of classifier(w)
204 };
205 
206 } // namespace shark {