Skip to content

Commit

Permalink
add coef_ attribute for linear kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
QinbinLi committed Mar 6, 2019
1 parent 6062b4f commit d71b447
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 0 deletions.
8 changes: 8 additions & 0 deletions include/thundersvm/model/svmmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class SvmModel {
//return coef
const SyncArray<float_type> &get_coef() const;

//return linear_coef
const SyncArray<float_type> &get_linear_coef() const;

//return rho
const SyncArray<float_type> &get_rho() const;

Expand All @@ -102,6 +105,7 @@ class SvmModel {
//return prob_predict
const vector<float> &get_prob_predict() const;

void compute_linear_coef_single_model(size_t n_feature);
//get the params, for scikit load params
void get_param(char* kernel_type, int* degree, float* gamma, float* coef0, int* probability);
protected:
Expand All @@ -128,6 +132,10 @@ class SvmModel {
*/

SyncArray<float_type> coef;


///weights assigned to the features. Only available in the case of a linear kernel
SyncArray<float_type> linear_coef;
/**
* support vectors of this model. The support vectors is grouped in classes 0,1,2,.... The sequence of them in each
* group is as they appear in original dataset. A training instance is saved as a support vector IFF it is a
Expand Down
3 changes: 3 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ The usage of thundersvm scikit interface is similar to sklearn.svm.
*dual_coef_*: array, shape = [n_class-1, n_SV]\
coefficients of the support vector in the decision function. For multiclass, coefficient for all 1-vs-1 classifiers. The layout of the coefficients in the multiclass case is somewhat non-trivial.

*coef_*: array, shape = [n_class * (n_class-1)/2, n_features]\
Weights assigned to the features (coefficients in the primal problem). This is only available in the case of a linear kernel.

*intercept_*: array, shape = [n_class * (n_class-1) / 2]\
constants in decision function.

Expand Down
7 changes: 7 additions & 0 deletions python/thundersvmScikit.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ def fit(self, X, y):
self.n_binary_model = rho_size
rho = (c_float * rho_size)()
thundersvm.get_rho(rho, rho_size, c_void_p(self.model))

if self.kernel == 'linear':
coef = (c_float * (self.n_binary_model * self.n_sv))()
thundersvm.get_linear_coef(coef, self.n_binary_model, self.n_features, c_void_p(self.model))
self.coef_ = np.array([coef[index] for index in range(0, self.n_binary_model * self.n_features)]).astype(float)
self.coef_ = np.reshape(self.coef_, (self.n_binary_model, self.n_features))

self.intercept_ = np.array([rho[index] for index in range(0, rho_size)]).astype(float)

self.row = np.array([csr_row[index] for index in range(0, self.n_sv + 1)])
Expand Down
4 changes: 4 additions & 0 deletions src/thundersvm/model/nusvr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ void NuSVR::train(const DataSet &dataset, SvmParam param) {
NuSMOSolver solver(true);
solver.solve(kernelMatrix, y, alpha_2, rho.host_data()[0], f_val, param.epsilon, param.C, param.C, ws_size, max_iter);
save_svr_coef(alpha_2, dataset.instances());

if(param.kernel_type == SvmParam::LINEAR){
compute_linear_coef_single_model(dataset.n_features());
}
}

void NuSVR::model_setup(const DataSet &dataset, SvmParam &param) {
Expand Down
4 changes: 4 additions & 0 deletions src/thundersvm/model/oneclass_svc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ void OneClassSVC::train(const DataSet &dataset, SvmParam param) {
n_total_sv = sv.size();
coef.resize(coef_vec.size());
coef.copy_from(coef_vec.data(), coef_vec.size());

if(param.kernel_type == SvmParam::LINEAR){
compute_linear_coef_single_model(dataset.n_features());
}
}

vector<float_type> OneClassSVC::predict(const DataSet::node2d &instances, int batch_size) {
Expand Down
20 changes: 20 additions & 0 deletions src/thundersvm/model/svc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ void SVC::train(const DataSet &dataset, SvmParam param) {
}
}

///TODO: Use coef instead of alpha_data to compute linear_coef_data
if(param.kernel_type == SvmParam::LINEAR){
int k = 0;
linear_coef.resize(n_binary_models * dataset_.n_features());
float_type *linear_coef_data = linear_coef.host_data();
for (int i = 0; i < n_classes; i++){
for (int j = i + 1; j < n_classes; j++){
const float_type *alpha_data = alpha[k].host_data();
DataSet::node2d ins = dataset_.instances(i, j);//get instances of class i and j
for(int iid = 0; iid < ins.size(); iid++) {
for (int fid = 0; fid < ins[iid].size(); fid++) {
if(alpha_data[iid] != 0)
linear_coef_data[k * dataset_.n_features() + ins[iid][fid].index - 1] += alpha_data[iid] * ins[iid][fid].value;
}
}
k++;
}
}
}

//train probability
if (1 == param.probability) {
LOG(INFO) << "performing probability train";
Expand Down
15 changes: 15 additions & 0 deletions src/thundersvm/model/svmmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ const SyncArray<float_type> &SvmModel::get_coef() const {
return coef;
}

const SyncArray<float_type> &SvmModel::get_linear_coef() const {
return linear_coef;
}

const SyncArray<float_type> &SvmModel::get_rho() const {
return rho;
}
Expand Down Expand Up @@ -374,3 +378,14 @@ void SvmModel::get_param(char* kernel_type, int* degree, float* gamma, float* co
*coef0 = param.coef0;
*probability = param.probability;
}

void SvmModel::compute_linear_coef_single_model(size_t n_feature){
linear_coef.resize(n_feature);
float_type* linear_coef_data = linear_coef.host_data();
float_type* coef_data = coef.host_data();
for(int i = 0; i < n_total_sv; i++){
for(int j = 0; j < sv[i].size(); j++){
linear_coef_data[sv[i][j].index - 1] += coef_data[i] * sv[i][j].value;
}
}
};
4 changes: 4 additions & 0 deletions src/thundersvm/model/svr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ void SVR::train(const DataSet &dataset, SvmParam param) {
CSMOSolver solver;
solver.solve(kernelMatrix, y, alpha_2, rho.host_data()[0], f_val, param.epsilon, param.C, param.C, ws_size, max_iter);
save_svr_coef(alpha_2, dataset.instances());

if(param.kernel_type == SvmParam::LINEAR){
compute_linear_coef_single_model(dataset.n_features());
}
}

void SVR::save_svr_coef(const SyncArray<float_type> &alpha_2, const DataSet::node2d &instances) {
Expand Down
9 changes: 9 additions & 0 deletions src/thundersvm/thundersvm-scikit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,15 @@ extern "C" {
}
}

void get_linear_coef(float* linear_coef, int n_binary_model, int n_feature, SvmModel* model){
SyncArray<float_type > coef(n_binary_model * n_feature);
coef.copy_from(model->get_linear_coef());
float_type * coef_ptr = coef.host_data();
for(int i = 0; i < coef.size(); i++){
linear_coef[i] = coef_ptr[i];
}
}

void get_rho(float* rho_, int rho_size, SvmModel* model){
SyncArray<float_type > rho(rho_size);
rho.copy_from(model->get_rho());
Expand Down

0 comments on commit d71b447

Please sign in to comment.