26 #include <tbb/parallel_for.h>
31 const std::vector<std::shared_ptr<Analyzer::Expr>>& feature_exprs,
32 const std::vector<std::vector<std::string>>& cat_feature_keys,
33 const std::vector<int64_t>& feature_permutations,
35 std::vector<std::shared_ptr<Analyzer::Expr>> casted_feature_exprs;
36 const size_t num_feature_exprs = feature_exprs.size();
37 const size_t num_cat_features = cat_feature_keys.size();
39 if (num_cat_features > num_feature_exprs) {
40 throw std::runtime_error(
"More categorical keys than features.");
43 auto get_int_constant_expr = [](int32_t const_val) {
46 return makeExpr<Analyzer::Constant>(
SQLTypeInfo(
kINT,
false),
false, d);
49 for (
size_t original_feature_idx = 0; original_feature_idx < num_feature_exprs;
50 ++original_feature_idx) {
51 const auto feature_idx = feature_permutations.empty()
52 ? original_feature_idx
53 : feature_permutations[original_feature_idx];
54 auto& feature_expr = feature_exprs[feature_idx];
55 const auto& feature_ti = feature_expr->get_type_info();
56 if (feature_ti.is_number()) {
61 casted_feature_exprs.emplace_back(makeExpr<Analyzer::UOper>(
64 CHECK(feature_ti.is_string()) <<
"Expected text type";
65 if (!feature_ti.is_text_encoding_dict()) {
66 throw std::runtime_error(
"Expected dictionary-encoded text column.");
68 if (original_feature_idx >= num_cat_features) {
69 throw std::runtime_error(
"Model not trained on text type for column.");
71 const auto& str_dict_key = feature_ti.getStringDictKey();
72 const auto str_dict_proxy = executor->getStringDictionaryProxy(str_dict_key,
true);
73 for (
const auto& cat_feature_key : cat_feature_keys[original_feature_idx]) {
80 auto is_null_expr = makeExpr<Analyzer::UOper>(
85 auto is_null_then_expr =
88 std::pair<std::shared_ptr<Analyzer::Expr>, std::shared_ptr<Analyzer::Expr>>>
90 when_then_exprs.emplace_back(std::make_pair(is_null_expr, is_null_then_expr));
93 const auto str_id = str_dict_proxy->getIdOfString(cat_feature_key);
94 auto str_id_expr = get_int_constant_expr(str_id);
96 auto key_for_string_expr = makeExpr<Analyzer::KeyForStringExpr>(feature_expr);
99 std::shared_ptr<Analyzer::Expr> str_equality_expr =
107 auto cast_expr = makeExpr<Analyzer::UOper>(
111 casted_feature_exprs.emplace_back(makeExpr<Analyzer::CaseExpr>(
116 return casted_feature_exprs;
121 const std::string& model_name,
122 const std::shared_ptr<AbstractMLModel>& abstract_model,
125 const auto linear_reg_model =
130 CHECK(linear_reg_model);
131 const auto& model_coefs = linear_reg_model->getCoefs();
132 const auto& cat_feature_keys = linear_reg_model->getCatFeatureKeys();
139 linear_reg_model->getModelMetadata().getFeaturePermutations(),
142 auto get_double_constant_expr = [](
double const_val) {
148 std::shared_ptr<Analyzer::Expr>
result;
156 for (
size_t model_coef_idx = 0; model_coef_idx < model_coefs.size(); ++model_coef_idx) {
157 auto coef_value_expr = get_double_constant_expr(model_coefs[model_coef_idx]);
158 if (model_coef_idx ==
size_t(0)) {
160 result = coef_value_expr;
163 const auto& casted_regressor_expr = casted_regressor_exprs[model_coef_idx - 1];
170 casted_regressor_expr);
172 result = makeExpr<Analyzer::BinOper>(
179 return codegenArith(dynamic_cast<Analyzer::BinOper*>(result.get()), co);
184 const std::string& model_name,
185 const std::shared_ptr<AbstractMLModel>& model,
188 const auto tree_model = std::dynamic_pointer_cast<AbstractTreeModel>(model);
193 const int64_t num_trees =
static_cast<int64_t
>(tree_model->getNumTrees());
195 const auto& cat_feature_keys = tree_model->getCatFeatureKeys();
199 tree_model->getModelMetadata().getFeaturePermutations(),
206 std::vector<llvm::Value*> regressor_values;
207 for (
const auto& casted_regressor_expr : casted_regressor_exprs) {
208 regressor_values.emplace_back(
codegen(casted_regressor_expr.get(),
false, co)[0]);
212 std::vector<std::vector<DecisionTreeEntry>> decision_trees(num_trees);
214 auto tree_build_timer =
DEBUG_TIMER(
"Tree Visitors Dispatched");
216 [&](
const tbb::blocked_range<int64_t>& r) {
217 const auto start_tree_idx = r.begin();
218 const auto end_tree_idx = r.end();
219 for (int64_t tree_idx = start_tree_idx; tree_idx < end_tree_idx;
221 TreeModelVisitor tree_visitor(decision_trees[tree_idx]);
222 tree_model->traverseDF(tree_idx, tree_visitor);
231 std::vector<int64_t> decision_tree_offsets(num_trees + 1);
232 decision_tree_offsets[0] = 0;
233 for (int64_t tree_idx = 0; tree_idx < num_trees; ++tree_idx) {
234 decision_tree_offsets[tree_idx + 1] =
235 decision_tree_offsets[tree_idx] +
236 static_cast<int64_t
>(decision_trees[tree_idx].size());
239 VLOG(1) << tree_model->getModelTypeString() <<
" model has " << num_trees
240 <<
" trees and " << decision_tree_offsets[num_trees] <<
" total entries.";
248 auto tree_offset_correction_timer =
DEBUG_TIMER(
"Tree Offsets Corrected");
250 tbb::blocked_range<int64_t>(1, num_trees),
251 [&](
const tbb::blocked_range<int64_t>& r) {
252 const auto start_tree_idx = r.begin();
253 const auto end_tree_idx = r.end();
254 for (int64_t tree_idx = start_tree_idx; tree_idx < end_tree_idx; ++tree_idx) {
255 const int64_t start_offset = decision_tree_offsets[tree_idx];
256 auto& decision_tree = decision_trees[tree_idx];
257 const int64_t num_tree_entries =
static_cast<int64_t
>(decision_tree.size());
259 decision_tree_offsets[tree_idx + 1] - start_offset);
260 for (int64_t decision_entry_idx = 0; decision_entry_idx < num_tree_entries;
261 ++decision_entry_idx) {
262 if (decision_tree[decision_entry_idx].isSplitNode()) {
263 decision_tree[decision_entry_idx].left_child_row_idx += start_offset;
264 decision_tree[decision_entry_idx].right_child_row_idx += start_offset;
272 auto tree_model_prediction_mgr_timer =
273 DEBUG_TIMER(
"TreeModelPredictionMgr generation and codegen");
279 auto tree_model_prediction_mgr = std::make_unique<TreeModelPredictionMgr>(
284 decision_tree_offsets,
288 ->
codegen(regressor_values, co);
291 throw std::runtime_error(
"OneDAL not available.");
301 CHECK(model_constant_expr);
302 const auto model_datum = model_constant_expr->get_constval();
303 const auto model_name_ptr = model_datum.stringval;
304 CHECK(model_name_ptr);
305 const auto model_name = *model_name_ptr;
307 const auto model_type = abstract_model->getModelType();
309 if (abstract_model->getNumLogicalFeatures() !=
310 static_cast<int64_t
>(regressor_exprs.size())) {
311 std::ostringstream error_oss;
312 error_oss <<
"ML_PREDICT: Model '" << model_name
313 <<
"' expects different number of predictor variables ("
314 << abstract_model->getNumLogicalFeatures() <<
") than provided ("
315 << regressor_exprs.size() <<
").";
316 throw std::runtime_error(error_oss.str());
319 switch (model_type) {
329 throw std::runtime_error(
"Unsupported model type.");
340 CHECK(model_constant_expr);
341 const auto model_datum = model_constant_expr->get_constval();
342 const auto model_name_ptr = model_datum.stringval;
343 CHECK(model_name_ptr);
344 const auto model_name = *model_name_ptr;
346 const auto model_type = abstract_model->getModelType();
348 throw std::runtime_error(
"PCA_PROJECT: Model '" + model_name +
349 "' is not a PCA model.");
351 const auto pca_model = std::dynamic_pointer_cast<
PcaModel>(abstract_model);
353 if (pca_model->getNumLogicalFeatures() !=
static_cast<int64_t
>(feature_exprs.size())) {
354 std::ostringstream error_oss;
355 error_oss <<
"PCA_PROJECT: Model '" << model_name
356 <<
"' expects different number of predictor variables ("
357 << pca_model->getNumLogicalFeatures() <<
") than provided ("
358 << feature_exprs.size() <<
").";
359 throw std::runtime_error(error_oss.str());
363 auto pc_dimension_const_expr =
365 const auto pc_dimension_datum = pc_dimension_const_expr->
get_constval();
366 const auto pc_dimension = pc_dimension_datum.
intval - 1;
367 if (pc_dimension < 0 || pc_dimension >= pca_model->getNumFeatures()) {
368 std::ostringstream error_oss;
369 error_oss <<
"PCA_PROJECT: Invalid PC dimension (" << pc_dimension + 1
370 <<
") provided. Valid range is [1, " << pca_model->getNumFeatures() <<
"].";
371 throw std::runtime_error(error_oss.str());
374 const auto& column_means = pca_model->getColumnMeans();
375 const auto& column_std_devs = pca_model->getColumnStdDevs();
376 const auto& eigenvectors = pca_model->getEigenvectors();
378 const auto& cat_feature_keys = pca_model->getCatFeatureKeys();
383 pca_model->getModelMetadata().getFeaturePermutations(),
386 auto get_double_constant_expr = [](
double const_val) {
392 std::shared_ptr<Analyzer::Expr>
result;
394 for (
size_t feature_idx = 0; feature_idx < feature_exprs.size(); ++feature_idx) {
395 auto mean_expr = get_double_constant_expr(column_means[feature_idx]);
396 const auto& casted_feature_expr = casted_feature_exprs[feature_idx];
398 auto mean_diff_expr = makeExpr<Analyzer::BinOper>(
400 auto std_dev_expr = get_double_constant_expr(column_std_devs[feature_idx]);
401 auto z_score_expr = makeExpr<Analyzer::BinOper>(
403 auto pc_term_expr = get_double_constant_expr(eigenvectors[pc_dimension][feature_idx]);
404 auto pca_mul_expr = makeExpr<Analyzer::BinOper>(
406 if (feature_idx == 0) {
408 result = pca_mul_expr;
411 result = makeExpr<Analyzer::BinOper>(
418 return codegenArith(dynamic_cast<Analyzer::BinOper*>(result.get()), co);
llvm::Value * codegenLinRegPredict(const Analyzer::MLPredictExpr *, const std::string &model_name, const std::shared_ptr< AbstractMLModel > &model, const CompilationOptions &)
llvm::Value * codegenArith(const Analyzer::BinOper *, const CompilationOptions &)
llvm::Value * codegen(const std::vector< llvm::Value * > ®ressor_inputs, const CompilationOptions &co) const
std::vector< std::shared_ptr< Analyzer::Expr > > generated_encoded_and_casted_features(const std::vector< std::shared_ptr< Analyzer::Expr >> &feature_exprs, const std::vector< std::vector< std::string >> &cat_feature_keys, const std::vector< int64_t > &feature_permutations, Executor *executor)
const Expr * get_pc_dimension_value() const
const TreeModelPredictionMgr * moveTreeModelPredictionMgr(std::unique_ptr< const TreeModelPredictionMgr > &&tree_model_prediction_mgr)
std::shared_ptr< AbstractMLModel > getModel(const std::string &model_name) const
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Datum get_constval() const
const Expr * get_model_value() const
void parallel_for(const blocked_range< Int > &range, const Body &body, const Partitioner &p=Partitioner())
llvm::Value * codegenTreeRegPredict(const Analyzer::MLPredictExpr *, const std::string &model_name, const std::shared_ptr< AbstractMLModel > &model, const CompilationOptions &)
const std::vector< std::shared_ptr< Analyzer::Expr > > & get_feature_values() const
#define DEBUG_TIMER(name)
const Expr * get_model_value() const
Allocate GPU memory using GpuBuffers via DataMgr.
const std::vector< std::shared_ptr< Analyzer::Expr > > & get_regressor_values() const
Executor * executor() const