SHOGUN  4.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
GradientModelSelection.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * Written (W) 2013 Roman Votyakov
8  * Copyright (C) 2012 Jacob Walker
9  */
10 
11 
13 #ifdef USE_GPL_SHOGUN
14 
15 #ifdef HAVE_NLOPT
16 
20 #include <shogun/machine/Machine.h>
21 #include <nlopt.h>
22 
23 using namespace shogun;
24 
25 #ifndef DOXYGEN_SHOULD_SKIP_THIS
26 
28 struct nlopt_params
29 {
31  CMachineEvaluation* machine_eval;
32 
34  CParameterCombination* current_combination;
35 
37  CMap<TParameter*, CSGObject*>* parameter_dictionary;
38 
40  bool print_state;
41 };
42 
53 double nlopt_function(unsigned n, const double* x, double* grad, void* func_data)
54 {
55  nlopt_params* params=(nlopt_params*)func_data;
56 
57  CMachineEvaluation* machine_eval=params->machine_eval;
58  CParameterCombination* current_combination=params->current_combination;
59  CMap<TParameter*, CSGObject*>* parameter_dictionary=params->parameter_dictionary;
60  bool print_state=params->print_state;
61 
62  index_t offset=0;
63 
64  // set parameters from vector x
65  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
66  {
67  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
68 
69  TParameter* param=node->key;
70  CSGObject* parent=node->data;
71 
72  if (param->m_datatype.m_ctype==CT_VECTOR ||
73  param->m_datatype.m_ctype==CT_SGVECTOR ||
74  param->m_datatype.m_ctype==CT_SGMATRIX ||
75  param->m_datatype.m_ctype==CT_MATRIX)
76  {
77 
78  for (index_t j=0; j<param->m_datatype.get_num_elements(); j++)
79  {
80 
81  bool result=current_combination->set_parameter(param->m_name,
82  (float64_t)x[offset++], parent, j);
83  REQUIRE(result, "Parameter %s not found in combination tree\n",
84  param->m_name)
85  }
86  }
87  else
88  {
89  bool result=current_combination->set_parameter(param->m_name,
90  (float64_t)x[offset++], parent);
91  REQUIRE(result, "Parameter %s not found in combination tree\n",
92  param->m_name)
93  }
94  }
95 
96  // apply current combination to the machine
97  CMachine* machine=machine_eval->get_machine();
98  current_combination->apply_to_machine(machine);
99  if (print_state)
100  {
101  SG_SPRINT("Current combination\n");
102  current_combination->print_tree();
103  }
104  SG_UNREF(machine);
105 
106  // evaluate the machine
107  CEvaluationResult* evaluation_result=machine_eval->evaluate();
109  evaluation_result);
110  SG_UNREF(evaluation_result);
111 
112  if (print_state)
113  {
114  SG_SPRINT("Current result\n");
115  gradient_result->print_result();
116  }
117 
118  // get value of the function, gradients and parameter dictionary
119  SGVector<float64_t> value=gradient_result->get_value();
120  CMap<TParameter*, SGVector<float64_t> >* gradient=gradient_result->get_gradient();
121  CMap<TParameter*, CSGObject*>* gradient_dictionary=
122  gradient_result->get_paramter_dictionary();
123  SG_UNREF(gradient_result);
124 
125  offset=0;
126 
127  // set derivative for each parameter from parameter dictionary
128  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
129  {
130  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
131 
132  SGVector<float64_t> derivative;
133 
134  for (index_t j=0; j<gradient_dictionary->get_num_elements(); j++)
135  {
136  CMapNode<TParameter*, CSGObject*>* gradient_node=
137  gradient_dictionary->get_node_ptr(j);
138 
139  if (gradient_node->data==node->data &&
140  !strcmp(gradient_node->key->m_name, node->key->m_name))
141  {
142  derivative=gradient->get_element(gradient_node->key);
143  }
144  }
145 
146  REQUIRE(derivative.vlen, "Can't find gradient wrt %s parameter!\n",
147  node->key->m_name);
148 
149  memcpy(grad+offset, derivative.vector, sizeof(double)*derivative.vlen);
150 
151  offset+=derivative.vlen;
152  }
153 
154  SG_UNREF(gradient);
155  SG_UNREF(gradient_dictionary);
156 
157  return (double)(SGVector<float64_t>::sum(value));
158 }
159 
160 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
161 
162 CGradientModelSelection::CGradientModelSelection() : CModelSelection()
163 {
164  init();
165 }
166 
167 CGradientModelSelection::CGradientModelSelection(CMachineEvaluation* machine_eval,
168  CModelSelectionParameters* model_parameters)
169  : CModelSelection(machine_eval, model_parameters)
170 {
171  init();
172 }
173 
174 CGradientModelSelection::~CGradientModelSelection()
175 {
176 }
177 
178 void CGradientModelSelection::init()
179 {
180  m_max_evaluations=1000;
181  m_grad_tolerance=1e-6;
182 
183  SG_ADD(&m_grad_tolerance, "gradient_tolerance", "Gradient tolerance",
185  SG_ADD(&m_max_evaluations, "max_evaluations", "Maximum number of evaluations",
187 }
188 
189 CParameterCombination* CGradientModelSelection::select_model(bool print_state)
190 {
191  if (!m_model_parameters)
192  {
193  CMachine* machine=m_machine_eval->get_machine();
194 
195  CParameterCombination* current_combination=new CParameterCombination(machine);
196  SG_REF(current_combination);
197 
198  if (print_state)
199  {
200  SG_PRINT("Initial combination:\n");
201  current_combination->print_tree();
202  }
203 
204  // get total length of variables
205  index_t total_variables=current_combination->get_parameters_length();
206 
207  // build parameter->value map
210  current_combination->build_parameter_values_map(argument);
211 
212  // unroll current parameter combination into vector
213  SGVector<double> x(total_variables);
214  index_t offset=0;
215 
216  for (index_t i=0; i<argument->get_num_elements(); i++)
217  {
218  CMapNode<TParameter*, SGVector<float64_t> >* node=argument->get_node_ptr(i);
219  memcpy(x.vector+offset, node->data.vector, sizeof(double)*node->data.vlen);
220  offset+=node->data.vlen;
221  }
222 
223  SG_UNREF(argument);
224 
225  // create nlopt object and choose MMA (Method of Moving Asymptotes)
226  // optimization algorithm
227  nlopt_opt opt=nlopt_create(NLOPT_LD_MMA, total_variables);
228 
229  // currently we assume all parameters are positive
230  // (this is NOT true when inducing points and Full Matrix GaussianARDKernel are optimized)
231  // create lower bound vector (lb=-inf)
232  //SGVector<double> lower_bound(total_variables);
233  //lower_bound.set_const(1e-6);
234 
235  // create upper bound vector (ub=inf)
236  //SGVector<double> upper_bound(total_variables);
237  //upper_bound.set_const(HUGE_VAL);
238 
239  // set upper and lower bound
240  //nlopt_set_lower_bounds(opt, lower_bound.vector);
241  //nlopt_set_upper_bounds(opt, upper_bound.vector);
242 
243  // set maximum number of evaluations
244  nlopt_set_maxeval(opt, m_max_evaluations);
245 
246  // set absolute argument tolearance
247  nlopt_set_xtol_abs1(opt, m_grad_tolerance);
248  nlopt_set_ftol_abs(opt, m_grad_tolerance);
249 
250  // build parameter->sgobject map from current parameter combination
251  CMap<TParameter*, CSGObject*>* parameter_dictionary=
253  current_combination->build_parameter_parent_map(parameter_dictionary);
254 
255  // nlopt parameters
256  nlopt_params params;
257 
258  params.current_combination=current_combination;
259  params.machine_eval=m_machine_eval;
260  params.print_state=print_state;
261  params.parameter_dictionary=parameter_dictionary;
262 
263  // choose evaluation direction (minimize or maximize objective function)
264  if (m_machine_eval->get_evaluation_direction()==ED_MINIMIZE)
265  {
266  if (print_state)
267  SG_PRINT("Minimizing objective function:\n");
268 
269  nlopt_set_min_objective(opt, nlopt_function, &params);
270  }
271  else
272  {
273  if (print_state)
274  SG_PRINT("Maximizing objective function:\n");
275 
276  nlopt_set_max_objective(opt, nlopt_function, &params);
277  }
278 
279  // the minimum objective value, upon return
280  double minf;
281 
282  // optimize our function
283  nlopt_result result=nlopt_optimize(opt, x.vector, &minf);
284 
285  REQUIRE(result>0, "NLopt failed while optimizing objective function!\n");
286 
287  if (print_state)
288  {
289  SG_PRINT("Best combination:\n");
290  current_combination->print_tree();
291  }
292 
293  // clean up
294  nlopt_destroy(opt);
295  SG_UNREF(machine);
296  SG_UNREF(parameter_dictionary);
297 
298  return current_combination;
299  }
300  else
301  {
303  return NULL;
304  }
305 }
306 
307 #endif /* HAVE_NLOPT */
308 
309 #endif //USE_GPL_SHOGUN
int32_t index_t
Definition: common.h:62
bool set_parameter(const char *name, T value, CSGObject *parent, index_t index=-1)
T get_element(const K &key)
Definition: Map.h:171
parameter struct
#define REQUIRE(x,...)
Definition: SGIO.h:206
#define SG_NOTIMPLEMENTED
Definition: SGIO.h:139
int64_t get_num_elements()
Definition: DataType.cpp:464
void print_tree(int prefix_num=0) const
#define SG_REF(x)
Definition: SGObject.h:51
A generic learning machine interface.
Definition: Machine.h:143
Class to select parameters and their ranges for model selection. The structure is organized as a tree...
virtual void print_result()
CMapNode< K, T > * get_node_ptr(int32_t index)
Definition: Map.h:247
virtual CEvaluationResult * evaluate()=0
Abstract base class for model selection.
static CGradientResult * obtain_from_generic(CEvaluationResult *eval_result)
TSGDataType m_datatype
index_t vlen
Definition: SGVector.h:492
#define SG_PRINT(...)
Definition: SGIO.h:137
#define SG_SPRINT(...)
Definition: SGIO.h:180
Class SGObject is the base class of all shogun objects.
Definition: SGObject.h:112
CMachine * get_machine() const
virtual CMap< TParameter *, CSGObject * > * get_paramter_dictionary()
double float64_t
Definition: common.h:50
Abstract class that contains the result generated by the MachineEvaluation class. ...
Machine Evaluation is an abstract class that evaluates a machine according to some criterion...
virtual CMap< TParameter *, SGVector< float64_t > > * get_gradient()
static T sum(T *vec, int32_t len)
Return sum(vec)
Definition: SGVector.h:352
Class that holds ONE combination of parameters for a learning machine. The structure is organized as ...
virtual void build_parameter_parent_map(CMap< TParameter *, CSGObject * > *parent_map)
EContainerType m_ctype
Definition: DataType.h:71
#define SG_UNREF(x)
Definition: SGObject.h:52
all of classes and functions are contained in the shogun namespace
Definition: class_list.h:18
Container class that returns results from GradientEvaluation. It contains the function value as well ...
virtual SGVector< float64_t > get_value()
virtual uint32_t get_parameters_length()
virtual void build_parameter_values_map(CMap< TParameter *, SGVector< float64_t > > *values_map)
int32_t get_num_elements() const
Definition: Map.h:211
#define SG_ADD(...)
Definition: SGObject.h:81
void apply_to_machine(CMachine *machine) const
the class CMap, a map based on the hash-table. w: http://en.wikipedia.org/wiki/Hash_table ...
Definition: SGObject.h:36

SHOGUN Machine Learning Toolbox - Documentation