SHOGUN  4.1.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 
12 
13 #ifdef HAVE_NLOPT
14 
18 #include <shogun/machine/Machine.h>
19 #include <nlopt.h>
20 
21 using namespace shogun;
22 
23 #ifndef DOXYGEN_SHOULD_SKIP_THIS
24 
26 struct nlopt_params
27 {
29  CMachineEvaluation* machine_eval;
30 
32  CParameterCombination* current_combination;
33 
35  CMap<TParameter*, CSGObject*>* parameter_dictionary;
36 
38  bool print_state;
39 };
40 
51 double nlopt_function(unsigned n, const double* x, double* grad, void* func_data)
52 {
53  nlopt_params* params=(nlopt_params*)func_data;
54 
55  CMachineEvaluation* machine_eval=params->machine_eval;
56  CParameterCombination* current_combination=params->current_combination;
57  CMap<TParameter*, CSGObject*>* parameter_dictionary=params->parameter_dictionary;
58  bool print_state=params->print_state;
59 
60  index_t offset=0;
61 
62  // set parameters from vector x
63  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
64  {
65  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
66 
67  TParameter* param=node->key;
68  CSGObject* parent=node->data;
69 
70  if (param->m_datatype.m_ctype==CT_VECTOR ||
71  param->m_datatype.m_ctype==CT_SGVECTOR ||
72  param->m_datatype.m_ctype==CT_SGMATRIX ||
73  param->m_datatype.m_ctype==CT_MATRIX)
74  {
75 
76  for (index_t j=0; j<param->m_datatype.get_num_elements(); j++)
77  {
78 
79  bool result=current_combination->set_parameter(param->m_name,
80  (float64_t)x[offset++], parent, j);
81  REQUIRE(result, "Parameter %s not found in combination tree\n",
82  param->m_name)
83  }
84  }
85  else
86  {
87  bool result=current_combination->set_parameter(param->m_name,
88  (float64_t)x[offset++], parent);
89  REQUIRE(result, "Parameter %s not found in combination tree\n",
90  param->m_name)
91  }
92  }
93 
94  // apply current combination to the machine
95  CMachine* machine=machine_eval->get_machine();
96  current_combination->apply_to_machine(machine);
97  if (print_state)
98  {
99  SG_SPRINT("Current combination\n");
100  current_combination->print_tree();
101  }
102  SG_UNREF(machine);
103 
104  // evaluate the machine
105  CEvaluationResult* evaluation_result=machine_eval->evaluate();
107  evaluation_result);
108  SG_UNREF(evaluation_result);
109 
110  if (print_state)
111  {
112  SG_SPRINT("Current result\n");
113  gradient_result->print_result();
114  }
115 
116  // get value of the function, gradients and parameter dictionary
117  SGVector<float64_t> value=gradient_result->get_value();
118  CMap<TParameter*, SGVector<float64_t> >* gradient=gradient_result->get_gradient();
119  CMap<TParameter*, CSGObject*>* gradient_dictionary=
120  gradient_result->get_paramter_dictionary();
121  SG_UNREF(gradient_result);
122 
123  offset=0;
124 
125  // set derivative for each parameter from parameter dictionary
126  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
127  {
128  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
129 
130  SGVector<float64_t> derivative;
131 
132  for (index_t j=0; j<gradient_dictionary->get_num_elements(); j++)
133  {
134  CMapNode<TParameter*, CSGObject*>* gradient_node=
135  gradient_dictionary->get_node_ptr(j);
136 
137  if (gradient_node->data==node->data &&
138  !strcmp(gradient_node->key->m_name, node->key->m_name))
139  {
140  derivative=gradient->get_element(gradient_node->key);
141  }
142  }
143 
144  REQUIRE(derivative.vlen, "Can't find gradient wrt %s parameter!\n",
145  node->key->m_name);
146 
147  memcpy(grad+offset, derivative.vector, sizeof(double)*derivative.vlen);
148 
149  offset+=derivative.vlen;
150  }
151 
152  SG_UNREF(gradient);
153  SG_UNREF(gradient_dictionary);
154 
155  return (double)(SGVector<float64_t>::sum(value));
156 }
157 
158 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
159 
161 {
162  init();
163 }
164 
166  CModelSelectionParameters* model_parameters)
167  : CModelSelection(machine_eval, model_parameters)
168 {
169  init();
170 }
171 
173 {
174 }
175 
176 void CGradientModelSelection::init()
177 {
178  m_max_evaluations=1000;
179  m_grad_tolerance=1e-6;
180 
181  SG_ADD(&m_grad_tolerance, "gradient_tolerance", "Gradient tolerance",
183  SG_ADD(&m_max_evaluations, "max_evaluations", "Maximum number of evaluations",
185 }
186 
188 {
189  if (!m_model_parameters)
190  {
191  CMachine* machine=m_machine_eval->get_machine();
192 
193  CParameterCombination* current_combination=new CParameterCombination(machine);
194  SG_REF(current_combination);
195 
196  if (print_state)
197  {
198  SG_PRINT("Initial combination:\n");
199  current_combination->print_tree();
200  }
201 
202  // get total length of variables
203  index_t total_variables=current_combination->get_parameters_length();
204 
205  // build parameter->value map
208  current_combination->build_parameter_values_map(argument);
209 
210  // unroll current parameter combination into vector
211  SGVector<double> x(total_variables);
212  index_t offset=0;
213 
214  for (index_t i=0; i<argument->get_num_elements(); i++)
215  {
216  CMapNode<TParameter*, SGVector<float64_t> >* node=argument->get_node_ptr(i);
217  memcpy(x.vector+offset, node->data.vector, sizeof(double)*node->data.vlen);
218  offset+=node->data.vlen;
219  }
220 
221  SG_UNREF(argument);
222 
223  // create nlopt object and choose MMA (Method of Moving Asymptotes)
224  // optimization algorithm
225  nlopt_opt opt=nlopt_create(NLOPT_LD_MMA, total_variables);
226 
227  // currently we assume all parameters are positive
228  // (this is NOT true when inducing points and Full Matrix GaussianARDKernel are optimized)
229  // create lower bound vector (lb=-inf)
230  SGVector<double> lower_bound(total_variables);
231  lower_bound.set_const(1e-6);
232 
233  // create upper bound vector (ub=inf)
234  SGVector<double> upper_bound(total_variables);
235  upper_bound.set_const(HUGE_VAL);
236 
237  // set upper and lower bound
238  nlopt_set_lower_bounds(opt, lower_bound.vector);
239  nlopt_set_upper_bounds(opt, upper_bound.vector);
240 
241  // set maximum number of evaluations
242  nlopt_set_maxeval(opt, m_max_evaluations);
243 
244  // set absolute argument tolearance
245  nlopt_set_xtol_abs1(opt, m_grad_tolerance);
246  nlopt_set_ftol_abs(opt, m_grad_tolerance);
247 
248  // build parameter->sgobject map from current parameter combination
249  CMap<TParameter*, CSGObject*>* parameter_dictionary=
251  current_combination->build_parameter_parent_map(parameter_dictionary);
252 
253  // nlopt parameters
254  nlopt_params params;
255 
256  params.current_combination=current_combination;
257  params.machine_eval=m_machine_eval;
258  params.print_state=print_state;
259  params.parameter_dictionary=parameter_dictionary;
260 
261  // choose evaluation direction (minimize or maximize objective function)
263  {
264  if (print_state)
265  SG_PRINT("Minimizing objective function:\n");
266 
267  nlopt_set_min_objective(opt, nlopt_function, &params);
268  }
269  else
270  {
271  if (print_state)
272  SG_PRINT("Maximizing objective function:\n");
273 
274  nlopt_set_max_objective(opt, nlopt_function, &params);
275  }
276 
277  // the minimum objective value, upon return
278  double minf;
279 
280  // optimize our function
281  nlopt_result result=nlopt_optimize(opt, x.vector, &minf);
282 
283  REQUIRE(result>0, "NLopt failed while optimizing objective function!\n");
284 
285  if (print_state)
286  {
287  SG_PRINT("Best combination:\n");
288  current_combination->print_tree();
289  }
290 
291  // clean up
292  nlopt_destroy(opt);
293  SG_UNREF(machine);
294  SG_UNREF(parameter_dictionary);
295 
296  return current_combination;
297  }
298  else
299  {
301  return NULL;
302  }
303 }
304 
305 #endif /* HAVE_NLOPT */
virtual CParameterCombination * select_model(bool print_state=false)
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.
CModelSelectionParameters * m_model_parameters
static CGradientResult * obtain_from_generic(CEvaluationResult *eval_result)
CMachineEvaluation * m_machine_eval
TSGDataType m_datatype
index_t vlen
Definition: SGVector.h:494
#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:354
Class that holds ONE combination of parameters for a learning machine. The structure is organized as ...
EEvaluationDirection get_evaluation_direction()
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
void set_const(T const_elem)
Definition: SGVector.cpp:152
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