Fix svm runtime (replaces #91, #33) (#101)

* Fix svm runtime
This commit is contained in:
Xavier Dupré 2019-05-14 22:04:18 +02:00 committed by GitHub
parent 406770c484
commit d32d2fbfb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 262 additions and 162 deletions

View file

@ -287,39 +287,56 @@ static inline void ComputeSoftmaxZero(std::vector<float>& values) {
template <typename T>
void write_scores(std::vector<T>& scores, POST_EVAL_TRANSFORM post_transform, int64_t write_index, Tensor* Z,
int add_second_class) {
if (post_transform == POST_EVAL_TRANSFORM::PROBIT && scores.size() == 1) {
scores[0] = ComputeProbit(scores[0]);
} else if (scores.size() >= 2) { //multiclass
if (post_transform == POST_EVAL_TRANSFORM::LOGISTIC) {
for (float& score : scores) {
score = ComputeLogistic(score);
}
} else if (post_transform == POST_EVAL_TRANSFORM::SOFTMAX) {
ComputeSoftmax(scores);
} else if (post_transform == POST_EVAL_TRANSFORM::SOFTMAX_ZERO) {
ComputeSoftmaxZero(scores);
if (scores.size() >= 2) {
switch (post_transform) {
case POST_EVAL_TRANSFORM::PROBIT:
for (float& score : scores)
score = ComputeProbit(score);
break;
case POST_EVAL_TRANSFORM::LOGISTIC:
for (float& score : scores)
score = ComputeLogistic(score);
break;
case POST_EVAL_TRANSFORM::SOFTMAX:
ComputeSoftmax(scores);
break;
case POST_EVAL_TRANSFORM::SOFTMAX_ZERO:
ComputeSoftmaxZero(scores);
break;
default:
case POST_EVAL_TRANSFORM::NONE:
break;
}
} else { //binary case
if (add_second_class == 0 && scores.size() == 1) { //0=all positive weights, winning class is positive
scores.push_back(scores[0]);
scores[0] = 1.f - scores[0]; //put opposite score in positive slot
} else if (add_second_class == 1 && scores.size() == 1) { //1 = all positive weights, winning class is negative
scores.push_back(scores[0]);
scores[0] = 1.f - scores[0]; //put opposite score in positive slot
} else if (add_second_class == 2 && scores.size() == 1) { //2 = mixed weights, winning class is positive
if (post_transform == POST_EVAL_TRANSFORM::LOGISTIC) {
scores.push_back(ComputeLogistic(scores[0]));
scores[0] = ComputeLogistic(-scores[0]);
} else {
scores.push_back(scores[0]);
scores[0] = -scores[0];
}
} else if (add_second_class == 3 && scores.size() == 1) { //3 = mixed weights, winning class is negative
if (post_transform == POST_EVAL_TRANSFORM::LOGISTIC) {
scores.push_back(ComputeLogistic(scores[0]));
scores[0] = ComputeLogistic(-scores[0]);
} else {
scores.push_back(-scores[0]);
} else if (scores.size() == 1) { //binary case
if (post_transform == POST_EVAL_TRANSFORM::PROBIT) {
scores[0] = ComputeProbit(scores[0]);
} else {
switch (add_second_class) {
case 0: //0=all positive weights, winning class is positive
scores.push_back(scores[0]);
scores[0] = 1.f - scores[0]; //put opposite score in positive slot
break;
case 1: //1 = all positive weights, winning class is negative
scores.push_back(scores[0]);
scores[0] = 1.f - scores[0]; //put opposite score in positive slot
break;
case 2: //2 = mixed weights, winning class is positive
if (post_transform == POST_EVAL_TRANSFORM::LOGISTIC) {
scores.push_back(ComputeLogistic(scores[0])); //ml_logit(scores[k]);
scores[0] = ComputeLogistic(-scores[0]);
} else {
scores.push_back(scores[0]);
scores[0] = -scores[0];
}
break;
case 3: //3 = mixed weights, winning class is negative
if (post_transform == POST_EVAL_TRANSFORM::LOGISTIC) {
scores.push_back(ComputeLogistic(scores[0])); //ml_logit(scores[k]);
scores[0] = ComputeLogistic(-scores[0]);
} else {
scores.push_back(-scores[0]);
}
break;
}
}
}

View file

@ -75,6 +75,32 @@ SVMClassifier<T>::SVMClassifier(const OpKernelInfo& info)
}
}
template <typename LabelType>
int _set_score_svm(Tensor* Y, float max_weight, const int64_t maxclass, const int64_t n,
POST_EVAL_TRANSFORM post_transform_, const std::vector<float>& proba_, bool weights_are_all_positive_,
const std::vector<LabelType>& classlabels, LabelType posclass, LabelType negclass) {
int write_additional_scores = -1;
auto output_data = Y->template MutableData<LabelType>();
if (classlabels.size() == 2) {
write_additional_scores = post_transform_ == POST_EVAL_TRANSFORM::NONE ? 2 : 0;
if (proba_.size() == 0) {
if (weights_are_all_positive_ && max_weight >= 0.5)
output_data[n] = classlabels[1];
else if (max_weight > 0 && !weights_are_all_positive_)
output_data[n] = classlabels[1];
else
output_data[n] = classlabels[maxclass];
} else {
output_data[n] = classlabels[maxclass];
}
} else if (max_weight > 0) {
output_data[n] = posclass;
} else {
output_data[n] = negclass;
}
return write_additional_scores;
}
template <typename T>
Status SVMClassifier<T>::Compute(OpKernelContext* ctx) const {
const Tensor* X = ctx->Input<Tensor>(0);
@ -83,40 +109,51 @@ Status SVMClassifier<T>::Compute(OpKernelContext* ctx) const {
int64_t N = X->Shape().NumDimensions() == 1 ? 1 : X->Shape()[0];
Tensor* Y = ctx->Output(0, TensorShape({N}));
Tensor* Z;
std::vector<int64_t> dims;
if (mode_ == SVM_TYPE::SVM_SVC && proba_.size() == 0)
dims = {static_cast<int64_t>(N), static_cast<int64_t>(class_count_ * (class_count_ - 1) / 2)};
else
dims = {static_cast<int64_t>(N), static_cast<int64_t>(class_count_)};
Z = ctx->Output(1, TensorShape(dims));
int64_t nb_columns = class_count_;
if (proba_.size() == 0 && vector_count_ > 0) {
if (class_count_ > 2)
nb_columns = class_count_ * (class_count_ - 1) / 2;
else
nb_columns = 2;
}
const auto* x_data = X->template Data<T>();
std::vector<int64_t> dims{N, nb_columns};
Tensor* Z = ctx->Output(1, TensorShape(dims));
const T* x_data = X->template Data<T>();
int64_t zindex = 0;
for (int64_t n = 0; n < N; n++) //for each example
{
int64_t current_weight_0 = n * stride;
int64_t maxclass = -1;
double maxweight = 0.f;
std::vector<float> decisions;
std::vector<float> scores;
std::vector<float> kernels;
std::vector<int64_t> votes;
if (mode_ == SVM_TYPE::SVM_SVC) {
if (vector_count_ == 0 && mode_ == SVM_TYPE::SVM_LINEAR) {
for (int64_t j = 0; j < class_count_; j++) { //for each class
auto val = kernel_dot(x_data, current_weight_0, coefficients_, feature_count_ * j,
feature_count_, get_kernel_type());
val += rho_[0];
scores.push_back(val);
}
} else {
if (vector_count_ == 0)
return Status(common::ONNXRUNTIME, common::FAIL, "No support vectors.");
int evals = 0;
for (int64_t j = 0; j < vector_count_; j++) {
float val = kernel_dot(x_data, current_weight_0, support_vectors_, feature_count_ * j, feature_count_, get_kernel_type());
auto val = kernel_dot(x_data, current_weight_0, support_vectors_, feature_count_ * j,
feature_count_, get_kernel_type());
kernels.push_back(val);
}
for (int64_t j = 0; j < class_count_; j++) {
votes.push_back(0);
}
int evals = 0;
for (int64_t i = 0; i < class_count_; i++) { //for each class
for (int64_t j = i + 1; j < class_count_; j++) { //for each class
float sum = 0;
votes.resize(class_count_, 0);
for (int64_t i = 0; i < class_count_; i++) { // for each class
for (int64_t j = i + 1; j < class_count_; j++) { // for each class
double sum = 0;
int64_t start_index_i = starting_vector_[i]; // *feature_count_;
int64_t start_index_j = starting_vector_[j]; // *feature_count_;
@ -125,120 +162,71 @@ Status SVMClassifier<T>::Compute(OpKernelContext* ctx) const {
int64_t pos1 = (vector_count_) * (j - 1);
int64_t pos2 = (vector_count_) * (i);
for (int64_t m = 0; m < class_i_support_count; m++) {
float val1 = coefficients_[pos1 + start_index_i + m];
float val2 = kernels[start_index_i + m];
sum += val1 * val2;
}
for (int64_t m = 0; m < class_j_support_count; m++) {
float val1 = coefficients_[pos2 + start_index_j + m];
float val2 = kernels[start_index_j + m];
sum += val1 * val2;
}
const float* val1 = &(coefficients_[pos1 + start_index_i]);
const float* val2 = &(kernels[start_index_i]);
for (int64_t m = 0; m < class_i_support_count; ++m, ++val1, ++val2)
sum += *val1 * *val2;
val1 = &(coefficients_[pos2 + start_index_j]);
val2 = &(kernels[start_index_j]);
for (int64_t m = 0; m < class_j_support_count; ++m, ++val1, ++val2)
sum += *val1 * *val2;
sum += rho_[evals];
scores.push_back(sum);
if (sum > 0) {
votes[i]++;
} else {
votes[j]++;
}
evals++; //index into rho
scores.push_back((float)sum);
++(votes[sum > 0 ? i : j]);
++evals; //index into rho
}
}
} else if (mode_ == SVM_TYPE::SVM_LINEAR) { //liblinear
for (int64_t j = 0; j < class_count_; j++) { //for each class
float val = kernel_dot(x_data, current_weight_0, coefficients_, feature_count_ * j, feature_count_, get_kernel_type());
val += rho_[0];
scores.push_back(val);
}
}
if (proba_.size() > 0 && mode_ == SVM_TYPE::SVM_SVC) {
//compute probabilities from the scores
std::vector<float> estimates;
std::vector<float> probsp2;
int64_t num = class_count_ * class_count_;
for (int64_t m = 0; m < num; m++) {
probsp2.push_back(0.f); //min prob
}
for (int64_t m = 0; m < class_count_; m++) {
estimates.push_back(0.f); //min prob
}
std::vector<float> probsp2(num, 0.f);
std::vector<float> estimates(class_count_, 0.f);
int64_t index = 0;
for (int64_t i = 0; i < class_count_; i++) {
for (int64_t j = i + 1; j < class_count_; j++) {
for (int64_t i = 0; i < class_count_; ++i) {
int64_t p1 = i * class_count_ + i + 1;
int64_t p2 = (i + 1) * class_count_ + i;
for (int64_t j = i + 1; j < class_count_; ++j, ++index) {
float val1 = sigmoid_probability(scores[index], proba_[index], probb_[index]);
float val2 = std::max(val1, 1.0e-7f);
probsp2[i * class_count_ + j] = std::min(val2, 1 - 1.0e-7f);
probsp2[j * class_count_ + i] = 1 - probsp2[i * class_count_ + j];
index++;
val2 = std::min(val2, 1 - 1.0e-7f);
probsp2[p1] = val2;
probsp2[p2] = 1 - val2;
++p1;
p2 += class_count_;
}
}
multiclass_probability(class_count_, probsp2, estimates);
//copy probabilities back into scores
// copy probabilities back into scores
scores.resize(estimates.size());
for (int64_t k = 0; k < static_cast<int64_t>(estimates.size()); k++) {
scores[k] = estimates[k];
}
std::copy(estimates.begin(), estimates.end(), scores.begin());
}
int64_t maxvotes = 0;
float max_weight = 0;
if (votes.size() > 0) {
for (int64_t k = 0; k < static_cast<int64_t>(votes.size()); k++) {
if (votes[k] > maxvotes) {
maxvotes = votes[k];
maxclass = k;
}
}
auto it_maxvotes = std::max_element(votes.begin(), votes.end());
maxclass = std::distance(votes.begin(), it_maxvotes);
} else {
for (int64_t k = 0; k < static_cast<int64_t>(scores.size()); k++) {
if (scores[k] > maxweight) {
maxclass = k;
maxweight = scores[k];
}
}
auto it_max_weight = std::max_element(scores.begin(), scores.end());
maxclass = std::distance(scores.begin(), it_max_weight);
max_weight = *it_max_weight;
}
//write top class
// write top class
// onnx specs expects one column per class.
int write_additional_scores = -1;
if (rho_.size() == 1) //binary
{
if (rho_.size() == 1) {
if (using_strings_) {
if (classlabels_strings_.size() == 2 && weights_are_all_positive_ && maxweight >= 0.5 && proba_.size() == 0) {
Y->template MutableData<std::string>()[n] = classlabels_strings_[1]; //positive label
write_additional_scores = 0;
} else if (classlabels_strings_.size() == 2 && maxweight > 0 && !weights_are_all_positive_ && proba_.size() == 0) {
Y->template MutableData<std::string>()[n] = classlabels_strings_[1]; //positive label
write_additional_scores = 0;
} else if (classlabels_strings_.size() == 2 && proba_.size() > 0) { //this case all classes are in their rightful spot
Y->template MutableData<std::string>()[n] = classlabels_strings_[maxclass]; //whichever label
write_additional_scores = -1;
} else if (classlabels_strings_.size() == 2) {
Y->template MutableData<std::string>()[n] = classlabels_strings_[0]; //negative label
write_additional_scores = 1;
} else if (maxweight > 0) {
Y->template MutableData<std::string>()[n] = "1"; //positive label
} else {
Y->template MutableData<std::string>()[n] = "0"; //negative label
}
} else //no strings
{
if (classlabels_ints_.size() == 2 && weights_are_all_positive_ && maxweight >= 0.5 && proba_.size() == 0) {
Y->template MutableData<int64_t>()[n] = classlabels_ints_[1]; //positive label
write_additional_scores = 0;
} else if (classlabels_ints_.size() == 2 && maxweight > 0 && !weights_are_all_positive_ && proba_.size() == 0) {
Y->template MutableData<int64_t>()[n] = classlabels_ints_[0]; //pos label
write_additional_scores = 0;
} else if (classlabels_ints_.size() == 2 && proba_.size() > 0) //this case all classes are in their rightful spot
{
Y->template MutableData<int64_t>()[n] = classlabels_ints_[maxclass]; //whichever label
write_additional_scores = -1;
} else if (classlabels_ints_.size() == 2) {
Y->template MutableData<int64_t>()[n] = classlabels_ints_[0]; //negative label
write_additional_scores = 1;
} else if (maxweight > 0) {
Y->template MutableData<int64_t>()[n] = 1; //positive label
} else {
Y->template MutableData<int64_t>()[n] = 0; //negative label
}
write_additional_scores = _set_score_svm<std::string>(
Y, max_weight, maxclass, n, post_transform_, proba_,
weights_are_all_positive_, classlabels_strings_, "1", "0");
} else {
write_additional_scores = _set_score_svm<int64_t>(
Y, max_weight, maxclass, n, post_transform_, proba_,
weights_are_all_positive_, classlabels_ints_, 1, 0);
}
} else { //multiclass
if (using_strings_) {

View file

@ -30,31 +30,30 @@ class SVMCommon {
KERNEL get_kernel_type() const { return kernel_type_; }
float kernel_dot(const T* A, int64_t a, const std::vector<float>& B, int64_t b, int64_t len, KERNEL k) const {
float sum = 0.f;
double sum = 0;
const T* pA = A + a;
const float* pB = B.data() + b;
if (k == KERNEL::POLY) {
for (int64_t i = 0; i < len; i++) {
sum += B[b + i] * static_cast<float>(A[a + i]);
}
for (int64_t i = len; i > 0; --i, ++pA, ++pB)
sum += *pA * *pB;
sum = gamma_ * sum + coef0_;
sum = std::pow(sum, degree_);
} else if (k == KERNEL::SIGMOID) {
for (int64_t i = 0; i < len; i++) {
sum += B[b + i] * static_cast<float>(A[a + i]);
}
for (int64_t i = len; i > 0; --i, ++pA, ++pB)
sum += *pA * *pB;
sum = gamma_ * sum + coef0_;
sum = std::tanh(sum);
} else if (k == KERNEL::RBF) {
for (int64_t i = 0; i < len; i++) {
float val = static_cast<float>(A[a + i]) - B[b + i];
sum += (val * val);
for (int64_t i = len; i > 0; --i, ++pA, ++pB) {
double val = *pA - *pB;
sum += val * val;
}
sum = std::exp(-gamma_ * sum);
} else if (k == KERNEL::LINEAR) {
for (int64_t i = 0; i < len; i++) {
sum += B[b + i] * static_cast<float>(A[a + i]);
}
for (int64_t i = len; i > 0; --i, ++pA, ++pB)
sum += *pA * *pB;
}
return sum;
return (float)sum;
}
private:

View file

@ -10,14 +10,20 @@ namespace test {
TEST(MLOpTest, SVMClassifierMulticlassSVC) {
OpTester test("SVMClassifier", 1, onnxruntime::kMLDomain);
std::vector<float> dual_coefficients = {1.14360327f, 1.95968249f, -1.175683f, -1.92760275f, -1.32575698f, -1.32575698f, 0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, -1.06631298f, -1.06631298f, 0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, 1.f, -1.f};
std::vector<float> support_vectors = {0.f, 0.5f, 32.f, 2.f, 2.9f, -32.f, 1.f, 1.5f, 1.f, 3.f, 13.3f, -11.f, 12.f, 12.9f, -312.f, 43.f, 413.3f, -114.f};
std::vector<float> dual_coefficients = {1.14360327f, 1.95968249f, -1.175683f, -1.92760275f, -1.32575698f,
-1.32575698f, 0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f,
-1.06631298f, -1.06631298f, 0.66332785f, 0.66242913f, 0.53120854f,
0.53510444f, 1.f, -1.f};
std::vector<float> support_vectors = {0.f, 0.5f, 32.f, 2.f, 2.9f, -32.f, 1.f, 1.5f, 1.f, 3.f,
13.3f, -11.f, 12.f, 12.9f, -312.f, 43.f, 413.3f, -114.f};
std::vector<int64_t> classes = {0, 1, 2, 3};
std::vector<int64_t> vectors_per_class = {2, 2, 1, 1};
std::vector<float> rho = {0.5279583f, 0.32605162f, 0.32605162f, 0.06663721f, 0.06663721f, 0.f};
std::vector<float> kernel_params = {0.001f, 0.f, 3.f}; //gamma, coef0, degree
std::vector<float> X = {1.f, 0.0f, 0.4f, 3.0f, 44.0f, -3.f, 12.0f, 12.9f, -312.f, 23.0f, 11.3f, -222.f, 23.0f, 11.3f, -222.f, 23.0f, 3311.3f, -222.f, 23.0f, 11.3f, -222.f, 43.0f, 413.3f, -114.f};
std::vector<float> X = {1.f, 0.0f, 0.4f, 3.0f, 44.0f, -3.f, 12.0f, 12.9f, -312.f, 23.0f,
11.3f, -222.f, 23.0f, 11.3f, -222.f, 23.0f, 3311.3f, -222.f, 23.0f,
11.3f, -222.f, 43.0f, 413.3f, -114.f};
std::vector<int64_t> predictions = {1, 1, 2, 0, 0, 0, 0, 3};
std::vector<float> scores = {
-0.956958294f, 0.799815655f, 0.799815655f, 0.988598406f, 0.988598406f, 0,
@ -47,12 +53,18 @@ TEST(MLOpTest, SVMClassifierMulticlassSVC) {
TEST(MLOpTest, SVMClassifierMulticlassLinearSVC) {
OpTester test("SVMClassifier", 1, onnxruntime::kMLDomain);
std::vector<float> dual_coefficients = {-1.55181212e-01f, 2.42698956e-01f, 7.01893432e-03f, 4.07614474e-01f, -3.24927823e-02f, 2.79897536e-04f, -1.95771302e-01f, -3.52437368e-01f, -2.15973096e-02f, -4.38190277e-01f, 4.56869105e-02f, -1.29375499e-02f};
std::vector<float> dual_coefficients = {-1.55181212e-01f, 2.42698956e-01f, 7.01893432e-03f,
4.07614474e-01f, -3.24927823e-02f, 2.79897536e-04f,
-1.95771302e-01f, -3.52437368e-01f, -2.15973096e-02f,
-4.38190277e-01f, 4.56869105e-02f, -1.29375499e-02f};
std::vector<int64_t> classes = {0, 1, 2, 3};
std::vector<float> rho = {-0.07489691f, -0.1764396f, -0.21167431f, -0.51619097f};
std::vector<float> kernel_params = {0.001f, 0.f, 3.f}; //gamma, coef0, degree
std::vector<float> X = {1.f, 0.0f, 0.4f, 3.0f, 44.0f, -3.f, 12.0f, 12.9f, -312.f, 23.0f, 11.3f, -222.f, 23.0f, 11.3f, -222.f, 23.0f, 3311.3f, -222.f, 23.0f, 11.3f, -222.f, 43.0f, 413.3f, -114.f};
std::vector<float> X = {1.f, 0.0f, 0.4f, 3.0f, 44.0f, -3.f,
12.0f, 12.9f, -312.f, 23.0f, 11.3f, -222.f,
23.0f, 11.3f, -222.f, 23.0f, 3311.3f, -222.f,
23.0f, 11.3f, -222.f, 43.0f, 413.3f, -114.f};
std::vector<int64_t> predictions = {1, 0, 1, 1, 1, 0, 1, 0};
std::vector<float> scores = {
-0.227270544f, 0.332829535f, -0.279307127f, -0.518262208f,
@ -115,5 +127,89 @@ TEST(MLOpTest, SVMClassifierSVCProbabilities) {
test.Run();
}
TEST(MLOpTest, SVMClassifierSVC) {
OpTester test("SVMClassifier", 1, onnxruntime::kMLDomain);
std::vector<float> coefficients = {1.14360327f, 1.95968249f, -1.175683f, -1.92760275f, -1.32575698f, -1.32575698f,
0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, -1.06631298f, -1.06631298f,
0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, 1.f, -1.f};
std::vector<float> support_vectors = {0.f, 0.5f, 32.f, 2.f, 2.9f, -32.f,
1.f, 1.5f, 1.f, 3.f, 13.3f, -11.f,
12.f, 12.9f, -312.f, 43.f, 413.3f, -114.f};
std::vector<float> rho = {0.5279583f};
std::vector<float> kernel_params = {0.001f, 0.f, 3.f}; //gamma, coef0, degree
std::vector<int64_t> classes = {0, 1};
std::vector<int64_t> vectors_per_class = {3, 3};
std::vector<float> X = {1.f, 0.0f, 0.4f,
3.0f, 44.0f, -3.f,
12.0f, 12.9f, -312.f,
23.0f, 11.3f, -222.f,
23.0f, 11.3f, -222.f};
std::vector<float> scores_predictions = {
0.95695829391479492f, -0.95695829391479492f,
0.1597825288772583f, -0.1597825288772583f,
0.797798752784729f, -0.797798752784729f,
-0.52760261297225952f, 0.52760261297225952f,
-0.52760261297225952f, 0.52760261297225952f};
std::vector<int64_t> class_predictions = {1, 1, 1, 0, 0};
test.AddAttribute("kernel_type", std::string("RBF"));
test.AddAttribute("coefficients", coefficients);
test.AddAttribute("support_vectors", support_vectors);
test.AddAttribute("vectors_per_class", vectors_per_class);
test.AddAttribute("rho", rho);
test.AddAttribute("kernel_params", kernel_params);
test.AddAttribute("classlabels_ints", classes);
test.AddInput<float>("X", {5, 3}, X);
test.AddOutput<int64_t>("Y", {5}, class_predictions);
test.AddOutput<float>("Z", {5, 2}, scores_predictions);
test.Run();
}
TEST(MLOpTest, SVMClassifierSVCDouble) {
OpTester test("SVMClassifier", 1, onnxruntime::kMLDomain);
std::vector<float> coefficients = {1.14360327f, 1.95968249f, -1.175683f, -1.92760275f, -1.32575698f, -1.32575698f,
0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, -1.06631298f, -1.06631298f,
0.66332785f, 0.66242913f, 0.53120854f, 0.53510444f, 1.f, -1.f};
std::vector<float> support_vectors = {0.f, 0.5f, 32.f, 2.f, 2.9f, -32.f,
1.f, 1.5f, 1.f, 3.f, 13.3f, -11.f,
12.f, 12.9f, -312.f, 43.f, 413.3f, -114.f};
std::vector<float> rho = {0.5279583f};
std::vector<float> kernel_params = {0.001f, 0.f, 3.f}; //gamma, coef0, degree
std::vector<int64_t> classes = {0, 1};
std::vector<int64_t> vectors_per_class = {3, 3};
std::vector<double> X = {1.f, 0.0f, 0.4f,
3.0f, 44.0f, -3.f,
12.0f, 12.9f, -312.f,
23.0f, 11.3f, -222.f,
23.0f, 11.3f, -222.f};
std::vector<float> scores_predictions = {
0.95695829391479492f, -0.95695829391479492f,
0.1597825288772583f, -0.1597825288772583f,
0.797798752784729f, -0.797798752784729f,
-0.52760261297225952f, 0.52760261297225952f,
-0.52760261297225952f, 0.52760261297225952f};
std::vector<int64_t> class_predictions = {1, 1, 1, 0, 0};
test.AddAttribute("kernel_type", std::string("RBF"));
test.AddAttribute("coefficients", coefficients);
test.AddAttribute("support_vectors", support_vectors);
test.AddAttribute("vectors_per_class", vectors_per_class);
test.AddAttribute("rho", rho);
test.AddAttribute("kernel_params", kernel_params);
test.AddAttribute("classlabels_ints", classes);
test.AddInput<double>("X", {5, 3}, X);
test.AddOutput<int64_t>("Y", {5}, class_predictions);
test.AddOutput<float>("Z", {5, 2}, scores_predictions);
test.Run();
}
} // namespace test
} // namespace onnxruntime