PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PLearnerDiagonalKernel.cc 00004 // 00005 // Copyright (C) 2009 Nicolas Chapados 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: Nicolas Chapados 00036 00040 #include "PLearnerDiagonalKernel.h" 00041 #include <plearn/math/pl_math.h> 00042 00043 namespace PLearn { 00044 using namespace std; 00045 00046 PLEARN_IMPLEMENT_OBJECT( 00047 PLearnerDiagonalKernel, 00048 "Diagonal kernel from the output of a PLearner.", 00049 "The output of this kernel is given by:\n" 00050 "\n" 00051 " k(x,x) = isp_signal_sigma * exp(learner->computeOutput(x))\n" 00052 "\n" 00053 "and is 0 for x != y.\n" 00054 "\n" 00055 "This is useful for representing heteroscedastic noise in Gaussian\n" 00056 "Processes, where the log-noise process is the output of another learner\n" 00057 "(e.g. another Gaussian Process).\n" 00058 ); 00059 00060 00061 PLearnerDiagonalKernel::PLearnerDiagonalKernel() 00062 : m_isp_signal_sigma(0.) 00063 { } 00064 00065 00066 //##### declareOptions ###################################################### 00067 00068 void PLearnerDiagonalKernel::declareOptions(OptionList& ol) 00069 { 00070 declareOption( 00071 ol, "learner", 00072 &PLearnerDiagonalKernel::m_learner, 00073 OptionBase::buildoption, 00074 "Learner we are taking output from."); 00075 00076 declareOption( 00077 ol, "isp_signal_sigma", 00078 &PLearnerDiagonalKernel::m_isp_signal_sigma, 00079 OptionBase::buildoption, 00080 "Inverse softplus of the global noise variance. Default value = 0.0."); 00081 00082 // Now call the parent class' declareOptions 00083 inherited::declareOptions(ol); 00084 } 00085 00086 00087 //##### build ############################################################### 00088 00089 void PLearnerDiagonalKernel::build() 00090 { 00091 // ### Nothing to add here, simply calls build_ 00092 inherited::build(); 00093 build_(); 00094 } 00095 00096 00097 //##### build_ ############################################################## 00098 00099 void PLearnerDiagonalKernel::build_() 00100 { 00101 if (m_learner.isNull()) 00102 PLERROR("PLearnerDiagonalKernel::build: the option 'learner' must be specified"); 00103 00104 // At build-time, we don't yet know the learner outputsize 00105 // if (m_learner->outputsize() != 1) 00106 // PLERROR("PLearnerDiagonalKernel::build: the learner must have an outputsize of 1; " 00107 // "current outputsize is %d", m_learner->outputsize()); 00108 00109 // Ensure that we multiply in Kronecker terms 00110 inherited::m_default_value = 1.0; 00111 } 00112 00113 00114 //##### evaluate ############################################################ 00115 00116 real PLearnerDiagonalKernel::evaluate(const Vec& x1, const Vec& x2) const 00117 { 00118 PLASSERT( x1.size() == x2.size() ); 00119 PLASSERT( ! m_learner.isNull() && m_learner->outputsize() == 1); 00120 00121 m_output_buffer.resize(m_learner->outputsize()); 00122 00123 if (x1 == x2) { 00124 real gating_term = inherited::evaluate(x1,x2); 00125 real sigma = softplus(m_isp_signal_sigma); 00126 m_learner->computeOutput(x1, m_output_buffer); 00127 real diag_term = exp(m_output_buffer[0]); 00128 return sigma * gating_term * diag_term; 00129 } 00130 else 00131 return 0.0; 00132 } 00133 00134 00135 //##### computeGramMatrix ################################################### 00136 00137 void PLearnerDiagonalKernel::computeGramMatrix(Mat K) const 00138 { 00139 PLASSERT( K.size() == 0 || m_data_cache.size() > 0 ); // Ensure data cached OK 00140 PLASSERT( ! m_learner.isNull() && m_learner->outputsize() == 1); 00141 00142 m_output_buffer.resize(m_learner->outputsize()); 00143 00144 // Most elements are zero, except for the diagonal 00145 K.fill(0.0); 00146 00147 real sigma = softplus(m_isp_signal_sigma); 00148 int n = m_data_cache.length(); 00149 00150 PLASSERT( K.length() == n && K.width() == n ); 00151 00152 for (int i=0 ; i<n ; ++i) { 00153 real gating_term = inherited::evaluate_i_j(i, i); 00154 Vec input_i = m_data_cache(i); 00155 m_learner->computeOutput(input_i, m_output_buffer); 00156 real diag_term = exp(m_output_buffer[0]); 00157 K(i,i) = sigma * gating_term * diag_term; 00158 } 00159 00160 if (cache_gram_matrix) { 00161 gram_matrix.resize(n,n); 00162 gram_matrix << K; 00163 gram_matrix_is_cached = true; 00164 } 00165 } 00166 00167 00168 //##### computeGramMatrixDerivative ######################################### 00169 00170 void PLearnerDiagonalKernel::computeGramMatrixDerivative( 00171 Mat& KD, const string& kernel_param, real epsilon) const 00172 { 00173 static const string ISS("isp_signal_sigma"); 00174 00175 if (kernel_param == ISS) { 00176 computeGramMatrixDerivIspSignalSigma(KD); 00177 00178 // computeGramMatrixDerivNV< 00179 // PLearnerDiagonalKernel, 00180 // &PLearnerDiagonalKernel::derivIspSignalSigma>(KD, this, -1); 00181 } 00182 else 00183 inherited::computeGramMatrixDerivative(KD, kernel_param, epsilon); 00184 } 00185 00186 00187 //##### evaluate_all_i_x #################################################### 00188 00189 void PLearnerDiagonalKernel::evaluate_all_i_x(const Vec& x, const Vec& k_xi_x, 00190 real squared_norm_of_x, int istart) const 00191 { 00192 evaluateAllIXNV<PLearnerDiagonalKernel>(x, k_xi_x, istart); 00193 } 00194 00195 00196 //##### computeGramMatrixDerivIspSignalSigma ################################ 00197 00198 void PLearnerDiagonalKernel::computeGramMatrixDerivIspSignalSigma(Mat& KD) const 00199 { 00200 int l = data->length(); 00201 KD.resize(l,l); 00202 PLASSERT_MSG( 00203 gram_matrix.width() == l && gram_matrix.length() == l, 00204 "To compute the derivative with respect to 'isp_signal_sigma', the\n" 00205 "Gram matrix must be precomputed and cached in PLearnerDiagonalKernel."); 00206 00207 KD << gram_matrix; 00208 KD *= sigmoid(m_isp_signal_sigma)/softplus(m_isp_signal_sigma); 00209 } 00210 00211 //##### makeDeepCopyFromShallowCopy ######################################### 00212 00213 void PLearnerDiagonalKernel::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00214 { 00215 deepCopyField(m_learner, copies); 00216 deepCopyField(m_output_buffer, copies); 00217 inherited::makeDeepCopyFromShallowCopy(copies); 00218 } 00219 00220 } // end of namespace PLearn 00221 00222 00223 /* 00224 Local Variables: 00225 mode:c++ 00226 c-basic-offset:4 00227 c-file-style:"stroustrup" 00228 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00229 indent-tabs-mode:nil 00230 fill-column:79 00231 End: 00232 */ 00233 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :