SHOGUN  3.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SoftMaxLikelihood.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) The Shogun Machine Learning Toolbox
3  * Written (w) 2014 Parijat Mazumdar, Wu Lin
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are those
27  * of the authors and should not be interpreted as representing official policies,
28  * either expressed or implied, of the Shogun Development Team.
29  */
30 
32 
33 #ifdef HAVE_EIGEN3
34 
37 
38 using namespace shogun;
39 using namespace Eigen;
40 
42 {
43 }
44 
46 {
47 }
48 
50  SGVector<float64_t> func) const
51 {
52  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
54  "Labels must be type of CMulticlassLabels\n")
55 
56  SGVector<int32_t> labels=((CMulticlassLabels*) lab)->get_int_labels();
57  for (int32_t i=0;i<labels.vlen;i++)
58  REQUIRE(((labels[i]>-1)&&(labels[i]<func.vlen/labels.vlen)),
59  "Labels must be between 0 and C(ie %d here). Currently labels[%d] is"
60  "%d\n",func.vlen/labels.vlen,i,labels[i]);
61 
62  // labels.vlen=num_rows func.vlen/num_rows=num_cols
63  Map<MatrixXd> eigen_f(func.vector,labels.vlen,func.vlen/labels.vlen);
64 
65  // log_sum_exp trick
66  VectorXd max_coeff=eigen_f.rowwise().maxCoeff();
67  eigen_f=eigen_f.array().colwise()-max_coeff.array();
68  VectorXd log_sum_exp=((eigen_f.array().exp()).rowwise().sum()).array().log();
69  log_sum_exp=log_sum_exp+max_coeff;
70 
71  // restore original matrix
72  eigen_f=eigen_f.array().colwise()+max_coeff.array();
73 
75  Map<VectorXd> eigen_ret(ret.vector,ret.vlen);
76 
77  for (int32_t i=0;i<labels.vlen;i++)
78  eigen_ret(i)=eigen_f(i,labels[i]);
79 
80  eigen_ret=eigen_ret-log_sum_exp;
81 
82  return ret;
83 }
84 
86  const CLabels* lab, SGVector<float64_t> func, index_t i) const
87 {
88  int32_t num_rows=lab->get_num_labels();
89  int32_t num_cols=func.vlen/num_rows;
90  SGMatrix<float64_t> f=SGMatrix<float64_t>(func.vector,num_rows,num_cols,false);
91 
92  if (i==1)
93  return get_log_probability_derivative1_f(lab,f);
94  else if (i==2)
95  return get_log_probability_derivative2_f(f);
96  else
97  return get_log_probability_derivative3_f(f);
98 }
99 
100 SGVector<float64_t> CSoftMaxLikelihood::get_log_probability_derivative1_f(
101  const CLabels* lab, SGMatrix<float64_t> func) const
102 {
103  REQUIRE(lab, "Labels are required (lab should not be NULL)\n")
104  REQUIRE(lab->get_label_type()==LT_MULTICLASS,
105  "Labels must be type of CMulticlassLabels\n")
106  REQUIRE(lab->get_num_labels()==func.num_rows, "Number of labels must match "
107  "number of vectors in function\n")
108 
109  SGVector<int32_t> labels=((CMulticlassLabels*) lab)->get_int_labels();
110  for (int32_t i=0;i<labels.vlen;i++)
111  REQUIRE(((labels[i]>-1)&&(labels[i]<func.num_cols)),
112  "Labels must be between 0 and C(ie %d here). Currently labels[%d] is"
113  "%d\n",func.num_cols,i,labels[i]);
114 
115  SGVector<float64_t> ret=SGVector<float64_t>(func.num_rows*func.num_cols);
116  memcpy(ret.vector,func.matrix,func.num_rows*func.num_cols*sizeof(float64_t));
117 
118  //pi
119  Map<MatrixXd> eigen_ret(ret.vector,func.num_rows,func.num_cols);
120 
121  // with log_sum_exp trick
122  VectorXd max_coeff=eigen_ret.rowwise().maxCoeff();
123  eigen_ret=eigen_ret.array().colwise()-max_coeff.array();
124  VectorXd log_sum_exp=((eigen_ret.array().exp()).rowwise().sum()).array().log();
125  eigen_ret=(eigen_ret.array().colwise()-log_sum_exp.array()).exp();
126 
127  // without log_sum_exp trick
128  //eigen_ret=eigen_ret.array().exp();
129  //VectorXd tmp=eigen_ret.rowwise().sum();
130  //eigen_ret=eigen_ret.array().colwise()/tmp.array();
131 
132  MatrixXd y=MatrixXd::Zero(func.num_rows,func.num_cols);
133 
134  for (int32_t i=0;i<labels.vlen;i++)
135  y(i,labels[i])=1.;
136 
137  eigen_ret=y-eigen_ret;
138 
139  return ret;
140 }
141 
142 SGVector<float64_t> CSoftMaxLikelihood::get_log_probability_derivative2_f(SGMatrix<float64_t> func) const
143 {
144  SGVector<float64_t> ret=SGVector<float64_t>(func.num_rows*func.num_cols*func.num_cols);
145  Map<MatrixXd> eigen_ret(ret.vector,func.num_rows*func.num_cols,func.num_cols);
146 
147  Map<MatrixXd> eigen_f(func.matrix,func.num_rows,func.num_cols);
148 
149  MatrixXd f1= eigen_f.array().exp();
150  VectorXd tmp=f1.rowwise().sum();
151  f1=f1.array().colwise()/tmp.array();
152 
153  for (int32_t i=0;i<eigen_f.rows();i++)
154  {
155  eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())=
156  f1.transpose().col(i)*f1.row(i);
157  VectorXd D=eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())
158  .diagonal().array().sqrt();
159  eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())-=
160  MatrixXd(D.asDiagonal());
161  }
162 
163  return ret;
164 }
165 
166 SGVector<float64_t> CSoftMaxLikelihood::get_log_probability_derivative3_f(SGMatrix<float64_t>
167  func) const
168 {
170 
171  Map<MatrixXd> eigen_f(func.matrix,func.num_rows,func.num_cols);
172 
173  MatrixXd f1= eigen_f.array().exp();
174  VectorXd tmp=f1.rowwise().sum();
175  f1=f1.array().colwise()/tmp.array();
176 
177  for (int32_t i=0;i<func.num_rows;i++)
178  {
179  for (int32_t c1=0;c1<func.num_cols;c1++)
180  {
181  for (int32_t c2=0;c2<func.num_cols;c2++)
182  {
183  for (int32_t c3=0;c3<func.num_cols;c3++)
184  {
185  float64_t sum_temp=0;
186  if ((c1==c2) && (c2==c3))
187  sum_temp+=f1(i,c1);
188  if (c1==c2)
189  sum_temp=sum_temp-f1(i,c1)*f1(i,c3);
190  if (c1==c3)
191  sum_temp=sum_temp-f1(i,c1)*f1(i,c2);
192  if (c2==c3)
193  sum_temp=sum_temp-f1(i,c1)*f1(i,c2);
194  sum_temp+=2.0*f1(i,c1)*f1(i,c2)*f1(i,c3);
195 
196  ret[i*CMath::pow(func.num_cols,3)+
197  c1*CMath::pow(func.num_cols,2)+c2*func.num_cols+c3]=sum_temp;
198  }
199  }
200  }
201  }
202 
203  return ret;
204 }
205 
206 #endif /* HAVE_EIGEN3 */

SHOGUN Machine Learning Toolbox - Documentation