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