libeblearn
/home/rex/ebltrunk/core/libeblearn/include/ebl_normalization.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2011 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 using namespace std;
00034 
00035 namespace ebl {
00036 
00038   // divisive_norm_module
00039 
00040   template <typename T, class Tstate>
00041   divisive_norm_module<T,Tstate>::
00042   divisive_norm_module(idxdim &kerdim_, int nf, bool mirror_, bool threshold_,
00043                        parameter<T,Tstate> *param_, const char *name_, bool af,
00044                        double cgauss, bool fsum_div, float fsum_split,
00045                        double epsilon_)
00046     : module_1_1<T,Tstate>(name_), mirror(mirror_), param(param_),
00047       convvar(true, name_),
00048       sqrtmod((T) .5), // square root module
00049       invmod(-1), // inverse module
00050       sqmod(2), // square module
00051       // by default, pass 0 for threshold and values
00052       // but every fprop updates these values
00053       thres((T) 1.0, (T) 1.0), // threshold module
00054       // create internal states, explanations are in fprop
00055       threshold(threshold_), nfeatures(nf), kerdim(kerdim_),
00056       across_features(af), epsilon(epsilon_) {
00057     // create weighting kernel
00058     if (kerdim.order() != 2)
00059       eblerror("expected kernel dimensions with order 2 but found order "
00060                << kerdim.order() << " in " << kerdim);
00061     w = create_gaussian_kernel<T>(kerdim, cgauss);
00062     idxdim stride(1, 1);
00063     // prepare convolutions and their kernels
00064     idx<intg> table = one2one_table(nfeatures);
00065     divconv = new convolution_module<T,Tstate>(param, kerdim, stride, table, 
00066                                                "divnorm_conv");
00067     idx_bloop1(kx, divconv->kernel.x, T)
00068       idx_copy(w, kx);
00070     if (across_features)
00071       idx_dotc(divconv->kernel.x, 1 / idx_sum(divconv->kernel.x),
00072                divconv->kernel.x);
00073     // convvar
00074     if (mirror) // switch between zero and mirror padding
00075       padding = new mirrorpad_module<T,Tstate>((w.dim(0) - 1)/2,
00076                                                 (w.dim(1) - 1)/2);
00077     else
00078       padding = new zpad_module<T,Tstate>(w.get_idxdim());
00079     convvar.add_module(padding);
00080     convvar.add_module(divconv);
00084     if (across_features)
00085       convvar.add_module(new fsum_module<T,Tstate>(fsum_div, fsum_split));
00086   }
00087 
00088   template <typename T, class Tstate>
00089   bool divisive_norm_module<T,Tstate>::optimize_fprop(Tstate &in, Tstate &out) {
00090     // memory optimization
00091     // if (false) {//hi && ho) { // dual buffers are provided, use them
00092     cout << "Using dual buffer memory optimization in divisive_norm_module"
00093          << endl;
00094     insq = out;
00095     invar = in;
00096     instd = out;
00097     thstd = in;
00098     invstd = out;
00099     return false;
00100   }
00101   
00102   template <typename T, class Tstate>
00103   divisive_norm_module<T,Tstate>::~divisive_norm_module() {
00104   }
00105       
00106   template <typename T, class Tstate>
00107   void divisive_norm_module<T,Tstate>::fprop(Tstate &in, Tstate &out) {  
00109     sqmod.fprop(in, insq);
00111     convvar.fprop(insq, invar);
00112     idx_addc(invar.x, (T) epsilon, invar.x); // TODO: temporary, avoid div by 0
00113     // if learning filters, make sure they stay positive
00114     //    if (param) idx_abs(divconv->kernel.x, divconv->kernel.x);
00116     sqrtmod.fprop(invar, instd);
00117     // the threshold is the average of all the standard deviations over
00118     // the entire input. values below it will be set to the threshold.
00119     if (threshold) { // don't update threshold for inputs
00121       T mm = (T) (idx_sum(instd.x) / (T) instd.size());
00122       thres.thres = mm;
00123       thres.val = mm;
00124     }
00126     thres.fprop(instd, thstd);
00128     invmod.fprop(thstd, invstd);
00130     mcw.fprop(in, invstd, out);
00131   }
00132 
00133   template <typename T, class Tstate>
00134   void divisive_norm_module<T,Tstate>::bprop(Tstate &in, Tstate &out) {
00136     insq.clear_dx();
00137     invar.clear_dx();
00138     instd.clear_dx();
00139     thstd.clear_dx();
00140     invstd.clear_dx();
00141     convvar.clear_dx();
00143     mcw.bprop(in, invstd, out);
00145     invmod.bprop(thstd, invstd);
00147     thres.bprop(instd, thstd);
00149     sqrtmod.bprop(invar, instd);
00151     convvar.bprop(insq, invar);
00153     sqmod.bprop(in, insq);
00154   }
00155 
00156   template <typename T, class Tstate>
00157   void divisive_norm_module<T,Tstate>::bbprop(Tstate &in, Tstate &out) {
00158     insq.clear_ddx();
00159     invar.clear_ddx();
00160     instd.clear_ddx();
00161     thstd.clear_ddx();
00162     invstd.clear_ddx();
00163     convvar.clear_ddx();
00165     mcw.bbprop(in, invstd, out);
00167     invmod.bbprop(thstd, invstd);
00169     thres.bbprop(instd, thstd);
00171     sqrtmod.bbprop(invar, instd);
00173     convvar.bbprop(insq, invar);
00175     sqmod.bbprop(in, insq);
00176   }
00177 
00178   template <typename T, class Tstate>
00179   void divisive_norm_module<T,Tstate>::dump_fprop(Tstate &in, Tstate &out) {  
00180     fprop(in, out);
00181     convvar.dump_fprop(insq, invar);
00182   }
00183 
00184   template <typename T, class Tstate>
00185   divisive_norm_module<T,Tstate>* divisive_norm_module<T,Tstate>::
00186   copy(parameter<T,Tstate> *p) {
00187     divisive_norm_module<T,Tstate> *d =
00188       new divisive_norm_module<T,Tstate>(kerdim, nfeatures, mirror,
00189                                          threshold, p, this->name());
00190     if (!p) // assign same parameter state if no parameters were specified      
00191       d->divconv->kernel = divconv->kernel;
00192     return d;
00193   }
00194   
00195   template <typename T, class Tstate>
00196   std::string divisive_norm_module<T, Tstate>::describe() {
00197     std::string desc;
00198     desc << "divisive_norm module " << this->name() << " with kernel "
00199          << kerdim << ", using " << (mirror ? "mirror" : "zero") << " padding"
00200          << ", using " << (param ? "learned" : "fixed") << " filter " << w;
00201     return desc;
00202   }
00203 
00205   // subtractive_norm_module
00206 
00207   template <typename T, class Tstate>
00208   subtractive_norm_module<T,Tstate>::
00209   subtractive_norm_module(idxdim &kerdim_, int nf, bool mirror_,
00210                           bool global_norm_, parameter<T,Tstate> *param_,
00211                           const char *name_, bool af, double cgauss,
00212                           bool fsum_div, float fsum_split)
00213     : module_1_1<T,Tstate>(name_), param(param_), convmean(true, name_), 
00214       global_norm(global_norm_), nfeatures(nf),
00215       kerdim(kerdim_), across_features(af), mirror(mirror_) {
00216     // create weighting kernel
00217     if (kerdim.order() != 2)
00218       eblerror("expected kernel dimensions with order 2 but found order "
00219                << kerdim.order() << " in " << kerdim);
00220     w = create_gaussian_kernel<T>(kerdim, cgauss);
00221     idxdim stride(1, 1);
00222     // prepare convolutions and their kernels
00223     idx<intg> table = one2one_table(nfeatures);
00224     meanconv = new convolution_module<T,Tstate>(param, kerdim, stride, table, 
00225                                                "subnorm_conv");
00226     idx_bloop1(kx, meanconv->kernel.x, T)
00227       idx_copy(w, kx);
00229     if (across_features)
00230       idx_dotc(meanconv->kernel.x, 1 / idx_sum(meanconv->kernel.x),
00231                meanconv->kernel.x);
00232     // convvar    
00233     if (mirror) // switch between zero and mirror padding
00234       padding = new mirrorpad_module<T,Tstate>((w.dim(0) - 1)/2,
00235                                                (w.dim(1) - 1)/2);
00236     else
00237       padding = new zpad_module<T,Tstate>(w.get_idxdim());
00238     convmean.add_module(padding);
00239     convmean.add_module(meanconv);
00243     if (across_features)
00244       convmean.add_module(new fsum_module<T,Tstate>(fsum_div, fsum_split));
00245   }
00246 
00247   template <typename T, class Tstate>
00248   subtractive_norm_module<T,Tstate>::~subtractive_norm_module() {
00249   }
00250       
00251   template <typename T, class Tstate>
00252   bool subtractive_norm_module<T,Tstate>::
00253   optimize_fprop(Tstate &in, Tstate &out) {
00254     // memory optimization
00255     // if (false) {//hi && ho) { // dual buffers are provided, use them
00256     cout << "Using dual buffer memory optimization in subtractive_norm_module"
00257          << endl;
00258     inmean = out;
00259     return true;
00260   }
00261   
00262   template <typename T, class Tstate>
00263   void subtractive_norm_module<T,Tstate>::fprop(Tstate &in, Tstate &out) {
00264     if (global_norm) // global normalization
00265       idx_std_normalize(in.x, in.x, (T*) NULL);
00266     // inmean = sum_j (w_j * in_j)
00267     convmean.fprop(in, inmean);
00268     // inzmean = in - inmean
00269     difmod.fprop(in, inmean, out);
00270   }
00271 
00272   template <typename T, class Tstate>
00273   void subtractive_norm_module<T,Tstate>::bprop(Tstate &in, Tstate &out) {
00274     // clear derivatives
00275     inmean.clear_dx();
00276     convmean.clear_dx();
00277     // in - mean
00278     difmod.bprop(in, inmean, out);
00279     // sum_j (w_j * in_j)
00280     convmean.bprop(in, inmean);
00281   }
00282 
00283   template <typename T, class Tstate>
00284   void subtractive_norm_module<T,Tstate>::bbprop(Tstate &in, Tstate &out) {
00285     // clear derivatives
00286     inmean.clear_ddx();
00287     convmean.clear_ddx();
00289     difmod.bbprop(in, inmean, out);
00291     convmean.bbprop(in, inmean);
00292   }
00293 
00294   template <typename T, class Tstate>
00295   void subtractive_norm_module<T,Tstate>::dump_fprop(Tstate &in, Tstate &out) {
00296     fprop(in, out);
00297     convmean.dump_fprop(in, inmean);
00298   }
00299 
00300   template <typename T, class Tstate>
00301   subtractive_norm_module<T,Tstate>* subtractive_norm_module<T,Tstate>::
00302   copy(parameter<T,Tstate> *p) {
00303     subtractive_norm_module<T,Tstate> *d = new subtractive_norm_module<T,Tstate>
00304       (kerdim, nfeatures, mirror, global_norm, p, this->name(),
00305        across_features);
00306     if (!p) // assign same parameter state if no parameters were specified
00307       d->meanconv->kernel = meanconv->kernel;
00308     return d;
00309   }
00310   
00311   template <typename T, class Tstate>
00312   std::string subtractive_norm_module<T, Tstate>::describe() {
00313     std::string desc;
00314     desc << "subtractive_norm module with " << (param ? "learned" : "fixed")
00315          << " mean weighting and kernel " << meanconv->kernel.x
00316          << ", " << (global_norm ? "" : "not ")
00317          << "using global normalization";
00318     return desc;
00319   }
00320 
00322   // contrast_norm_module
00323 
00324   template <typename T, class Tstate>
00325   contrast_norm_module<T,Tstate>::
00326   contrast_norm_module(idxdim &kerdim, int nf, bool mirror, bool threshold,
00327                        bool gnorm_, parameter<T,Tstate> *param,
00328                        const char *name_, bool af, bool lm, double cgauss,
00329                        bool fsum_div, float fsum_split, double epsilon)
00330     : module_1_1<T,Tstate>(name_),
00331       subnorm(kerdim, nf, mirror, gnorm_, lm ? param : NULL, name_, af, cgauss,
00332               fsum_div, fsum_split),
00333       divnorm(kerdim, nf, mirror, threshold, param, name_, af, cgauss,
00334               fsum_div, fsum_split, epsilon),
00335       learn_mean(lm) {
00336   }
00337 
00338   template <typename T, class Tstate>
00339   bool contrast_norm_module<T,Tstate>::optimize_fprop(Tstate &in, Tstate &out) {
00340     // memory optimization
00341     // if (false) {//hi && ho) { // dual buffers are provided, use them
00342     cout << "Using dual buffer memory optimization in contrast_norm_module"
00343          << endl;
00344     return true;
00345   }
00346   
00347   template <typename T, class Tstate>
00348   contrast_norm_module<T,Tstate>::~contrast_norm_module() {
00349   }
00350       
00351   template <typename T, class Tstate>
00352   void contrast_norm_module<T,Tstate>::fprop(Tstate &in, Tstate &out) {
00353     // subtractive normalization
00354     subnorm.fprop(in, tmp);
00355     // divisive normalization
00356     divnorm.fprop(tmp, out);
00357   }
00358 
00359   template <typename T, class Tstate>
00360   void contrast_norm_module<T,Tstate>::bprop(Tstate &in, Tstate &out) {
00361     // clear derivatives
00362     tmp.clear_dx();
00363     // divisive normalization
00364     divnorm.bprop(tmp, out);
00365     // subtractive normalization
00366     subnorm.bprop(in, tmp);
00367   }
00368 
00369   template <typename T, class Tstate>
00370   void contrast_norm_module<T,Tstate>::bbprop(Tstate &in, Tstate &out) {
00371     tmp.clear_ddx();
00372     // divisive normalization
00373     divnorm.bbprop(tmp, out);
00374     // subtractive normalization
00375     subnorm.bbprop(in, tmp);
00376   }
00377 
00378   template <typename T, class Tstate>
00379   void contrast_norm_module<T,Tstate>::dump_fprop(Tstate &in, Tstate &out) {
00380     subnorm.dump_fprop(in, tmp);
00381     divnorm.dump_fprop(tmp, out);    
00382   }
00383 
00384   template <typename T, class Tstate>
00385   contrast_norm_module<T,Tstate>* contrast_norm_module<T,Tstate>::
00386   copy(parameter<T,Tstate> *p) {
00387     contrast_norm_module<T,Tstate> *d = new contrast_norm_module<T,Tstate>
00388       (divnorm.kerdim, divnorm.nfeatures, divnorm.mirror, divnorm.threshold,
00389        global_norm, p, this->name(), divnorm.across_features, learn_mean);
00390     if (!p) { // assign same parameter state if no parameters were specified
00391       d->divnorm.divconv->kernel = divnorm.divconv->kernel;
00392       d->subnorm.meanconv->kernel = subnorm.meanconv->kernel;
00393     }
00394     return d;
00395   }
00396   
00397   template <typename T, class Tstate>
00398   std::string contrast_norm_module<T, Tstate>::describe() {
00399     std::string desc;
00400     desc << "contrast_norm module with " << subnorm.describe()
00401          << " and " << divnorm.describe();
00402     return desc;
00403   }
00404 
00406   // laplacian_module
00407 
00408   template <typename T, class Tstate>
00409   laplacian_module<T,Tstate>::
00410   laplacian_module(int nf, bool mirror_, bool global_norm_, const char *name_)
00411     : module_1_1<T,Tstate>(name_), mirror(mirror_),
00412       global_norm(global_norm_), nfeatures(nf) {
00413     // create filter
00414     filter = create_burt_adelson_kernel<T>();
00415     idxdim kerdim = filter.get_idxdim();
00416     idxdim stride(1,1);
00417     // prepare convolution
00418     idx<intg> table = one2one_table(nfeatures);
00419     conv =
00420       new convolution_module<T,Tstate>(&param, kerdim, stride, table);
00421     idx_bloop1(kx, conv->kernel.x, T)
00422       idx_copy(filter, kx);
00423     // create modules
00424     if (mirror) // switch between zero and mirror padding
00425       pad = new mirrorpad_module<T,Tstate>((kerdim.dim(0) - 1)/2,
00426                                            (kerdim.dim(1) - 1)/2);
00427     else
00428       pad = new zpad_module<T,Tstate>(filter.get_idxdim());
00429   }
00430 
00431   template <typename T, class Tstate>
00432   laplacian_module<T,Tstate>::~laplacian_module() {
00433     delete conv;
00434     delete pad;
00435   }
00436       
00437   template <typename T, class Tstate>
00438   void laplacian_module<T,Tstate>::fprop(Tstate &in, Tstate &out) {  
00439     if (global_norm) // global normalization
00440       idx_std_normalize(in.x, in.x, (T*) NULL);
00441     if (in.x.order() != padded.x.order()
00442         || in.x.order() != filtered.x.order()) {
00443       idxdim d(in.x.get_idxdim());
00444       d.setdims(1);
00445       padded = Tstate(d);
00446       filtered = Tstate(d);
00447     }
00448     pad->fprop(in, padded);
00449     conv->fprop(padded, filtered);
00450     diff.fprop(in, filtered, out);
00451   }
00452 
00453   template <typename T, class Tstate>
00454   laplacian_module<T,Tstate>* laplacian_module<T,Tstate>::copy() {
00455     return new laplacian_module<T,Tstate>(nfeatures, mirror, global_norm,
00456                                           this->name());
00457   }
00458   
00459   template <typename T, class Tstate>
00460   std::string laplacian_module<T, Tstate>::describe() {
00461     std::string desc;
00462     desc << "laplacian module " << this->name()
00463          << ", using " << (mirror ? "mirror" : "zero") << " padding"
00464          << ", " << (global_norm ? "" : "not ")
00465          << "using global normalization, using filter " << filter;
00466          // << ": " << filter.str();
00467     return desc;
00468   }
00469   
00470 } // end namespace ebl