00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00041
#include "ClassifierFromDensity.h"
00042
#include <plearn/vmat/ConcatColumnsVMatrix.h>
00043
#include <plearn/vmat/VMat_maths.h>
00044
#include <plearn/ker/Kernel.h>
00045
#include <plearn/ker/ClassErrorCostFunction.h>
00046
#include <plearn/ker/NegLogProbCostFunction.h>
00047
00048
namespace PLearn {
00049
using namespace std;
00050
00051 ClassifierFromDensity::ClassifierFromDensity()
00052 :nclasses(-1), output_log_probabilities(0), normalize_probabilities(1)
00053 {
00054
00055 }
00056
00057
PLEARN_IMPLEMENT_OBJECT(
ClassifierFromDensity,
"A classifier built from density estimators using Bayes' rule.",
00058
"ClassifierFromDensity allowd to build a classifier\n"
00059
"by building one density estimator for each class, \n"
00060
"and using Bayes rule to combine them. \n");
00061
00062 void ClassifierFromDensity::declareOptions(
OptionList& ol)
00063 {
00064
declareOption(ol,
"nclasses", &ClassifierFromDensity::nclasses, OptionBase::buildoption,
00065
"The number of classes");
00066
declareOption(ol,
"estimators", &ClassifierFromDensity::estimators, OptionBase::buildoption,
00067
"The array of density estimators, one for each class. \n"
00068
"You may also specify just one that will be replicated as many times as there are classes.");
00069
declareOption(ol,
"log_priors", &ClassifierFromDensity::log_priors, OptionBase::buildoption,
00070
"The log of the class prior probabilities");
00071
declareOption(ol,
"output_log_probabilities", &ClassifierFromDensity::output_log_probabilities, OptionBase::buildoption,
00072
"Whether computeOutput yields log-probabilities or probabilities (of classes given inputs)");
00073
declareOption(ol,
"normalize_probabilities", &ClassifierFromDensity::normalize_probabilities, OptionBase::buildoption,
00074
"Whether to normalize the probabilities (if not just compute likelihood * prior for each class)");
00075
00076
00077 inherited::declareOptions(ol);
00078 }
00079
00080 void ClassifierFromDensity::build_()
00081 {
00082
if(
estimators.
size()==1)
00083 {
00084
estimators.
resize(
nclasses);
00085
for(
int i=1; i<
nclasses; i++)
00086
estimators[i] =
PLearn::deepCopy(
estimators[0]);
00087 }
00088
else if(
estimators.
size()!=
nclasses)
00089
PLERROR(
"In ClassifierFromDensity: specified %d estimators but there are %d classes",
estimators.
size(),
nclasses);
00090 }
00091
00092
00093 void ClassifierFromDensity::build()
00094 {
00095 inherited::build();
00096
build_();
00097 }
00098
00099
00100 void ClassifierFromDensity::makeDeepCopyFromShallowCopy(map<const void*, void*>& copies)
00101 {
00102 inherited::makeDeepCopyFromShallowCopy(copies);
00103
deepCopyField(
estimators, copies);
00104
deepCopyField(
log_priors, copies);
00105 }
00106
00107
00108 int ClassifierFromDensity::outputsize()
const
00109
{
00110
return nclasses;
00111 }
00112
00113 void ClassifierFromDensity::forget()
00114 {
00115 stage=0;
00116
for(
int c=0; c<
estimators.
length(); c++)
00117
estimators[c]->forget();
00118 }
00119
00120 void ClassifierFromDensity::train()
00121 {
00122
if(
targetsize()!=1)
00123
PLERROR(
"In ClassifierFromDensity: expecting a targetsize of 1 (class index between 0 and nclasses-1), not %d !!",
targetsize());
00124
00125
if(!train_stats)
00126 train_stats =
new VecStatsCollector();
00127
00128
if(nstages<stage)
00129
forget();
00130
00131
if(stage==0)
00132 {
00133
log_priors.
resize(
nclasses);
00134
00135 map<real, TVec<int> > indices =
indicesOfOccurencesInColumn(train_set,
inputsize());
00136
00137
for(
int c=0; c<
nclasses; c++)
00138
log_priors[c] =
log(
real(indices[
real(c)].length())) -
log(
real(train_set.
length()));
00139
00140
string expd =
getExperimentDirectory();
00141
00142
for(
int c=0; c<nclasses; c++)
00143 {
00144
if(verbosity>=1)
00145 cerr <<
">>> Training class " << c;
00146
VMat set_c = train_set.
rows(indices[c]);
00147
int in_sz = set_c->inputsize();
00148
int targ_sz = set_c->targetsize();
00149
int we_sz = set_c->weightsize();
00150
00151
if(we_sz==0)
00152 {
00153 set_c = set_c.
subMatColumns(0,in_sz);
00154 set_c->defineSizes(in_sz, 0, 0);
00155 }
00156
else
00157 {
00158 set_c =
hconcat(set_c.
subMatColumns(0,in_sz), set_c.
subMatColumns(in_sz+targ_sz,we_sz));
00159 set_c->defineSizes(in_sz,0,we_sz);
00160 }
00161
if(expd!=
"")
00162
estimators[c]->setExperimentDirectory(expd+
"Class"+
tostring(c));
00163
if(verbosity>=1)
00164 cerr <<
" ( " << set_c.
length() <<
" samples)" <<
endl;
00165
estimators[c]->setTrainingSet(set_c);
00166
estimators[c]->train();
00167 }
00168 stage = 1;
00169 }
00170 }
00171
00172 void ClassifierFromDensity::computeOutput(
const Vec& input,
Vec& output)
const
00173
{
00174 output.
resize(
nclasses);
00175
00176
real logprob;
00177
Vec logprobvec(1,&logprob);
00178
double log_of_sumprob = 0.;
00179
00180
for(
int c=0; c<
nclasses; c++)
00181 {
00182
estimators[c]->computeOutput(input, logprobvec);
00183
double logprob_c = logprob +
log_priors[c];
00184 output[c] = logprob_c;
00185
if (
normalize_probabilities)
00186 {
00187
if(c==0)
00188 log_of_sumprob = logprob_c;
00189
else
00190 log_of_sumprob =
logadd(log_of_sumprob, logprob_c);
00191 }
00192 }
00193
00194
00195
00196
00197
if (
normalize_probabilities)
00198 output -=
real(log_of_sumprob);
00199
else if (nclasses==2)
00200 output[1] -= output[0];
00201
00202
00203
if (!
output_log_probabilities)
00204
exp(output, output);
00205
00206
00207
00208 }
00209
00210 void ClassifierFromDensity::computeCostsFromOutputs(
const Vec& input,
const Vec& output,
00211
const Vec& target,
Vec& costs)
const
00212
{
00213
static CostFunc cl_er;
00214
static CostFunc cond_p;
00215
if(!cl_er)
00216 cl_er =
class_error();
00217
if(!cond_p)
00218 cond_p =
condprob_cost();
00219
00220 costs.
resize(2);
00221 costs[0] = cl_er->evaluate(output, target);
00222 costs[1] = cond_p->evaluate(output, target);
00223 }
00224
00225 TVec<string> ClassifierFromDensity::getTestCostNames()
const
00226
{
00227
TVec<string> cnames(2);
00228 cnames[0] =
"class_error";
00229 cnames[1] =
"condprob_cost";
00230
return cnames;
00231 }
00232
00233 TVec<string> ClassifierFromDensity::getTrainCostNames()
const
00234
{
00235
return TVec<string>();
00236 }
00237
00238
00239
00240 }