KernelExpansion.h
Go to the documentation of this file.
1//===========================================================================
2/*!
3 *
4 *
5 * \brief Affine linear kernel function expansion
6 *
7 * \par
8 * Affine linear kernel expansions resulting from Support
9 * vector machine (SVM) training and other kernel methods.
10 *
11 *
12 *
13 *
14 * \author T. Glasmachers
15 * \date 2007-2011
16 *
17 *
18 * \par Copyright 1995-2017 Shark Development Team
19 *
20 * <BR><HR>
21 * This file is part of Shark.
22 * <https://shark-ml.github.io/Shark/>
23 *
24 * Shark is free software: you can redistribute it and/or modify
25 * it under the terms of the GNU Lesser General Public License as published
26 * by the Free Software Foundation, either version 3 of the License, or
27 * (at your option) any later version.
28 *
29 * Shark is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public License
35 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
36 *
37 */
38//===========================================================================
39
40
41#ifndef SHARK_MODELS_KERNELEXPANSION_H
42#define SHARK_MODELS_KERNELEXPANSION_H
43
46#include <shark/Data/Dataset.h>
47#include <shark/Data/DataView.h>
48
49namespace shark {
50
51
52///
53/// \brief Linear model in a kernel feature space.
54///
55/// An affine linear kernel expansion is a model of the type
56/// \f[ x : \mathbb{R}^d \to \mathbb{R}^d \enspace , \enspace x \mapsto \sum_{n=1}^{\ell} \alpha_n k(x_n, x) + b \enspace ,\f]
57/// with parameters \f$ \alpha_n \in \mathbb{R}^{d} \f$ for all
58/// \f$ n \in \{1, \dots, \ell\} \f$ and \f$ b \in \mathbb{R}^d \f$.
59///
60/// One way in which the possibility for vector-valued input and output of dimension \f$ d \f$ may be interpreted
61/// is as allowing for a KernelExpansion model for \f$ d \f$ different classes/outputs in multi-class problems. Then,
62/// the i-th column of the matrix #m_alpha is the KernelExpansion for class/output i.
63///
64/// For a choice of kernel, see \ref kernels.
65///
66/// \tparam InputType Type of basis elements supplied to the kernel
67/// \ingroup models
68template<class InputType>
69class KernelExpansion : public AbstractModel<InputType, RealVector>
70{
71public:
76
77 // //////////////////////////////////////////////////////////
78 // //////////// CONSTRUCTORS /////////////////////
79 // //////////////////////////////////////////////////////////
80
82
86
87 KernelExpansion(KernelType* kernel, Data<InputType> const& basis,bool offset, std::size_t outputs = 1){
88 SHARK_ASSERT(kernel != NULL);
90 }
91
92 void setStructure(KernelType* kernel, Data<InputType> const& basis,bool offset, std::size_t outputs = 1){
93 SHARK_ASSERT(kernel != NULL);
95 if(offset)
96 m_b.resize(outputs);
97 m_basis = basis;
98 m_alpha.resize(basis.numberOfElements(), outputs);
99 m_alpha.clear();
100 }
101
102 /// \brief From INameable: return the class name.
103 std::string name() const
104 { return "KernelExpansion"; }
105
106 /// dimensionality of the output RealVector
108 return m_alpha.size2();
109 }
110
112 return Shape();
113 }
114
115 // //////////////////////////////////////////////////////////
116 // /////////// ALL THINGS KERNEL //////////////////////
117 // //////////////////////////////////////////////////////////
118
119 KernelType const* kernel() const{
120 return mep_kernel;
121 }
123 return mep_kernel;
124 }
128
129 // //////////////////////////////////////////////////////////
130 // /////// ALL THINGS ALPHA AND OFFSET ////////////////
131 // //////////////////////////////////////////////////////////
132
133 bool hasOffset() const{
134 return m_b.size() != 0;
135 }
136 RealMatrix& alpha(){
137 return m_alpha;
138 }
139 RealMatrix const& alpha() const{
140 return m_alpha;
141 }
142 double& alpha(std::size_t example, std::size_t cls){
143 return m_alpha(example, cls);
144 }
145 double const& alpha(std::size_t example, std::size_t cls) const{
146 return m_alpha(example, cls);
147 }
148 RealVector& offset(){
149 SHARK_RUNTIME_CHECK(hasOffset(), "[KernelExpansion::offset] invalid call for object without offset term");
150 return m_b;
151 }
152 RealVector const& offset() const{
153 SHARK_RUNTIME_CHECK(hasOffset(), "[KernelExpansion::offset] invalid call for object without offset term");
154 return m_b;
155 }
156 double& offset(std::size_t cls){
157 SHARK_RUNTIME_CHECK(hasOffset(), "[KernelExpansion::offset] invalid call for object without offset term");
158 return m_b(cls);
159 }
160 double const& offset(std::size_t cls) const{
161 SHARK_RUNTIME_CHECK(hasOffset(), "[KernelExpansion::offset] invalid call for object without offset term");
162 return m_b(cls);
163 }
164
165 // //////////////////////////////////////////////////////////
166 // //////// ALL THINGS UNDERLYING DATA ////////////////
167 // //////////////////////////////////////////////////////////
168
169
170 Data<InputType> const& basis() const {
171 return m_basis;
172 }
173
175 return m_basis;
176 }
177
178 /// The sparsify method removes non-support-vectors from
179 /// its set of basis vectors and the coefficient matrix.
180 void sparsify(){
181 std::size_t ic = m_basis.numberOfElements();
182 std::vector<std::size_t> svIndices;
183 for (std::size_t i=0; i != ic; ++i){
184 if (blas::norm_1(row(m_alpha, i)) > 0.0){
185 svIndices.push_back(i);
186 }
187 }
188 //project basis on the support vectors
189 m_basis = toDataset(subset(toView(m_basis),svIndices));
190
191 //reduce alpha to it's support vector variables
192 RealMatrix a(svIndices.size(), m_alpha.size2());
193 for (std::size_t i=0; i!= svIndices.size(); ++i){
194 noalias(row(a,i)) = row(m_alpha,svIndices[i]);
195 }
196 swap(m_alpha,a);
197 }
198
199 // //////////////////////////////////////////////////////////
200 // //////// ALL THINGS KERNEL PARAMETERS //////////////
201 // //////////////////////////////////////////////////////////
202
203 RealVector parameterVector() const{
204 if (hasOffset()){
205 return to_vector(m_alpha) | m_b;
206 }
207 else{
208 return to_vector(m_alpha);
209 }
210 }
211
212 void setParameterVector(RealVector const& newParameters){
213 SHARK_RUNTIME_CHECK(newParameters.size() == numberOfParameters(), "Invalid size of the parameter vector");
214 std::size_t numParams = m_alpha.size1() * m_alpha.size2();
215 noalias(to_vector(m_alpha)) = subrange(newParameters, 0, numParams);
216 if (hasOffset())
217 noalias(m_b) = subrange(newParameters, numParams, numParams + m_b.size());
218 }
219
220 std::size_t numberOfParameters() const{
221 if (hasOffset())
222 return m_alpha.size1() * m_alpha.size2() + m_b.size();
223 else
224 return m_alpha.size1() * m_alpha.size2();
225 }
226
227 // //////////////////////////////////////////////////////////
228 // //////// ALL THINGS EVALUATION //////////////
229 // //////////////////////////////////////////////////////////
230
231 boost::shared_ptr<State> createState()const{
232 return boost::shared_ptr<State>(new EmptyState());
233 }
234
235 using AbstractModel<InputType, RealVector>::eval;
236 void eval(BatchInputType const& patterns, BatchOutputType& output)const{
237 std::size_t numPatterns = batchSize(patterns);
238 SHARK_ASSERT(mep_kernel != NULL);
239
240 output.resize(numPatterns,m_alpha.size2());
241 if (hasOffset())
242 output = repeat(m_b,numPatterns);
243 else
244 output.clear();
245
246 std::size_t batchStart = 0;
247 for (std::size_t i=0; i != m_basis.numberOfBatches(); i++){
248 std::size_t batchEnd = batchStart+batchSize(m_basis.batch(i));
249 //evaluate kernels
250 //results in a matrix of the form where a column consists of the kernel evaluation of
251 //pattern i with respect to the batch of the basis,this gives a good memory alignment
252 //in the following matrix matrix product
253 RealMatrix kernelEvaluations = (*mep_kernel)(m_basis.batch(i),patterns);
254
255 //get the part of the alpha matrix which is suitable for this batch
256 auto batchAlpha = subrange(m_alpha,batchStart,batchEnd,0,m_alpha.size2());
257 noalias(output) += prod(trans(kernelEvaluations),batchAlpha);
258 batchStart = batchEnd;
259 }
260 }
261 void eval(BatchInputType const& patterns, BatchOutputType& outputs, State & state)const{
262 eval(patterns, outputs);
263 }
264
265 // //////////////////////////////////////////////////////////
266 // //////// ALL THINGS SERIALIZATION //////////////
267 // //////////////////////////////////////////////////////////
268
269 /// From ISerializable, reads a model from an archive
270 void read( InArchive & archive ){
271 SHARK_ASSERT(mep_kernel != NULL);
272
273 archive >> m_alpha;
274 archive >> m_b;
275 archive >> m_basis;
276 archive >> (*mep_kernel);
277 }
278
279 /// From ISerializable, writes a model to an archive
280 void write( OutArchive & archive ) const{
281 SHARK_ASSERT(mep_kernel != NULL);
282
283 archive << m_alpha;
284 archive << m_b;
285 archive << m_basis;
286 archive << const_cast<KernelType const&>(*mep_kernel);//prevent compilation warning
287 }
288
289// //////////////////////////////////////////////////////////
290// //////// MEMBERS //////////////
291// //////////////////////////////////////////////////////////
292
293protected:
294 /// kernel function used in the expansion
296
297 /// "support" basis vectors
299
300 /// kernel coefficients
301 RealMatrix m_alpha;
302
303 /// offset or bias term
304 RealVector m_b;
305};
306
307///
308/// \brief Linear classifier in a kernel feature space.
309///
310/// This model is a simple wrapper for the KernelExpansion calculating the arg max
311/// of the outputs of the model. This is the model used by kernel classifier models like SVMs.
312///
313/// \ingroup models
314template<class InputType>
331
332
333}
334#endif