SHOGUN  5.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
GradientModelSelection.cpp
Go to the documentation of this file.
1 /* * This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation; either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * Written (W) 2016 Wu Lin
7  * Written (W) 2013 Roman Votyakov
8  * Copyright (C) 2012 Jacob Walker
9  */
10 
12 
16 #include <shogun/machine/Machine.h>
20 
21 
22 
23 using namespace shogun;
24 
25 namespace shogun
26 {
27 #ifndef DOXYGEN_SHOULD_SKIP_THIS
28 
29 class GradientModelSelectionCostFunction: public FirstOrderCostFunction
30 {
31 public:
32  GradientModelSelectionCostFunction():FirstOrderCostFunction() { init(); }
33  virtual ~GradientModelSelectionCostFunction() { SG_UNREF(m_obj); }
34  void set_target(CGradientModelSelection *obj)
35  {
36  REQUIRE(obj,"Obj must set\n");
37  if(m_obj!=obj)
38  {
39  SG_REF(obj);
40  SG_UNREF(m_obj);
41  m_obj=obj;
42  }
43  }
44  void unset_target(bool is_unref)
45  {
46  if(is_unref)
47  {
48  SG_UNREF(m_obj);
49  }
50  m_obj=NULL;
51  }
52 
53  virtual float64_t get_cost()
54  {
55  REQUIRE(m_obj,"Object not set\n");
56  return m_obj->get_cost(m_val, m_grad, m_func_data);
57  }
58 
59  virtual SGVector<float64_t> obtain_variable_reference()
60  {
61  REQUIRE(m_obj,"Object not set\n");
62  return m_val;
63  }
64  virtual SGVector<float64_t> get_gradient()
65  {
66  REQUIRE(m_obj,"Object not set\n");
67  return m_grad;
68  }
69 
70  virtual const char* get_name() const { return "GradientModelSelectionCostFunction"; }
71 
72  virtual void set_func_data(void *func_data)
73  {
74  REQUIRE(func_data != NULL, "func_data must set\n");
75  m_func_data = func_data;
76  }
77 
78  virtual void set_variables(SGVector<float64_t> val)
79  {
80  m_val = SGVector<float64_t>(val.vlen);
81  m_grad = SGVector<float64_t>(val.vlen);
82  std::copy(val.vector,val.vector+val.vlen,m_val.vector);
83  }
84 private:
85  void init()
86  {
87  m_obj=NULL;
88  SG_ADD((CSGObject **)&m_obj, "GradientModelSelectionCostFunction__m_obj",
89  "obj in GradientModelSelectionCostFunction", MS_NOT_AVAILABLE);
90  m_func_data = NULL;
91  m_val = SGVector<float64_t>();
92  SG_ADD(m_val, "GradientModelSelectionCostFunction__m_val",
93  "val in GradientModelSelectionCostFunction", MS_NOT_AVAILABLE);
94  m_grad = SGVector<float64_t>();
95  SG_ADD(m_grad, "GradientModelSelectionCostFunction__m_grad",
96  "grad in GradientModelSelectionCostFunction", MS_NOT_AVAILABLE);
97  }
98 
100  void* m_func_data;
101  SGVector<float64_t> m_val;
102  SGVector<float64_t> m_grad;
103 };
104 
105 
107 struct nlopt_params
108 {
110  CParameterCombination* current_combination;
111 
113  CMap<TParameter*, CSGObject*>* parameter_dictionary;
114 
116  bool print_state;
117 };
118 
120 {
121  REQUIRE(func_data!=NULL, "func_data must set\n");
122  REQUIRE(model_vars.vlen==model_grads.vlen, "length of variable (%d) and gradient (%d) must equal\n",
123  model_vars.vlen, model_grads.vlen);
124 
125  nlopt_params* params=(nlopt_params*)func_data;
126 
127  CParameterCombination* current_combination=params->current_combination;
128  CMap<TParameter*, CSGObject*>* parameter_dictionary=params->parameter_dictionary;
129  bool print_state=params->print_state;
130 
131  index_t offset=0;
132 
133  // set parameters from vector model_vars
134  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
135  {
136  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
137 
138  TParameter* param=node->key;
139  CSGObject* parent=node->data;
140 
141  if (param->m_datatype.m_ctype==CT_VECTOR ||
142  param->m_datatype.m_ctype==CT_SGVECTOR ||
143  param->m_datatype.m_ctype==CT_SGMATRIX ||
144  param->m_datatype.m_ctype==CT_MATRIX)
145  {
146 
147  for (index_t j=0; j<param->m_datatype.get_num_elements(); j++)
148  {
149 
150  bool result=current_combination->set_parameter(param->m_name,
151  model_vars[offset++], parent, j);
152  REQUIRE(result, "Parameter %s not found in combination tree\n",
153  param->m_name)
154  }
155  }
156  else
157  {
158  bool result=current_combination->set_parameter(param->m_name,
159  model_vars[offset++], parent);
160  REQUIRE(result, "Parameter %s not found in combination tree\n",
161  param->m_name)
162  }
163  }
164 
165  // apply current combination to the machine
166  CMachine* machine=m_machine_eval->get_machine();
167  current_combination->apply_to_machine(machine);
168  if (print_state)
169  {
170  SG_SPRINT("Current combination\n");
171  current_combination->print_tree();
172  }
173  SG_UNREF(machine);
174 
175  // evaluate the machine
176  CEvaluationResult* evaluation_result=m_machine_eval->evaluate();
178  evaluation_result);
179  SG_UNREF(evaluation_result);
180 
181  if (print_state)
182  {
183  SG_SPRINT("Current result\n");
184  gradient_result->print_result();
185  }
186 
187  // get value of the function, gradients and parameter dictionary
188  SGVector<float64_t> value=gradient_result->get_value();
189 
190  float64_t cost = SGVector<float64_t>::sum(value);
191 
192  if (CMath::is_nan(cost) || CMath::is_infinity(cost))
193  {
195  return cost;
196  else
197  return -cost;
198  }
199 
200  CMap<TParameter*, SGVector<float64_t> >* gradient=gradient_result->get_gradient();
201  CMap<TParameter*, CSGObject*>* gradient_dictionary=
202  gradient_result->get_paramter_dictionary();
203  SG_UNREF(gradient_result);
204 
205  offset=0;
206 
207  // set derivative for each parameter from parameter dictionary
208  for (index_t i=0; i<parameter_dictionary->get_num_elements(); i++)
209  {
210  CMapNode<TParameter*, CSGObject*>* node=parameter_dictionary->get_node_ptr(i);
211 
212  SGVector<float64_t> derivative;
213 
214  for (index_t j=0; j<gradient_dictionary->get_num_elements(); j++)
215  {
216  CMapNode<TParameter*, CSGObject*>* gradient_node=
217  gradient_dictionary->get_node_ptr(j);
218 
219  if (gradient_node->data==node->data &&
220  !strcmp(gradient_node->key->m_name, node->key->m_name))
221  {
222  derivative=gradient->get_element(gradient_node->key);
223  }
224  }
225 
226  REQUIRE(derivative.vlen, "Can't find gradient wrt %s parameter!\n",
227  node->key->m_name);
228 
229  memcpy(model_grads.vector+offset, derivative.vector, sizeof(float64_t)*derivative.vlen);
230 
231  offset+=derivative.vlen;
232  }
233 
234  SG_UNREF(gradient);
235  SG_UNREF(gradient_dictionary);
236 
238  {
239  return cost;
240  }
241  else
242  {
243  model_grads.scale(-1);
244  return -cost;
245  }
246 
247 }
248 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
249 
251 {
252  REQUIRE(minimizer!=NULL, "Minimizer must set\n");
253  SG_REF(minimizer);
255  m_mode_minimizer=minimizer;
256 }
257 
258 
260 {
261  init();
262 }
263 
265  CModelSelectionParameters* model_parameters)
266  : CModelSelection(machine_eval, model_parameters)
267 {
268  init();
269 }
270 
272 {
274 }
275 
276 void CGradientModelSelection::init()
277 {
280 
282  "mode_minimizer", "Minimizer used in mode selection", MS_NOT_AVAILABLE);
283 
284 }
285 
287 {
288  if (!m_model_parameters)
289  {
290  CMachine* machine=m_machine_eval->get_machine();
291 
292  CParameterCombination* current_combination=new CParameterCombination(machine);
293  SG_REF(current_combination);
294 
295  if (print_state)
296  {
297  SG_PRINT("Initial combination:\n");
298  current_combination->print_tree();
299  }
300 
301  // get total length of variables
302  index_t total_variables=current_combination->get_parameters_length();
303 
304  // build parameter->value map
307  current_combination->build_parameter_values_map(argument);
308 
309  // unroll current parameter combination into vector
310  SGVector<float64_t> model_vars = SGVector<float64_t>(total_variables);
311 
312  index_t offset=0;
313 
314  for (index_t i=0; i<argument->get_num_elements(); i++)
315  {
316  CMapNode<TParameter*, SGVector<float64_t> >* node=argument->get_node_ptr(i);
317  memcpy(model_vars.vector+offset, node->data.vector, sizeof(float64_t)*node->data.vlen);
318  offset+=node->data.vlen;
319  }
320 
321  SG_UNREF(argument);
322 
323  // build parameter->sgobject map from current parameter combination
324  CMap<TParameter*, CSGObject*>* parameter_dictionary=
326  current_combination->build_parameter_parent_map(parameter_dictionary);
327 
328  //data for computing the gradient
329  nlopt_params params;
330 
331  params.current_combination=current_combination;
332  params.print_state=print_state;
333  params.parameter_dictionary=parameter_dictionary;
334 
335  // choose evaluation direction (minimize or maximize objective function)
336  if (print_state)
337  {
339  {
340  SG_PRINT("Minimizing objective function:\n");
341  }
342  else
343  {
344  SG_PRINT("Maximizing objective function:\n");
345  }
346  }
347 
349  cost_fun->set_target(this);
350  cost_fun->set_variables(model_vars);
351  cost_fun->set_func_data(&params);
352  bool cleanup=false;
353 #ifdef USE_REFERENCE_COUNTING
354  if(this->ref_count()>1)
355  cleanup=true;
356 #endif
357 
361  cost_fun->unset_target(cleanup);
362  SG_UNREF(cost_fun);
363 
364  if (print_state)
365  {
366  SG_PRINT("Best combination:\n");
367  current_combination->print_tree();
368  }
369 
370  SG_UNREF(machine);
371  SG_UNREF(parameter_dictionary);
372 
373  return current_combination;
374  }
375  else
376  {
378  return NULL;
379  }
380 }
381 
382 }
virtual CParameterCombination * select_model(bool print_state=false)
Model selection class which searches for the best model by a gradient-search.
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
virtual float64_t get_cost(SGVector< float64_t > model_vars, SGVector< float64_t > model_grads, void *func_data)
#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
void scale(T alpha)
Scale vector inplace.
Definition: SGVector.cpp:841
virtual void set_minimizer(FirstOrderMinimizer *minimizer)
#define SG_REF(x)
Definition: SGObject.h:54
A generic learning machine interface.
Definition: Machine.h:143
The class wraps the Shogun's C-style LBFGS minimizer.
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:115
CMachine * get_machine() const
virtual void unset_cost_function(bool is_unref=true)
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
The first order cost function base class.
Class that holds ONE combination of parameters for a learning machine. The structure is organized as ...
virtual float64_t minimize()=0
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:55
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 ...
static int is_infinity(double f)
checks whether a float is infinity
Definition: Math.cpp:247
static int is_nan(double f)
checks whether a float is nan
Definition: Math.cpp:234
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:84
void apply_to_machine(CMachine *machine) const
T * data() const
Definition: SGVector.h:116
virtual void set_cost_function(FirstOrderCostFunction *fun)
the class CMap, a map based on the hash-table. w: http://en.wikipedia.org/wiki/Hash_table ...
Definition: SGObject.h:39
The first order minimizer base class.

SHOGUN Machine Learning Toolbox - Documentation