SHOGUN  v2.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PrimalMosekSOSVM.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) 2012 Fernando José Iglesias García
8  * Copyright (C) 2012 Fernando José Iglesias García
9  */
10 
11 #ifdef USE_MOSEK
12 
14 #include <shogun/lib/List.h>
17 
18 using namespace shogun;
19 
20 CPrimalMosekSOSVM::CPrimalMosekSOSVM()
22 {
23 }
24 
25 CPrimalMosekSOSVM::CPrimalMosekSOSVM(
26  CStructuredModel* model,
27  CLossFunction* loss,
28  CStructuredLabels* labs)
29 : CLinearStructuredOutputMachine(model, loss, labs)
30 {
31 }
32 
33 void CPrimalMosekSOSVM::init()
34 {
35  SG_ADD(&m_slacks, "m_slacks", "Slacks vector", MS_NOT_AVAILABLE);
36 }
37 
38 CPrimalMosekSOSVM::~CPrimalMosekSOSVM()
39 {
40 }
41 
42 bool CPrimalMosekSOSVM::train_machine(CFeatures* data)
43 {
44  if (data)
45  set_features(data);
46 
47  CFeatures* model_features = get_features();
48  // Check that the scenary is correct to start with training
49  m_model->check_training_setup();
50 
51  // Dimensionality of the joint feature space
52  int32_t M = m_model->get_dim();
53  // Number of auxiliary variables in the optimization vector
54  int32_t num_aux = m_model->get_num_aux();
55  // Number of auxiliary constraints
56  int32_t num_aux_con = m_model->get_num_aux_con();
57  // Number of training examples
58  int32_t N = model_features->get_num_vectors();
59 
60  // Interface with MOSEK
61  CMosek* mosek = new CMosek(0, M+num_aux+N);
62  SG_REF(mosek);
63  if ( mosek->get_rescode() != MSK_RES_OK )
64  {
65  SG_PRINT("Mosek object could not be properly created..."
66  "aborting training of PrimalMosekSOSVM\n");
67 
68  return false;
69  }
70 
71  // Initialize the terms of the optimization problem
72  SGMatrix< float64_t > A, B, C;
73  SGVector< float64_t > a, b, lb, ub;
74  m_model->init_opt(A, a, B, b, lb, ub, C);
75 
76  // Input terms of the problem that do not change between iterations
77  if ( mosek->init_sosvm(M, N, num_aux, num_aux_con, C, lb, ub, A, b) != MSK_RES_OK )
78  {
79  // MOSEK error took place
80  return false;
81  }
82 
83  // Initialize the weight vector
84  m_w = SGVector< float64_t >(M);
85  m_w.zero();
86 
87  m_slacks = SGVector< float64_t >(N);
88  m_slacks.zero();
89 
90  // Initialize the list of constraints
91  // Each element in results is a list of CResultSet with the constraints
92  // associated to each training example
93  CDynamicObjectArray* results = new CDynamicObjectArray(N);
94  SG_REF(results);
95  for ( int32_t i = 0 ; i < N ; ++i )
96  {
97  CList* list = new CList(true);
98  results->push_back(list);
99  }
100 
101  // Initialize variables used in the loop
102  int32_t num_con = num_aux_con; // number of constraints
103  int32_t old_num_con = num_con;
104  float64_t slack = 0.0;
105  float64_t max_slack = 0.0;
106  CResultSet* result = NULL;
107  CResultSet* cur_res = NULL;
108  CList* cur_list = NULL;
109  bool exception = false;
110 
111  SGVector< float64_t > sol(M+num_aux+N);
112  sol.zero();
113 
114  SGVector< float64_t > aux(num_aux);
115 
116  do
117  {
118  old_num_con = num_con;
119 
120  for ( int32_t i = 0 ; i < N ; ++i )
121  {
122  // Predict the result of the ith training example
123  result = m_model->argmax(m_w, i);
124 
125  // Compute the loss associated with the prediction
126  slack = m_loss->loss( compute_loss_arg(result) );
127  cur_list = (CList*) results->get_element(i);
128 
129  // Update the list of constraints
130  if ( cur_list->get_num_elements() > 0 )
131  {
132  // Find the maximum loss within the elements of
133  // the list of constraints
134  cur_res = (CResultSet*) cur_list->get_first_element();
135  max_slack = -CMath::INFTY;
136 
137  while ( cur_res != NULL )
138  {
139  max_slack = CMath::max(max_slack,
140  m_loss->loss( compute_loss_arg(cur_res) ));
141 
142  SG_UNREF(cur_res);
143  cur_res = (CResultSet*) cur_list->get_next_element();
144  }
145 
146  if ( slack > max_slack )
147  {
148  // The current training example is a
149  // violated constraint
150  if ( ! insert_result(cur_list, result) )
151  {
152  exception = true;
153  break;
154  }
155 
156  add_constraint(mosek, result, num_con, i);
157  ++num_con;
158  }
159  }
160  else
161  {
162  // First iteration of do ... while, add constraint
163  if ( ! insert_result(cur_list, result) )
164  {
165  exception = true;
166  break;
167  }
168 
169  add_constraint(mosek, result, num_con, i);
170  ++num_con;
171  }
172 
173  SG_UNREF(cur_list);
174  SG_UNREF(result);
175  }
176 
177  // Solve the QP
178  mosek->optimize(sol);
179  for ( int32_t i = 0 ; i < M+num_aux+N ; ++i )
180  {
181  if ( i < M )
182  m_w[i] = sol[i];
183  else if ( i < M+num_aux )
184  aux[i-M] = sol[i];
185  else
186  m_slacks[i-M-num_aux] = sol[i];
187  }
188 
189  } while ( old_num_con != num_con && ! exception );
190 
191  // Free resources
192  SG_UNREF(results);
193  SG_UNREF(mosek);
194  SG_UNREF(model_features);
195  return true;
196 }
197 
198 float64_t CPrimalMosekSOSVM::compute_loss_arg(CResultSet* result) const
199 {
200  // Dimensionality of the joint feature space
201  int32_t M = m_w.vlen;
202 
203  return SGVector< float64_t >::dot(m_w.vector, result->psi_pred.vector, M) +
204  result->delta -
205  SGVector< float64_t >::dot(m_w.vector, result->psi_truth.vector, M);
206 }
207 
208 bool CPrimalMosekSOSVM::insert_result(CList* result_list, CResultSet* result) const
209 {
210  bool succeed = result_list->insert_element(result);
211 
212  if ( ! succeed )
213  {
214  SG_PRINT("ResultSet could not be inserted in the list..."
215  "aborting training of PrimalMosekSOSVM\n");
216  }
217 
218  return succeed;
219 }
220 
221 bool CPrimalMosekSOSVM::add_constraint(
222  CMosek* mosek,
223  CResultSet* result,
224  index_t con_idx,
225  index_t train_idx) const
226 {
227  int32_t M = m_model->get_dim();
228  SGVector< float64_t > dPsi(M);
229 
230  for ( int i = 0 ; i < M ; ++i )
231  dPsi[i] = result->psi_pred[i] - result->psi_truth[i];
232 
233  return ( mosek->add_constraint_sosvm(dPsi, con_idx, train_idx,
234  m_model->get_num_aux(), -result->delta) == MSK_RES_OK );
235 }
236 
237 #endif /* USE_MOSEK */

SHOGUN Machine Learning Toolbox - Documentation