Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/ml/test/test_svmsgd.cpp
16354 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// Intel License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Third party copyrights are property of their respective owners.
15
//
16
// Redistribution and use in source and binary forms, with or without modification,
17
// are permitted provided that the following conditions are met:
18
//
19
// * Redistribution's of source code must retain the above copyright notice,
20
// this list of conditions and the following disclaimer.
21
//
22
// * Redistribution's in binary form must reproduce the above copyright notice,
23
// this list of conditions and the following disclaimer in the documentation
24
// and/or other materials provided with the distribution.
25
//
26
// * The name of Intel Corporation may not be used to endorse or promote products
27
// derived from this software without specific prior written permission.
28
//
29
// This software is provided by the copyright holders and contributors "as is" and
30
// any express or implied warranties, including, but not limited to, the implied
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
33
// indirect, incidental, special, exemplary, or consequential damages
34
// (including, but not limited to, procurement of substitute goods or services;
35
// loss of use, data, or profits; or business interruption) however caused
36
// and on any theory of liability, whether in contract, strict liability,
37
// or tort (including negligence or otherwise) arising in any way out of
38
// the use of this software, even if advised of the possibility of such damage.
39
//
40
//M*/
41
42
#include "test_precomp.hpp"
43
44
namespace opencv_test { namespace {
45
46
using cv::ml::SVMSGD;
47
using cv::ml::TrainData;
48
49
class CV_SVMSGDTrainTest : public cvtest::BaseTest
50
{
51
public:
52
enum TrainDataType
53
{
54
UNIFORM_SAME_SCALE,
55
UNIFORM_DIFFERENT_SCALES
56
};
57
58
CV_SVMSGDTrainTest(const Mat &_weights, float shift, TrainDataType type, double precision = 0.01);
59
private:
60
virtual void run( int start_from );
61
static float decisionFunction(const Mat &sample, const Mat &weights, float shift);
62
void makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses);
63
void generateSameBorders(int featureCount);
64
void generateDifferentBorders(int featureCount);
65
66
TrainDataType type;
67
double precision;
68
std::vector<std::pair<float,float> > borders;
69
cv::Ptr<TrainData> data;
70
cv::Mat testSamples;
71
cv::Mat testResponses;
72
static const int TEST_VALUE_LIMIT = 500;
73
};
74
75
void CV_SVMSGDTrainTest::generateSameBorders(int featureCount)
76
{
77
float lowerLimit = -TEST_VALUE_LIMIT;
78
float upperLimit = TEST_VALUE_LIMIT;
79
80
for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
81
{
82
borders.push_back(std::pair<float,float>(lowerLimit, upperLimit));
83
}
84
}
85
86
void CV_SVMSGDTrainTest::generateDifferentBorders(int featureCount)
87
{
88
float lowerLimit = -TEST_VALUE_LIMIT;
89
float upperLimit = TEST_VALUE_LIMIT;
90
cv::RNG rng(0);
91
92
for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
93
{
94
int crit = rng.uniform(0, 2);
95
96
if (crit > 0)
97
{
98
borders.push_back(std::pair<float,float>(lowerLimit, upperLimit));
99
}
100
else
101
{
102
borders.push_back(std::pair<float,float>(lowerLimit/1000, upperLimit/1000));
103
}
104
}
105
}
106
107
float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift)
108
{
109
return static_cast<float>(sample.dot(weights)) + shift;
110
}
111
112
void CV_SVMSGDTrainTest::makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses)
113
{
114
int featureCount = weights.cols;
115
116
samples.create(samplesCount, featureCount, CV_32FC1);
117
for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
118
{
119
rng.fill(samples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second);
120
}
121
122
responses.create(samplesCount, 1, CV_32FC1);
123
124
for (int i = 0 ; i < samplesCount; i++)
125
{
126
responses.at<float>(i) = decisionFunction(samples.row(i), weights, shift) > 0 ? 1.f : -1.f;
127
}
128
129
}
130
131
CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDataType _type, double _precision)
132
{
133
type = _type;
134
precision = _precision;
135
136
int featureCount = weights.cols;
137
138
switch(type)
139
{
140
case UNIFORM_SAME_SCALE:
141
generateSameBorders(featureCount);
142
break;
143
case UNIFORM_DIFFERENT_SCALES:
144
generateDifferentBorders(featureCount);
145
break;
146
default:
147
CV_Error(CV_StsBadArg, "Unknown train data type");
148
}
149
150
RNG rng(0);
151
152
Mat trainSamples;
153
Mat trainResponses;
154
int trainSamplesCount = 10000;
155
makeData(trainSamplesCount, weights, shift, rng, trainSamples, trainResponses);
156
data = TrainData::create(trainSamples, cv::ml::ROW_SAMPLE, trainResponses);
157
158
int testSamplesCount = 100000;
159
makeData(testSamplesCount, weights, shift, rng, testSamples, testResponses);
160
}
161
162
void CV_SVMSGDTrainTest::run( int /*start_from*/ )
163
{
164
cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
165
166
svmsgd->train(data);
167
168
Mat responses;
169
170
svmsgd->predict(testSamples, responses);
171
172
int errCount = 0;
173
int testSamplesCount = testSamples.rows;
174
175
CV_Assert((responses.type() == CV_32FC1) && (testResponses.type() == CV_32FC1));
176
for (int i = 0; i < testSamplesCount; i++)
177
{
178
if (responses.at<float>(i) * testResponses.at<float>(i) < 0)
179
errCount++;
180
}
181
182
float err = (float)errCount / testSamplesCount;
183
184
if ( err > precision )
185
{
186
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
187
}
188
}
189
190
void makeWeightsAndShift(int featureCount, Mat &weights, float &shift)
191
{
192
weights.create(1, featureCount, CV_32FC1);
193
cv::RNG rng(0);
194
double lowerLimit = -1;
195
double upperLimit = 1;
196
197
rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit);
198
shift = static_cast<float>(rng.uniform(-featureCount, featureCount));
199
}
200
201
202
TEST(ML_SVMSGD, trainSameScale2)
203
{
204
int featureCount = 2;
205
206
Mat weights;
207
208
float shift = 0;
209
makeWeightsAndShift(featureCount, weights, shift);
210
211
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE);
212
test.safe_run();
213
}
214
215
TEST(ML_SVMSGD, trainSameScale5)
216
{
217
int featureCount = 5;
218
219
Mat weights;
220
221
float shift = 0;
222
makeWeightsAndShift(featureCount, weights, shift);
223
224
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE);
225
test.safe_run();
226
}
227
228
TEST(ML_SVMSGD, trainSameScale100)
229
{
230
int featureCount = 100;
231
232
Mat weights;
233
234
float shift = 0;
235
makeWeightsAndShift(featureCount, weights, shift);
236
237
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE, 0.02);
238
test.safe_run();
239
}
240
241
TEST(ML_SVMSGD, trainDifferentScales2)
242
{
243
int featureCount = 2;
244
245
Mat weights;
246
247
float shift = 0;
248
makeWeightsAndShift(featureCount, weights, shift);
249
250
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
251
test.safe_run();
252
}
253
254
TEST(ML_SVMSGD, trainDifferentScales5)
255
{
256
int featureCount = 5;
257
258
Mat weights;
259
260
float shift = 0;
261
makeWeightsAndShift(featureCount, weights, shift);
262
263
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
264
test.safe_run();
265
}
266
267
TEST(ML_SVMSGD, trainDifferentScales100)
268
{
269
int featureCount = 100;
270
271
Mat weights;
272
273
float shift = 0;
274
makeWeightsAndShift(featureCount, weights, shift);
275
276
CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
277
test.safe_run();
278
}
279
280
TEST(ML_SVMSGD, twoPoints)
281
{
282
Mat samples(2, 2, CV_32FC1);
283
samples.at<float>(0,0) = 0;
284
samples.at<float>(0,1) = 0;
285
samples.at<float>(1,0) = 1000;
286
samples.at<float>(1,1) = 1;
287
288
Mat responses(2, 1, CV_32FC1);
289
responses.at<float>(0) = -1;
290
responses.at<float>(1) = 1;
291
292
cv::Ptr<TrainData> trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);
293
294
Mat realWeights(1, 2, CV_32FC1);
295
realWeights.at<float>(0) = 1000;
296
realWeights.at<float>(1) = 1;
297
298
float realShift = -500000.5;
299
300
float normRealWeights = static_cast<float>(cv::norm(realWeights)); // TODO cvtest
301
realWeights /= normRealWeights;
302
realShift /= normRealWeights;
303
304
cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
305
svmsgd->setOptimalParameters();
306
svmsgd->train( trainData );
307
308
Mat foundWeights = svmsgd->getWeights();
309
float foundShift = svmsgd->getShift();
310
311
float normFoundWeights = static_cast<float>(cv::norm(foundWeights)); // TODO cvtest
312
foundWeights /= normFoundWeights;
313
foundShift /= normFoundWeights;
314
EXPECT_LE(cv::norm(Mat(foundWeights - realWeights)), 0.001); // TODO cvtest
315
EXPECT_LE(std::abs((foundShift - realShift) / realShift), 0.05);
316
}
317
318
}} // namespace
319
320