libeblearn
/home/rex/ebltrunk/core/libeblearn/include/ebl_cost.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Yann LeCun and Pierre Sermanet *
00003  *   yann@cs.nyu.edu, pierre.sermanet@gmail.com *
00004  *   All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Redistribution under a license not approved by the Open Source
00014  *       Initiative (http://www.opensource.org) must display the
00015  *       following acknowledgement in all advertising material:
00016  *        This product includes software developed at the Courant
00017  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00018  *     * The names of the authors may not be used to endorse or promote products
00019  *       derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00025  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00028  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  ***************************************************************************/
00032 
00033 namespace ebl {
00034 
00036   // cost_module
00037   
00038   template<typename T1, typename T2, class Tstate1, class Tstate2>
00039   cost_module<T1,T2,Tstate1,Tstate2>::cost_module(idx<T1> &targets_)
00040     : targets(targets_), in2(targets.select(0, 0)), energies(targets_.dim(0)) {
00041   }
00042 
00043   template<typename T1, typename T2, class Tstate1, class Tstate2>  
00044   cost_module<T1,T2,Tstate1,Tstate2>::~cost_module() {
00045   }
00046 
00048   // euclidean_module
00049 
00050   template <typename T1, typename T2, class Tstate1, class Tstate2>
00051   euclidean_module<T1,T2,Tstate1,Tstate2>::euclidean_module(idx<T1> &targets_)
00052     : cost_module<T1,T2,Tstate1,Tstate2>(targets_) {
00053   }
00054 
00055   template <typename T1, typename T2, class Tstate1, class Tstate2>
00056   euclidean_module<T1,T2,Tstate1,Tstate2>::~euclidean_module() {
00057   }
00058 
00059   template <typename T1, typename T2, class Tstate1, class Tstate2>
00060   void euclidean_module<T1,T2,Tstate1,Tstate2>::
00061   fprop(Tstate1 &in1, Tstate2 &label, Tstate1 &energy) {
00062     idx<T1> target = targets.select(0, label.x.get());
00063     idx_copy(target, in2.x);
00064     // squared distance between in1 and target
00065     idx_sqrdist(in1.x, in2.x, energy.x);
00066     idx_dotc(energy.x, 0.5, energy.x); // multiply by .5
00067   }
00068   
00069   template <typename T1, typename T2, class Tstate1, class Tstate2>
00070   void euclidean_module<T1,T2,Tstate1,Tstate2>::
00071   bprop(Tstate1 &in1, Tstate2 &label, Tstate1 &energy) {
00072     idx_checkorder1(energy.x, 0); // energy.x must have an order of 0
00073     idx_sub(in1.x, in2.x, in1.dx); // derivative with respect to in1
00074     idx_dotc(in1.dx, energy.dx.get(), in1.dx); // multiply by energy derivative
00075     idx_minus(in1.dx, in2.dx); // derivative with respect to in2
00076   }
00077 
00078   // mse has this funny property that the bbprop method mixes up the
00079   // the first derivative after with the second derivative before, and
00080   // vice versa. Only the first combination is used here.
00081   template <typename T1, typename T2, class Tstate1, class Tstate2>
00082   void euclidean_module<T1,T2,Tstate1,Tstate2>::
00083   bbprop(Tstate1 &in1, Tstate2 &label, Tstate1 &energy) {
00084     idx_fill(in1.ddx, energy.dx.get());
00085   }
00086 
00087   template <typename T1, typename T2, class Tstate1, class Tstate2>
00088   double euclidean_module<T1,T2,Tstate1,Tstate2>::
00089   infer2(Tstate1 &i1, Tstate2 &infered_label, 
00090          infer_param &ip, Tstate2 *label, Tstate1 *energy) {
00091     infered_label.x.set(0);
00092     Tstate1 tmp;
00093     idx_bloop1(e, energies, T1) {
00094       fprop(i1, infered_label, tmp);
00095       idx_copy(tmp.x, e);
00096       infered_label.x.set(infered_label.x.get() + 1);
00097     }
00098     // TODO: use logadd_layer like in gblearn2 on energies?
00099     if (label && energy) // if groundtruth is passed, fill in its energy
00100       energy->x.set(energies.get(label->x.get())); 
00101     infered_label.x.set((T2) idx_indexmin(energies));
00102     return 0.0;
00103   }
00104 
00106   // logadd_layer
00107 
00108   template <class T>
00109   logadd_layer<T>::logadd_layer(intg thick, intg si, intg sj) {
00110     expdist = idx<T>(thick, si, sj);
00111     sumexp = idx<T>(thick);             // scaled partition function
00112   }
00113 
00114   template <class T>
00115   void logadd_layer<T>::fprop(fstate_idx<T> *in, fstate_idx<T> *out) {
00116     intg thick = in->x.dim(0);
00117     intg si = in->x.dim(1);
00118     intg sj = in->x.dim(2);
00119     expdist.resize(thick, si, sj);
00120     out->x.resize(thick);
00121     if (1 == (si * sj)) {
00122       // save time and precision if no replication
00123       idx<T> inx(in->x.select(2, 0));
00124       idx<T> m(inx.select(1, 0));
00125       idx<T> ed(expdist.select(2, 0));
00126       idx<T> ed1(ed.select(1, 0));
00127       idx_fill(ed1, 1.0);
00128       idx_fill(sumexp, 1.0);
00129       idx_copy(m, out->x);
00130     }   else {
00131       // spatially replicated
00132       // loop over output units
00133       { idx_bloop4(m, in->x, T, outx, out->x, T,
00134                    ed, expdist, T, sx, sumexp, T) {
00135           // first compute smallest element of m
00136           T mini = m.get(0, 0);
00137           { idx_bloop1(m1, m, T) {
00138               { idx_bloop1(m0, m1, T) {
00139                   if (m0.get() < mini)
00140                     mini = m0.get();
00141                 }
00142               }
00143             }
00144           }
00145           // now do log-add, and save exponentials
00146           T r = 0.0;
00147           T w = 1 / (si * sj);
00148           { idx_bloop2(m1, m, T, ed1, ed, T) {
00149               { idx_bloop2(m0, m1, T, ed0, ed1, T) {
00150                   ed0.set(w * exp(mini - m0.get()));
00151                   r += ed0.get();
00152                 }
00153               }
00154             }
00155           }
00156           sx.set(r);
00157           // put result in output
00158           outx.set(mini - log(r));
00159         }
00160       }
00161     }
00162   }
00163 
00164   template <class T>
00165   void logadd_layer<T>::bprop(fstate_idx<T> *in, fstate_idx<T> *out) {
00166     intg si = in->dx.dim(1);
00167     intg sj = in->dx.dim(2);
00168     if ((si * sj) == 1) {
00169       // save time and precision if no replication
00170       idx<T> indx(in->dx.select(2, 0));
00171       idx<T> m(indx.select(1, 0));
00172       idx_copy(out->dx, m);
00173     } else {
00174       // spatially replicated
00175       // loop over output units
00176       { idx_bloop4(m, in->dx, T, o, out->dx, T,
00177                    ed, expdist, T, sx, sumexp, T) {
00178           { idx_bloop2(m1, m, T, ed1, ed, T) {
00179               { idx_bloop2(m0, m1, T, ed0, ed1, T) {
00180                   m0.set(ed0.get() * o.get() / sx.get());
00181                 }
00182               }
00183             }
00184           }
00185         }
00186       }
00187     }
00188   }
00189 
00190   template <class T>
00191   void logadd_layer<T>::bbprop(fstate_idx<T> *in, fstate_idx<T> *out) {
00192     { idx_bloop2(o, out->ddx, T, i, in->ddx, T) {
00193         idx_fill(i, o.get());
00194       }
00195     }
00196   }
00197   
00199   // distance_l2
00200   
00201   template <class T>
00202   distance_l2<T>::distance_l2() { 
00203   }
00204   
00205   template <class T>
00206   distance_l2<T>::~distance_l2() { 
00207   }
00208   
00209   template <class T>
00210   void distance_l2<T>::fprop(fstate_idx<T> &in1, fstate_idx<T> &in2,
00211                              fstate_idx<T> &energy) { 
00212     // squared distance between in1 and target
00213     idx_sqrdist(in1.x, in2.x, energy.x);
00214     idx_dotc(energy.x, 0.5, energy.x); // multiply by .5
00215   }
00216   
00217   template <class T>
00218   void distance_l2<T>::bprop(fstate_idx<T> &in1, fstate_idx<T> &in2,
00219                              fstate_idx<T> &energy) {
00220     idx_checkorder1(energy.x, 0); // energy.x must have an order of 0
00221     idxdim d(in1.x);
00222     if (!tmp.same_dim(d)) { // keep tmp buffer around to avoid allocations
00223       idx<T> tmp2(d);
00224       tmp = tmp2;
00225     }
00226     idx_sub(in1.x, in2.x, tmp);
00227     idx_dotc(tmp, energy.dx.get(), tmp); // multiply by energy derivative
00228     idx_add(in1.dx, tmp, in1.dx); // derivative with respect to in1
00229     idx_sub(in2.dx, tmp, in2.dx); // derivative with respect to in2
00230   }
00231   
00232   template <class T>
00233   void distance_l2<T>::bbprop(fstate_idx<T> &in1, fstate_idx<T> &in2,
00234                               fstate_idx<T> &energy) { 
00235     idx_addc(in1.ddx, energy.dx.get(), in1.ddx);
00236     idx_addc(in2.ddx, energy.dx.get(), in2.ddx);
00237   }
00238   
00239   template <class T>
00240   void distance_l2<T>::forget(forget_param_linear &fp) { 
00241     err_not_implemented(); }
00242 
00243   template <class T>
00244   void distance_l2<T>::infer2_copy(fstate_idx<T> &in1, fstate_idx<T> &in2,
00245                                    fstate_idx<T> &energy) {
00246     idx_copy(in1.x, in2.x);
00247     idx_clear(energy.x);
00248   }
00249     
00251   // penalty_l1
00252 
00253   template <class T>
00254   penalty_l1<T>::penalty_l1(T threshold_)
00255     : ebm_1<T>("penalty_l1"), threshold(threshold_) {
00256   }
00257   
00258   template <class T>
00259   penalty_l1<T>::~penalty_l1() { 
00260   }
00261 
00262   template <class T>
00263   void penalty_l1<T>::fprop(fstate_idx<T> &in, fstate_idx<T> &energy) { 
00264     idx_sumabs(in.x, energy.x);
00265   }
00266   
00267   template <class T>
00268   void penalty_l1<T>::bprop(fstate_idx<T> &in, fstate_idx<T> &energy) { 
00269     idx_thresdotc_acc(in.x, energy.dx.get(), threshold, in.dx);
00270   }
00271   
00272   template <class T>
00273   void penalty_l1<T>::bbprop(fstate_idx<T> &in, fstate_idx<T> &energy) { 
00274     idx_addc(in.ddx, energy.dx.get(), in.ddx);
00275   }
00276   
00277   template <class T>
00278   void penalty_l1<T>::forget(forget_param_linear &fp) { 
00279     err_not_implemented(); }
00280   
00281 } // end namespace ebl