rf_full.cpp

00001 //
00002 //  Copyright (c) 2005-2007
00003 //  James N Knight
00004 //
00005 //  Permission to use, copy, modify, distribute and sell this software
00006 //  and its documentation for any purpose is hereby granted without fee,
00007 //  provided that the above copyright notice appear in all copies and
00008 //  that both that copyright notice and this permission notice appear
00009 //  in supporting documentation.  The authors make no representations
00010 //  about the suitability of this software for any purpose.
00011 //  It is provided "as is" without express or implied warranty.
00012 //
00013 //  
00014 // See http://homepages.inf.ed.ac.uk/svijayak/publications/vijayakumar-NeuCom2005.pdf
00015 // for the original publication of this algorithm.
00016 
00017 
00018 
00019 #include <boost/numeric/ublas/vector.hpp>
00020 #include <boost/numeric/ublas/matrix.hpp>
00021 #include <boost/numeric/ublas/matrix_expression.hpp>
00022 #include <boost/numeric/ublas/triangular.hpp>
00023 #include <boost/numeric/ublas/io.hpp>
00024 
00025 #include <algorithm>
00026 #include <iomanip>
00027 
00028 #include <math.h>
00029 
00030 #include "rf_full.hpp"
00031 #include "my_expression.hpp"
00032 
00033 RFFull::RFFull()
00034 {
00035 
00036 }
00037 
00038 RFFull::RFFull(Types::Input c) : 
00039     RF(c),
00040     D(c.size(),c.size()), 
00041     M(c.size(),c.size()), 
00042     alpha(c.size(),c.size()),
00043     dwdM(c.size(),c.size()),
00044     dJ2dM(c.size(),c.size()),
00045     dJdM(c.size(),c.size()),
00046     meta_h(c.size(),c.size()),
00047     b(c.size(),c.size()),
00048     dJ2_2dM_2(c.size(),c.size()), 
00049     dw_2dM_2(c.size(),c.size()), 
00050     aux(c.size(),c.size())
00051 {
00052     D.assign(d_def*ublas::identity_matrix<Types::RValue>(c.size()));
00053     M.assign(sqrt(d_def)*ublas::identity_matrix<Types::RValue>(c.size()));
00054     alpha.assign(ublas::scalar_matrix<Types::RParam>(c.size(),c.size(),alpha_init));
00055 
00056     dwdM.clear();
00057     dJ2dM.clear();
00058     dJdM.clear();
00059     dJ2_2dM_2.clear();
00060     dw_2dM_2.clear();
00061     aux.clear();
00062 
00063     meta_h.clear();
00064     b.assign(ublas::scalar_matrix<Types::RParam>(c.size(),c.size(),std::log(alpha_init+1e-10)));
00065 }
00066 
00067 RFFull::RFFull(Types::Input c, const boost::program_options::variables_map& vm) : 
00068     RF(c,vm),
00069     D(c.size(),c.size()), 
00070     M(c.size(),c.size()), 
00071     alpha(c.size(),c.size()),
00072     dwdM(c.size(),c.size()),
00073     dJ2dM(c.size(),c.size()),
00074     dJdM(c.size(),c.size()),
00075     meta_h(c.size(),c.size()),
00076     b(c.size(),c.size()),
00077     dJ2_2dM_2(c.size(),c.size()), 
00078     dw_2dM_2(c.size(),c.size()), 
00079     aux(c.size(),c.size())
00080 {
00081     D.assign(d_def*ublas::identity_matrix<Types::RValue>(c.size()));
00082     M.assign(sqrt(d_def)*ublas::identity_matrix<Types::RValue>(c.size()));
00083 
00084     alpha.assign(ublas::scalar_matrix<Types::RParam>(c.size(),c.size(),alpha_init));
00085 
00086     dwdM.clear();
00087     dJ2dM.clear();
00088     dJdM.clear();
00089     dJ2_2dM_2.clear();
00090     dw_2dM_2.clear();
00091     aux.clear();
00092 
00093     meta_h.clear();
00094     b.assign(ublas::scalar_matrix<Types::RParam>(c.size(),c.size(),std::log(alpha_init+1e-10)));
00095 }
00096 
00097 RFFull::RFFull(const RFFull& rf, Types::Input c, const boost::program_options::variables_map& vm) : 
00098     RF(c, vm),
00099     D(c.size(),c.size()), 
00100     M(c.size(),c.size()), 
00101     alpha(c.size(),c.size()),
00102     dwdM(c.size(),c.size()),
00103     dJ2dM(c.size(),c.size()),
00104     dJdM(c.size(),c.size()),
00105     meta_h(c.size(),c.size()),
00106     b(c.size(),c.size()),
00107     dJ2_2dM_2(c.size(),c.size()), 
00108     dw_2dM_2(c.size(),c.size()), 
00109     aux(c.size(),c.size())
00110 {
00111     std::cerr << "Adding Receptive Field" << std::endl;
00112     alpha.assign(rf.getAlpha());
00113     D.assign(rf.getD());
00114     M.assign(rf.getM());
00115 
00116     dwdM.clear();
00117     dJ2dM.clear();
00118     dJdM.clear();
00119     dJ2_2dM_2.clear();
00120     dw_2dM_2.clear();
00121     aux.clear();
00122 
00123     meta_h.clear();
00124     b.assign(ublas::scalar_matrix<Types::RParam>(c.size(),c.size(),std::log(alpha_init+1e-10)));
00125 }
00126 
00127 
00128 Types::RValue RFFull::learn(Types::Input x, Types::Output y, Types::RValueP w) {
00129     // get the current activation
00130 //    const Types::RValue w = getActivation(x);
00131 
00132     // update some sufficient statistics
00133     const Types::RValue W_old = W;
00134     W = lambda * W + w;
00135 
00136     //update the local model
00137     localModel.learn(x,y,w,W,W_old);
00138 
00139     // stuff from local model, this relies on learn being called first, perhaps I should rework this
00140     const Types::RValue e_cv = localModel.get_e_cv();
00141     const Types::RValue e = localModel.get_e();
00142     Types::Input z = localModel.get_z();
00143 
00144     // Update the distance matrix as in Equation 3.6 and Table 4
00145     // \f$ M^{n+1} = M^n - \alpha \frac{\partial J}{\partial M} \f$
00146     
00147     // do some strange stuff to help with numerical stability
00148     Types::Input derivative = localModel.check_derivatives();
00149 
00150     if(derivative(0) != 0){    // update is ok
00151 
00152         // update squared error trackers
00153         e_2 = lambda * e_2 + w*e*e;
00154         
00155         // this seems odd but paper says update it here, before use
00156         // update a_E
00157         a_E = lambda * a_E + w*e_cv*e_cv;
00158 
00159         Types::RValue transient_multiplier = std::min(1.0, pow( e_2 / (a_E + 1e-10) , 4));
00160 
00161         // compute \f$ \sum_{i=1}^M \frac{\partial J_1}{\partial w} \f$
00162         q = element_div(element_prod(z,derivative),localModel.get_a_zz());
00163 
00164         // sufficient statistic for confidence intervals
00165         a_pk = lambda*a_pk + w*w*prec_inner_prod(q,z);
00166 
00167         const Types::RValue dJ1dw = (e_cv*e_cv)/W - 2*e/W * prec_inner_prod(q,a_H) - 2/W*prec_inner_prod(element_prod(q,q),a_G) - a_E/(W*W);
00168 
00169         temp2 = x - center;
00170 
00171         dwdM.clear();
00172 
00173         // M is upper triangular
00174         for(int k=0; k<dwdM.size1(); ++k)
00175             for(int l=k; l<dwdM.size2(); ++l){
00176                 Types::RValue sum_aux = 0;
00177                 Types::RValue dDdM_2 = 0;
00178                 
00179                 // compute dDdM
00180                 for(int i=0; i<dwdM.size1(); ++i){
00181                     sum_aux += D(i,l)*M(k,i)*2;
00182                     dwdM(k,l) += temp2(i)*temp2(l)*M(k,i)*((i==l)?2:1);
00183 
00184                     if(meta)
00185                         dDdM_2 += (M(k,i)*M(k,i)*((i==l)?2:1)) * 2;
00186 
00187                 }
00188                 
00189                 dwdM(k,l) = -0.5 * w * dwdM(k,l);
00190                 dJ2dM(k,l) = 2 * gamma / center.size() * sum_aux;
00191 
00192                 if(meta)
00193                 {
00194                     dJ2_2dM_2(k,l) = 2*gamma/center.size()*(2*D(l,l) + dDdM_2);
00195                     dw_2dM_2(k,l) = dwdM(k,l)*dwdM(k,l)/w - w*temp2(k)*temp2(k);
00196                 }
00197 
00198             }
00199 
00200         dJdM = dJ1dw * dwdM + (w/W)*dJ2dM;
00201 
00202         // compute h
00203         const Types::RValue h = w * prec_inner_prod(z,q);
00204     
00205         if(meta){
00206             const Types::RValue dJ1_2dw_2 = -(e_cv*e_cv)/(W*W)
00207                                   + 2*e*e*h/(W*w)
00208                                     + a_E/(W*W*W)
00209                                     - 2/W*((-(e/W) - 2*e*prec_inner_prod(q,z))*prec_inner_prod(q,a_H))
00210                                     - 1/(W*W)*( (e_cv*e_cv) - 2*e*prec_inner_prod(q,a_H) );
00211 
00212             dJ_2dM_2 = (dw_2dM_2*dJ1dw + element_prod(dwdM,dwdM)*dJ1_2dw_2) + w/W*dJ2_2dM_2;
00213 
00214             aux = meta_alpha * transient_multiplier * element_prod(dJdM,meta_h);
00215 
00216             for(int i=0; i<aux.size1(); ++i)
00217                 for(int j=i; j<aux.size2(); ++j)
00218                     if(fabs(aux(i,j)) > 0.1)
00219                         aux(i,j) = 0.1 * ((aux(i,j)>0)?1:-1);
00220 
00221             b -= aux;
00222 
00223             for(int i=0; i<b.size1(); ++i)
00224                 for(int j=i; j<b.size2(); ++j)
00225                     if(fabs(b(i,j)) > 10)
00226                         b(i,j) = 10 * ((b(i,j)>0)?1:-1);
00227 
00228             //alpha = exp(b);
00229             alpha = (ublas::apply_to_all<ublas::scalar_exp<Types::RValue> >( b ));
00230 
00231             aux = ublas::scalar_matrix<Types::RValue>(alpha.size1(),alpha.size2(),1.0) - (element_prod(alpha,dJ_2dM_2)*transient_multiplier);
00232 
00233             for(int i=0; i<aux.size1(); ++i)
00234                 for(int j=i; j<aux.size2(); ++j)
00235                     if(aux(i,j) < 0.0)
00236                         aux(i,j) = 0;
00237 
00238             meta_h = element_prod(meta_h,aux) - element_prod(alpha,dJdM)*transient_multiplier;
00239         }
00240         
00241         // update a_H, a_G
00242         H_temp =  lambda * a_H + (w*e_cv*z*transient_multiplier)/(1-h);
00243         a_H = element_prod(derivative, H_temp) + element_prod(ublas::scalar_vector<Types::RValue>(derivative.size(),1.0)-derivative,a_H);
00244         H_temp = lambda * a_G + (w*w*(e_cv*e_cv)*element_prod(z,z)*transient_multiplier)/(1-h);
00245         a_G = element_prod(derivative, H_temp) + element_prod(ublas::scalar_vector<Types::RValue>(derivative.size(),1.0)-derivative,a_G);
00246 
00247         // reduce learning rate for elements of M where the update is large
00248         Types::RValue maxM = 0.0;
00249         for(int i=0; i<M.size1(); ++i)
00250             for(int j=i; j<M.size2(); ++j)
00251                 if(fabs(M(i,j)) > maxM)
00252                     maxM = fabs(M(i,j));
00253 
00254         for(int i=0; i<alpha.size1(); ++i)
00255             for(int j=i; j<alpha.size2(); ++j)
00256                 if(alpha(i,j) * dJdM(i,j) * transient_multiplier > .1*maxM)
00257                     alpha(i,j) /= 2;
00258 
00259 
00260         // update M and D
00261         M -= element_prod(alpha,dJdM) * transient_multiplier;
00262         D = prod(trans(M),M);
00263 
00264     }
00265 
00266 
00267     // Check if projection needs to be added, update local ss if projection added
00268     if(localModel.updateNumProjections()){
00269         int R = a_H.size()+1;
00270         a_H.resize(R);
00271         a_H(R-1) = 0;
00272         a_G.resize(R);
00273         a_G(R-1) = 0;
00274         H_temp.resize(R);
00275     }
00276 
00277 }
00278 
00279 std::ostream& operator<<(std::ostream& out, const RFFull& rf)
00280 {
00281     out << rf.center(0) << " " << rf.center(1) << " ";
00282     out << rf.D(0,0) << " " << rf.D(0,1) << " " << rf.D(1,0) << " " << rf.D(1,1) << std::endl;
00283 }

Generated on Fri Jul 27 00:24:01 2007 for LWPR by  doxygen 1.5.1