libeblearn
|
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>(¶m, 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