mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-08 17:17:15 +00:00
Revert the last changes on tree ensemble classifier (#1498)
Revert PR #1015 and PR #1276 . Because PR #1015 is causing test failures, but I can't revert it individually. I have to revert it together with #1276
This commit is contained in:
parent
4ace393bea
commit
e0829b2b13
2 changed files with 80 additions and 214 deletions
|
|
@ -293,58 +293,6 @@ void TreeEnsembleClassifier<T>::Initialize() {
|
|||
base_values_.size() == weights_classes_.size());
|
||||
}
|
||||
|
||||
void get_max_weight(const std::map<int64_t, float>& classes, int64_t& maxclass, float& maxweight) {
|
||||
maxclass = -1;
|
||||
maxweight = 0.f;
|
||||
for (auto& classe : classes) {
|
||||
if (maxclass == -1 || classe.second > maxweight) {
|
||||
maxclass = classe.first;
|
||||
maxweight = classe.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_weight_class_positive(std::map<int64_t, float>& classes, float& pos_weight) {
|
||||
auto it_classes = classes.find(1);
|
||||
pos_weight = it_classes == classes.end()
|
||||
? (classes.size() > 0 ? classes[0] : 0.f) // only 1 class
|
||||
: it_classes->second;
|
||||
}
|
||||
|
||||
template <typename LabelType>
|
||||
void _set_score_binary(int64_t i, LabelType* y_data, int& write_additional_scores,
|
||||
bool weights_are_all_positive_,
|
||||
std::map<int64_t, float>& classes,
|
||||
const std::vector<LabelType>& classes_labels_,
|
||||
const std::set<int64_t>& weights_classes_,
|
||||
LabelType positive_label, LabelType negative_label) {
|
||||
float pos_weight;
|
||||
get_weight_class_positive(classes, pos_weight);
|
||||
if (classes_labels_.size() == 2 && weights_classes_.size() == 1) {
|
||||
if (weights_are_all_positive_) {
|
||||
if (pos_weight > 0.5) {
|
||||
y_data[i] = classes_labels_[1]; // positive label
|
||||
write_additional_scores = 0;
|
||||
} else {
|
||||
y_data[i] = classes_labels_[0]; // negative label
|
||||
write_additional_scores = 1;
|
||||
}
|
||||
} else {
|
||||
if (pos_weight > 0) {
|
||||
y_data[i] = classes_labels_[1]; // positive label
|
||||
write_additional_scores = 2;
|
||||
} else {
|
||||
y_data[i] = classes_labels_[0]; // negative label
|
||||
write_additional_scores = 3;
|
||||
}
|
||||
}
|
||||
} else if (pos_weight > 0) {
|
||||
y_data[i] = positive_label; // positive label
|
||||
} else {
|
||||
y_data[i] = negative_label; // negative label
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
common::Status TreeEnsembleClassifier<T>::Compute(OpKernelContext* context) const {
|
||||
const Tensor& X = *context->Input<Tensor>(0);
|
||||
|
|
@ -358,41 +306,37 @@ common::Status TreeEnsembleClassifier<T>::Compute(OpKernelContext* context) cons
|
|||
int64_t N = x_dims.size() == 1 ? 1 : x_dims[0];
|
||||
Tensor* Y = context->Output(0, TensorShape({N}));
|
||||
auto* Z = context->Output(1, TensorShape({N, class_count_}));
|
||||
|
||||
int64_t zindex = 0;
|
||||
const T* x_data = X.template Data<T>();
|
||||
|
||||
common::Status status;
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
// for each class
|
||||
std::vector<float> scores;
|
||||
scores.reserve(class_count_);
|
||||
for (int64_t i = 0; i < N; ++i) {
|
||||
int64_t zindex = i * class_count_;
|
||||
std::vector<float> scores;
|
||||
scores.clear();
|
||||
int64_t current_weight_0 = i * stride;
|
||||
std::map<int64_t, float> classes;
|
||||
// fill in base values, this might be empty but that is ok
|
||||
for (int64_t k = 0, end = static_cast<int64_t>(base_values_.size()); k < end; ++k) {
|
||||
auto p1 = std::make_pair<int64_t&, const float&>(k, base_values_[k]);
|
||||
classes.insert(p1);
|
||||
}
|
||||
// walk each tree from its root
|
||||
for (size_t j = 0, end = roots_.size(); j < end; ++j) {
|
||||
auto process_status = ProcessTreeNode(classes, roots_[j], x_data, current_weight_0);
|
||||
if (!process_status.IsOK()) {
|
||||
status = process_status;
|
||||
}
|
||||
ORT_RETURN_IF_ERROR(ProcessTreeNode(classes, roots_[j], x_data, current_weight_0));
|
||||
}
|
||||
float maxweight = 0.f;
|
||||
int64_t maxclass = -1;
|
||||
// write top class
|
||||
int write_additional_scores = -1;
|
||||
if (class_count_ > 2) {
|
||||
// add base values
|
||||
std::map<int64_t, float>::iterator it_classes;
|
||||
for (int64_t k = 0, end = static_cast<int64_t>(base_values_.size()); k < end; ++k) {
|
||||
it_classes = classes.find(k);
|
||||
if (it_classes == classes.end()) {
|
||||
auto p1 = std::make_pair<int64_t&, const float&>(k, base_values_[k]);
|
||||
classes.insert(p1);
|
||||
} else {
|
||||
it_classes->second += base_values_[k];
|
||||
for (auto& classe : classes) {
|
||||
if (maxclass == -1 || classe.second > maxweight) {
|
||||
maxclass = classe.first;
|
||||
maxweight = classe.second;
|
||||
}
|
||||
}
|
||||
get_max_weight(classes, maxclass, maxweight);
|
||||
if (using_strings_) {
|
||||
Y->template MutableData<std::string>()[i] = classlabels_strings_[maxclass];
|
||||
} else {
|
||||
|
|
@ -400,32 +344,68 @@ common::Status TreeEnsembleClassifier<T>::Compute(OpKernelContext* context) cons
|
|||
}
|
||||
} else // binary case
|
||||
{
|
||||
if (base_values_.size() == 2) {
|
||||
// add base values
|
||||
std::map<int64_t, float>::iterator it_classes;
|
||||
it_classes = classes.find(1);
|
||||
if (it_classes == classes.end()) {
|
||||
// base_value_[0] is not used. It assumes base_value[0] == base_value[1] in this case.
|
||||
// The specification does not forbid it but does not say what the output should be in that case.
|
||||
std::map<int64_t, float>::iterator it_classes0 = classes.find(0);
|
||||
classes[1] = base_values_[1] + it_classes0->second;
|
||||
it_classes0->second = -classes[1];
|
||||
} else {
|
||||
// binary as multiclass
|
||||
it_classes->second += base_values_[1];
|
||||
classes[0] += base_values_[0];
|
||||
}
|
||||
}
|
||||
maxweight = !classes.empty() ? classes[0] : 0.f; // only 1 class
|
||||
if (using_strings_) {
|
||||
_set_score_binary<std::string>(i, Y->template MutableData<std::string>(),
|
||||
write_additional_scores, weights_are_all_positive_,
|
||||
classes, classlabels_strings_,
|
||||
weights_classes_, "1", "0");
|
||||
auto* y_data = Y->template MutableData<std::string>();
|
||||
if (classlabels_strings_.size() == 2 &&
|
||||
weights_are_all_positive_ &&
|
||||
maxweight > 0.5 &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_strings_[1]; // positive label
|
||||
write_additional_scores = 0;
|
||||
} else if (classlabels_strings_.size() == 2 &&
|
||||
weights_are_all_positive_ &&
|
||||
maxweight <= 0.5 &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_strings_[0]; // negative label
|
||||
write_additional_scores = 1;
|
||||
} else if (classlabels_strings_.size() == 2 &&
|
||||
maxweight > 0 &&
|
||||
!weights_are_all_positive_ && weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_strings_[1]; // pos label
|
||||
write_additional_scores = 2;
|
||||
} else if (classlabels_strings_.size() == 2 &&
|
||||
maxweight <= 0 &&
|
||||
!weights_are_all_positive_ &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_strings_[0]; // neg label
|
||||
write_additional_scores = 3;
|
||||
} else if (maxweight > 0) {
|
||||
y_data[i] = "1"; // positive label
|
||||
} else {
|
||||
y_data[i] = "0"; // negative label
|
||||
}
|
||||
} else {
|
||||
_set_score_binary<int64_t>(i, Y->template MutableData<int64_t>(),
|
||||
write_additional_scores, weights_are_all_positive_,
|
||||
classes, classlabels_int64s_,
|
||||
weights_classes_, 1, 0);
|
||||
auto* y_data = Y->template MutableData<int64_t>();
|
||||
if (classlabels_int64s_.size() == 2 &&
|
||||
weights_are_all_positive_ &&
|
||||
maxweight > 0.5 &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_int64s_[1]; // positive label
|
||||
write_additional_scores = 0;
|
||||
} else if (classlabels_int64s_.size() == 2 &&
|
||||
weights_are_all_positive_ &&
|
||||
maxweight <= 0.5 &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_int64s_[0]; // negative label
|
||||
write_additional_scores = 1;
|
||||
} else if (classlabels_int64s_.size() == 2 &&
|
||||
maxweight > 0 &&
|
||||
!weights_are_all_positive_ &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_int64s_[1]; // pos label
|
||||
write_additional_scores = 2;
|
||||
} else if (classlabels_int64s_.size() == 2 &&
|
||||
maxweight <= 0 &&
|
||||
!weights_are_all_positive_ &&
|
||||
weights_classes_.size() == 1) {
|
||||
y_data[i] = classlabels_int64s_[0]; // neg label
|
||||
write_additional_scores = 3;
|
||||
} else if (maxweight > 0) {
|
||||
y_data[i] = 1; // positive label
|
||||
} else {
|
||||
y_data[i] = 0; // negative label
|
||||
}
|
||||
}
|
||||
}
|
||||
// write float values, might not have all the classes in the output yet
|
||||
|
|
@ -445,9 +425,10 @@ common::Status TreeEnsembleClassifier<T>::Compute(OpKernelContext* context) cons
|
|||
}
|
||||
}
|
||||
write_scores(scores, post_transform_, zindex, Z, write_additional_scores);
|
||||
} // namespace ml
|
||||
return status;
|
||||
} // namespace ml
|
||||
zindex += scores.size();
|
||||
} // for every batch
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
common::Status TreeEnsembleClassifier<T>::ProcessTreeNode(std::map<int64_t, float>& classes,
|
||||
|
|
|
|||
|
|
@ -151,120 +151,5 @@ TEST(MLOpTest, TreeEnsembleClassifierBinary) {
|
|||
test.Run();
|
||||
}
|
||||
|
||||
TEST(MLOpTest, TreeEnsembleClassifierBinaryBaseValue) {
|
||||
OpTester test("TreeEnsembleClassifier", 1, onnxruntime::kMLDomain);
|
||||
|
||||
// The example was generated by the following python script:
|
||||
// model = GradientBoostingClassifier(n_estimators = 1, max_depth = 2)
|
||||
// X, y = make_classification(10, n_features = 4, random_state = 42)
|
||||
// X = X[:, :2]
|
||||
// model.fit(X, y)
|
||||
// model.init_.class_prior_ = np.array([0.231, 0.231])
|
||||
|
||||
std::vector<float> base_values = {-1.202673316001892f, -1.202673316001892f};
|
||||
std::vector<int64_t> class_ids = {0, 0, 0};
|
||||
std::vector<int64_t> class_nodeids = {2, 3, 4};
|
||||
std::vector<int64_t> class_treeids = {0, 0, 0};
|
||||
std::vector<float> class_weights = {-0.2f, -0.06f, 0.2f};
|
||||
std::vector<int64_t> classlabels_int64s = {0, 1};
|
||||
std::vector<int64_t> nodes_falsenodeids = {4, 3, 0, 0, 0};
|
||||
std::vector<int64_t> nodes_featureids = {0, 0, 0, 0, 0};
|
||||
std::vector<float> nodes_hitrates = {1, 1, 1, 1, 1};
|
||||
std::vector<int64_t> nodes_missing_value_tracks_true = {0, 0, 0, 0, 0};
|
||||
std::vector<std::string> nodes_modes = {"BRANCH_LEQ", "BRANCH_LEQ", "LEAF", "LEAF", "LEAF"};
|
||||
std::vector<int64_t> nodes_nodeids = {0, 1, 2, 3, 4};
|
||||
std::vector<int64_t> nodes_treeids = {0, 0, 0, 0, 0};
|
||||
std::vector<int64_t> nodes_truenodeids = {1, 2, 0, 0, 0};
|
||||
std::vector<float> nodes_values = {0.21111594140529633f, -0.8440752029418945f, 0, 0, 0};
|
||||
std::string post_transform = "LOGISTIC";
|
||||
|
||||
std::vector<float> X = {-0.92533575f, -1.14021544f, -0.46171143f, -0.58723065f, 1.44044386f, 1.77736657f};
|
||||
std::vector<int64_t> results = {0, 0, 0};
|
||||
std::vector<float> probs = {};
|
||||
std::vector<float> log_probs = {};
|
||||
std::vector<float> scores{0.802607834f, 0.197392166f, 0.779485941f, 0.220514059f, 0.731583834f, 0.268416166f};
|
||||
|
||||
//define the context of the operator call
|
||||
const int N = 3;
|
||||
test.AddAttribute("base_values", base_values);
|
||||
test.AddAttribute("class_ids", class_ids);
|
||||
test.AddAttribute("class_nodeids", class_nodeids);
|
||||
test.AddAttribute("class_treeids", class_treeids);
|
||||
test.AddAttribute("class_weights", class_weights);
|
||||
test.AddAttribute("classlabels_int64s", classlabels_int64s);
|
||||
test.AddAttribute("nodes_falsenodeids", nodes_falsenodeids);
|
||||
test.AddAttribute("nodes_featureids", nodes_featureids);
|
||||
test.AddAttribute("nodes_hitrates", nodes_hitrates);
|
||||
test.AddAttribute("nodes_modes", nodes_modes);
|
||||
test.AddAttribute("nodes_nodeids", nodes_nodeids);
|
||||
test.AddAttribute("nodes_treeids", nodes_treeids);
|
||||
test.AddAttribute("nodes_truenodeids", nodes_truenodeids);
|
||||
test.AddAttribute("nodes_values", nodes_values);
|
||||
test.AddAttribute("post_transform", post_transform);
|
||||
|
||||
test.AddInput<float>("X", {N, 2}, X);
|
||||
test.AddOutput<int64_t>("Y", {N}, results);
|
||||
test.AddOutput<float>("Z", {N, 2}, scores);
|
||||
|
||||
test.Run();
|
||||
}
|
||||
|
||||
TEST(MLOpTest, TreeEnsembleClassifierBinaryBaseValueNull) {
|
||||
OpTester test("TreeEnsembleClassifier", 1, onnxruntime::kMLDomain);
|
||||
|
||||
// The example was generated by the following python script:
|
||||
// model = GradientBoostingClassifier(n_estimators = 1, max_depth = 2)
|
||||
// X, y = make_classification(10, n_features = 4, random_state = 42)
|
||||
// X = X[:, :2]
|
||||
// model.fit(X, y)
|
||||
|
||||
std::vector<float> base_values = {0, 0};
|
||||
std::vector<int64_t> class_ids = {0, 0, 0};
|
||||
std::vector<int64_t> class_nodeids = {2, 3, 4};
|
||||
std::vector<int64_t> class_treeids = {0, 0, 0};
|
||||
std::vector<float> class_weights = {-0.2f, -0.0666f, 0.2f};
|
||||
std::vector<int64_t> classlabels_int64s = {0, 1};
|
||||
std::vector<int64_t> nodes_falsenodeids = {4, 3, 0, 0, 0};
|
||||
std::vector<int64_t> nodes_featureids = {0, 0, 0, 0, 0};
|
||||
std::vector<float> nodes_hitrates = {1, 1, 1, 1, 1};
|
||||
std::vector<int64_t> nodes_missing_value_tracks_true = {0, 0, 0, 0, 0};
|
||||
std::vector<std::string> nodes_modes = {"BRANCH_LEQ", "BRANCH_LEQ", "LEAF", "LEAF", "LEAF"};
|
||||
std::vector<int64_t> nodes_nodeids = {0, 1, 2, 3, 4};
|
||||
std::vector<int64_t> nodes_treeids = {0, 0, 0, 0, 0};
|
||||
std::vector<int64_t> nodes_truenodeids = {1, 2, 0, 0, 0};
|
||||
std::vector<float> nodes_values = {0.24055418372154236f, -0.8440752029418945f, 0, 0, 0};
|
||||
std::string post_transform = "LOGISTIC";
|
||||
|
||||
std::vector<float> X = {-0.92533575f, -1.14021544f, -0.46171143f, -0.58723065f, 1.44044386f, 1.77736657f};
|
||||
std::vector<int64_t> results = {0, 0, 1};
|
||||
std::vector<float> probs = {};
|
||||
std::vector<float> log_probs = {};
|
||||
std::vector<float> scores{0.549834f, 0.450166f, 0.5166605f, 0.4833395f, 0.450166f, 0.549834f};
|
||||
|
||||
//define the context of the operator call
|
||||
const int N = 3;
|
||||
test.AddAttribute("base_values", base_values);
|
||||
test.AddAttribute("class_ids", class_ids);
|
||||
test.AddAttribute("class_nodeids", class_nodeids);
|
||||
test.AddAttribute("class_treeids", class_treeids);
|
||||
test.AddAttribute("class_weights", class_weights);
|
||||
test.AddAttribute("classlabels_int64s", classlabels_int64s);
|
||||
test.AddAttribute("nodes_falsenodeids", nodes_falsenodeids);
|
||||
test.AddAttribute("nodes_featureids", nodes_featureids);
|
||||
test.AddAttribute("nodes_hitrates", nodes_hitrates);
|
||||
test.AddAttribute("nodes_modes", nodes_modes);
|
||||
test.AddAttribute("nodes_nodeids", nodes_nodeids);
|
||||
test.AddAttribute("nodes_treeids", nodes_treeids);
|
||||
test.AddAttribute("nodes_truenodeids", nodes_truenodeids);
|
||||
test.AddAttribute("nodes_values", nodes_values);
|
||||
test.AddAttribute("post_transform", post_transform);
|
||||
|
||||
test.AddInput<float>("X", {N, 2}, X);
|
||||
test.AddOutput<int64_t>("Y", {N}, results);
|
||||
test.AddOutput<float>("Z", {N, 2}, scores);
|
||||
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
Loading…
Reference in a new issue