PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // MultiTargetOneHotVMatrix.cc 00004 // 00005 // Copyright (C) 2004 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 /* ******************************************************* 00036 * $Id: MultiTargetOneHotVMatrix.cc,v 1.7 2005/03/16 18:26:25 delallea Exp $ 00037 ******************************************************* */ 00038 00039 // Authors: Olivier Delalleau 00040 00044 #include "MultiTargetOneHotVMatrix.h" 00045 #include <plearn/math/TMat_maths.h> 00046 00047 namespace PLearn { 00048 using namespace std; 00049 00051 // MultiTargetOneHotVMatrix // 00053 MultiTargetOneHotVMatrix::MultiTargetOneHotVMatrix() 00054 : missing_target(-FLT_MAX), 00055 reweight_targets(false), 00056 target_val("specific_target"), 00057 verbosity(1), 00058 hot_value(1), 00059 cold_value(0) 00060 { 00061 } 00062 00063 PLEARN_IMPLEMENT_OBJECT(MultiTargetOneHotVMatrix, 00064 "This VMatrix transforms a multi-target source into a single target one with an added one-hot vector.", 00065 "The source VMatrix is given by its input part (in 'source'), and by its target part\n" 00066 "(in 'source_target'). The target being d-dimensional, each data point is repeated\n" 00067 "in this VMatrix as many times as it has non-missing targets. For each non-missing\n" 00068 "target, a one-hot vector (with a '1' corresponding to this target index) is added\n" 00069 "to the input part, and the target value (now 1-dimensional) is either the value for\n" 00070 "this target, or the maximum of all target values (depending on 'target_val').\n" 00071 "If the 'target_descriptor' option is set, it must be a VMat of length 'd', that\n" 00072 "gives an additional input descriptor to append to each example depending on the\n" 00073 "target. This VMat's first column must be the name of the target, which must\n" 00074 "correspond to a field name in 'source_target'.\n" 00075 "If one wants to set a weight, it must be set in 'source'.\n" 00076 ); 00077 00079 // declareOptions // 00081 void MultiTargetOneHotVMatrix::declareOptions(OptionList& ol) 00082 { 00083 // ### Declare all of this object's options here 00084 // ### For the "flags" of each option, you should typically specify 00085 // ### one of OptionBase::buildoption, OptionBase::learntoption or 00086 // ### OptionBase::tuningoption. Another possible flag to be combined with 00087 // ### is OptionBase::nosave 00088 00089 declareOption(ol, "source_target", &MultiTargetOneHotVMatrix::source_target, OptionBase::buildoption, 00090 "The VMat containing the target information for each sample of 'source'."); 00091 00092 declareOption(ol, "target_descriptor", &MultiTargetOneHotVMatrix::target_descriptor, OptionBase::buildoption, 00093 "The VMat containing the additional target descriptors (optional)."); 00094 00095 declareOption(ol, "missing_target", &MultiTargetOneHotVMatrix::missing_target, OptionBase::buildoption, 00096 "A target in the source VMatrix equal to this value will be treated as missing."); 00097 00098 declareOption(ol, "reweight_targets", &MultiTargetOneHotVMatrix::reweight_targets, OptionBase::buildoption, 00099 "If set to 1, a weight column will be appended, with a weight of 1 for the most\n" 00100 "frequent target, and > 1 for other targets (=> equal weight to each target)."); 00101 00102 declareOption(ol, "target_val", &MultiTargetOneHotVMatrix::target_val, OptionBase::buildoption, 00103 "How the target value is computed:\n" 00104 " - 'max' : the maximum of all targets\n" 00105 " - 'specific_target' : the value of the target considered"); 00106 00107 declareOption(ol, "verbosity", &MultiTargetOneHotVMatrix::verbosity, OptionBase::buildoption, 00108 "Controls the amount of output."); 00109 00110 declareOption(ol, "hot_value", &MultiTargetOneHotVMatrix::hot_value, OptionBase::buildoption, 00111 "Hot value in one-hot representation. If it is the same as the cold_value,\n" 00112 "then the actual target value, as defined by the target_val option, is used."); 00113 00114 declareOption(ol, "cold_value", &MultiTargetOneHotVMatrix::cold_value, OptionBase::buildoption, 00115 "Cold value in one-hot representation."); 00116 00117 declareOption(ol, "source_and_target", &MultiTargetOneHotVMatrix::source_and_target, OptionBase::buildoption, 00118 "The VMat containing both the source (input) and target information."); 00119 00120 00121 // Now call the parent class' declareOptions 00122 inherited::declareOptions(ol); 00123 } 00124 00126 // build // 00128 void MultiTargetOneHotVMatrix::build() 00129 { 00130 inherited::build(); 00131 build_(); 00132 } 00133 00135 // build_ // 00137 void MultiTargetOneHotVMatrix::build_() 00138 { 00139 // ### This method should do the real building of the object, 00140 // ### according to set 'options', in *any* situation. 00141 // ### Typical situations include: 00142 // ### - Initial building of an object from a few user-specified options 00143 // ### - Building of a "reloaded" object: i.e. from the complete set of all serialised options. 00144 // ### - Updating or "re-building" of an object after a few "tuning" options have been modified. 00145 // ### You should assume that the parent class' build_() has already been called. 00146 00147 if (source && source_target) { 00148 updateMtime(source); 00149 updateMtime(source_target); 00150 updateMtime(target_descriptor); 00151 updateMtime(source_and_target); 00152 00153 if (source->targetsize() > 0) 00154 PLERROR("In MultiTargetOneHotVMatrix::build_ - The source VMatrix must have a targetsize <= 0"); 00155 if (source->length() != source_target->length()) 00156 PLERROR("In MultiTargetOneHotVMatrix::build_ - 'source' and 'source_target' must have same length"); 00157 // We need to browse through the data. 00158 PP<ProgressBar> pb; 00159 if (verbosity >= 1) 00160 pb = new ProgressBar("Building new data view", source->length()); 00161 // int target_col = source->inputsize(); 00162 Vec targets(source_target->width()); 00163 int data_width = 3; 00164 if (target_descriptor) 00165 data_width++; 00166 if (reweight_targets) 00167 data_width++; 00168 data.resize(0, data_width); 00169 Vec data_row(data_width); 00170 int count = 0; 00171 TVec<int> count_targets; 00172 if (reweight_targets) { 00173 count_targets.resize(source_target->width()); 00174 count_targets.clear(); 00175 } 00176 for (int i = 0; i < source->length(); i++) { 00177 data_row[0] = i; 00178 source_target->getRow(i, targets); 00179 if (target_val == "max") 00180 data_row[2] = max(targets); 00181 for (int j = 0; j < targets.length(); j++) { 00182 data_row[1] = j; 00183 if (!is_missing(targets[j]) && targets[j] != missing_target) { 00184 count++; 00185 if (target_val == "specific_target") 00186 data_row[2] = targets[j]; 00187 data.appendRow(data_row); 00188 if (reweight_targets) 00189 count_targets[j]++; 00190 } 00191 } 00192 if (pb) 00193 pb->update(i+1); 00194 } 00195 if (reweight_targets) { 00196 int max_target = argmax(count_targets); 00197 if (count_targets[max_target] == 0) 00198 PLERROR("In MultiTargetOneHotVMatrix::build_ - A target does not appear in the dataset, cannot reweight targets"); 00199 Vec target_weights(count_targets.length()); 00200 for (int i = 0; i < target_weights.length(); i++) { 00201 target_weights[i] = real(count_targets[max_target]) / real(count_targets[i]); 00202 if (verbosity >= 5) 00203 cout << "Weight for target " << i << ": " << target_weights[i] 00204 << " (count = " << count_targets[i] << ")" << endl; 00205 } 00206 for (int i = 0; i < data.length(); i++) 00207 data(i, data_width - 1) = target_weights[int(data(i, 1))]; 00208 } 00209 source_inputsize = source->width(); 00210 weightsize_ = 0; 00211 if (source->weightsize() > 0) { 00212 // There are weights. 00213 source_inputsize -= source->weightsize(); 00214 weightsize_ = source->weightsize(); 00215 } 00216 00217 length_ = count; 00218 inputsize_ = source_inputsize + source_target->width(); 00219 if (target_descriptor) { 00220 inputsize_ += target_descriptor->width() - 1; 00221 // Also build mapping from a target index to a row in 'target_descriptor'. 00222 int count_found = 0; 00223 TVec<int> map_target(source_target->width()); 00224 for (int i = 0; i < target_descriptor->length(); i++) { 00225 string target_name = target_descriptor->getString(i, 0); 00226 int field_index = source_target->fieldIndex(target_name); 00227 if (field_index >= 0) { 00228 map_target[field_index] = i; 00229 count_found++; 00230 } 00231 } 00232 if (count_found != source_target->width()) 00233 PLERROR("In MultiTargetOneHotVMatrix::build_ - Could not find all target descriptors in 'target_descriptor'"); 00234 // Now fill 'data' accordingly. 00235 for (int i = 0; i < data.length(); i++) 00236 data(i, 3) = map_target[int(data(i, 1))]; 00237 } 00238 targetsize_ = 1; 00239 width_ = inputsize_ + targetsize_ + weightsize_; 00240 // Add field names. 00241 TVec<VMField> source_infos = source->getFieldInfos(); 00242 TVec<VMField> f_infos(source_infos.length()); 00243 f_infos << source_infos; 00244 f_infos.resize(inputsize_); 00245 TVec<VMField> source_target_infos = source_target->getFieldInfos(); 00246 f_infos.subVec(source_inputsize, source_target_infos.length()) << source_target_infos; 00247 if (target_descriptor) { 00248 TVec<VMField> target_des_infos = target_descriptor->getFieldInfos(); 00249 f_infos.subVec(source_inputsize + source_target->width(), target_descriptor->width() - 1) 00250 << target_des_infos.subVec(1, target_des_infos.length() - 1); 00251 } 00252 f_infos.append(VMField(target_val, VMField::UnknownType)); 00253 if (weightsize_ > 0) { 00254 f_infos.append(source_infos.subVec( 00255 source_infos.length() - source->weightsize(), source->weightsize())); 00256 } 00257 if (reweight_targets) { 00258 if (weightsize_ >= 0) 00259 weightsize_++; 00260 else 00261 weightsize_ = 1; 00262 f_infos.append(VMField("target_weight", VMField::UnknownType)); 00263 width_++; 00264 } 00265 setFieldInfos(f_infos); 00266 // setMetaInfoFromSource(); 00267 } 00268 else if(source_and_target) 00269 { 00270 // We need to browse through the data. 00271 PP<ProgressBar> pb; 00272 if (verbosity >= 1) 00273 pb = new ProgressBar("Building new data view", source_and_target->length()); 00274 // int target_col = source->inputsize(); 00275 Vec targets(source_and_target->targetsize()); 00276 real weight; 00277 Vec input(source_and_target->inputsize()); 00278 int data_width = 3; 00279 if (target_descriptor) 00280 data_width++; 00281 if (reweight_targets) 00282 data_width++; 00283 data.resize(0, data_width); 00284 Vec data_row(data_width); 00285 int count = 0; 00286 TVec<int> count_targets; 00287 if (reweight_targets) { 00288 count_targets.resize(source_and_target->targetsize()); 00289 count_targets.clear(); 00290 } 00291 for (int i = 0; i < source_and_target->length(); i++) { 00292 data_row[0] = i; 00293 source_and_target->getExample(i, input,targets,weight); 00294 if (target_val == "max") 00295 data_row[2] = max(targets); 00296 for (int j = 0; j < targets.length(); j++) { 00297 data_row[1] = j; 00298 if (!is_missing(targets[j]) && targets[j] != missing_target) { 00299 count++; 00300 if (target_val == "specific_target") 00301 data_row[2] = targets[j]; 00302 data.appendRow(data_row); 00303 if (reweight_targets) 00304 count_targets[j]++; 00305 } 00306 } 00307 if (pb) 00308 pb->update(i+1); 00309 } 00310 if (reweight_targets) { 00311 int max_target = argmax(count_targets); 00312 if (count_targets[max_target] == 0) 00313 PLERROR("In MultiTargetOneHotVMatrix::build_ - A target does not appear in the dataset, cannot reweight targets"); 00314 Vec target_weights(count_targets.length()); 00315 for (int i = 0; i < target_weights.length(); i++) { 00316 target_weights[i] = real(count_targets[max_target]) / real(count_targets[i]); 00317 if (verbosity >= 5) 00318 cout << "Weight for target " << i << ": " << target_weights[i] 00319 << " (count = " << count_targets[i] << ")" << endl; 00320 } 00321 for (int i = 0; i < data.length(); i++) 00322 data(i, data_width - 1) = target_weights[int(data(i, 1))]; 00323 } 00324 source_inputsize = source_and_target->inputsize(); 00325 weightsize_ = 0; 00326 if (source_and_target->weightsize() > 0) { 00327 // There are weights. 00328 // source_inputsize -= source_and_target->weightsize(); 00329 weightsize_ = source_and_target->weightsize(); 00330 } 00331 00332 length_ = count; 00333 inputsize_ = source_inputsize + source_and_target->targetsize(); 00334 if (target_descriptor) { 00335 inputsize_ += target_descriptor->width() - 1; 00336 // Also build mapping from a target index to a row in 'target_descriptor'. 00337 int count_found = 0; 00338 TVec<int> map_target(source_and_target->targetsize()); 00339 for (int i = 0; i < target_descriptor->length(); i++) { 00340 string target_name = target_descriptor->getString(i, 0); 00341 int field_index = source_and_target->fieldIndex(target_name) - source_and_target->inputsize(); 00342 if (field_index >= 0) { 00343 map_target[field_index] = i; 00344 count_found++; 00345 } 00346 } 00347 if (count_found != source_and_target->targetsize()) 00348 PLERROR("In MultiTargetOneHotVMatrix::build_ - Could not find all target descriptors in 'target_descriptor'"); 00349 // Now fill 'data' accordingly. 00350 for (int i = 0; i < data.length(); i++) 00351 data(i, 3) = map_target[int(data(i, 1))]; 00352 } 00353 targetsize_ = 1; 00354 width_ = inputsize_ + targetsize_ + weightsize_; 00355 // Add field names. 00356 TVec<VMField> source_infos = source_and_target->getFieldInfos(); 00357 TVec<VMField> f_infos(source_infos.length()); 00358 f_infos << source_infos; 00359 f_infos.resize(inputsize_); 00360 //TVec<VMField> source_target_infos = source_target->getFieldInfos(); 00361 //f_infos.subVec(source_inputsize, source_target_infos.length()) << source_target_infos; 00362 if (target_descriptor) { 00363 TVec<VMField> target_des_infos = target_descriptor->getFieldInfos(); 00364 f_infos.subVec(source_inputsize + source_and_target->targetsize(), target_descriptor->width() - 1) 00365 << target_des_infos.subVec(1, target_des_infos.length() - 1); 00366 } 00367 f_infos.append(VMField(target_val, VMField::UnknownType)); 00368 if (weightsize_ > 0) { 00369 f_infos.append(source_infos.subVec( 00370 source_infos.length() - source_and_target->weightsize(), source_and_target->weightsize())); 00371 } 00372 if (reweight_targets) { 00373 if (weightsize_ >= 0) 00374 weightsize_++; 00375 else 00376 weightsize_ = 1; 00377 f_infos.append(VMField("target_weight", VMField::UnknownType)); 00378 width_++; 00379 } 00380 setFieldInfos(f_infos); 00381 // setMetaInfoFromSource(); 00382 } 00383 00384 00385 } 00386 00388 // getNewRow // 00390 void MultiTargetOneHotVMatrix::getNewRow(int i, const Vec& v) const 00391 { 00392 PLASSERT( (source && source_target) || source_and_target); 00393 int is = source_inputsize; 00394 int ts; 00395 if(source_and_target) 00396 { 00397 ts = source_and_target->targetsize(); 00398 // Get the input part. 00399 source_and_target->getSubRow(int(data(i,0)), 0, v.subVec(0, is)); 00400 } 00401 else 00402 { 00403 ts = source_target->width(); 00404 // Get the input part. 00405 source->getSubRow(int(data(i,0)), 0, v.subVec(0, is)); 00406 } 00407 // Fill the one-hot vector. 00408 v.subVec(is, ts).fill(cold_value); 00409 if(hot_value == cold_value || (is_missing(cold_value) && is_missing(hot_value))) 00410 v[is + int(data(i, 1))] = data(i,2); 00411 else 00412 v[is + int(data(i, 1))] = hot_value; 00413 if (target_descriptor) 00414 // Fill the target descriptor. 00415 target_descriptor->getSubRow(int(data(i, 3)), 1, 00416 v.subVec(is + ts, target_descriptor->width() - 1)); 00417 // Fill the target. 00418 v[inputsize_] = data(i, 2); 00419 // Fill the (potential) weight. 00420 if (weightsize_ > 0) 00421 { 00422 if(source_and_target) 00423 source_and_target->getSubRow(int(data(i, 0)), source_and_target->width()-source_and_target->weightsize(), v.subVec(inputsize_ + targetsize_, source_and_target->weightsize())); 00424 else 00425 source->getSubRow(int(data(i, 0)), is, v.subVec(inputsize_ + targetsize_, source->weightsize())); 00426 } 00427 if (reweight_targets) 00428 v[v.length() - 1] = data(i, 3); 00429 } 00430 00432 // makeDeepCopyFromShallowCopy // 00434 void MultiTargetOneHotVMatrix::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00435 { 00436 inherited::makeDeepCopyFromShallowCopy(copies); 00437 deepCopyField(data, copies); 00438 deepCopyField(source_target, copies); 00439 deepCopyField(target_descriptor, copies); 00440 deepCopyField(source_and_target, copies); 00441 } 00442 00443 } // end of namespace PLearn 00444