216 lines
6.7 KiB
C++
216 lines
6.7 KiB
C++
|
|
// ThunderSVMWrapper.cpp : Defines the exported functions for the DLL.
|
||
|
|
//
|
||
|
|
|
||
|
|
#include "pch.h"
|
||
|
|
#include "framework.h"
|
||
|
|
#include "ThunderSVMWrapper.h"
|
||
|
|
#include "thundersvm/thundersvm.h"
|
||
|
|
#include "thundersvm/model/svmmodel.h"
|
||
|
|
#include "thundersvm/model/svc.h"
|
||
|
|
#include <cmath>
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
extern "C" void __cdecl print_log(const char *str) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct problem {
|
||
|
|
int r;
|
||
|
|
int c;
|
||
|
|
DataSet::node2d x;
|
||
|
|
vector<double> y;
|
||
|
|
DataSet dataset;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct SVMWrapper {
|
||
|
|
SVC *model;
|
||
|
|
int cols;
|
||
|
|
int classes;
|
||
|
|
double *means;
|
||
|
|
double *sdevs;
|
||
|
|
SvmParam param;
|
||
|
|
struct problem problem;
|
||
|
|
};
|
||
|
|
|
||
|
|
typedef struct svm_node svmnode;
|
||
|
|
|
||
|
|
void make_svmnode_array(DataSet::node2d &dataset, float features[], int rows, int cols, double *means, double *sdevs, int rescale) {
|
||
|
|
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++) {
|
||
|
|
dataset[r] = vector<DataSet::node>(cols);
|
||
|
|
int idx = 0;
|
||
|
|
for (int c = 0; c < cols; c++) {
|
||
|
|
dataset[r][c].index = c + 1;
|
||
|
|
dataset[r][c].value = (float)((features[r * cols + c] - means[c]) * sdevs[c]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void make_problem(struct problem &problem, float features[], float labels[], int rows, int cols, double *means, double *sdevs) {
|
||
|
|
problem.r = rows;
|
||
|
|
problem.c = cols;
|
||
|
|
problem.y = vector<double>(rows);
|
||
|
|
for (int i = 0; i < rows; i++)
|
||
|
|
problem.y[i] = (double)labels[i];
|
||
|
|
problem.x = DataSet::node2d(rows);
|
||
|
|
make_svmnode_array(problem.x, features, rows, cols, means, sdevs, 1);
|
||
|
|
problem.dataset = DataSet(problem.x, cols, problem.y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void destroy_problem(struct problem &problem) {
|
||
|
|
problem.y.clear();
|
||
|
|
problem.x.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C" {
|
||
|
|
__declspec(dllexport) void *__cdecl trainModel(float features[], float labels[], float weights[], int rows, int cols, int classes, int probability, float C) {
|
||
|
|
if (!(rows > 0 && cols > 0))
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
//svm_set_print_string_function(print_log);
|
||
|
|
|
||
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
||
|
|
sw->cols = cols;
|
||
|
|
sw->classes = classes;
|
||
|
|
sw->means = new double[cols];
|
||
|
|
sw->sdevs = new double[cols];
|
||
|
|
|
||
|
|
sw->param.svm_type = SvmParam::C_SVC;
|
||
|
|
sw->param.kernel_type = SvmParam::RBF;
|
||
|
|
sw->param.degree = 3;
|
||
|
|
sw->param.gamma = 1.0 / (double)cols;
|
||
|
|
sw->param.coef0 = 0;
|
||
|
|
sw->param.nu = 0.5;
|
||
|
|
sw->param.C = C;
|
||
|
|
sw->param.epsilon = 0.001;
|
||
|
|
sw->param.p = 0.1;
|
||
|
|
sw->param.probability = probability;
|
||
|
|
sw->param.nr_weight = 0;
|
||
|
|
sw->param.weight_label = NULL;
|
||
|
|
sw->param.weight = NULL;
|
||
|
|
|
||
|
|
if (weights != NULL) {
|
||
|
|
sw->param.nr_weight = classes;
|
||
|
|
sw->param.weight_label = new int[classes];
|
||
|
|
sw->param.weight = new double[classes];
|
||
|
|
for (int i = 0; i < classes; i++) {
|
||
|
|
sw->param.weight_label[i] = i;
|
||
|
|
sw->param.weight[i] = (double)weights[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
make_problem(sw->problem, features, labels, rows, cols, sw->means, sw->sdevs);
|
||
|
|
sw->model = new SVC();//svm_train(sw->problem, &sw->param);
|
||
|
|
sw->model->train(sw->problem.dataset, sw->param);
|
||
|
|
|
||
|
|
if (weights != NULL) {
|
||
|
|
delete sw->param.weight_label;
|
||
|
|
delete sw->param.weight;
|
||
|
|
}
|
||
|
|
|
||
|
|
return sw;
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) void __cdecl predict(void *ptr, float features[], float predictions[], double probabilities[], int rows) {
|
||
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
||
|
|
int cols = sw->cols;
|
||
|
|
|
||
|
|
DataSet::node2d instances = DataSet::node2d(rows);
|
||
|
|
make_svmnode_array(instances, features, rows, sw->cols, sw->means, sw->sdevs, 0);
|
||
|
|
vector<double> predicted = sw->model->predict(instances, -1);
|
||
|
|
instances.clear();
|
||
|
|
for (int r = 0; r < rows; r++)
|
||
|
|
predictions[r] = (float)predicted[r];
|
||
|
|
predicted.clear();
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) void *__cdecl loadModel(char *filename, int cols, int classes, double means[], double sdevs[]) {
|
||
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
||
|
|
sw->cols = cols;
|
||
|
|
sw->model = new SVC();
|
||
|
|
sw->model->load_from_file(filename);
|
||
|
|
sw->classes = classes;
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) void *__cdecl loadModelString(char *modelString, int cols, int classes, double means[], double sdevs[]) {
|
||
|
|
struct SVMWrapper *sw = new SVMWrapper();
|
||
|
|
sw->cols = cols;
|
||
|
|
sw->model = new SVC();
|
||
|
|
sw->model->load_from_string(modelString);
|
||
|
|
sw->classes = classes;
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
__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];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) const char *__cdecl saveModelString(void *ptr) {
|
||
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
||
|
|
string model = sw->model->save_to_string();
|
||
|
|
return _strdup(model.c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) int __cdecl saveModel(void *ptr, char *filename) {
|
||
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
||
|
|
sw->model->save_to_file(string(filename));
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
__declspec(dllexport) void __cdecl destroyModel(void *ptr) {
|
||
|
|
struct SVMWrapper *sw = (struct SVMWrapper *)ptr;
|
||
|
|
delete sw->means;
|
||
|
|
delete sw->sdevs;
|
||
|
|
delete sw->model;
|
||
|
|
destroy_problem(sw->problem);
|
||
|
|
delete sw;
|
||
|
|
}
|
||
|
|
}
|