SHOGUN
v3.2.0
|
00001 /* 00002 * This program is free software; you can redistribute it and/or modify 00003 * it under the terms of the GNU General Public License as published by 00004 * the Free Software Foundation; either version 3 of the License, or 00005 * (at your option) any later version. 00006 * 00007 * Written (W) 1999-2010 Soeren Sonnenburg 00008 * Written (W) 2011 Abhinav Maurya 00009 * Written (W) 2012 Heiko Strathmann 00010 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society 00011 * Copyright (C) 2010 Berlin Institute of Technology 00012 */ 00013 00014 #include <shogun/lib/common.h> 00015 #include <shogun/base/Parameter.h> 00016 #include <shogun/kernel/GaussianKernel.h> 00017 #include <shogun/features/DotFeatures.h> 00018 #include <shogun/features/DenseFeatures.h> 00019 #include <shogun/io/SGIO.h> 00020 00021 using namespace shogun; 00022 00023 CGaussianKernel::CGaussianKernel() : CDotKernel() 00024 { 00025 init(); 00026 } 00027 00028 CGaussianKernel::CGaussianKernel(int32_t size, float64_t w) : CDotKernel(size) 00029 { 00030 init(); 00031 set_width(w); 00032 } 00033 00034 CGaussianKernel::CGaussianKernel(CDotFeatures* l, CDotFeatures* r, 00035 float64_t w, int32_t size) : CDotKernel(size) 00036 { 00037 init(); 00038 set_width(w); 00039 init(l,r); 00040 } 00041 00042 CGaussianKernel::~CGaussianKernel() 00043 { 00044 cleanup(); 00045 } 00046 00047 CGaussianKernel* CGaussianKernel::obtain_from_generic(CKernel* kernel) 00048 { 00049 if (kernel->get_kernel_type()!=K_GAUSSIAN) 00050 { 00051 SG_SERROR("CGaussianKernel::obtain_from_generic(): provided kernel is " 00052 "not of type CGaussianKernel!\n"); 00053 } 00054 00055 /* since an additional reference is returned */ 00056 SG_REF(kernel); 00057 return (CGaussianKernel*)kernel; 00058 } 00059 00060 #include <typeinfo> 00061 CSGObject *CGaussianKernel::shallow_copy() const 00062 { 00063 // TODO: remove this after all the classes get shallow_copy properly implemented 00064 // this assert is to avoid any subclass of CGaussianKernel accidentally called 00065 // with the implement here 00066 ASSERT(typeid(*this) == typeid(CGaussianKernel)) 00067 CGaussianKernel *ker = new CGaussianKernel(cache_size, width); 00068 if (lhs) 00069 { 00070 ker->init(lhs, rhs); 00071 } 00072 return ker; 00073 } 00074 00075 void CGaussianKernel::cleanup() 00076 { 00077 if (sq_lhs != sq_rhs) 00078 SG_FREE(sq_rhs); 00079 sq_rhs = NULL; 00080 00081 SG_FREE(sq_lhs); 00082 sq_lhs = NULL; 00083 00084 CKernel::cleanup(); 00085 } 00086 00087 void CGaussianKernel::precompute_squared_helper(float64_t* &buf, CDotFeatures* df) 00088 { 00089 ASSERT(df) 00090 int32_t num_vec=df->get_num_vectors(); 00091 buf=SG_MALLOC(float64_t, num_vec); 00092 00093 for (int32_t i=0; i<num_vec; i++) 00094 buf[i]=df->dot(i,df, i); 00095 } 00096 00097 bool CGaussianKernel::init(CFeatures* l, CFeatures* r) 00098 { 00100 cleanup(); 00101 00102 CDotKernel::init(l, r); 00103 precompute_squared(); 00104 return init_normalizer(); 00105 } 00106 00107 float64_t CGaussianKernel::compute(int32_t idx_a, int32_t idx_b) 00108 { 00109 if (!m_compact) 00110 { 00111 float64_t result=sq_lhs[idx_a]+sq_rhs[idx_b] 00112 -2*CDotKernel::compute(idx_a, idx_b); 00113 return CMath::exp(-result/width); 00114 } 00115 00116 int32_t len_features, power; 00117 len_features=((CDenseFeatures<float64_t>*) lhs)->get_num_features(); 00118 power=(len_features%2==0) ? (len_features+1):len_features; 00119 00120 float64_t result=sq_lhs[idx_a]+sq_rhs[idx_b]-2*CDotKernel::compute(idx_a,idx_b); 00121 float64_t result_multiplier=1-(sqrt(result/width))/3; 00122 00123 if (result_multiplier<=0) 00124 result_multiplier=0; 00125 else 00126 result_multiplier=pow(result_multiplier, power); 00127 00128 return result_multiplier*exp(-result/width); 00129 } 00130 00131 void CGaussianKernel::load_serializable_post() throw (ShogunException) 00132 { 00133 CKernel::load_serializable_post(); 00134 precompute_squared(); 00135 } 00136 00137 void CGaussianKernel::precompute_squared() 00138 { 00139 if (!lhs || !rhs) 00140 return; 00141 00142 precompute_squared_helper(sq_lhs, (CDotFeatures*) lhs); 00143 00144 if (lhs==rhs) 00145 sq_rhs=sq_lhs; 00146 else 00147 precompute_squared_helper(sq_rhs, (CDotFeatures*) rhs); 00148 } 00149 00150 SGMatrix<float64_t> CGaussianKernel::get_parameter_gradient( 00151 const TParameter* param, index_t index) 00152 { 00153 REQUIRE(lhs && rhs, "Features not set!\n") 00154 00155 if (!strcmp(param->m_name, "width")) 00156 { 00157 SGMatrix<float64_t> derivative=SGMatrix<float64_t>(num_lhs, num_rhs); 00158 00159 for (int j=0; j<num_lhs; j++) 00160 for (int k=0; k<num_rhs; k++) 00161 { 00162 float64_t element=sq_lhs[j]+sq_rhs[k]-2*CDotKernel::compute(j,k); 00163 derivative(j,k)=exp(-element/width)*element/(width*width); 00164 } 00165 00166 return derivative; 00167 } 00168 else 00169 { 00170 SG_ERROR("Can't compute derivative wrt %s parameter\n", param->m_name); 00171 return SGMatrix<float64_t>(); 00172 } 00173 } 00174 00175 void CGaussianKernel::init() 00176 { 00177 set_width(1.0); 00178 set_compact_enabled(false); 00179 sq_lhs=NULL; 00180 sq_rhs=NULL; 00181 SG_ADD(&width, "width", "Kernel width", MS_AVAILABLE, GRADIENT_AVAILABLE); 00182 SG_ADD(&m_compact, "compact", "Compact enabled option", MS_AVAILABLE); 00183 }