model.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/matrix_proxy.hpp>
00020 #include <boost/numeric/ublas/vector_proxy.hpp>
00021 #include <boost/numeric/ublas/vector_expression.hpp>
00022 #include <boost/numeric/ublas/io.hpp>
00023 
00024 #include <iostream>
00025 #include <iomanip>
00026 
00027 //#include <boost/numeric/bindings/atlas/cblas.hpp>
00028 //namespace bindings = boost::numeric::bindings::atlas;
00029 
00030 #include "model.hpp"
00031 
00032 Model::Model() {
00033 
00034 };
00035 
00036 Model::Model(int input_dim) : N(input_dim),R(2),
00037                                                             beta_0(0), 
00038                                                             x_0(N),
00039                                                             MSE(R),
00040                                                             data_count(R), derivatives_ok(R),
00041                                                             a_zz(R),a_zres(R),a_xz(N,R),
00042                                                             y_target(R),e_cv(R),
00043                                                             u(N,R),p(N,R),
00044                                                             x_res(N,R+1),beta(R),z(R),
00045                                                             x_temp(N), u_temp(N,R)
00046 {
00047 
00048     u.clear();
00049     p.clear();
00050 
00051     u_temp.clear();
00052 
00053     // initialize projections to identity matrix
00054     u(0,0) = 1;
00055     p(0,0) = 1;
00056 
00057     if(N>1){
00058         u(1,1) = 1;
00059         p(1,1) = 1;
00060     }
00061 
00062     lambda = .999;
00063     phi = 0.5;
00064 
00065     x_0.clear();
00066     beta.clear();
00067     MSE.clear();
00068 
00069     // might move this into initilizer list
00070     data_count = ublas::scalar_vector<Types::RValue>(R,1e-10);
00071     derivatives_ok = ublas::zero_vector<Types::RValue>(R);
00072     a_zz = ublas::scalar_vector<Types::RValue>(R,1e-10);
00073 
00074     a_zres.clear();
00075     a_xz.clear();
00076 }
00077 
00078 Model::Model(int input_dim, const boost::program_options::variables_map& vm) : N(input_dim),R(2),
00079                                                             beta_0(0), 
00080                                                             x_0(N),
00081                                                             MSE(R),
00082                                                             data_count(R), derivatives_ok(R),
00083                                                             a_zz(R),a_zres(R),a_xz(N,R),
00084                                                             y_target(R),e_cv(R),
00085                                                             u(N,R),p(N,R),
00086                                                             x_res(N,R+1),beta(R),z(R),
00087                                                             x_temp(N), u_temp(N,R)
00088 {
00089 
00090     u.clear();
00091     p.clear();
00092 
00093     u_temp.clear();
00094 
00095     // initialize projections to identity matrix
00096     u(0,0) = 1;
00097     p(0,0) = 1;
00098 
00099     if(N>1){
00100         u(1,1) = 1;
00101         p(1,1) = 1;
00102     }
00103 
00104     lambda = vm["lambda"].as<Types::RParam>();
00105     phi = vm["phi"].as<Types::RParam>();
00106 
00107     x_0.clear();
00108     beta.clear();
00109 
00110     MSE.clear();
00111 
00112     // might move this into initilizer list
00113     data_count = ublas::scalar_vector<Types::RValue>(R,1e-10);
00114     derivatives_ok = ublas::zero_vector<Types::RValue>(R);
00115     a_zz = ublas::scalar_vector<Types::RValue>(R,1e-10);
00116 
00117     a_zres.clear();
00118     a_xz.clear();
00119 }
00120 
00121 
00122 void Model::learn(Types::Input x, Types::Output y, Types::RValue w, Types::RValue W, Types::RValue W_old){
00123     x_0 = (lambda * W_old * x_0 + w * x)/W;
00124     beta_0 = (lambda * W_old * beta_0 + w * y)/W;
00125 
00126     // update current prediction error
00127     column(x_res,0) = x - x_0;
00128     y_hat = beta_0;
00129 
00130     for(int r=0; r<R; ++r){
00131         z(r) = prec_inner_prod(column(x_res,r),column(u,r));
00132         //z(r) = bindings::dot(column(x_res,r),column(u,r));
00133 
00134         y_hat += beta(r) * z(r);
00135         e_cv(r) = y-y_hat;
00136         
00137         column(x_res,r+1) = column(x_res,r) - z(r) * column(p,r);
00138         MSE(r) = lambda * MSE(r) + w * (y-y_hat) * (y-y_hat);
00139     }
00140     
00141     y_target(0) = y-beta_0;
00142     ublas::project(y_target, ublas::range(1,R)).assign(ublas::project(e_cv,ublas::range(0,R-1)));
00143 
00144 
00145     // update the local model
00146     res = y - beta_0;
00147     for(int r=0; r<R; ++r){
00148         a_zz(r) = lambda * a_zz(r) + w * z(r) * z(r);
00149 
00150         //a_zres(r) = lambda * a_zres(r) + w * z(r) * res;
00151         a_zres(r) = lambda * a_zres(r) + w * z(r) * y_target(r);
00152 
00153         beta(r) = a_zres(r) / a_zz(r);
00154         
00155         column(a_xz,r) = lambda * column(a_xz,r) + w * column(x_res,r) * z(r);
00156 
00157         // normalize the projections here rather than in the use above
00158         Types::RParam lambda_slow = 1 - (1-lambda)/10;
00159 
00160         //column(u_temp,r) = lambda_slow * column(u_temp,r) + w * res*column(x_res,r);
00161         column(u_temp,r) = lambda_slow * column(u_temp,r) + w * y_target(r)*column(x_res,r);
00162         
00163         Types::RValue norm_coeff = ublas::norm_2(column(u_temp,r));
00164         if(norm_coeff > 0)
00165             column(u,r) = column(u_temp,r)/norm_coeff;
00166 
00167         column(p,r) = column(a_xz,r) / a_zz(r);
00168 
00169         res -= z(r) * beta(r);
00170     }
00171 
00172     e = res;
00173 
00174     // update amount of data seen
00175     data_count = lambda * data_count + ublas::scalar_vector<Types::RValue>(R,1.0);
00176 
00177 }
00178 
00179 bool Model::trustworthy() const
00180 {
00181     bool trust = true;
00182     
00183     for(int r=0; r<R; ++r)
00184         trust = trust && (data_count(r) > 2*N);    
00185 
00186     return trust;
00187 }
00188 
00189 Types::Input Model::check_derivatives() const
00190 {
00191     for(int r=0; r<R; ++r)
00192         derivatives_ok(r) = (data_count(r) > 0.1/(1-lambda));
00193 
00194     return derivatives_ok;
00195 }
00196 
00197 bool Model::updateNumProjections()
00198 {
00199     if( (R < N) && 
00200             (MSE(R-1)/MSE(R-2) <= phi) &&
00201             data_count(R-1)/data_count(0) > .9 &&
00202             data_count(R-1)*(1-lambda) > 0.5
00203             ){
00204         
00205         std::cerr << "****************** Adding Projection: " << x_0 << " ******************" << std::endl;
00206         
00207         // add projection
00208         R += 1;
00209 
00210         // add new projections to u and p all 1s
00211         u.resize(N,R);
00212         p.resize(N,R);
00213         a_xz.resize(N,R);
00214 
00215         for(int i=0; i<N; ++i){
00216             u(i,R-1) = (i == R-1);
00217             p(i,R-1) = (i == R-1);
00218             a_xz(i,R-1) = 0;
00219         }
00220 
00221         a_zz.resize(R);
00222         a_zz(R-1) = 1e-10;
00223         
00224         a_zres.resize(R);
00225 
00226         MSE.resize(R);
00227         MSE(R-1) = 0;
00228 
00229         e_cv.resize(R);
00230         y_target.resize(R);
00231 
00232         u_temp.resize(N,R);
00233         for (int i=0;i<N;++i)
00234             u_temp(i,R-1) = 0;
00235 
00236         data_count.resize(R);
00237         data_count(R-1) = 1e-10;
00238         derivatives_ok.resize(R);
00239         derivatives_ok(R-1) = 0;
00240 
00241         x_res.resize(N,R+1);
00242         beta.resize(R);
00243         z.resize(R);
00244         
00245         return true;
00246     }
00247     else
00248         return false;
00249 }
00250 
00251 Types::OutputT Model::predict(Types::Input x) const {
00252     Types::OutputT y = beta_0;
00253 
00254     Types::vector &x_local = const_cast<Types::vector&>(x_temp);
00255 
00256     x_local = x - x_0;
00257 
00258     for(int r=0; r<R; ++r){
00259         Types::RValue s = prec_inner_prod(column(u,r),x_local);
00260         //Types::RValue s = bindings::dot(column(u,r),x_local);
00261         y += beta(r) * s;
00262         x_local -= s * column(p,r);
00263     }
00264 
00265     return y;
00266         
00267 }
00268 
00269 void Model::project(Types::Input x, Types::vector& z) const {
00270     z.resize(x.size());
00271     z = x - x_0;
00272 
00273     for(int r=0; r<R; ++r){
00274         Types::RValue s = prec_inner_prod(column(u,r),z);
00275         //Types::RValue s = bindings::dot(column(u,r),z);
00276         z -= s * column(p,r);
00277     }
00278 }
00279 
00280 std::ostream& operator<<(std::ostream& out, const Model& m)
00281 {
00282     out << m.u << std::endl;
00283 }
00284 

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