PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // RandomSamplesVMatrix.cc 00004 // 00005 // Copyright (C) 2006 Olivier Delalleau 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // 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 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 // Authors: Olivier Delalleau 00036 00040 #include "RandomSamplesVMatrix.h" 00041 #include <plearn/vmat/VMatLanguage.h> 00042 00043 namespace PLearn { 00044 using namespace std; 00045 00046 PLEARN_IMPLEMENT_OBJECT( 00047 RandomSamplesVMatrix, 00048 "VMat that samples on-the-fly random examples from its source.", 00049 "More precisely, this VMat will:\n" 00050 "- contain all examples from its source that match the 'is_preserved'\n" 00051 " VPL program (by default, no example is systematically preserved)\n" 00052 "- fill the rest of the data with random source examples that do not\n" 00053 " match that program\n" 00054 "\n" 00055 "It is important to note that random examples are sampled at each call\n" 00056 "of the 'getNewRow(..)' method, so that the data viewed by this VMatrix\n" 00057 "is not constant (except for the rows that are preserved).\n" 00058 "\n" 00059 "The ordering of the examples is random, and the total length of this\n" 00060 "VMat is determined from the 'length' option, or from the number of non-\n" 00061 "preserved examples if the 'n_non_preserved' option is set.\n" 00062 ); 00063 00065 // RandomSamplesVMatrix // 00067 RandomSamplesVMatrix::RandomSamplesVMatrix(): 00068 alternate_targets(false), 00069 is_preserved("0"), 00070 n_non_preserved(-1), 00071 seed(1827), 00072 random_gen(new PRandom()) 00073 { 00074 } 00075 00077 // declareOptions // 00079 void RandomSamplesVMatrix::declareOptions(OptionList& ol) 00080 { 00081 // ### Declare all of this object's options here. 00082 // ### For the "flags" of each option, you should typically specify 00083 // ### one of OptionBase::buildoption, OptionBase::learntoption or 00084 // ### OptionBase::tuningoption. If you don't provide one of these three, 00085 // ### this option will be ignored when loading values from a script. 00086 // ### You can also combine flags, for example with OptionBase::nosave: 00087 // ### (OptionBase::buildoption | OptionBase::nosave) 00088 00089 declareOption(ol, "is_preserved", &RandomSamplesVMatrix::is_preserved, 00090 OptionBase::buildoption, 00091 "VPL program that indicates if a sample is preserved."); 00092 00093 declareOption(ol, "n_non_preserved", 00094 &RandomSamplesVMatrix::n_non_preserved, 00095 OptionBase::buildoption, 00096 "If given a non-negative value, it indicates the total number of\n" 00097 "non-preserved examples that are added to this VMat, and overrides\n" 00098 "the 'length' option. Two special negative values can be used:\n" 00099 " -1: this option is ignored, and the number of non-preserved\n" 00100 " samples is set so that this VMat has either the desired length\n" 00101 " (if the 'length' option is provided), or the same length as\n" 00102 " its source otherwise.\n" 00103 " -2: the number of non-preserved examples is set exactly to match\n" 00104 " the number of preserved examples."); 00105 00106 declareOption(ol, "alternate_targets", 00107 &RandomSamplesVMatrix::alternate_targets, 00108 OptionBase::buildoption, 00109 "If set to 1, then this VMat will never sample two consecutive rows\n" 00110 "having the same target."); 00111 00112 declareOption(ol, "seed", &RandomSamplesVMatrix::seed, 00113 OptionBase::buildoption, 00114 "Seed for random number generation."); 00115 00116 // Now call the parent class' declareOptions 00117 inherited::declareOptions(ol); 00118 } 00119 00121 // build // 00123 void RandomSamplesVMatrix::build() 00124 { 00125 inherited::build(); 00126 build_(); 00127 } 00128 00130 // build_ // 00132 void RandomSamplesVMatrix::build_() 00133 { 00134 if (!source) 00135 return; 00136 00137 random_gen->manual_seed(seed); 00138 00139 // Initialize VPL program. 00140 VMatLanguage program; 00141 TVec<string> fieldnames; 00142 program.setSource(source); 00143 program.compileString(is_preserved, fieldnames); 00144 00145 // Find out which samples need to be kept. 00146 int n = source->length(); 00147 Vec row(source->width()); 00148 Vec result(1); 00149 non_preserved.resize(0); 00150 indices.resize(0); 00151 for (int i = 0; i < n; i++) { 00152 program.run(i, result); 00153 if (fast_exact_is_equal(result[0], 1)) 00154 // Sample i is to be preserved. 00155 indices.append(i); 00156 else 00157 non_preserved.append(i); 00158 } 00159 00160 // Find out length of this VMat if the 'n_non_preserved' option is set. 00161 PLASSERT( n_non_preserved >= 0 || n_non_preserved == -1 || 00162 n_non_preserved == -2 ); 00163 if (n_non_preserved >= 0) 00164 length_ = indices.length() + n_non_preserved; 00165 else if (n_non_preserved == -2) 00166 length_ = indices.length() * 2; 00167 else if (length_ < 0) 00168 length_ = source->length(); 00169 00170 // Specific pre-processing for the case where 'alternate_targets' is true. 00171 if (alternate_targets) { 00172 // Currently this feature is not implemented when we preserve examples 00173 // (just because it is a bit more complex). 00174 if (!indices.isEmpty()) 00175 PLERROR("In RandomSamplesVMatrix::build_ - The 'alternate_targets'" 00176 " option is not implemented yet in the case where some " 00177 "examples are preserved. Please implement it!"); 00178 if (source->targetsize() != 1) 00179 PLERROR("In RandomSamplesVMatrix::build_ - The source must have " 00180 "a targetsize of 1 in order to use the " 00181 "'alternate_targets' option"); 00182 // First we need to find the number of targets. 00183 map<real, TVec<int> > by_target_map; // Map a target to its samples. 00184 Vec input, target; 00185 real weight; 00186 target_to_idx.clear(); 00187 for (int i = 0; i < source->length(); i++) { 00188 source->getExample(i, input, target, weight); 00189 by_target_map[target[0]].append(i); 00190 if (target_to_idx.count(target[0]) == 0) { 00191 int n_cur = target_to_idx.size(); 00192 target_to_idx[target[0]] = n_cur; 00193 } 00194 } 00195 int n_targets = by_target_map.size(); 00196 // Convert from map to vector (for convenience). 00197 by_target.resize(n_targets); 00198 map<real, TVec<int> >::const_iterator it = by_target_map.begin(); 00199 for (int i = 0; i < n_targets; i++, it++) 00200 by_target[i] = it->second; 00201 // Build a map from a target index to all other target indices that may 00202 // be used afterwards, with corresponding probabilities. 00203 target_list.resize(n_targets); 00204 target_distr.resize(n_targets); 00205 for (int i = 0; i < n_targets; i++) { 00206 TVec<int>& tl = target_list[i]; 00207 tl.resize(0); 00208 Vec& td = target_distr[i]; 00209 td.resize(0); 00210 int n_others = 0; 00211 00212 for (int j = 0; j < n_targets; j++) 00213 if (j != i) { 00214 tl.append(j); // This is the list of all targets, 00215 // excluding 'i'. 00216 td.append(by_target[j].length()); 00217 n_others += by_target[j].length(); 00218 } 00219 td /= real(n_others); // Normalize probabilities. 00220 } 00221 00222 // Resize 'last_targets'. 00223 last_targets.resize(source->length()); 00224 } 00225 00226 // Fill in 'indices' with as many -1 as necessary. 00227 if (indices.length() > length_) 00228 PLERROR("In RandomSamplesVMatrix::build_ - The number of preserved" 00229 "samples (%d) is higher than the length of this VMat (%d)", 00230 indices.length(), length_); 00231 while (indices.length() != length_) 00232 indices.append(-1); 00233 00234 // Shuffle the list of indices. 00235 random_gen->shuffleElements(indices); 00236 00237 setMetaInfoFromSource(); 00238 } 00239 00241 // getNewRow // 00243 void RandomSamplesVMatrix::getNewRow(int i, const Vec& v) const 00244 { 00245 if (indices[i] >= 0) 00246 source->getRow(indices[i], v); 00247 else { 00248 int random_sample; 00249 if (alternate_targets && i > 0) { 00250 // Note that the first sample may be any class since it has no 00251 // previous sample in this VMat. 00252 real previous_target = last_targets[i - 1]; 00253 int previous_target_idx = target_to_idx[previous_target]; 00254 int random_target = random_gen->multinomial_sample( 00255 target_distr[previous_target_idx]); 00256 const TVec<int>& candidates = 00257 by_target[target_list[previous_target_idx][random_target]]; 00258 int random_sample_idx = random_gen->uniform_multinomial_sample( 00259 candidates.length()); 00260 random_sample = candidates[random_sample_idx]; 00261 PLASSERT( non_preserved.length() == source->length() ); 00262 } else { 00263 random_sample = 00264 random_gen->uniform_multinomial_sample(non_preserved.length()); 00265 } 00266 source->getRow(non_preserved[random_sample], v); 00267 if (alternate_targets) 00268 last_targets[i] = v[source->inputsize()]; 00269 } 00270 } 00271 00273 // makeDeepCopyFromShallowCopy // 00275 void RandomSamplesVMatrix::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00276 { 00277 inherited::makeDeepCopyFromShallowCopy(copies); 00278 00279 deepCopyField(random_gen, copies); 00280 deepCopyField(non_preserved, copies); 00281 deepCopyField(indices, copies); 00282 deepCopyField(last_targets, copies); 00283 deepCopyField(target_list, copies); 00284 deepCopyField(target_distr, copies); 00285 deepCopyField(by_target, copies); 00286 } 00287 00288 } // end of namespace PLearn 00289 00290 00291 /* 00292 Local Variables: 00293 mode:c++ 00294 c-basic-offset:4 00295 c-file-style:"stroustrup" 00296 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00297 indent-tabs-mode:nil 00298 fill-column:79 00299 End: 00300 */ 00301 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :