libeblearn
|
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