2020-02-08 21:08:21 +01:00
|
|
|
// SVMWrapper.cpp : Defines the exported functions for the DLL application.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include "svm.h"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
extern "C" void __cdecl print_log(const char *str) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct SVMWrapper {
|
|
|
|
|
struct svm_model *model;
|
|
|
|
|
int cols;
|
2020-02-13 22:24:41 +01:00
|
|
|
int classes;
|
2020-02-08 21:08:21 +01:00
|
|
|
double *means;
|
|
|
|
|
double *sdevs;
|
|
|
|
|
struct svm_parameter param;
|
|
|
|
|
struct svm_problem *problem;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct svm_node svmnode;
|
|
|
|
|
|
|
|
|
|
svmnode **make_svmnode_array(float features[], int rows, int cols, double *means, double *sdevs, int rescale) {
|
|
|
|
|
svmnode **x = new svmnode*[rows];
|
|
|
|
|
svmnode *nodes = new svmnode[rows * (cols + 1)];
|
|
|
|
|
|
|
|
|
|
double row_factor = 1.0 / (double)rows;
|
|
|
|
|
if (rescale) {
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
means[c] = 0;
|
|
|
|
|
sdevs[c] = 0;
|
|
|
|
|
}
|
|
|
|
|
for (int r = 0; r < rows; r++) {
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
means[c] += (double)features[r * cols + c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
means[c] *= row_factor;
|
|
|
|
|
}
|
|
|
|
|
for (int r = 0; r < rows; r++) {
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
double sq_diff = ((double)features[r * cols + c] - means[c]);
|
|
|
|
|
sq_diff *= sq_diff;
|
|
|
|
|
sdevs[c] += sq_diff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
sdevs[c] *= row_factor;
|
|
|
|
|
sdevs[c] = sqrt(sdevs[c]);
|
|
|
|
|
sdevs[c] = 1.0 / sdevs[c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int r = 0; r < rows; r++) {
|
|
|
|
|
x[r] = &(nodes[r * (cols + 1)]);
|
|
|
|
|
int idx = 0;
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
x[r][c].index = c + 1;
|
|
|
|
|
x[r][c].value = ((double)features[r * cols + c] - means[c]) * sdevs[c];
|
|
|
|
|
}
|
|
|
|
|
x[r][cols].index = -1;
|
|
|
|
|
}
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void make_problem(struct svm_problem *problem, float features[], float labels[], int rows, int cols, double *means, double *sdevs) {
|
|
|
|
|
problem->l = rows;
|
|
|
|
|
problem->y = new double[rows];
|
|
|
|
|
for (int i = 0; i < rows; i++)
|
|
|
|
|
problem->y[i] = (double)labels[i];
|
|
|
|
|
problem->x = make_svmnode_array(features, rows, cols, means, sdevs, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroy_svmnode_array(svmnode **x) {
|
|
|
|
|
delete x[0];
|
|
|
|
|
delete x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroy_problem(struct svm_problem *problem) {
|
|
|
|
|
delete problem->y;
|
|
|
|
|
destroy_svmnode_array(problem->x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
2020-02-13 22:24:41 +01:00
|
|
|
__declspec(dllexport) void *__cdecl trainModel(float features[], float labels[], int rows, int cols, int classes, int probability, float C) {
|
2020-02-08 21:08:21 +01:00
|
|
|
if (!(rows > 0 && cols > 0))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
svm_set_print_string_function(print_log);
|
|
|
|
|
|
|
|
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
|
|
|
|
sw->cols = cols;
|
2020-02-13 22:24:41 +01:00
|
|
|
sw->classes = classes;
|
2020-02-08 21:08:21 +01:00
|
|
|
sw->means = new double[cols];
|
|
|
|
|
sw->sdevs = new double[cols];
|
|
|
|
|
|
|
|
|
|
sw->param.svm_type = C_SVC;
|
|
|
|
|
sw->param.kernel_type = RBF;
|
|
|
|
|
sw->param.degree = 3;
|
|
|
|
|
sw->param.gamma = 1.0 / (double)cols;
|
|
|
|
|
sw->param.coef0 = 0;
|
|
|
|
|
sw->param.nu = 0.5;
|
|
|
|
|
sw->param.cache_size = 100;
|
2020-02-13 22:24:41 +01:00
|
|
|
sw->param.C = C;
|
2020-02-08 21:08:21 +01:00
|
|
|
sw->param.eps = 0.001;
|
|
|
|
|
sw->param.p = 0.1;
|
|
|
|
|
sw->param.shrinking = 1;
|
2020-02-13 22:24:41 +01:00
|
|
|
sw->param.probability = probability;
|
2020-02-08 21:08:21 +01:00
|
|
|
sw->param.nr_weight = 0;
|
|
|
|
|
sw->param.weight_label = NULL;
|
|
|
|
|
sw->param.weight = NULL;
|
|
|
|
|
|
|
|
|
|
sw->problem = new struct svm_problem();
|
|
|
|
|
make_problem(sw->problem, features, labels, rows, cols, sw->means, sw->sdevs);
|
|
|
|
|
sw->model = svm_train(sw->problem, &sw->param);
|
|
|
|
|
|
|
|
|
|
return sw;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 22:24:41 +01:00
|
|
|
__declspec(dllexport) void __cdecl predict(void *ptr, float features[], float predictions[], double probabilities[], int rows) {
|
2020-02-08 21:08:21 +01:00
|
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
|
|
|
|
int cols = sw->cols;
|
|
|
|
|
|
|
|
|
|
svmnode **x = make_svmnode_array(features, rows, cols, sw->means, sw->sdevs, 0);
|
|
|
|
|
for (int r = 0; r < rows; r++)
|
2020-02-13 22:24:41 +01:00
|
|
|
predictions[r] = (float)svm_predict_probability(sw->model, x[r], &(probabilities[r * sw->classes]));
|
2020-02-08 21:08:21 +01:00
|
|
|
destroy_svmnode_array(x);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 22:24:41 +01:00
|
|
|
__declspec(dllexport) void *__cdecl loadModel(char *filename, int cols, int classes, double means[], double sdevs[]) {
|
2020-02-08 21:08:21 +01:00
|
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
|
|
|
|
sw->cols = cols;
|
|
|
|
|
sw->model = svm_load_model(filename);
|
2020-02-13 22:24:41 +01:00
|
|
|
sw->classes = classes;
|
2020-02-08 21:08:21 +01:00
|
|
|
sw->means = new double[cols];
|
|
|
|
|
sw->sdevs = new double[cols];
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
sw->means[c] = means[c];
|
|
|
|
|
sw->sdevs[c] = sdevs[c];
|
|
|
|
|
}
|
|
|
|
|
return sw;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 22:24:41 +01:00
|
|
|
__declspec(dllexport) void *__cdecl loadModelString(char *modelString, int cols, int classes, double means[], double sdevs[]) {
|
2020-02-08 21:08:21 +01:00
|
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
|
|
|
|
sw->cols = cols;
|
|
|
|
|
sw->model = svm_load_model_string(modelString);
|
2020-02-13 22:24:41 +01:00
|
|
|
sw->classes = classes;
|
2020-02-08 21:08:21 +01:00
|
|
|
sw->means = new double[cols];
|
|
|
|
|
sw->sdevs = new double[cols];
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
sw->means[c] = means[c];
|
|
|
|
|
sw->sdevs[c] = sdevs[c];
|
|
|
|
|
}
|
|
|
|
|
sw->problem = NULL;
|
|
|
|
|
return sw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__declspec(dllexport) void __cdecl getScales(void *ptr, double means[], double sdevs[]) {
|
|
|
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
|
|
|
|
int cols = sw->cols;
|
|
|
|
|
for (int c = 0; c < cols; c++) {
|
|
|
|
|
means[c] = sw->means[c];
|
|
|
|
|
sdevs[c] = sw->sdevs[c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 22:24:41 +01:00
|
|
|
__declspec(dllexport) char *__cdecl saveModelString (void *ptr) {
|
2020-02-08 21:08:21 +01:00
|
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
|
|
|
|
return svm_save_model_string(sw->model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__declspec(dllexport) int __cdecl saveModel(void *ptr, char *filename) {
|
|
|
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
|
|
|
|
return svm_save_model(filename, sw->model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__declspec(dllexport) void __cdecl destroyModel(void *ptr) {
|
|
|
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
|
|
|
|
delete sw->means;
|
|
|
|
|
delete sw->sdevs;
|
|
|
|
|
svm_free_and_destroy_model(&sw->model);
|
|
|
|
|
if (sw->problem != NULL) {
|
|
|
|
|
destroy_problem(sw->problem);
|
|
|
|
|
delete sw->problem;
|
|
|
|
|
}
|
|
|
|
|
delete sw;
|
|
|
|
|
}
|
|
|
|
|
}
|