1 // Copyright (C) 2009 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 4 #include "tester.h" 5 #include <dlib/svm.h> 6 #include <dlib/rand.h> 7 #include <dlib/string.h> 8 #include <vector> 9 #include <sstream> 10 #include <ctime> 11 12 namespace 13 { 14 using namespace test; 15 using namespace dlib; 16 using namespace std; 17 dlib::logger dlog("test.ekm_and_lisf"); 18 19 20 class empirical_kernel_map_tester : public tester 21 { 22 /*! 23 WHAT THIS OBJECT REPRESENTS 24 This object represents a unit test. When it is constructed 25 it adds itself into the testing framework. 26 !*/ 27 public: empirical_kernel_map_tester()28 empirical_kernel_map_tester ( 29 ) : 30 tester ( 31 "test_ekm_and_lisf", // the command line argument name for this test 32 "Run tests on the empirical_kernel_map and linearly_independent_subset_finder objects.", // the command line argument description 33 0 // the number of command line arguments for this test 34 ) 35 { 36 thetime = time(0); 37 } 38 39 time_t thetime; 40 dlib::rand rnd; 41 42 template <typename T> validate(const T & ekm_small,const T & ekm_big)43 void validate ( 44 const T& ekm_small, 45 const T& ekm_big 46 ) 47 { 48 matrix<double> tmat; 49 projection_function<typename T::kernel_type> proj; 50 51 ekm_small.get_transformation_to(ekm_big, tmat, proj); 52 DLIB_TEST(tmat.nr() == ekm_big.out_vector_size()); 53 DLIB_TEST(tmat.nc() == ekm_small.out_vector_size()); 54 DLIB_TEST((unsigned long)proj.basis_vectors.size() == ekm_big.basis_size() - ekm_small.basis_size()); 55 for (unsigned long i = 0; i < 6; ++i) 56 { 57 const typename T::sample_type temp = randm(4,1,rnd); 58 DLIB_TEST(length(ekm_big.project(temp) - (tmat*ekm_small.project(temp) + proj(temp))) < 1e-10); 59 } 60 } 61 62 test_transformation_stuff()63 void test_transformation_stuff() 64 { 65 typedef matrix<double,0,1> sample_type; 66 typedef radial_basis_kernel<sample_type> kernel_type; 67 const kernel_type kern(1); 68 69 70 for (unsigned long n = 1; n < 6; ++n) 71 { 72 print_spinner(); 73 for (unsigned long extra = 1; extra < 10; ++extra) 74 { 75 std::vector<sample_type> samps_small, samps_big; 76 linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000); 77 linearly_independent_subset_finder<kernel_type> lisf_big(kern, 1000); 78 for (unsigned long i = 0; i < n; ++i) 79 { 80 samps_small.push_back(randm(4,1,rnd)); 81 samps_big.push_back(samps_small.back()); 82 lisf_big.add(samps_small.back()); 83 lisf_small.add(samps_small.back()); 84 } 85 for (unsigned long i = 0; i < extra; ++i) 86 { 87 samps_big.push_back(randm(4,1,rnd)); 88 lisf_big.add(samps_big.back()); 89 } 90 91 92 // test no lisf 93 { 94 empirical_kernel_map<kernel_type> ekm_small, ekm_big; 95 ekm_small.load(kern, samps_small); 96 ekm_big.load(kern, samps_big); 97 98 validate(ekm_small, ekm_big); 99 } 100 101 // test with lisf 102 { 103 empirical_kernel_map<kernel_type> ekm_small, ekm_big; 104 ekm_small.load(lisf_small); 105 ekm_big.load(lisf_big); 106 107 validate(ekm_small, ekm_big); 108 } 109 110 // test with partly lisf 111 { 112 empirical_kernel_map<kernel_type> ekm_small, ekm_big; 113 ekm_small.load(kern, samps_small); 114 ekm_big.load(lisf_big); 115 116 validate(ekm_small, ekm_big); 117 } 118 119 // test with partly lisf 120 { 121 empirical_kernel_map<kernel_type> ekm_small, ekm_big; 122 ekm_small.load(lisf_small); 123 ekm_big.load(kern, samps_big); 124 125 validate(ekm_small, ekm_big); 126 } 127 128 } 129 } 130 131 132 // test what happens if the bigger ekm only has repeated basis vectors 133 { 134 empirical_kernel_map<kernel_type> ekm_big, ekm_small; 135 std::vector<sample_type> samps_big, samps_small; 136 137 sample_type temp = randm(4,1,rnd); 138 139 samps_small.push_back(temp); 140 samps_big.push_back(temp); 141 samps_big.push_back(temp); 142 143 ekm_big.load(kern, samps_big); 144 ekm_small.load(kern, samps_small); 145 146 validate(ekm_small, ekm_big); 147 148 } 149 { 150 empirical_kernel_map<kernel_type> ekm_big, ekm_small; 151 linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000); 152 std::vector<sample_type> samps_big; 153 154 sample_type temp = randm(4,1,rnd); 155 156 lisf_small.add(temp); 157 samps_big.push_back(temp); 158 samps_big.push_back(temp); 159 160 ekm_big.load(kern, samps_big); 161 ekm_small.load(lisf_small); 162 163 validate(ekm_small, ekm_big); 164 165 } 166 { 167 empirical_kernel_map<kernel_type> ekm_big, ekm_small; 168 std::vector<sample_type> samps_big, samps_small; 169 170 sample_type temp = randm(4,1,rnd); 171 sample_type temp2 = randm(4,1,rnd); 172 173 samps_small.push_back(temp); 174 samps_small.push_back(temp2); 175 samps_big.push_back(temp); 176 samps_big.push_back(temp2); 177 samps_big.push_back(randm(4,1,rnd)); 178 179 ekm_big.load(kern, samps_big); 180 ekm_small.load(kern, samps_small); 181 182 validate(ekm_small, ekm_big); 183 184 } 185 { 186 empirical_kernel_map<kernel_type> ekm_big, ekm_small; 187 linearly_independent_subset_finder<kernel_type> lisf_small(kern, 1000); 188 std::vector<sample_type> samps_big; 189 190 sample_type temp = randm(4,1,rnd); 191 sample_type temp2 = randm(4,1,rnd); 192 193 lisf_small.add(temp); 194 lisf_small.add(temp2); 195 samps_big.push_back(temp); 196 samps_big.push_back(temp2); 197 samps_big.push_back(temp); 198 199 ekm_big.load(kern, samps_big); 200 ekm_small.load(lisf_small); 201 202 validate(ekm_small, ekm_big); 203 204 } 205 206 207 } 208 209 210 perform_test()211 void perform_test ( 212 ) 213 { 214 ++thetime; 215 typedef matrix<double,0,1> sample_type; 216 //dlog << LINFO << "time seed: " << thetime; 217 //rnd.set_seed(cast_to_string(thetime)); 218 219 220 typedef radial_basis_kernel<sample_type> kernel_type; 221 222 223 for (int n = 1; n < 10; ++n) 224 { 225 print_spinner(); 226 dlog << LINFO << "matrix size " << n; 227 228 std::vector<sample_type> samples; 229 // make some samples 230 for (int i = 0; i < n; ++i) 231 { 232 samples.push_back(randm(4,1,rnd)); 233 // double up the samples just to mess with the lisf 234 if (n > 5) 235 samples.push_back(samples.back()); 236 } 237 238 dlog << LINFO << "samples.size(): "<< samples.size(); 239 240 const kernel_type kern(1); 241 242 linearly_independent_subset_finder<kernel_type> lisf(kern, 100, 1e-4); 243 unsigned long count = 0; 244 for (unsigned long i = 0; i < samples.size(); ++i) 245 { 246 if (lisf.add(samples[i])) 247 { 248 DLIB_TEST(equal(lisf[lisf.size()-1], samples[i])); 249 ++count; 250 } 251 } 252 DLIB_TEST(count == lisf.size()); 253 254 DLIB_TEST(lisf.size() == (unsigned int)n); 255 256 257 dlog << LINFO << "lisf.size(): "<< lisf.size(); 258 259 // make sure the kernel matrices coming out of the lisf are correct 260 DLIB_TEST(dlib::equal(lisf.get_kernel_matrix(), kernel_matrix(kern, lisf), 1e-8)); 261 DLIB_TEST(dlib::equal(lisf.get_inv_kernel_marix(), inv(kernel_matrix(kern, lisf.get_dictionary())), 1e-8)); 262 263 empirical_kernel_map<kernel_type> ekm; 264 ekm.load(lisf); 265 DLIB_TEST(ekm.basis_size() == lisf.size()); 266 267 std::vector<sample_type> proj_samples; 268 for (unsigned long i = 0; i < samples.size(); ++i) 269 { 270 double err; 271 proj_samples.push_back(ekm.project(samples[i], err)); 272 DLIB_TEST(err <= 1e-4); 273 const double error_agreement = std::abs(err - lisf.projection_error(samples[i])); 274 dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement; 275 DLIB_TEST(error_agreement < 1e-11); 276 } 277 278 for (int i = 0; i < 5; ++i) 279 { 280 sample_type temp = randm(4,1,rnd); 281 double err; 282 ekm.project(temp, err); 283 const double error_agreement = std::abs(err - lisf.projection_error(temp)); 284 dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement; 285 DLIB_TEST(error_agreement < 1e-11); 286 } 287 288 // make sure the EKM did the projection correctly 289 DLIB_TEST(dlib::equal(kernel_matrix(kern, samples), kernel_matrix(linear_kernel<sample_type>(), proj_samples), 1e-5)); 290 } 291 292 293 test_transformation_stuff(); 294 295 } 296 }; 297 298 // Create an instance of this object. Doing this causes this test 299 // to be automatically inserted into the testing framework whenever this cpp file 300 // is linked into the project. Note that since we are inside an unnamed-namespace 301 // we won't get any linker errors about the symbol a being defined multiple times. 302 empirical_kernel_map_tester a; 303 304 } 305 306 307