1 // Copyright (C) 2010 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 4 5 #include <dlib/matrix.h> 6 #include <sstream> 7 #include <string> 8 #include <cstdlib> 9 #include <ctime> 10 #include <vector> 11 #include "../stl_checked.h" 12 #include "../array.h" 13 #include "../rand.h" 14 #include "checkerboard.h" 15 #include <dlib/statistics.h> 16 17 #include "tester.h" 18 #include <dlib/svm.h> 19 20 21 namespace 22 { 23 24 using namespace test; 25 using namespace dlib; 26 using namespace std; 27 28 logger dlog("test.svm_c_linear"); 29 30 typedef matrix<double, 0, 1> sample_type; 31 typedef std::vector<std::pair<unsigned int, double> > sparse_sample_type; 32 33 // ---------------------------------------------------------------------------------------- 34 run_prior_test()35 void run_prior_test() 36 { 37 typedef matrix<double,3,1> sample_type; 38 typedef linear_kernel<sample_type> kernel_type; 39 40 svm_c_linear_trainer<kernel_type> trainer; 41 42 std::vector<sample_type> samples; 43 std::vector<double> labels; 44 45 sample_type samp; 46 samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1); 47 samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1); 48 49 trainer.set_c(10); 50 decision_function<kernel_type> df = trainer.train(samples, labels); 51 52 trainer.set_prior(df); 53 54 samples.clear(); 55 labels.clear(); 56 samp = 1, 0, 0; samples.push_back(samp); labels.push_back(+1); 57 samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1); 58 59 df = trainer.train(samples, labels); 60 61 samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1); 62 matrix<double,1,2> rs = test_binary_decision_function(df, samples, labels); 63 dlog << LINFO << rs; 64 DLIB_TEST(rs(0) == 1); 65 DLIB_TEST(rs(1) == 1); 66 67 dlog << LINFO << trans(df.basis_vectors(0)); 68 DLIB_TEST(df.basis_vectors(0)(0) > 0); 69 DLIB_TEST(df.basis_vectors(0)(1) < 0); 70 DLIB_TEST(df.basis_vectors(0)(2) > 0); 71 } 72 run_prior_sparse_test()73 void run_prior_sparse_test() 74 { 75 typedef std::map<unsigned long,double> sample_type; 76 typedef sparse_linear_kernel<sample_type> kernel_type; 77 78 svm_c_linear_trainer<kernel_type> trainer; 79 80 std::vector<sample_type> samples; 81 std::vector<double> labels; 82 83 sample_type samp; 84 samp[0] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear(); 85 samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear(); 86 87 trainer.set_c(10); 88 decision_function<kernel_type> df = trainer.train(samples, labels); 89 90 trainer.set_prior(df); 91 92 samples.clear(); 93 labels.clear(); 94 samp[2] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear(); 95 samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear(); 96 97 df = trainer.train(samples, labels); 98 99 matrix<double,1,2> rs = test_binary_decision_function(df, samples, labels); 100 dlog << LINFO << rs; 101 DLIB_TEST(rs(0) == 1); 102 DLIB_TEST(rs(1) == 1); 103 104 matrix<double,0,1> w = sparse_to_dense(df.basis_vectors(0)); 105 dlog << LINFO << trans(w); 106 DLIB_TEST(w(0) > 0.1); 107 DLIB_TEST(w(1) < -0.1); 108 DLIB_TEST(w(2) > 0.1); 109 } 110 get_simple_points(std::vector<sample_type> & samples,std::vector<double> & labels)111 void get_simple_points ( 112 std::vector<sample_type>& samples, 113 std::vector<double>& labels 114 ) 115 { 116 samples.clear(); 117 labels.clear(); 118 sample_type samp(2); 119 120 samp = 0,0; 121 samples.push_back(samp); 122 labels.push_back(-1); 123 124 samp = 0,1; 125 samples.push_back(samp); 126 labels.push_back(-1); 127 128 samp = 3,0; 129 samples.push_back(samp); 130 labels.push_back(+1); 131 132 samp = 3,1; 133 samples.push_back(samp); 134 labels.push_back(+1); 135 } 136 137 // ---------------------------------------------------------------------------------------- 138 get_simple_points_sparse(std::vector<sparse_sample_type> & samples,std::vector<double> & labels)139 void get_simple_points_sparse ( 140 std::vector<sparse_sample_type>& samples, 141 std::vector<double>& labels 142 ) 143 { 144 samples.clear(); 145 labels.clear(); 146 sparse_sample_type samp; 147 148 samp.push_back(make_pair(0, 0.0)); 149 samp.push_back(make_pair(1, 0.0)); 150 samples.push_back(samp); 151 labels.push_back(-1); 152 153 samp.clear(); 154 samp.push_back(make_pair(0, 0.0)); 155 samp.push_back(make_pair(1, 1.0)); 156 samples.push_back(samp); 157 labels.push_back(-1); 158 159 samp.clear(); 160 samp.push_back(make_pair(0, 3.0)); 161 samp.push_back(make_pair(1, 0.0)); 162 samples.push_back(samp); 163 labels.push_back(+1); 164 165 samp.clear(); 166 samp.push_back(make_pair(0, 3.0)); 167 samp.push_back(make_pair(1, 1.0)); 168 samples.push_back(samp); 169 labels.push_back(+1); 170 } 171 172 // ---------------------------------------------------------------------------------------- 173 test_sparse()174 void test_sparse ( 175 ) 176 { 177 print_spinner(); 178 dlog << LINFO << "test with sparse vectors"; 179 std::vector<sparse_sample_type> samples; 180 std::vector<double> labels; 181 182 sample_type samp; 183 184 get_simple_points_sparse(samples,labels); 185 186 svm_c_linear_trainer<sparse_linear_kernel<sparse_sample_type> > trainer; 187 trainer.set_c(1e4); 188 //trainer.be_verbose(); 189 trainer.set_epsilon(1e-11); 190 191 192 double obj; 193 decision_function<sparse_linear_kernel<sparse_sample_type> > df = trainer.train(samples, labels, obj); 194 dlog << LDEBUG << "obj: "<< obj; 195 DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, obj); 196 197 DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); 198 DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); 199 DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); 200 DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); 201 202 203 // While we are at it, make sure the krr_trainer works with sparse samples 204 krr_trainer<sparse_linear_kernel<sparse_sample_type> > krr; 205 206 df = krr.train(samples, labels); 207 DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); 208 DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); 209 DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); 210 DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); 211 212 213 // Now test some of the sparse helper functions 214 DLIB_TEST(max_index_plus_one(samples) == 2); 215 DLIB_TEST(max_index_plus_one(samples[0]) == 2); 216 217 matrix<double,3,1> m; 218 m = 1; 219 add_to(m, samples[3]); 220 DLIB_TEST(m(0) == 1 + samples[3][0].second); 221 DLIB_TEST(m(1) == 1 + samples[3][1].second); 222 DLIB_TEST(m(2) == 1); 223 224 m = 1; 225 subtract_from(m, samples[3]); 226 DLIB_TEST(m(0) == 1 - samples[3][0].second); 227 DLIB_TEST(m(1) == 1 - samples[3][1].second); 228 DLIB_TEST(m(2) == 1); 229 230 m = 1; 231 add_to(m, samples[3], 2); 232 DLIB_TEST(m(0) == 1 + 2*samples[3][0].second); 233 DLIB_TEST(m(1) == 1 + 2*samples[3][1].second); 234 DLIB_TEST(m(2) == 1); 235 236 m = 1; 237 subtract_from(m, samples[3], 2); 238 DLIB_TEST(m(0) == 1 - 2*samples[3][0].second); 239 DLIB_TEST(m(1) == 1 - 2*samples[3][1].second); 240 DLIB_TEST(m(2) == 1); 241 242 } 243 244 // ---------------------------------------------------------------------------------------- 245 test_dense()246 void test_dense ( 247 ) 248 { 249 print_spinner(); 250 dlog << LINFO << "test with dense vectors"; 251 std::vector<sample_type> samples; 252 std::vector<double> labels; 253 254 sample_type samp; 255 256 get_simple_points(samples,labels); 257 258 svm_c_linear_trainer<linear_kernel<sample_type> > trainer; 259 trainer.set_c(1e4); 260 //trainer.be_verbose(); 261 trainer.set_epsilon(1e-11); 262 263 264 double obj; 265 decision_function<linear_kernel<sample_type> > df = trainer.train(samples, labels, obj); 266 dlog << LDEBUG << "obj: "<< obj; 267 DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, abs(obj - 0.72222222222)); 268 // There shouldn't be any margin violations since this dataset is so trivial. So that means the objective 269 // should be exactly the squared norm of the decision plane (times 0.5). 270 DLIB_TEST_MSG(abs(length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5 - 0.72222222222) < 1e-7, 271 length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5); 272 273 DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); 274 DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); 275 DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); 276 DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); 277 } 278 279 // ---------------------------------------------------------------------------------------- 280 281 class tester_svm_c_linear : public tester 282 { 283 public: tester_svm_c_linear()284 tester_svm_c_linear ( 285 ) : 286 tester ("test_svm_c_linear", 287 "Runs tests on the svm_c_linear_trainer.") 288 {} 289 perform_test()290 void perform_test ( 291 ) 292 { 293 test_dense(); 294 test_sparse(); 295 run_prior_test(); 296 run_prior_sparse_test(); 297 298 // test mixed sparse and dense dot products 299 { 300 std::map<unsigned int, double> sv; 301 matrix<double,0,1> dv(4); 302 303 dv = 1,2,3,4; 304 305 sv[0] = 1; 306 sv[3] = 1; 307 308 309 DLIB_TEST(dot(sv,dv) == 5); 310 DLIB_TEST(dot(dv,sv) == 5); 311 DLIB_TEST(dot(dv,dv) == 30); 312 DLIB_TEST(dot(sv,sv) == 2); 313 314 sv[10] = 9; 315 DLIB_TEST(dot(sv,dv) == 5); 316 } 317 318 // test mixed sparse dense assignments 319 { 320 std::map<unsigned int, double> sv, sv2; 321 std::vector<std::pair<unsigned int, double> > sv3; 322 matrix<double,0,1> dv(4), dv2; 323 324 dv = 1,2,3,4; 325 326 sv[0] = 1; 327 sv[3] = 1; 328 329 330 assign(dv2, dv); 331 332 DLIB_TEST(dv2.size() == 4); 333 DLIB_TEST(dv2(0) == 1); 334 DLIB_TEST(dv2(1) == 2); 335 DLIB_TEST(dv2(2) == 3); 336 DLIB_TEST(dv2(3) == 4); 337 338 assign(sv2, dv); 339 DLIB_TEST(sv2.size() == 4); 340 DLIB_TEST(sv2[0] == 1); 341 DLIB_TEST(sv2[1] == 2); 342 DLIB_TEST(sv2[2] == 3); 343 DLIB_TEST(sv2[3] == 4); 344 345 assign(sv2, sv); 346 DLIB_TEST(sv2.size() == 2); 347 DLIB_TEST(sv2[0] == 1); 348 DLIB_TEST(sv2[1] == 0); 349 DLIB_TEST(sv2[2] == 0); 350 DLIB_TEST(sv2[3] == 1); 351 352 assign(sv3, sv); 353 DLIB_TEST(sv3.size() == 2); 354 DLIB_TEST(sv3[0].second == 1); 355 DLIB_TEST(sv3[1].second == 1); 356 DLIB_TEST(sv3[0].first == 0); 357 DLIB_TEST(sv3[1].first == 3); 358 359 assign(sv3, dv); 360 DLIB_TEST(sv3.size() == 4); 361 DLIB_TEST(sv3[0].second == 1); 362 DLIB_TEST(sv3[1].second == 2); 363 DLIB_TEST(sv3[2].second == 3); 364 DLIB_TEST(sv3[3].second == 4); 365 DLIB_TEST(sv3[0].first == 0); 366 DLIB_TEST(sv3[1].first == 1); 367 DLIB_TEST(sv3[2].first == 2); 368 DLIB_TEST(sv3[3].first == 3); 369 370 assign(sv3, sv); 371 DLIB_TEST(sv3.size() == 2); 372 DLIB_TEST(sv3[0].second == 1); 373 DLIB_TEST(sv3[1].second == 1); 374 DLIB_TEST(sv3[0].first == 0); 375 DLIB_TEST(sv3[1].first == 3); 376 377 sv.clear(); 378 assign(sv, sv3); 379 DLIB_TEST(sv.size() == 2); 380 DLIB_TEST(sv[0] == 1); 381 DLIB_TEST(sv[1] == 0); 382 DLIB_TEST(sv[2] == 0); 383 DLIB_TEST(sv[3] == 1); 384 385 } 386 } 387 } a; 388 389 } 390 391 392 393