Skip to content

Commit fcf1dc3

Browse files
committed
feat: serialize and deserialize model
1 parent 9daba62 commit fcf1dc3

File tree

5 files changed

+55
-7
lines changed

5 files changed

+55
-7
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CXX = em++
33

44
CFLAGS = -Wall -Wconversion -O3 -fPIC --memory-init-file 0
55
BUILD_DIR=dist
6-
EXPORTED_FUNCTIONS="['_parse_command_line', '_create_svm_nodes', '_add_instance', '_libsvm_train_problem', '_libsvm_train', '_libsvm_predict_one', '_get_svr_epsilon', '_svm_free_model', '_svm_get_svm_type', '_svm_get_nr_sv', '_svm_get_nr_class', '_svm_get_sv_indices', '_svm_get_labels', '_libsvm_cross_validation', '_free_problem']"
6+
EXPORTED_FUNCTIONS="['_parse_command_line', '_create_svm_nodes', '_add_instance', '_libsvm_train_problem', '_libsvm_train', '_libsvm_predict_one', '_get_svr_epsilon', '_svm_free_model', '_svm_get_svm_type', '_svm_get_nr_sv', '_svm_get_nr_class', '_svm_get_sv_indices', '_svm_get_labels', '_libsvm_cross_validation', '_free_problem', '_serialize_model', '_deserialize_model']"
77

88
all: wasm asm
99

@@ -14,7 +14,7 @@ wasm: js-interfaces.c svm.o libsvm/svm.h
1414
mkdir -p $(BUILD_DIR)/wasm; $(CC) $(CFLAGS) js-interfaces.c svm.o -o $(BUILD_DIR)/wasm/libsvm.js --pre-js src/wasmPreJS.js -s -s BINARYEN_ASYNC_COMPILATION=1 -s NO_FILESYSTEM=1 -s BINARYEN=1 -s "BINARYEN_METHOD='native-wasm'" -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS=$(EXPORTED_FUNCTIONS)
1515

1616
asm: js-interfaces.c svm.o libsvm/svm.h
17-
mkdir -p $(BUILD_DIR)/asm; $(CC) $(CFLAGS) js-interfaces.c svm.o -o $(BUILD_DIR)/asm/libsvm.js --pre-js src/asmPreJS.js -s -s NO_FILESYSTEM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS=$(EXPORTED_FUNCTIONS)
17+
mkdir -p $(BUILD_DIR)/asm; $(CC) $(CFLAGS) js-interfaces.c svm.o -o $(BUILD_DIR)/asm/libsvm.js --pre-js src/asmPreJS.js -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS=$(EXPORTED_FUNCTIONS)
1818

1919
clean:
2020
rm -f *~ js-interfaces.o ./svm.o

examples/xor.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
'use strict';
22

33
function xor(SVM) {
4-
let svm = new SVM();
5-
const features = [[1,1],[-1, -1],[1,-1],[-1, 1]];
6-
const labels = [1,1,-1,-1];
4+
let svm = new SVM({
5+
kernel: SVM.KERNEL_TYPES.RBF,
6+
type: SVM.SVM_TYPES.C_SVC,
7+
gamma: 1,
8+
cost: 1
9+
});
10+
const features = [[0,0],[1, 1],[1,0],[0, 1]];
11+
const labels = [0, 0, 1, 1];
712
svm.train(features, labels);
8-
for(var i=0; i<features.length; i++) {
9-
var pred = svm.predictOne(features[i]);
13+
for(let i=0; i<features.length; i++) {
14+
const pred = svm.predictOne(features[i]);
1015
console.log(`actual: ${labels[i]}, predicted: ${pred}`);
1116
}
1217

js-interfaces.c

+24
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,30 @@ void add_instance(struct svm_problem* prob, double* features, int nb_dimensions,
119119
prob->y[i] = y;
120120
}
121121

122+
char* serialize_model(struct svm_model* model)
123+
{
124+
int success = svm_save_model("testfile.txt", model);
125+
if(success < 0) return success;
126+
FILE *f = fopen("testfile.txt", "rb");
127+
fseek(f, 0, SEEK_END);
128+
long fsize = ftell(f);
129+
fseek(f, 0, SEEK_SET); //same as rewind(f);
130+
131+
char *string = malloc(fsize + 1);
132+
fread(string, fsize, 1, f);
133+
fclose(f);
134+
135+
string[fsize] = 0;
136+
return string;
137+
}
138+
139+
struct svm_model* deserialize_model(const char* serialized) {
140+
FILE *f = fopen("testfile.txt", "w");
141+
fprintf(f, "%s", serialized);
142+
fclose(f);
143+
return svm_load_model("testfile.txt");
144+
}
145+
122146
struct svm_problem* create_svm_nodes(int nb_features, int nb_dimensions)
123147
{
124148
struct svm_problem* prob = Malloc(struct svm_problem, 1);

js-interfaces.h

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ void print_null(const char *s);
1111
void exit_with_help();
1212
void parse_command_line(const char* input_command, struct svm_parameter* param);
1313
void add_instance(struct svm_problem* prob, double* features, int nb_dimensions, double y, int i);
14+
char* serialize_model(struct svm_model* model);
15+
struct svm_model* deserialize_model(const char* serialized);
1416
struct svm_problem* create_svm_nodes(int nb_features, int nb_dimensions);
1517
void svm_free_model(struct svm_model *model);
1618
struct svm_model* libsvm_train_problem(struct svm_problem* prob, const char* command);

src/loadSVM.js

+17
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ module.exports = function (libsvm) {
1414
const svm_free_model = libsvm.cwrap('svm_free_model', null, ['number']);
1515
const svm_cross_validation = libsvm.cwrap('libsvm_cross_validation', null, ['number', 'string', 'number', 'number']);
1616
const free_problem = libsvm.cwrap('free_problem', null, ['number']);
17+
const serialize_model = libsvm.cwrap('serialize_model', 'number', ['number']);
18+
const deserialize_model = libsvm.cwrap('deserialize_model', 'number', ['string']);
19+
1720
/* eslint-enable camelcase */
1821

1922
const SVM_TYPES = {
@@ -110,8 +113,22 @@ module.exports = function (libsvm) {
110113
return getIntArrayFromModel(svm_get_sv_indices, this.model, nSV)
111114
.map(i => i - 1);
112115
}
116+
117+
serializeModel() {
118+
if(!this.model) throw new Error('Cannot serialize model. No model was trained');
119+
const result = serialize_model(this.model);
120+
const str = libsvm.Pointer_stringify(result);
121+
libsvm._free(result);
122+
return str;
123+
}
113124
}
114125

126+
SVM.load = function(serializedModel) {
127+
const svm = new SVM();
128+
svm.model = deserialize_model(serializedModel);
129+
return svm;
130+
};
131+
115132
SVM.SVM_TYPES = SVM_TYPES;
116133
SVM.KERNEL_TYPES = KERNEL_TYPES;
117134

0 commit comments

Comments
 (0)