/*! * Copyright 2017-2020 by Contributors * \file predictor.h * \brief Interface of predictor, * performs predictions for a gradient booster. */ #pragma once #include #include #include #include #include #include #include #include #include #include // Forward declarations namespace xgboost { class TreeUpdater; namespace gbm { struct GBTreeModel; } // namespace gbm } namespace xgboost { /** * \struct PredictionCacheEntry * * \brief Contains pointer to input matrix and associated cached predictions. */ struct PredictionCacheEntry { // A storage for caching prediction values HostDeviceVector predictions; // The version of current cache, corresponding number of layers of trees uint32_t version; // A weak pointer for checking whether the DMatrix object has expired. std::weak_ptr< DMatrix > ref; PredictionCacheEntry() : version { 0 } {} /* \brief Update the cache entry by number of versions. * * \param v Added versions. */ void Update(uint32_t v) { version += v; } }; /* \brief A container for managed prediction caches. */ class PredictionContainer { std::unordered_map container_; void ClearExpiredEntries(); public: PredictionContainer() = default; /* \brief Add a new DMatrix to the cache, at the same time this function will clear out * all expired caches by checking the `std::weak_ptr`. Caching an existing * DMatrix won't renew it. * * Passing in a `shared_ptr` is critical here. First to create a `weak_ptr` inside the * entry this shared pointer is necessary. More importantly, the life time of this * cache is tied to the shared pointer. * * Another way to make a safe cache is create a proxy to this entry, with anther shared * pointer defined inside, and pass this proxy around instead of the real entry. But * seems to be too messy. In XGBoost, functions like `UpdateOneIter` will have * (memory) safe access to the DMatrix as long as it's passed in as a `shared_ptr`. * * \param m shared pointer to the DMatrix that needs to be cached. * \param device Which device should the cache be allocated on. Pass * GenericParameter::kCpuId for CPU or positive integer for GPU id. * * \return the cache entry for passed in DMatrix, either an existing cache or newly * created. */ PredictionCacheEntry& Cache(std::shared_ptr m, int32_t device); /* \brief Get a prediction cache entry. This entry must be already allocated by `Cache` * method. Otherwise a dmlc::Error is thrown. * * \param m pointer to the DMatrix. * \return The prediction cache for passed in DMatrix. */ PredictionCacheEntry& Entry(DMatrix* m); /* \brief Get a const reference to the underlying hash map. Clear expired caches before * returning. */ decltype(container_) const& Container(); }; /** * \class Predictor * * \brief Performs prediction on individual training instances or batches of instances for * GBTree. Prediction functions all take a GBTreeModel and a DMatrix as input and * output a vector of predictions. The predictor does not modify any state of the * model itself. */ class Predictor { protected: /* * \brief Runtime parameters. */ GenericParameter const* generic_param_; public: explicit Predictor(GenericParameter const* generic_param) : generic_param_{generic_param} {} virtual ~Predictor() = default; /** * \brief Configure and register input matrices in prediction cache. * * \param cfg The configuration. */ virtual void Configure(const std::vector>& cfg); /** * \brief Generate batch predictions for a given feature matrix. May use * cached predictions if available instead of calculating from scratch. * * \param [in,out] dmat Feature matrix. * \param [in,out] out_preds The output preds. * \param model The model to predict from. * \param tree_begin The tree begin index. * \param ntree_limit (Optional) The ntree limit. 0 means do not * limit trees. */ virtual void PredictBatch(DMatrix* dmat, PredictionCacheEntry* out_preds, const gbm::GBTreeModel& model, int tree_begin, uint32_t const ntree_limit = 0) = 0; /** * \fn virtual void Predictor::UpdatePredictionCache( const gbm::GBTreeModel * &model, std::vector >* updaters, int * num_new_trees) = 0; * * \brief Update the internal prediction cache using newly added trees. Will * use the tree updater to do this if possible. Should be called as a part of * the tree boosting process to facilitate the look up of predictions * at a later time. * * \param model The model. * \param [in,out] updaters The updater sequence for gradient boosting. * \param num_new_trees Number of new trees. */ virtual void UpdatePredictionCache( const gbm::GBTreeModel& model, std::vector>* updaters, int num_new_trees, DMatrix* m, PredictionCacheEntry* predts) = 0; /** * \fn virtual void Predictor::PredictInstance( const SparsePage::Inst& * inst, std::vector* out_preds, const gbm::GBTreeModel& model, * * \brief online prediction function, predict score for one instance at a time * NOTE: use the batch prediction interface if possible, batch prediction is * usually more efficient than online prediction This function is NOT * threadsafe, make sure you only call from one thread. * * \param inst The instance to predict. * \param [in,out] out_preds The output preds. * \param model The model to predict from * \param ntree_limit (Optional) The ntree limit. */ virtual void PredictInstance(const SparsePage::Inst& inst, std::vector* out_preds, const gbm::GBTreeModel& model, unsigned ntree_limit = 0) = 0; /** * \fn virtual void Predictor::PredictLeaf(DMatrix* dmat, * std::vector* out_preds, const gbm::GBTreeModel& model, unsigned * ntree_limit = 0) = 0; * * \brief predict the leaf index of each tree, the output will be nsample * * ntree vector this is only valid in gbtree predictor. * * \param [in,out] dmat The input feature matrix. * \param [in,out] out_preds The output preds. * \param model Model to make predictions from. * \param ntree_limit (Optional) The ntree limit. */ virtual void PredictLeaf(DMatrix* dmat, std::vector* out_preds, const gbm::GBTreeModel& model, unsigned ntree_limit = 0) = 0; /** * \fn virtual void Predictor::PredictContribution( DMatrix* dmat, * std::vector* out_contribs, const gbm::GBTreeModel& model, * unsigned ntree_limit = 0) = 0; * * \brief feature contributions to individual predictions; the output will be * a vector of length (nfeats + 1) * num_output_group * nsample, arranged in * that order. * * \param [in,out] dmat The input feature matrix. * \param [in,out] out_contribs The output feature contribs. * \param model Model to make predictions from. * \param ntree_limit (Optional) The ntree limit. * \param tree_weights (Optional) Weights to multiply each tree by. * \param approximate Use fast approximate algorithm. * \param condition Condition on the condition_feature (0=no, -1=cond off, 1=cond on). * \param condition_feature Feature to condition on (i.e. fix) during calculations. */ virtual void PredictContribution(DMatrix* dmat, std::vector* out_contribs, const gbm::GBTreeModel& model, unsigned ntree_limit = 0, std::vector* tree_weights = nullptr, bool approximate = false, int condition = 0, unsigned condition_feature = 0) = 0; virtual void PredictInteractionContributions(DMatrix* dmat, std::vector* out_contribs, const gbm::GBTreeModel& model, unsigned ntree_limit = 0, std::vector* tree_weights = nullptr, bool approximate = false) = 0; /** * \brief Creates a new Predictor*. * * \param name Name of the predictor. * \param generic_param Pointer to runtime parameters. * \param cache Pointer to prediction cache. */ static Predictor* Create( std::string const& name, GenericParameter const* generic_param); }; /*! * \brief Registry entry for predictor. */ struct PredictorReg : public dmlc::FunctionRegEntryBase< PredictorReg, std::function> {}; #define XGBOOST_REGISTER_PREDICTOR(UniqueId, Name) \ static DMLC_ATTRIBUTE_UNUSED ::xgboost::PredictorReg& \ __make_##PredictorReg##_##UniqueId##__ = \ ::dmlc::Registry<::xgboost::PredictorReg>::Get()->__REGISTER__(Name) } // namespace xgboost