libeblearngui
|
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 // supervised_trainer_gui 00037 00038 template <class Tnet, class Tdata, class Tlabel> 00039 supervised_trainer_gui<Tnet, Tdata, Tlabel>:: 00040 supervised_trainer_gui(const char *title_, bool scroll_) 00041 : _st(NULL), _ds(NULL), _last_ds(NULL), 00042 datasource_wid(-1), datasource_wid2(-1), 00043 datasource_wid3(-1), datasource_wid4(-1), 00044 internals_wid(-1), internals_wid2(-1), internals_wid3(-1), 00045 scroll(scroll_), scroll_added(false), pos(0), dsgui(NULL) { 00046 if (title_) { 00047 title0 = title_; 00048 title0 << ": "; 00049 } 00050 } 00051 00052 template <class Tnet, class Tdata, class Tlabel> 00053 supervised_trainer_gui<Tnet, Tdata, Tlabel>::~supervised_trainer_gui() { 00054 if (w) w->replace_scroll_box_with_copy(this); 00055 } 00056 00057 template <class Tnet, class Tdata, class Tlabel> 00058 void supervised_trainer_gui<Tnet, Tdata, Tlabel>:: 00059 display_datasource(supervised_trainer<Tnet, Tdata, Tlabel> &st, 00060 labeled_datasource<Tnet, Tdata, Tlabel> &ds, 00061 infer_param &infp, 00062 unsigned int nh, unsigned int nw, unsigned int h0, 00063 unsigned int w0, double zoom, int wid, const char *title, 00064 bool scrolling) { 00065 // copy parameters 00066 _st = &st; 00067 _infp = &infp; 00068 _nh = nh; 00069 _nw = nw; 00070 _h0 = h0; 00071 _w0 = w0; 00072 if (!dsgui) 00073 dsgui = new labeled_datasource_gui<Tnet, Tdata, Tlabel>(false); 00074 // do a deep copy of dataset only when necessary 00075 if (scroll && !scrolling && (_last_ds != &ds)) { 00076 if (_ds) 00077 delete _ds; 00078 _ds = new labeled_datasource<Tnet, Tdata, Tlabel>(ds); 00079 dsgui->_ds = _ds; 00080 } 00081 _last_ds = &ds; 00082 // init datasource 00083 st.init(ds); 00084 vector<string*> lblstr; 00085 class_datasource<Tnet,Tdata,Tlabel> *cds = 00086 dynamic_cast<class_datasource<Tnet,Tdata,Tlabel>*>(&ds); 00087 if (cds) 00088 lblstr = cds->get_label_strings(); 00089 idxdim d = ds.sample_dims(); 00090 _h1 = h0 + nh * (d.dim(0) + 1) * 3; 00091 _w1 = w0 + nw * (d.dim(1) + 1) * 3; 00092 _zoom = zoom; 00093 // if no window given, create a new one or reuse previous one 00094 datasource_wid = (wid >= 0) ? wid : 00095 ((datasource_wid >= 0) ? datasource_wid : 00096 new_window((title ? title : "Supervised Trainer"))); 00097 select_window(datasource_wid); 00098 if (scroll && !scroll_added) { 00099 gui.add_scroll_box((scroll_box*) this); 00100 scroll_added = true; 00101 } 00102 disable_window_updates(); 00103 if (wid == -1) // clear only if we created the window 00104 clear_window(); 00105 // top left coordinates of datasets display 1 and 2 00106 unsigned int w01 = nh * (d.dim(1) + 2) + 5, h01 = h0 + 35; 00107 unsigned int w02 = (nh * (d.dim(1) + 2) + 5) * 2, h02 = h0 + 35; 00108 // working variables 00109 unsigned int h1 = h01, w1 = w01, nh1 = 0; 00110 unsigned int h2 = h02, w2 = w02, i2 = 0; 00111 bool correct; 00112 00113 // display top 00114 gui << set_colors(255, 0, 0, 255, 255, 255, 255, 127) << gui_only(); 00115 gui << at(h0, w0) << ds.name(); 00116 gui << black_on_white(); 00117 gui << at(h0 + 17, w0) << "Groundtruth"; 00118 gui << at(h0 + 17, w01) << "Correct & incorrect answers"; 00119 gui << at(h0 + 17, w02) << "Incorrect only"; 00120 gui << white_on_transparent(); 00121 00122 // 0. display dataset with groundtruth labels 00123 dsgui->display(ds, nh, nw, h0 + 35, w0, zoom, datasource_wid, NULL, true); 00124 00125 // loop on nh * nw first samples 00126 gui << white_on_transparent(); 00127 // loop to reach pos 00128 ds.seek_begin(); 00129 for (unsigned int p = 0; p < pos; ++p) 00130 ds.next(); // FIXME add a seek(p) method to ds 00131 for (unsigned int i = 0; (i < ds.size()) && (i2 < nh * nw); ++i) { 00132 // test sample 00133 ds.fprop_label_net(*st.label); 00134 correct = st.test_sample(ds, *st.label, *st.answers, infp); 00135 ds.next(); 00136 idx<Tnet> m = st.machine.in1.x.select(0, 0); 00137 00138 // 1. display dataset with incorrect and correct answers 00139 if (nh1 < nh) { 00140 draw_matrix_frame(m, (correct?0:128), 0, 0, h1, w1, zoom, zoom); 00141 if ((lblstr.size() > 0) && (lblstr[(int)st.answers->x.gget()])) 00142 gui << at(h1 + 2, w1 + 2) 00143 << (lblstr[(int)st.answers->x.gget()])->c_str(); 00144 w1 += d.dim(2) + 2; 00145 if (((i + 1) % nw == 0) && (i > 1)) { 00146 w1 = w01; 00147 h1 += d.dim(1) + 2; 00148 nh1++; 00149 } 00150 } 00151 // 2. display first nh * nw incorrect answers 00152 if (!correct) { 00153 draw_matrix_frame(m, (correct?0:128), 0, 0, h2, w2, zoom, zoom); 00154 if ((lblstr.size() > 0) && (lblstr[(int)st.answers->x.gget()])) 00155 gui << at(h2 + 2, w2 + 2) 00156 << (lblstr[(int)st.answers->x.gget()])->c_str(); 00157 w2 += d.dim(2) + 2; 00158 if (((i2 + 1) % nw == 0) && (i2 > 1)) { 00159 w2 = w02; 00160 h2 += d.dim(1) + 2; 00161 } 00162 i2++; 00163 } 00164 } 00165 enable_window_updates(); 00166 } 00167 00168 template <class Tnet, class Tdata, class Tlabel> 00169 void supervised_trainer_gui<Tnet, Tdata, Tlabel>:: 00170 display_internals(supervised_trainer<Tnet, Tdata, Tlabel> &st, 00171 labeled_datasource<Tnet, Tdata, Tlabel> &ds, 00172 infer_param &infp, gd_param &args, 00173 unsigned int ninternals, unsigned int display_h0, 00174 unsigned int display_w0, double display_zoom, 00175 int wid, const char *title) { 00176 if (ninternals == 0) return ; 00177 internals_wid = (wid >= 0) ? wid : 00178 ((internals_wid >= 0) ? internals_wid : 00179 new_window((title ? 00180 title : "Supervised Trainer: internal fprop states"))); 00181 internals_wid2 = (wid >= 0) ? wid : 00182 ((internals_wid2 >= 0) ? internals_wid2 : 00183 new_window((title ? 00184 title : "Supervised Trainer: internal bprop states"))); 00185 internals_wid3 = (wid >= 0) ? wid : 00186 ((internals_wid3 >= 0) ? internals_wid3 : 00187 new_window((title ? 00188 title : "Supervised Trainer: internal bbprop states"))); 00189 // freeze and clear display updates 00190 select_window(internals_wid); 00191 disable_window_updates(); 00192 clear_window(); 00193 select_window(internals_wid2); 00194 disable_window_updates(); 00195 clear_window(); 00196 select_window(internals_wid3); 00197 disable_window_updates(); 00198 clear_window(); 00199 // prepare dataset 00200 st.init(ds); 00201 unsigned int wfdisp = 0, hfdisp = 0; 00202 unsigned int wfdisp2 = 0, hfdisp2 = 0; 00203 unsigned int wfdisp3 = 0, hfdisp3 = 0; 00204 00205 // display first ninternals samples 00206 trainable_module_gui mg; 00207 bbstate_idx<Tnet> input(ds.sample_dims()); 00208 bbstate_idx<Tlabel> label(ds.label_dims()); 00209 for (unsigned int i = 0; (i < ds.size()) && (i < ninternals); ++i) { 00210 // prepare input 00211 ds.fprop(input, label); 00212 // // fprop and bprop 00213 // //st.test_sample(*st.input, st.label, infp); 00214 // // TODO: display is influencing learning, remove influence 00215 // // st.learn_sample(*st.input, st.label.get(), args); 00216 // st.machine.fprop(*st.input, st.label, st.energy); 00217 // st.param.clear_dx(); 00218 // st.machine.bprop(*st.input, st.label, st.energy); 00219 // st.param.clear_ddx(); 00220 // st.machine.bbprop(*st.input, st.label, st.energy); 00221 00222 // display fprop 00223 mg.display_fprop(st.machine, input, label, st.energy, 00224 hfdisp, wfdisp, display_zoom, (Tnet) -1.0, (Tnet) 1.0, 00225 true, internals_wid); 00226 // display bprop 00227 select_window(internals_wid2); 00228 mg.display_bprop(st.machine, input, label, st.energy, 00229 hfdisp2, wfdisp2, display_zoom, (Tnet) -1.0, (Tnet) 1.0, 00230 true, internals_wid2); 00231 // display bprop 00232 select_window(internals_wid3); 00233 mg.display_bbprop(st.machine, input, label, st.energy, 00234 hfdisp3, wfdisp3, display_zoom, (Tnet) -.01, (Tnet) .01, 00235 true, internals_wid3); 00236 ds.next(); // next sample 00237 hfdisp += 10; 00238 hfdisp2 += 10; 00239 hfdisp3 += 10; 00240 } 00241 // unfreeze display updates 00242 select_window(internals_wid); 00243 enable_window_updates(); 00244 select_window(internals_wid2); 00245 enable_window_updates(); 00246 select_window(internals_wid3); 00247 enable_window_updates(); 00248 } 00249 00250 template <class Tnet, class Tdata, class Tlabel> 00251 void supervised_trainer_gui<Tnet, Tdata, Tlabel>:: 00252 display_correctness(bool incorrect, bool up, 00253 supervised_trainer<Tnet, Tdata, Tlabel> &st, 00254 labeled_datasource<Tnet, Tdata, Tlabel> &ds, 00255 infer_param &infp, 00256 unsigned int nh, unsigned int nw, 00257 bool print_raw_outputs, bool draw_all_jitter, 00258 unsigned int h0, unsigned int w0, double zoom, int wid, 00259 const char *title, bool scrolling) { 00260 if (!ds.bkeep_outputs) 00261 eblerror("answers are not kept in datasource, activate keeping by " 00262 << "setting keep_outputs = 1"); 00263 // copy parameters 00264 _st = &st; 00265 _infp = &infp; 00266 _nh = nh; 00267 _nw = nw; 00268 _h0 = h0; 00269 _w0 = w0; 00270 if (!dsgui) 00271 dsgui = new labeled_datasource_gui<Tnet, Tdata, Tlabel>(false); 00272 // do a deep copy of dataset only when necessary 00273 if (scroll && !scrolling && (_last_ds != &ds)) { 00274 if (_ds) 00275 delete _ds; 00276 _ds = new labeled_datasource<Tnet, Tdata, Tlabel>(ds); 00277 dsgui->_ds = _ds; 00278 } 00279 _last_ds = &ds; 00280 // init datasource 00281 st.init(ds); 00282 class_datasource<Tnet,Tdata,Tlabel> *cds = 00283 dynamic_cast<class_datasource<Tnet,Tdata,Tlabel>*>(&ds); 00284 // find out sample size 00285 idxdim d = ds.sample_dims(); 00286 _h1 = h0 + nh * (d.dim(0) + 1) * 3; 00287 _w1 = w0 + nw * (d.dim(1) + 1) * 3; 00288 _zoom = zoom; 00289 string corname = (incorrect ? "incorrect" : "correct"); 00290 title1 = title0; 00291 title1 << "Incorrect classifications, lowest energies first (pid " 00292 << pid() << ")"; 00293 title2 = title0; 00294 title2 << "Incorrect classifications, highest energies first (pid " 00295 << pid() << ")"; 00296 title3 = title0; 00297 title3 << "Correct classifications, lowest energies first (pid " 00298 << pid() << ")"; 00299 title4 = title0; 00300 title4 << "Correct classifications, highest energies first (pid " 00301 << pid() << ")"; 00302 // if no window given, create a new one or reuse previous one 00303 if (incorrect) { // incorrect window 00304 if (up) { 00305 datasource_wid2 = (wid >= 0) ? wid : 00306 ((datasource_wid2 >= 0) ? datasource_wid2 : 00307 new_window((title ? title : title1.c_str()))); 00308 select_window(datasource_wid2); 00309 } else { 00310 datasource_wid3 = (wid >= 0) ? wid : 00311 ((datasource_wid3 >= 0) ? datasource_wid3 : 00312 new_window((title ? title : title2.c_str()))); 00313 select_window(datasource_wid3); 00314 } 00315 } else { // correct window 00316 if (up) { 00317 datasource_wid = (wid >= 0) ? wid : 00318 ((datasource_wid >= 0) ? datasource_wid : 00319 new_window((title ? title : title3.c_str()))); 00320 select_window(datasource_wid); 00321 } else { 00322 datasource_wid4 = (wid >= 0) ? wid : 00323 ((datasource_wid4 >= 0) ? datasource_wid4 : 00324 new_window((title ? title : title4.c_str()))); 00325 select_window(datasource_wid4); 00326 } 00327 } 00328 if (scroll && !scroll_added) { 00329 gui.add_scroll_box((scroll_box*) this); 00330 scroll_added = true; 00331 } 00332 disable_window_updates(); 00333 if (wid == -1) // clear only if we created the window 00334 clear_window(); 00335 // top left coordinates of datasets display 1 and 2 00336 unsigned int w01 = w0, h01 = h0 + 20; 00337 unsigned int h1 = h01, w1 = w01, nh1 = 0; 00338 00339 // get the indices of incorrect or correct samples ordered by their energies 00340 // this assumes that all samples have already been tested for correctness 00341 intg tally = idx_sum<intg>(ds.correct); 00342 if (incorrect) tally = ds.count_included_samples() - tally; 00343 idx<intg> indices(tally); 00344 idx<double> energies(tally); 00345 intg inc = 0, i = 0; 00346 if(!incorrect) { 00347 idx_bloop2(correct, ds.correct, ubyte, energy, ds.energies, double) { 00348 if (ds.included_sample(i)) { 00349 if (correct.get() == !incorrect) { // found correct or incorrect sample 00350 indices.set(i, inc); 00351 energies.set(energy.get(), inc); 00352 inc++; 00353 } 00354 } 00355 i++; // data iterator 00356 } 00357 } 00358 else return; // TODO: fix bug for incorrect samples. 00359 00360 // if (inc != indices.dim(0)) 00361 // eblerror("expected " << indices.dim(0) << " " << corname 00362 // << " samples but found " << inc); 00363 00364 // display top 00365 gui << set_colors(255, 0, 0, 255, 255, 255, 255, 127) << gui_only(); 00366 gui << at(h0, w0) << ds.name() << ": "; 00367 gui << black_on_white(); 00368 if (inc == 0) { 00369 gui << "no " << corname << " samples." << endl; 00370 enable_window_updates(); 00371 return ; 00372 } 00373 // TODO: energies becomes unrealistic garbage sometimes, gets fp exceptions 00374 // gui << indices.dim(0) << " / " << ds.correct.dim(0) << " " 00375 // << corname << " samples with energies max: " 00376 // << (double) idx_max(energies) << " min: " << (double) idx_min(energies); 00377 gui << white_on_transparent(); 00378 00379 // sort indices by energy 00380 if (up) idx_sortup(energies, indices); 00381 else idx_sortdown(energies, indices); 00382 00383 // loop on nh * nw first samples 00384 Tlabel answer, bgid = -1; 00385 if (cds) 00386 cds->get_class_id("bg"); 00387 bbstate_idx<Tnet> input(ds.sample_dims()); 00388 mstate<bbstate_idx<Tnet> > minput; 00389 bbstate_idx<Tlabel> label(ds.label_dims()); 00390 bbstate_idx<Tnet> jitt(1, 1); 00391 uint hmax = 0; 00392 for (unsigned int i = 0; (i < indices.dim(0)) && (i < nh * nw); ++i) { 00393 if (indices.get(i) >= ds.raw_outputs.dim(0)) break ; 00394 idx<Tnet> raw = ds.raw_outputs.select(0, indices.get(i)); 00395 idx<Tnet> answers = ds.answers.select(0, indices.get(i)); 00396 idx<Tnet> target = ds.targets.select(0, indices.get(i)); 00397 answer = (Tlabel) answers.get(0); 00398 ds.select_sample(indices.get(i)); 00399 minput.clear(); 00400 if (ds.mstate_samples()) ds.fprop_data(minput); 00401 else { 00402 ds.fprop_data(input); 00403 minput.push_back_new(input); 00404 } 00405 ds.fprop_label(label); 00406 uint ht = 0, wt = 0; 00407 00408 // 1. display dataset with incorrect and correct answers 00409 if (nh1 < nh) { 00410 // draw sample 00411 for (uint a = 0; a < minput.size(); ++a) { 00412 idx<Tnet> m = minput[a].x.shift_dim(0, 2); 00413 draw_matrix(m, h1, w1 + wt, zoom, zoom); 00414 wt += m.dim(1) + 2; 00415 ht = std::max(ht, (uint) m.dim(0)); 00416 hmax = std::max(hmax, (uint) m.dim(0)); 00417 } 00418 ostringstream s; 00419 s.precision(2); 00420 if (cds) 00421 s << cds->get_class_name((int)answer) << " "; 00422 s << energies.get(i); 00423 gui << at(h1 + 2, w1 + 2) << s.str().c_str(); 00424 // print raw outputs 00425 if (print_raw_outputs) { 00426 for (uint a = 0; a < raw.dim(0); ++a) { 00427 s.str(""); s << raw.get(a); 00428 gui << at(h1 + 17 + a * 15, w1 + 2) << s.str().c_str(); 00429 } 00430 } else { // print outputs answers 00431 for (uint a = 0; a < answers.dim(0); ++a) { 00432 s.str(""); s << answers.get(a); 00433 gui << at(h1 + 17 + a * 15, w1 + 2) << s.str().c_str(); 00434 } 00435 } 00436 // print target info 00437 //ds.fprop_jitter(jitt); 00438 for (uint a = 0; a < target.dim(0); ++a) { 00439 s.str(""); s << target.gget(a); 00440 gui << at(h1 + 17 + a * 15, w1 + wt - 35) << s.str().c_str(); 00441 } 00442 // print correct info when incorrect 00443 if (incorrect && cds) { 00444 s.str(""); 00445 s << "(" << cds->get_class_name((int) label.x.get(0)) << ")"; 00446 gui << at(h1 + d.dim(0) - 15, w1 + 2) << s.str().c_str(); 00447 } 00448 // draw scale box if not a background class 00449 if (answer != bgid && answers.dim(0) > 2) { 00450 float scale = answers.gget(2), hoff = 0, woff = 0; 00451 rect<float> r; 00452 if (scale > 0) { 00453 scale = 1 / scale; 00454 if (answers.dim(0) == 5) { 00455 hoff = answers.gget(3) * ht; 00456 woff = answers.gget(4) * ht; 00457 } 00458 r = rect<float>(h1 + hoff, w1 + woff, ht, wt); 00459 r.scale_centered(scale, scale); 00460 draw_box(r, 0, 0, 255); 00461 // draw all groundtruth 00462 if (draw_all_jitter) { 00463 ds.fprop_jitter(jitt); 00464 idx_bloop1(ji, jitt.x, Tnet) { 00465 scale = ji.gget(0); // TODO: fix hardcoded offset 00466 if (scale != 0) { 00467 scale = 1 / scale; 00468 hoff = ji.gget(1) * ht;// TODO: fix hardcoded offset 00469 woff = ji.gget(2) * ht;// TODO: fix hardcoded offset 00470 r = rect<float>(h1 + hoff, w1 + woff, ht, wt); 00471 r.scale_centered(scale, scale); 00472 draw_box(r, 0, 255, 0); 00473 } 00474 } 00475 } 00476 } 00477 // draw groundtruth box 00478 scale = target.gget(2); // TODO: fix hardcoded offset 00479 if (scale != 0) { 00480 scale = 1 / scale; 00481 hoff = target.gget(3) * ht;// TODO: fix hardcoded offset 00482 woff = target.gget(4) * ht;// TODO: fix hardcoded offset 00483 r = rect<float>(h1 + hoff, w1 + woff, ht, wt); 00484 r.scale_centered(scale, scale); 00485 draw_box(r, 255, 0, 0); 00486 } 00487 } 00488 // if ((ds.lblstr) && (ds.lblstr->at(st.answer.x.get()))) 00489 // gui << at(h1 + 2, w1 + 2) 00490 // << (ds.lblstr->at(st.answer.x.get()))->c_str(); 00491 w1 += wt + 2; 00492 if (((i + 1) % nw == 0) && (i > 1)) { 00493 w1 = w01; 00494 h1 += hmax + 2; 00495 nh1++; 00496 hmax = 0; 00497 } 00498 } 00499 } 00500 enable_window_updates(); 00501 } 00502 00504 // inherited methods to implement for scrolling capabilities 00505 00506 template<class Tnet, class Tdata, class Tlabel> 00507 void supervised_trainer_gui<Tnet, Tdata, Tlabel>::display_next() { 00508 if (next_page()) { 00509 pos = MIN(_ds->size(), pos + _nh * _nw); 00510 00511 display_datasource(*_st, *_ds, *_infp, _nh, _nw, _h0, _w0, _zoom, 00512 -1, NULL, true); 00513 } 00514 } 00515 00516 template<class Tnet, class Tdata, class Tlabel> 00517 void supervised_trainer_gui<Tnet, Tdata, Tlabel>::display_previous() { 00518 if (previous_page()) { 00519 pos = std::max((uint) 0, pos - _nh * _nw); 00520 display_datasource(*_st, *_ds, *_infp, _nh, _nw, _h0, _w0, _zoom, 00521 -1, NULL, true); 00522 } 00523 } 00524 00525 template<class Tnet, class Tdata, class Tlabel> 00526 unsigned int supervised_trainer_gui<Tnet, Tdata, Tlabel>::max_pages() { 00527 return dsgui->max_pages(); 00528 } 00529 00530 template<class Tnet, class Tdata, class Tlabel> 00531 supervised_trainer_gui<Tnet, Tdata, Tlabel>* 00532 supervised_trainer_gui<Tnet, Tdata, Tlabel>::copy() { 00533 // scroll_box0* supervised_trainer_gui<Tnet, Tdata, Tlabel>::copy() { 00534 cout << "supervsed_trainer_gui::copy."<<endl; 00535 supervised_trainer_gui<Tnet, Tdata, Tlabel> *stcopy = 00536 new supervised_trainer_gui<Tnet, Tdata, Tlabel>(*this); 00537 stcopy->dsgui = dsgui->copy(); 00538 stcopy->_ds = _ds; 00539 stcopy->_last_ds = _last_ds; 00540 stcopy->_st = _st; 00541 return stcopy; 00542 } 00543 00544 } // end namespace ebl