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::shared_ptr<AbstractMLModel>& abstract_model,
124 const auto linear_reg_model =
129 CHECK(linear_reg_model);
130 const auto& model_coefs = linear_reg_model->getCoefs();
131 const auto& cat_feature_keys = linear_reg_model->getCatFeatureKeys();
138 linear_reg_model->getModelMetadata().getFeaturePermutations(),
141 auto get_double_constant_expr = [](
double const_val) {
147 std::shared_ptr<Analyzer::Expr>
result;
155 for (
size_t model_coef_idx = 0; model_coef_idx < model_coefs.size(); ++model_coef_idx) {
156 auto coef_value_expr = get_double_constant_expr(model_coefs[model_coef_idx]);
157 if (model_coef_idx ==
size_t(0)) {
159 result = coef_value_expr;
162 const auto& casted_regressor_expr = casted_regressor_exprs[model_coef_idx - 1];
169 casted_regressor_expr);
171 result = makeExpr<Analyzer::BinOper>(
178 return codegenArith(dynamic_cast<Analyzer::BinOper*>(result.get()), co);
183 const std::shared_ptr<AbstractTreeModel>& tree_model,
186 const int64_t num_trees =
static_cast<int64_t
>(tree_model->getNumTrees());
188 const auto& cat_feature_keys = tree_model->getCatFeatureKeys();
192 tree_model->getModelMetadata().getFeaturePermutations(),
199 std::vector<llvm::Value*> regressor_values;
200 for (
const auto& casted_regressor_expr : casted_regressor_exprs) {
201 regressor_values.emplace_back(
codegen(casted_regressor_expr.get(),
false, co)[0]);
205 std::vector<std::vector<DecisionTreeEntry>> decision_trees(num_trees);
207 auto tree_build_timer =
DEBUG_TIMER(
"Tree Visitors Dispatched");
209 [&](
const tbb::blocked_range<int64_t>& r) {
210 const auto start_tree_idx = r.begin();
211 const auto end_tree_idx = r.end();
212 for (int64_t tree_idx = start_tree_idx; tree_idx < end_tree_idx;
214 TreeModelVisitor tree_visitor(decision_trees[tree_idx]);
215 tree_model->traverseDF(tree_idx, tree_visitor);
224 std::vector<int64_t> decision_tree_offsets(num_trees + 1);
225 decision_tree_offsets[0] = 0;
226 for (int64_t tree_idx = 0; tree_idx < num_trees; ++tree_idx) {
227 decision_tree_offsets[tree_idx + 1] =
228 decision_tree_offsets[tree_idx] +
229 static_cast<int64_t
>(decision_trees[tree_idx].size());
232 VLOG(1) << tree_model->getModelTypeString() <<
" model has " << num_trees
233 <<
" trees and " << decision_tree_offsets[num_trees] <<
" total entries.";
241 auto tree_offset_correction_timer =
DEBUG_TIMER(
"Tree Offsets Corrected");
243 tbb::blocked_range<int64_t>(1, num_trees),
244 [&](
const tbb::blocked_range<int64_t>& r) {
245 const auto start_tree_idx = r.begin();
246 const auto end_tree_idx = r.end();
247 for (int64_t tree_idx = start_tree_idx; tree_idx < end_tree_idx; ++tree_idx) {
248 const int64_t start_offset = decision_tree_offsets[tree_idx];
249 auto& decision_tree = decision_trees[tree_idx];
250 const int64_t num_tree_entries =
static_cast<int64_t
>(decision_tree.size());
252 decision_tree_offsets[tree_idx + 1] - start_offset);
253 for (int64_t decision_entry_idx = 0; decision_entry_idx < num_tree_entries;
254 ++decision_entry_idx) {
255 if (decision_tree[decision_entry_idx].isSplitNode()) {
256 decision_tree[decision_entry_idx].left_child_row_idx += start_offset;
257 decision_tree[decision_entry_idx].right_child_row_idx += start_offset;
265 auto tree_model_prediction_mgr_timer =
266 DEBUG_TIMER(
"TreeModelPredictionMgr generation and codegen");
272 auto tree_model_prediction_mgr = std::make_unique<TreeModelPredictionMgr>(
277 decision_tree_offsets,
281 ->
codegen(regressor_values, co);
284 throw std::runtime_error(
"OneDAL not available.");
294 CHECK(model_constant_expr);
295 const auto model_datum = model_constant_expr->get_constval();
296 const auto model_name_ptr = model_datum.stringval;
297 CHECK(model_name_ptr);
298 const auto model_name = *model_name_ptr;
300 const auto model_type = abstract_model->getModelType();
302 if (abstract_model->getNumLogicalFeatures() !=
303 static_cast<int64_t
>(regressor_exprs.size())) {
304 std::ostringstream error_oss;
305 error_oss <<
"ML_PREDICT: Model '" << model_name
306 <<
"' expects different number of predictor variables ("
307 << abstract_model->getNumLogicalFeatures() <<
") than provided ("
308 << regressor_exprs.size() <<
").";
309 throw std::runtime_error(error_oss.str());
312 switch (model_type) {
319 if (
auto tree_model =
320 std::dynamic_pointer_cast<AbstractTreeModel>(abstract_model)) {
323 throw std::runtime_error(
324 "Invalid ML model codegen call. Input model is not of expected 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 * codegenTreeRegPredict(const Analyzer::MLPredictExpr *, const std::shared_ptr< AbstractTreeModel > &tree_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
llvm::Value * codegenLinRegPredict(const Analyzer::MLPredictExpr *, const std::shared_ptr< AbstractMLModel > &model, const CompilationOptions &)
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())
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