1 // This is mul/clsfy/tests/test_rbf_svm_smo.cxx
2 // Copyright: (C) 2001 British Telecommunications PLC
3 #include <vector>
4 #include <iostream>
5 #include <iomanip>
6 #include <ios>
7 #include <string>
8 #include "testlib/testlib_test.h"
9 //:
10 // \file
11 // \brief Tests clsfy_rbf_svm and clsfy_rbf_svm_smo_1_builder
12 // \author Ian Scott
13 // Test construction, IO etc.
14
15 #ifdef _MSC_VER
16 # include "vcl_msvc_warnings.h"
17 #endif
18 #include <clsfy/clsfy_rbf_svm.h>
19 #include <clsfy/clsfy_rbf_svm_smo_1_builder.h>
20 #include <clsfy/clsfy_k_nearest_neighbour.h>
21 #include <clsfy/clsfy_rbf_parzen.h>
22 #include <vpdfl/vpdfl_axis_gaussian.h>
23 #include <vpdfl/vpdfl_axis_gaussian_sampler.h>
24 #include "vnl/vnl_random.h"
25 #include "vsl/vsl_binary_loader.h"
26 #include <mbl/mbl_data_array_wrapper.h>
27 #include "vul/vul_timer.h"
28 #include "vpl/vpl.h" // vpl_unlink()
29
30 #ifndef LEAVE_FILES_BEHIND
31 #define LEAVE_FILES_BEHIND 0
32 #endif
33
34 //=======================================================================
test_rbf_svm_smo()35 void test_rbf_svm_smo()
36 {
37 std::cout << "*************************************\n"
38 << " Testing clsfy_rbf_svm_smo_1_builder\n"
39 << "*************************************\n";
40
41 std::cout<<"======== TESTING BUILDING ===========\n";
42
43 std::vector<vpdfl_axis_gaussian_sampler *> generator(4);//
44 constexpr unsigned nDims = 2;
45 vnl_vector<double> mean0(nDims), var0(nDims), mean1(nDims), var1(nDims), mean2(nDims), var2(nDims), mean3(nDims), var3(nDims);
46 vpdfl_axis_gaussian PDF0, PDF1, PDF2, PDF3;
47
48 mean0.fill(0.0); mean0(0) = 1.5;
49 mean1.fill(0.0); mean1(0) = -1.5;
50 mean2.fill(0.0); mean2(1) = 1.5;
51 mean3.fill(0.0); mean3(1) = -1.5;
52
53 constexpr double trainPrincipleVariance = 0.5;
54 var0.fill(trainPrincipleVariance/10.0); var0(0) = trainPrincipleVariance;
55 var1.fill(trainPrincipleVariance/10.0); var1(0) = trainPrincipleVariance;
56 var2.fill(trainPrincipleVariance/10.0); var2(1) = trainPrincipleVariance;
57 var3.fill(trainPrincipleVariance/10.0); var3(1) = trainPrincipleVariance;
58
59 PDF0.set(mean0, var0);
60 PDF1.set(mean1, var1);
61 PDF2.set(mean2, var2);
62 PDF3.set(mean3, var3);
63
64 generator[0] = (vpdfl_axis_gaussian_sampler *)PDF0.new_sampler();
65 generator[1] = (vpdfl_axis_gaussian_sampler *)PDF1.new_sampler();
66 generator[2] = (vpdfl_axis_gaussian_sampler *)PDF2.new_sampler();
67 generator[3] = (vpdfl_axis_gaussian_sampler *)PDF3.new_sampler();
68 vnl_random rng;
69 rng.reseed(333248);
70 constexpr unsigned nSamples = 200;
71 std::vector<unsigned> labels(nSamples);
72 std::vector<vnl_vector<double> > data(nSamples);
73 vnl_vector<double> s;
74 std::cout << "Generating test data\n";
75 std::vector<unsigned> labelcount(4, 0u);
76 for (unsigned int i=0; i<nSamples; i++)
77 {
78 int c = rng.lrand32(3);
79 labels[i] = c/2;
80 labelcount[c] ++;
81 generator[c]->sample(s);
82 data[i] = s;
83 }
84
85 constexpr unsigned nTestSamples = 1000;
86 std::vector<unsigned> testLabels(nTestSamples);
87 std::vector<vnl_vector<double> > testingVectors(nTestSamples);
88 for (unsigned int i=0; i<nTestSamples; i++)
89 {
90 int c = rng.lrand32(3);
91 testLabels[i] = c/2;
92 generator[c]->sample(s);
93 testingVectors[i]=s;
94 }
95
96 delete generator[0];
97 delete generator[1];
98 delete generator[2];
99 delete generator[3];
100
101 mbl_data_array_wrapper<vnl_vector<double> > trainingVectors(data);
102
103
104 std::cout << "****************The Training set****************\n";
105 std::cout << "The number of labels from each generators are respectively ";
106 std::cout << labelcount[0] << ' ' << labelcount[1] << ' ' << labelcount[2] << ' ' << labelcount[3] << std::endl;
107
108 vnl_vector<double> x(nDims);
109 std::vector<double> out(1);
110 x.fill(0.0);
111 std::cout << "x(1) varies across from -2 to + 2\n";
112 std::cout << "x(0) varies down from -2 to + 2\n";
113
114 clsfy_k_nearest_neighbour knn;
115 knn.set(data, labels);
116 knn.set_k(3);
117 std::cout << std::endl << "KNN output\n";
118 std::cout << std::setprecision(4);
119 for (x(0) = -2; x(0) <= 2 ; x(0) += 0.25)
120 {
121 for (x(1) = -2; x(1) <= 2 ; x(1) += 0.25)
122 {
123 knn.class_probabilities(out, x);
124 std::cout << std::fixed << std::setw(3) << out[0] << ' ';
125 }
126 std::cout << std::endl;
127 }
128
129 for (x(0) = -2; x(0) <= 2 ; x(0) += 0.25)
130 {
131 for (x(1) = -2; x(1) <= 2 ; x(1) += 0.25)
132 {
133 std::cout << knn.classify(x);
134 }
135 std::cout << std::endl;
136 }
137
138 clsfy_rbf_parzen win;
139 win.set(data, labels);
140 win.set_rbf_width(0.08);
141 win.set_power(10);
142 std::cout << std::endl << "Training data distribution\n";
143 std::cout << std::setprecision(1);
144 for (x(0) = -2; x(0) <= 2 ; x(0) += 0.25)
145 {
146 for (x(1) = -2; x(1) <= 2 ; x(1) += 0.25)
147 {
148 double v = win.weightings(x);
149 if (v < 0.01)
150 std::cout << " 0 ";
151 else
152 std::cout << std::fixed << std::setw(4) << v << ' ';
153 }
154 std::cout << std::endl;
155 }
156
157 std::cout << "\n*********Testing Support Vector Training*********\n";
158 std::cout << std::setprecision(6) << std::resetiosflags(std::ios::floatfield);
159
160 clsfy_rbf_svm_smo_1_builder builder;
161 builder.set_bound_on_multipliers(1e2);
162 builder.set_rbf_width(1.05);
163
164 clsfy_rbf_svm classifier3;
165
166 vul_timer mytimer;
167
168 double error = builder.build(classifier3, trainingVectors, labels);
169
170 long realtime = mytimer.real();
171 std::cout << "\nOptimisation took " << realtime/1000.0 << " seconds\n";
172 std::cout << "\nLagrangians ";
173 for (unsigned i=0; i < classifier3.n_support_vectors(); ++i)
174 std::cout << classifier3.lagrangians()[i] << " ";
175 std::cout << std::endl;
176
177 std::cout << "Training Error " << error << std::endl;
178 #if 0
179 mbl_data_wrapper<vnl_vector<double> > &data = trainingVectors.vectorData();
180 data.first();
181 for (unsigned int i=0; i<nSamples; i++)
182 {
183 std::cout << i << '\t' << std::setw(8) << pClassifier->log_l(data.current()) << '\t' << pClassifier->classify(data.current()) <<
184 " should be " << labels(i) <<std::endl;
185 data.next();
186 }
187 #endif
188 // print input, print output
189
190 std::cout << std::setprecision(4);
191 for (x(0) = -2; x(0) <= 2 ; x(0) += 0.25)
192 {
193 for (x(1) = -2; x(1) <= 2 ; x(1) += 0.25)
194 {
195 classifier3.class_probabilities(out, x);
196 std::cout << std::fixed << std::setw(3) << out[0] << ' ';
197 }
198 std::cout << std::endl;
199 }
200
201 for (x(0) = -2; x(0) <= 2 ; x(0) += 0.25)
202 {
203 for (x(1) = -2; x(1) <= 2 ; x(1) += 0.25)
204 {
205 std::cout << classifier3.classify(x);
206 }
207 std::cout << std::endl;
208 }
209
210 std::cout << "There are " << classifier3.n_support_vectors() << " Support Vectors\n";
211
212 TEST_NEAR("Training Error < 0.05", error, 0.0, 0.05);
213
214 std::cout << "\nError on Testing set ";
215 mbl_data_array_wrapper<vnl_vector<double> > test_vector_data(testingVectors);
216 double testError = clsfy_test_error(classifier3, test_vector_data, testLabels);
217 std::cout << testError << std::endl;
218
219 TEST_NEAR("Test Error < 0.1", testError, 0.0, 0.1);
220
221 std::cout << "\n****************Testing classifier IO**************\n";
222 vsl_add_to_binary_loader(clsfy_rbf_svm());
223 std::string test_path = "test_rbf_svm.bvl.tmp";
224
225 vsl_b_ofstream bfs_out(test_path);
226 TEST(("Opened " + test_path + " for writing").c_str(), (!bfs_out ), false);
227 vsl_b_write(bfs_out, classifier3);
228 vsl_b_write(bfs_out, (clsfy_classifier_base *) &classifier3);
229 bfs_out.close();
230
231 clsfy_rbf_svm svmi;
232 clsfy_classifier_base *pClassifier2=nullptr;
233
234 vsl_b_ifstream bfs_in(test_path);
235 TEST(("Opened " + test_path + " for reading").c_str(), (!bfs_in ), false);
236 vsl_b_read(bfs_in, svmi);
237 vsl_b_read(bfs_in, pClassifier2);
238 bfs_in.close();
239 #if !LEAVE_FILES_BEHIND
240 vpl_unlink(test_path.c_str());
241 #endif
242
243 std::cout<<"Saved : " << classifier3 << std::endl;
244 std::cout<<"Loaded: " << svmi << std::endl;
245 std::cout<<"Loaded: " << pClassifier2 << std::endl;
246
247 clsfy_rbf_svm &svmo = *(clsfy_rbf_svm *)&classifier3;
248
249 TEST("Saved Classifier = Loaded Classifier",
250 svmo.bias() == svmi.bias() &&
251 svmo.lagrangians() == svmi.lagrangians() &&
252 svmo.support_vectors() == svmi.support_vectors(),
253 true);
254
255 double ll_o = svmo.log_l(vnl_vector<double>(nDims, 0.3));
256 double ll_i = svmi.log_l(vnl_vector<double>(nDims, 0.3));
257 TEST_NEAR("Saved Classifier.log_l() = Loaded Classifier.log_l()",
258 ll_o, ll_i, 1e-11);
259
260 TEST("Saved Classifier = Classifier Loaded by Base Class Ptr",
261 svmo.is_a(), pClassifier2->is_a());
262
263 TEST("Loaded Classifier type = Original Classifier type",
264 pClassifier2->is_class(svmo.is_a()), true);
265
266 TEST("Loaded Classifier has base class type",
267 pClassifier2->is_class("clsfy_classifier_base"), true);
268
269 std::cout << std::setprecision(6) << std::resetiosflags(std::ios::floatfield);
270
271 delete pClassifier2;
272 vsl_delete_all_loaders();
273
274 std::cout << std::setprecision(6) << std::resetiosflags(std::ios::floatfield);
275 }
276
277 TESTMAIN(test_rbf_svm_smo);
278