SHOGUN  3.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultilabelCLRModel.cpp
Go to the documentation of this file.
1 /*
2  * This software is distributed under BSD 3-clause license (see LICENSE file).
3  *
4  * Copyright(C) 2014 Thoralf Klein
5  * Written(W) 2014 Thoralf Klein
6  * Written(W) 2014 Abinash Panda
7  */
8 
13 
14 using namespace shogun;
15 
18 {
19  init();
20 }
21 
23  CStructuredLabels * labels) : CStructuredModel(features, labels)
24 {
25  init();
26 }
27 
29  int32_t num_labels)
30 {
31  return new CMultilabelSOLabels(num_labels, m_num_classes);
32 }
33 
35 {
36 }
37 
38 void CMultilabelCLRModel::init()
39 {
40  SG_ADD(&m_num_classes, "num_classes", "Number of (binary) class assignment per label",
42  m_num_classes = 0;
43 }
44 
46 {
47  int32_t num_classes = ((CMultilabelSOLabels *)m_labels)->get_num_classes();
48  int32_t feats_dim = ((CDotFeatures *)m_features)->get_dim_feature_space();
49 
50  return feats_dim * (num_classes + 1);
51 }
52 
54  int32_t feat_idx, CStructuredData * y)
55 {
57  psi.zero();
58 
59  int32_t num_classes = ((CMultilabelSOLabels *)m_labels)->get_num_classes();
60  int32_t num_pos_labels = (CSparseMultilabel::obtain_from_generic(y))->
61  get_data().vlen;
62  int32_t num_neg_labels = num_classes - num_pos_labels;
63 
64  // the calibrated label is considered to be the last label
65  SGVector<float64_t> label_coeffs(num_classes + 1);
66  label_coeffs.zero();
67  // the label coefficients would be positive for the relevant/positive
68  // labels (P), negative for irrelevant/negative labels (N) and would be the
69  // difference of number of irrelevant labels and number of revelant labels
70  // for the calibrated/virtual label as
71  // labels_coeff = \sum_{i \in P}{l(i) - l(v)} + \sum_{j \in N}{l(v) - l(j)}
72  // where $v$ is the calibrated/virtual label
73  label_coeffs += CMultilabelSOLabels::to_dense(y, num_classes + 1, 1, -1);
74  label_coeffs[num_classes] = num_neg_labels - num_pos_labels;
75 
76  CDotFeatures * dot_feats = (CDotFeatures *)m_features;
78  int32_t feats_dim = dot_feats->get_dim_feature_space();
79 
80  for (index_t i = 0; i < num_classes + 1; i++)
81  {
82  float64_t coeff = label_coeffs[i];
83 
84  for (index_t j = 0; j < feats_dim; j++)
85  {
86  psi[i * feats_dim + j] = coeff * x[j];
87  }
88  }
89 
90  return psi;
91 }
92 
94 {
97 
98  ASSERT(y1_slabel != NULL);
99  ASSERT(y2_slabel != NULL);
100 
102  return delta_loss(
104  multi_labels->get_num_classes(), 1, 0),
106  multi_labels->get_num_classes(), 1, 0));
107 }
108 
110 {
111  REQUIRE(y1.vlen == y2.vlen, "Size of both the vectors should be same\n");
112 
113  float64_t loss = 0;
114 
115  for (index_t i = 0; i < y1.vlen; i++)
116  {
117  loss += delta_loss(y1[i], y2[i]);
118  }
119 
120  return loss;
121 }
122 
124 {
125  return y1 != y2 ? 1 : 0;
126 }
127 
128 SGVector<int32_t> CMultilabelCLRModel::to_sparse(SGVector<float64_t> dense_vec,
129  float64_t d_true, float64_t d_false)
130 {
131  int32_t size = 0;
132 
133  for (index_t i = 0; i < dense_vec.vlen; i++)
134  {
135  REQUIRE(dense_vec[i] == d_true || dense_vec[i] == d_false,
136  "The values of dense vector should be either (%d) or (%d).\n",
137  d_true, d_false);
138 
139  if (dense_vec[i] == d_true)
140  {
141  size++;
142  }
143  }
144 
145  SGVector<int32_t> sparse_vec(size);
146  index_t j = 0;
147 
148  for (index_t i = 0; i < dense_vec.vlen; i++)
149  {
150  if (dense_vec[i] == d_true)
151  {
152  sparse_vec[j] = i;
153  j++;
154  }
155  }
156 
157  return sparse_vec;
158 }
159 
161  bool const training)
162 {
163  CDotFeatures * dot_feats = (CDotFeatures *)m_features;
164  int32_t feats_dim = dot_feats->get_dim_feature_space();
165 
167 
168  if (training)
169  {
170  m_num_classes = multi_labs->get_num_classes();
171  }
172  else
173  {
174  REQUIRE(m_num_classes > 0, "The model needs to be trained before using "
175  "it for prediction\n");
176  }
177 
178  int32_t dim = get_dim();
179  ASSERT(dim == w.vlen);
180 
181  SGVector<float64_t> plus_minus_one(m_num_classes);
182 
183  if (training)
184  {
185  plus_minus_one.set_const(-1);
186 
188  multi_labs->get_label(feat_idx));
189  SGVector<int32_t> y_true_data = y_true->get_data();
190 
191  for (index_t i = 0; i < y_true_data.vlen; i++)
192  {
193  plus_minus_one[y_true_data[i]] = 1;
194  }
195 
196  SG_UNREF(y_true);
197  }
198  else
199  {
200  plus_minus_one.zero();
201  }
202 
203  float64_t score = 0, calibrated_score = 0;
204 
205  // last label (m_num_class + 1)th label is the calibrated/virtual label
206  calibrated_score = dot_feats->dense_dot(feat_idx, w.vector + m_num_classes * feats_dim,
207  feats_dim);
208 
209  SGVector<float64_t> class_product(m_num_classes);
210 
211  for (index_t i = 0; i < m_num_classes; i++)
212  {
213  score = dot_feats->dense_dot(feat_idx, w.vector + i * feats_dim,
214  feats_dim);
215  class_product[i] = score - calibrated_score;
216  }
217 
218  int32_t count = 0;
219  SGVector<float64_t> y_pred_dense(m_num_classes);
220  y_pred_dense.zero();
221 
222  for (index_t i = 0; i < m_num_classes; i++)
223  {
224  score = class_product[i] - plus_minus_one[i];
225 
226  if (score >= 0)
227  {
228  y_pred_dense[i] = 1;
229  count++;
230  }
231  }
232 
233  SGVector<int32_t> y_pred_sparse = to_sparse(y_pred_dense, 1, 0);
234  ASSERT(count == y_pred_sparse.vlen);
235 
236  CResultSet * ret = new CResultSet();
237  SG_REF(ret);
238  ret->psi_computed = true;
239 
240  CSparseMultilabel * y_pred = new CSparseMultilabel(y_pred_sparse);
241  SG_REF(y_pred);
242 
243  ret->psi_pred = get_joint_feature_vector(feat_idx, y_pred);
244  ret->score = SGVector<float64_t>::dot(w.vector, ret->psi_pred.vector, dim);
245  ret->argmax = y_pred;
246 
247  if (training)
248  {
249  ret->delta = CStructuredModel::delta_loss(feat_idx, y_pred);
251  feat_idx, feat_idx);
252  ret->score += (ret->delta - SGVector<float64_t>::dot(w.vector,
253  ret->psi_truth.vector, dim));
254  }
255 
256  return ret;
257 }
258 
260  float64_t regularization,
268 {
270 }
271 

SHOGUN Machine Learning Toolbox - Documentation