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
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-max_coeff*MatrixXd::Ones(1,eigen_f.cols());
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+max_coeff*MatrixXd::Ones(1,eigen_f.cols());
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  Map<MatrixXd> eigen_ret(ret.vector,func.num_rows,func.num_cols);
119  eigen_ret=eigen_ret.array().exp();
120  eigen_ret=eigen_ret.cwiseQuotient(eigen_ret.rowwise().sum()*MatrixXd::Ones(1,func.num_cols));
121 
122  MatrixXd y=MatrixXd::Zero(func.num_rows,func.num_cols);
123 
124  for (int32_t i=0;i<labels.vlen;i++)
125  y(i,labels[i])=1.;
126 
127  eigen_ret=y-eigen_ret;
128 
129  return ret;
130 }
131 
132 SGVector<float64_t> CSoftMaxLikelihood::get_log_probability_derivative2_f(SGMatrix<float64_t> func) const
133 {
134  SGVector<float64_t> ret=SGVector<float64_t>(func.num_rows*func.num_cols*func.num_cols);
135  Map<MatrixXd> eigen_ret(ret.vector,func.num_rows*func.num_cols,func.num_cols);
136 
137  Map<MatrixXd> eigen_f(func.matrix,func.num_rows,func.num_cols);
138 
139  MatrixXd f1= eigen_f.array().exp();
140  f1=f1.cwiseQuotient(f1.rowwise().sum()*MatrixXd::Ones(1,f1.cols()));
141 
142  for (int32_t i=0;i<eigen_f.rows();i++)
143  {
144  eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())=
145  f1.transpose().col(i)*f1.row(i);
146  VectorXd D=eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())
147  .diagonal().array().sqrt();
148  eigen_ret.block(i*eigen_f.cols(),0,eigen_f.cols(),eigen_f.cols())-=
149  MatrixXd(D.asDiagonal());
150  }
151 
152  return ret;
153 }
154 
155 SGVector<float64_t> CSoftMaxLikelihood::get_log_probability_derivative3_f(SGMatrix<float64_t>
156  func) const
157 {
159 
160  Map<MatrixXd> eigen_f(func.matrix,func.num_rows,func.num_cols);
161 
162  MatrixXd f1= eigen_f.array().exp();
163  f1=f1.cwiseQuotient(f1.rowwise().sum()*MatrixXd::Ones(1,f1.cols()));
164 
165  for (int32_t i=0;i<func.num_rows;i++)
166  {
167  for (int32_t c1=0;c1<func.num_cols;c1++)
168  {
169  for (int32_t c2=0;c2<func.num_cols;c2++)
170  {
171  for (int32_t c3=0;c3<func.num_cols;c3++)
172  {
173  float64_t sum_temp=0;
174  if ((c1==c2) && (c2==c3))
175  sum_temp+=f1(i,c1);
176  if (c1==c2)
177  sum_temp=sum_temp-f1(i,c1)*f1(i,c3);
178  if (c1==c3)
179  sum_temp=sum_temp-f1(i,c1)*f1(i,c2);
180  if (c2==c3)
181  sum_temp=sum_temp-f1(i,c1)*f1(i,c2);
182  sum_temp+=2.0*f1(i,c1)*f1(i,c2)*f1(i,c3);
183 
184  ret[i*CMath::pow(func.num_cols,3)+
185  c1*CMath::pow(func.num_cols,2)+c2*func.num_cols+c3]=sum_temp;
186  }
187  }
188  }
189  }
190 
191  return ret;
192 }
193 
194 #endif /* HAVE_EIGEN3 */

SHOGUN Machine Learning Toolbox - Documentation