/** * @file KCGPApproxOneClass.cpp * @brief One-Class Gaussian Process Regression for Classification: we approximate the inverse of the regularized kernel matrix using a diagonal matrix * @author Alexander Lütz * @date 22-05-2012 (dd-mm-yyyy) */ #include #include #include #include "core/vector/Algorithms.h" #include "core/vector/VVector.h" #include "KCGPApproxOneClass.h" using namespace std; using namespace NICE; using namespace OBJREC; KCGPApproxOneClass::KCGPApproxOneClass( const Config *conf, Kernel *kernel, const string & section ) : KernelClassifier ( conf, kernel ) { // this->kernelFunction = kernel; //overwrite the default optimization options, since we don't want to perform standard loo or marginal likelihood stuff Config config(*conf); string modestr = config.gS(section,"detection_mode"); if(strcmp("mean",modestr.c_str())==0){ this->mode=MEAN_DETECTION_MODE;cerr << "One-class classification via GP predictive _mean_ !!!"<staticNoise = conf->gD(section, "static_noise", 0.0); } KCGPApproxOneClass::KCGPApproxOneClass( const KCGPApproxOneClass & src ) : KernelClassifier ( src ) { this->matrixDInv = src.matrixDInv; this->InvDY = src.InvDY; this->mode = src.mode; this->staticNoise = src.staticNoise; } KCGPApproxOneClass::~KCGPApproxOneClass() { } void KCGPApproxOneClass::teach ( KernelData *kernelData, const NICE::Vector & y ) { fthrow( Exception, "KCGPApproxOneClass::teach: this method is not implemented for this specific type of classifier. Please use the second teach-method." ); } void KCGPApproxOneClass::teach (const LabeledSetVector &teachSet) { if ( this->kernelFunction == NULL ) fthrow( Exception, "KernelClassifier::teach: To use this function, you have to specify a kernel function using the constructor" ); //we do not have to allocate new storage here since these variables come from the interface KernelClassifier // NICE::VVector vecSet; teachSet.getFlatRepresentation (this->vecSet, this->vecSetLabels); if ( (this->vecSetLabels.Min() != 1) || (this->vecSetLabels.Max() != 1) ) { fthrow(Exception, "This classifier is suitable only for one-class classification problems, i.e. max(y) = min(y) = 1"); } this->matrixDInv.resize(this->vecSetLabels.size()); //compute D //start with adding some noise, if necessary if (this->staticNoise != 0.0) this->matrixDInv.set(this->staticNoise); else this->matrixDInv.set(0.0); //now sum up all entries of each row in the original kernel matrix double kernelScore(0.0); for (int i = 0; i < (int)this->vecSetLabels.size(); i++) { for (int j = i; j < (int)this->vecSetLabels.size(); j++) { kernelScore = this->kernelFunction->K(vecSet[i],vecSet[j]); this->matrixDInv[i] += kernelScore; if (i != j) this->matrixDInv[j] += kernelScore; } } //compute its inverse for (int i = 0; i < (int)this->vecSetLabels.size(); i++) { this->matrixDInv[i] = 1.0 / this->matrixDInv[i]; } //and multiply it from right with the label vector (precalculation for mean computation) if(this->mode==MEAN_DETECTION_MODE) { this->InvDY.resize ( this->vecSetLabels.size() ); for (int i = 0; i < (int)this->vecSetLabels.size(); i++) { this->InvDY[i] = this->vecSetLabels[i] * this->matrixDInv[i]; } } } ClassificationResult KCGPApproxOneClass::classifyKernel ( const NICE::Vector & kernelVector, double kernelSelf ) const { FullVector scores ( 2 ); scores[0] = 0.0; if(this->mode==MEAN_DETECTION_MODE) { // kernelSelf is not needed for the regression type of GP if ( kernelVector.size() != this->vecSetLabels.size() ) fthrow(Exception, "KCGPApproxOneClass::classifyKernel: size of kernel value vector " << kernelVector.size() << " does not match number of training points " << this->vecSetLabels.size() ); double yEstimate = kernelVector.scalarProduct ( InvDY ); scores[1] = yEstimate; } if(this->mode==VARIANCE_DETECTION_MODE) { if ( kernelVector.size() != this->vecSetLabels.size() ) fthrow(Exception, "KCGPApproxOneClass::classifyKernel: size of kernel value vector " << kernelVector.size() << " does not match number of training points " << this->vecSetLabels.size() ); NICE::Vector rightPart (this->vecSetLabels.size()); for (int i = 0; i < (int)this->vecSetLabels.size(); i++) { rightPart[i] = kernelVector[i] * this->matrixDInv[i]; } double uncertainty = kernelSelf - kernelVector.scalarProduct ( rightPart ); scores[1] = 1.0 - uncertainty; } ClassificationResult r ( scores[1]<0.5 ? 0 : 1, scores ); return r; } KCGPApproxOneClass *KCGPApproxOneClass::clone() const { return new KCGPApproxOneClass ( *this ); } void KCGPApproxOneClass::store(std::ostream& ofs, int type) const { ofs << this->matrixDInv << std::endl; ofs << this->InvDY << std::endl; ofs << this->mode << std::endl; ofs << this->staticNoise << std::endl; } void KCGPApproxOneClass::restore(std::istream& ifs, int type) { ifs >> this->matrixDInv; ifs >> this->InvDY; ifs >> this->mode; ifs >> this->staticNoise; } void KCGPApproxOneClass::clear() { }