diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_bit.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_bit.hpp new file mode 100644 index 0000000000..a94f735b1a --- /dev/null +++ b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_bit.hpp @@ -0,0 +1,184 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/boosting/data/view_statistic_decomposable_bit.hpp" +#include "mlrl/common/data/view_composite.hpp" +#include "mlrl/common/indices/index_vector_complete.hpp" +#include "mlrl/common/indices/index_vector_partial.hpp" + +namespace boosting { + + /** + * An one-dimensional vector that stores aggregated gradients and Hessians that have been calculated using a + * decomposable loss function in a bit vector. For each element in the vector a single gradient and Hessian is + * stored. + */ + class BitDecomposableStatisticVector final + : public CompositeView, AllocatedBitVector> { + public: + + /** + * @param view A reference to an object of type `BitDecomposableStatisticView` + * @param numElements The number of gradients and Hessians in the vector + * @param init True, if all gradients and Hessians in the vector should be initialized with zero, + * false otherwise + */ + BitDecomposableStatisticVector(const BitDecomposableStatisticView& view, uint32 numElements, + bool init = false); + + /** + * @param other A reference to an object of type `BitDecomposableStatisticVector` to be copied + */ + BitDecomposableStatisticVector(const BitDecomposableStatisticVector& other); + + /** + * Returns the number of gradients and Hessians in the vector. + * + * @return The number of gradients and Hessians + */ + uint32 getNumElements() const; + + /** + * Returns the number of bits per gradient or Hessian in the vector. + * + * @return The number of bits per gradient or Hessian + */ + uint32 getNumBitsPerElement() const; + + /** + * Adds all gradients and Hessians in another vector to this vector. + * + * @param vector A reference to an object of type `BitDecomposableStatisticVector` that stores the gradients + * and Hessians to be added to this vector + */ + void add(const BitDecomposableStatisticVector& vector); + + /** + * Adds all gradients and Hessians in a single row of a `BitDecomposableStatisticView` to this vector. + * + * @param view A reference to an object of type `BitDecomposableStatisticView` that stores the gradients + * and Hessians to be added to this vector + * @param row The index of the row to be added to this vector + */ + void add(const BitDecomposableStatisticView& view, uint32 row); + + /** + * Adds all gradients and Hessians in a single row of a `CContiguousView` to this vector. The gradients and + * Hessians to be added are multiplied by a specific weight. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be added to this vector + * @param row The index of the row to be added to this vector + * @param weight The weight, the gradients and Hessians should be multiplied by + */ + void add(const BitDecomposableStatisticView& view, uint32 row, float64 weight); + + /** + * Removes all gradients and Hessians in a single row of a `CContiguousView` from this vector. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and Hessians to + * be removed from this vector + * @param row The index of the row to be removed from this vector + */ + void remove(const BitDecomposableStatisticView& view, uint32 row); + + /** + * Removes all gradients and Hessians in a single row of a `CContiguousView` from this vector. The gradients + * and Hessians to be removed are multiplied by a specific weight. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be removed from this vector + * @param row The index of the row to be removed from this vector + * @param weight The weight, the gradients and Hessians should be multiplied by + */ + void remove(const BitDecomposableStatisticView& view, uint32 row, float64 weight); + + /** + * Adds certain gradients and Hessians in a single row of a `CContiguousView`, whose positions are given as + * a `CompleteIndexVector`, to this vector. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be added to this vector + * @param row The index of the row to be added to this vector + * @param indices A reference to a `CompleteIndexVector' that provides access to the indices + */ + void addToSubset(const BitDecomposableStatisticView& view, uint32 row, const CompleteIndexVector& indices); + + /** + * Adds certain gradients and Hessians in single row of a `CContiguousView`, whose positions are given as a + * `PartialIndexVector`, to this vector. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be added to this vector + * @param row The index of the row to be added to this vector + * @param indices A reference to a `PartialIndexVector' that provides access to the indices + */ + void addToSubset(const BitDecomposableStatisticView& view, uint32 row, const PartialIndexVector& indices); + + /** + * Adds certain gradients and Hessians in a single row of a `CContiguousView`, whose positions are given as + * a `CompleteIndexVector`, to this vector. The gradients and Hessians to be added are multiplied by a + * specific weight. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be added to this vector + * @param row The index of the row to be added to this vector + * @param indices A reference to a `CompleteIndexVector' that provides access to the indices + * @param weight The weight, the gradients and Hessians should be multiplied by + */ + void addToSubset(const BitDecomposableStatisticView& view, uint32 row, const CompleteIndexVector& indices, + float64 weight); + + /** + * Adds certain gradients and Hessians in single row of a `CContiguousView`, whose positions are given as a + * `PartialIndexVector`, to this vector. The gradients and Hessians to be added are multiplied by a specific + * weight. + * + * @param view A reference to an object of type `CContiguousView` that stores the gradients and + * Hessians to be added to this vector + * @param row The index of the row to be added to this vector + * @param indices A reference to a `PartialIndexVector' that provides access to the indices + * @param weight The weight, the gradients and Hessians should be multiplied by + */ + void addToSubset(const BitDecomposableStatisticView& view, uint32 row, const PartialIndexVector& indices, + float64 weight); + + /** + * Sets the gradients and Hessians in this vector to the difference `first - second` between the gradients + * and Hessians in two other vectors, considering only the gradients and Hessians in the first vector that + * correspond to the positions provided by a `CompleteIndexVector`. + * + * @param first A reference to an object of type `BitDecomposableStatisticVector` that stores the + * gradients and Hessians in the first vector + * @param firstIndices A reference to an object of type `CompleteIndexVector` that provides access to the + * indices + * @param second A reference to an object of type `BitDecomposableStatisticVector` that stores the + * gradients and Hessians in the second vector + */ + void difference(const BitDecomposableStatisticVector& first, const CompleteIndexVector& firstIndices, + const BitDecomposableStatisticVector& second); + + /** + * Sets the gradients and Hessians in this vector to the difference `first - second` between the gradients + * and Hessians in two other vectors, considering only the gradients and Hessians in the first vector that + * correspond to the positions provided by a `PartialIndexVector`. + * + * @param first A reference to an object of type `BitDecomposableStatisticVector` that stores the + * gradients and Hessians in the first vector + * @param firstIndices A reference to an object of type `PartialIndexVector` that provides access to the + * indices + * @param second A reference to an object of type `BitDecomposableStatisticVector` that stores the + * gradients and Hessians in the second vector + */ + void difference(const BitDecomposableStatisticVector& first, const PartialIndexVector& firstIndices, + const BitDecomposableStatisticVector& second); + + /** + * Sets all gradients and Hessians stored in the vector to zero. + */ + void clear(); + }; + +} diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_dense.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_dense.hpp index 6897b33c45..d6eaf3e180 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_dense.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_dense.hpp @@ -21,11 +21,13 @@ namespace boosting { public: /** + * @param view A reference to an object of type `CContiguousView` * @param numElements The number of gradients and Hessians in the vector * @param init True, if all gradients and Hessians in the vector should be initialized with zero, * false otherwise */ - DenseDecomposableStatisticVector(uint32 numElements, bool init = false); + DenseDecomposableStatisticVector(const CContiguousView>& view, uint32 numElements, + bool init = false); /** * @param other A reference to an object of type `DenseDecomposableStatisticVector` to be copied diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_sparse.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_sparse.hpp index 85cc705bde..069285b04c 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_sparse.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_decomposable_sparse.hpp @@ -138,11 +138,13 @@ namespace boosting { public: /** + * @param view A reference to an object of type `SparseSetView` * @param numElements The number of gradients and Hessians in the vector * @param init True, if all gradients and Hessians in the vector should be initialized with zero, * false otherwise */ - SparseDecomposableStatisticVector(uint32 numElements, bool init = false); + SparseDecomposableStatisticVector(const SparseSetView>& view, uint32 numElements, + bool init = false); /** * @param other A reference to an object of type `SparseDecomposableStatisticVector` to be copied diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_non_decomposable_dense.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_non_decomposable_dense.hpp index 4cc4132f01..324234157a 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_non_decomposable_dense.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/data/vector_statistic_non_decomposable_dense.hpp @@ -23,11 +23,13 @@ namespace boosting { public: /** - * @param numGradients The number of gradients in the vector - * @param init True, if all gradients and Hessians in the vector should be initialized with zero, - * false otherwise + * @param view A reference to an object of type `DenseNonDecomposableStatisticView` + * @param numGradients The number of gradients in the vector + * @param init True, if all gradients and Hessians in the vector should be initialized with zero, + * false otherwise */ - DenseNonDecomposableStatisticVector(uint32 numGradients, bool init = false); + DenseNonDecomposableStatisticVector(const DenseNonDecomposableStatisticView& view, uint32 numGradients, + bool init = false); /** * @param other A reference to an object of type `DenseNonDecomposableStatisticVector` to be copied diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/data/view_statistic_decomposable_bit.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/data/view_statistic_decomposable_bit.hpp new file mode 100644 index 0000000000..40828733b5 --- /dev/null +++ b/cpp/subprojects/boosting/include/mlrl/boosting/data/view_statistic_decomposable_bit.hpp @@ -0,0 +1,35 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/boosting/util/dll_exports.hpp" +#include "mlrl/common/data/view_matrix_bit.hpp" +#include "mlrl/common/data/view_matrix_composite.hpp" + +namespace boosting { + + /** + * Implements row-wise read and write access to the gradients and Hessians that have been calculated using a + * decomposable loss function and are stored in pre-allocated bit matrices. + */ + class MLRLBOOSTING_API BitDecomposableStatisticView + : public CompositeMatrix, AllocatedBitMatrix> { + public: + + /** + * @param numRows The number of rows in the view + * @param numCols The number of columns in the view + * @param numBits The number of bits per statistic in the view + */ + BitDecomposableStatisticView(uint32 numRows, uint32 numCols, uint32 numBits); + + /** + * @param other A reference to an object of type `BitDecomposableStatisticView` that should be copied + */ + BitDecomposableStatisticView(BitDecomposableStatisticView&& other); + + virtual ~BitDecomposableStatisticView() override {} + }; + +} diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/learner.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/learner.hpp index b99a9860ee..ec232e7b4e 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/learner.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/learner.hpp @@ -20,6 +20,9 @@ #include "mlrl/boosting/rule_evaluation/regularization_no.hpp" #include "mlrl/boosting/rule_model_assemblage/default_rule_auto.hpp" #include "mlrl/boosting/sampling/partition_sampling_auto.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" +#include "mlrl/boosting/statistics/quantization_no.hpp" +#include "mlrl/boosting/statistics/quantization_stochastic.hpp" #include "mlrl/boosting/statistics/statistic_format.hpp" #include "mlrl/boosting/statistics/statistic_format_auto.hpp" #include "mlrl/boosting/statistics/statistic_format_dense.hpp" @@ -77,6 +80,15 @@ namespace boosting { */ virtual SharedProperty getRegressionStatisticsConfig() = 0; + /** + * Returns a `Property` that allows to access the `IQuantizationConfig` that stores the configuration of the + * method for quantizing statistics about the quality of predictions for the training examples. + * + * @return A `Property` that allows to access the `IQuantizationConfig` that stores the configuration of the + * method for quantizing statistics about the quality of predictions for the training examples + */ + virtual Property getQuantizationConfig() = 0; + /** * Returns a `Property` that allows to access the `IRegularizationConfig` that stores the configuration of * the L1 regularization term. @@ -295,6 +307,48 @@ namespace boosting { } }; + /** + * Defines an interface for all classes that allow to configure a rule learner to not quantize statistics about the + * quality of predictions for the training examples. + */ + class MLRLBOOSTING_API INoQuantizationMixin : public virtual IBoostedRuleLearnerConfig { + public: + + virtual ~INoQuantizationMixin() override {} + + /** + * Configures the rule learner to not quantize statistics about the quality of predictions for the training + * examples. + */ + virtual void useNoQuantization() { + this->getQuantizationConfig().set(std::make_unique()); + } + }; + + /** + * Defines an interface for all classes that allow to configure a rule learner to quantize statistics using a + * stochastic rounding strategy. + */ + class MLRLBOOSTING_API IStochasticQuantizationMixin : public virtual IBoostedRuleLearnerConfig { + public: + + virtual ~IStochasticQuantizationMixin() override {} + + /** + * Configures the rule learner to quantize statistics about the quality of predictions for the training + * examples using a stochastic rounding strategy. + * + * @return A reference to an object of type `IStochasticQuantizationConfig` that allows further + * configuration of the quantization method + */ + virtual IStochasticQuantizationConfig& useStochasticQuantization() { + auto ptr = std::make_unique(this->getRNGConfig()); + IStochasticQuantizationConfig& ref = *ptr; + this->getQuantizationConfig().set(std::move(ptr)); + return ref; + } + }; + /** * Defines an interface for all classes that allow to configure a rule learner to not use L1 regularization. */ @@ -419,8 +473,9 @@ namespace boosting { */ virtual void useCompleteHeads() { this->getHeadConfig().set(std::make_unique( - this->getLabelBinningConfig(), this->getParallelStatisticUpdateConfig(), - this->getL1RegularizationConfig(), this->getL2RegularizationConfig())); + this->getQuantizationConfig(), this->getLabelBinningConfig(), + this->getParallelStatisticUpdateConfig(), this->getL1RegularizationConfig(), + this->getL2RegularizationConfig())); } }; @@ -441,8 +496,9 @@ namespace boosting { * the rule heads */ virtual IFixedPartialHeadConfig& useFixedPartialHeads() { - auto ptr = std::make_unique(this->getLabelBinningConfig(), - this->getParallelStatisticUpdateConfig()); + auto ptr = + std::make_unique(this->getQuantizationConfig(), this->getLabelBinningConfig(), + this->getParallelStatisticUpdateConfig()); IFixedPartialHeadConfig& ref = *ptr; this->getHeadConfig().set(std::move(ptr)); return ref; @@ -467,7 +523,8 @@ namespace boosting { * the rule heads */ virtual IDynamicPartialHeadConfig& useDynamicPartialHeads() { - auto ptr = std::make_unique(this->getLabelBinningConfig(), + auto ptr = std::make_unique(this->getQuantizationConfig(), + this->getLabelBinningConfig(), this->getParallelStatisticUpdateConfig()); IDynamicPartialHeadConfig& ref = *ptr; this->getHeadConfig().set(std::move(ptr)); @@ -489,8 +546,9 @@ namespace boosting { */ virtual void useSingleOutputHeads() { this->getHeadConfig().set(std::make_unique( - this->getLabelBinningConfig(), this->getParallelStatisticUpdateConfig(), - this->getL1RegularizationConfig(), this->getL2RegularizationConfig())); + this->getQuantizationConfig(), this->getLabelBinningConfig(), + this->getParallelStatisticUpdateConfig(), this->getL1RegularizationConfig(), + this->getL2RegularizationConfig())); } }; @@ -508,8 +566,9 @@ namespace boosting { */ virtual void useAutomaticHeads() { this->getHeadConfig().set(std::make_unique( - this->getLossConfig(), this->getLabelBinningConfig(), this->getParallelStatisticUpdateConfig(), - this->getL1RegularizationConfig(), this->getL2RegularizationConfig())); + this->getQuantizationConfig(), this->getLossConfig(), this->getLabelBinningConfig(), + this->getParallelStatisticUpdateConfig(), this->getL1RegularizationConfig(), + this->getL2RegularizationConfig())); } }; @@ -599,6 +658,7 @@ namespace boosting { virtual public IDefaultRuleMixin, virtual public INoL1RegularizationMixin, virtual public INoL2RegularizationMixin, + virtual public INoQuantizationMixin, virtual public INoLabelBinningMixin { public: @@ -611,6 +671,7 @@ namespace boosting { IRuleLearnerMixin::useDefaults(); this->useNoL1Regularization(); this->useNoL2Regularization(); + this->useNoQuantization(); this->useNoLabelBinning(); } }; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_classifier.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_classifier.hpp index 06beb4343b..5fa6c68bd3 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_classifier.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_classifier.hpp @@ -36,6 +36,7 @@ namespace boosting { virtual public IDenseStatisticsMixin, virtual public ISparseStatisticsMixin, virtual public IAutomaticStatisticsMixin, + virtual public IStochasticQuantizationMixin, virtual public IDecomposableLogisticLossMixin, virtual public IDecomposableSquaredErrorLossMixin, virtual public IDecomposableSquaredHingeLossMixin, diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_regressor.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_regressor.hpp index 65701427f2..d764cac8dd 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_regressor.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/learner_boomer_regressor.hpp @@ -37,6 +37,7 @@ namespace boosting { virtual public IDenseStatisticsMixin, virtual public ISparseStatisticsMixin, virtual public IAutomaticStatisticsMixin, + virtual public IStochasticQuantizationMixin, virtual public IDecomposableSquaredErrorLossMixin, virtual public INonDecomposableSquaredErrorLossMixin, virtual public IOutputWiseScorePredictorMixin, diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/learner_common.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/learner_common.hpp index 6e87b58f2f..c17f0071a8 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/learner_common.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/learner_common.hpp @@ -91,6 +91,11 @@ namespace boosting { */ std::shared_ptr regressionStatisticsConfigPtr_; + /** + * An unique pointer that stores the configuration of the method for quantizing statistics. + */ + std::unique_ptr quantizationConfigPtr_; + /** * A shared pointer that stores the configuration of the loss function that should be used in classification * problems. @@ -143,6 +148,10 @@ namespace boosting { return util::sharedProperty(regressionStatisticsConfigPtr_); } + Property getQuantizationConfig() override final { + return util::property(quantizationConfigPtr_); + } + Property getL1RegularizationConfig() override final { return util::property(l1RegularizationConfigPtr_); } diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_auto.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_auto.hpp index 615a2dfa73..ca9d95f8fd 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_auto.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_auto.hpp @@ -6,6 +6,7 @@ #include "mlrl/boosting/binning/label_binning.hpp" #include "mlrl/boosting/rule_evaluation/head_type.hpp" #include "mlrl/boosting/rule_evaluation/regularization.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/util/properties.hpp" @@ -19,6 +20,8 @@ namespace boosting { class AutomaticHeadConfig final : public IHeadConfig { private: + const ReadableProperty quantizationConfig_; + const ReadableProperty lossConfig_; const ReadableProperty labelBinningConfig_; @@ -32,6 +35,9 @@ namespace boosting { public: /** + * @param quantizationConfig A `ReadableProperty` that allows to access the `IQuantizationConfig` that + * stores the configuration of the method for quantizing gradients and + * Hessians * @param lossConfig A `ReadableProperty` that allows to access the `ILossConfig` that stores * the configuration of the loss function * @param labelBinningConfig A `ReadableProperty` that allows to access the `ILabelBinningConfig` that @@ -44,7 +50,8 @@ namespace boosting { * @param l2RegularizationConfig A `ReadableProperty` that allows to access the `IRegularizationConfig` * that stores the configuration of the L2 regularization */ - AutomaticHeadConfig(ReadableProperty lossConfig, + AutomaticHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty lossConfig, ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_complete.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_complete.hpp index f4cf14b76e..cf9b69fc28 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_complete.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_complete.hpp @@ -6,6 +6,7 @@ #include "mlrl/boosting/binning/label_binning.hpp" #include "mlrl/boosting/rule_evaluation/head_type.hpp" #include "mlrl/boosting/rule_evaluation/regularization.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/util/properties.hpp" @@ -19,6 +20,8 @@ namespace boosting { class CompleteHeadConfig final : public IHeadConfig { private: + const ReadableProperty quantizationConfig_; + const ReadableProperty labelBinningConfig_; const ReadableProperty multiThreadingConfig_; @@ -30,6 +33,9 @@ namespace boosting { public: /** + * @param quantizationConfig A `ReadableProperty` that allows to access the `IQuantizationConfig` that + * stores the configuration of the method for quantizing gradients and + * Hessians * @param labelBinningConfig A `ReadableProperty` that allows to access the `ILabelBinningConfig` that * stores the configuration of the method for assigning labels to bins * @param multiThreadingConfig A `ReadableProperty` that allows to access the `IMultiThreadingConfig` @@ -40,7 +46,8 @@ namespace boosting { * @param l2RegularizationConfig A `ReadableProperty` that allows to access the `IRegularizationConfig` * that stores the configuration of the L2 regularization */ - CompleteHeadConfig(ReadableProperty labelBinningConfig, + CompleteHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, ReadableProperty l2RegularizationConfig); diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.hpp index 26f48ecdc6..6063ba898e 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.hpp @@ -6,6 +6,7 @@ #include "mlrl/boosting/binning/label_binning.hpp" #include "mlrl/boosting/rule_evaluation/head_type.hpp" #include "mlrl/boosting/rule_evaluation/regularization.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/util/dll_exports.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/util/properties.hpp" @@ -77,6 +78,8 @@ namespace boosting { float32 exponent_; + const ReadableProperty quantizationConfig_; + const ReadableProperty labelBinningConfig_; const ReadableProperty multiThreadingConfig_; @@ -84,13 +87,16 @@ namespace boosting { public: /** + * @param quantizationConfig A `ReadableProperty` that allows to access the `IQuantizationConfig` that + * stores the configuration of the method for quantizing gradients and Hessians * @param labelBinningConfig A `ReadableProperty` that allows to access the `ILabelBinningConfig` that * stores the configuration of the method for assigning labels to bins * @param multiThreadingConfig A `ReadableProperty` that allows to access the `IMultiThreadingConfig` that * stores the configuration of the multi-threading behavior that should be used * for the parallel update of statistics */ - DynamicPartialHeadConfig(ReadableProperty labelBinningConfig, + DynamicPartialHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig); float32 getThreshold() const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_fixed.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_fixed.hpp index c26af6dac1..a06f5b2894 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_fixed.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_partial_fixed.hpp @@ -6,6 +6,7 @@ #include "mlrl/boosting/binning/label_binning.hpp" #include "mlrl/boosting/rule_evaluation/head_type.hpp" #include "mlrl/boosting/rule_evaluation/regularization.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/util/dll_exports.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/util/properties.hpp" @@ -92,6 +93,8 @@ namespace boosting { uint32 maxOutputs_; + const ReadableProperty quantizationConfig_; + const ReadableProperty labelBinningConfig_; const ReadableProperty multiThreadingConfig_; @@ -99,13 +102,16 @@ namespace boosting { public: /** + * @param quantizationConfig A `ReadableProperty` that allows to access the `IQuantizationConfig` that + * stores the configuration of the method for quantizing gradients and Hessians * @param labelBinningConfig A `ReadableProperty` that allows to access the `ILabelBinningConfig` that * stores the configuration of the method for assigning labels to bins * @param multiThreadingConfig A `ReadableProperty` that allows to access the `IMultiThreadingConfig` that * stores the configuration of the multi-threading behavior that should be used * for the parallel update of statistics */ - FixedPartialHeadConfig(ReadableProperty labelBinningConfig, + FixedPartialHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig); float32 getOutputRatio() const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_single.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_single.hpp index d35511fe2b..4584d2acfd 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_single.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/head_type_single.hpp @@ -6,6 +6,7 @@ #include "mlrl/boosting/binning/label_binning.hpp" #include "mlrl/boosting/rule_evaluation/head_type.hpp" #include "mlrl/boosting/rule_evaluation/regularization.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/util/properties.hpp" @@ -19,6 +20,8 @@ namespace boosting { class SingleOutputHeadConfig final : public IHeadConfig { private: + const ReadableProperty quantizationConfig_; + const ReadableProperty labelBinningConfig_; const ReadableProperty multiThreadingConfig_; @@ -30,6 +33,9 @@ namespace boosting { public: /** + * @param quantizationConfig A `ReadableProperty` that allows to access the `IQuantizationConfig` that + * stores the configuration of the method for quantizing gradients and + * Hessians * @param labelBinningConfig A `ReadableProperty` that allows to access the `ILabelBinningConfig` that * stores the configuration of the method for assigning labels to bins * @param multiThreadingConfig A `ReadableProperty` that allows to access the `IMultiThreadingConfig` @@ -40,7 +46,8 @@ namespace boosting { * @param l2RegularizationConfig A `ReadableProperty` that allows to access the `IRegularizationConfig` * that stores the configuration of the L2 regularization */ - SingleOutputHeadConfig(ReadableProperty labelBinningConfig, + SingleOutputHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, ReadableProperty l2RegularizationConfig); diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable.hpp index a419a37f44..f6d49b8ea4 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable.hpp @@ -3,6 +3,7 @@ */ #pragma once +#include "mlrl/boosting/data/vector_statistic_decomposable_bit.hpp" #include "mlrl/boosting/data/vector_statistic_decomposable_dense.hpp" #include "mlrl/boosting/rule_evaluation/rule_evaluation.hpp" #include "mlrl/common/indices/index_vector_complete.hpp" @@ -52,6 +53,36 @@ namespace boosting { */ virtual std::unique_ptr> create( const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const = 0; + + /** + * Creates a new instance of the class `IRuleEvaluation` that allows to calculate the predictions of rules + * that predict for all available outputs, based on the gradients and Hessians that are stored by a + * `BitDecomposableStatisticVector`. + * + * @param statisticVector A reference to an object of type `BitDecomposableStatisticVector`. This vector + * is only used to identify the function that is able to deal with this particular + * type of vector via function overloading + * @param indexVector A reference to an object of the type `CompleteIndexVector` that provides access + * to the indices of the outputs for which the rules may predict + * @return An unique pointer to an object of type `IRuleEvaluation` that has been created + */ + virtual std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const = 0; + + /** + * Creates a new instance of the class `IRuleEvaluation` that allows to calculate the predictions of rules + * that predict for a subset of the available outputs, based on the gradients and Hessians that are stored + * by a `BitDecomposableStatisticVector`. + * + * @param statisticVector A reference to an object of type `BitDecomposableStatisticVector`. This vector + * is only used to identify the function that is able to deal with this particular + * type of vector via function overloading + * @param indexVector A reference to an object of the type `PartialIndexVector` that provides access + * to the indices of the outputs for which the rules may predict + * @return An unique pointer to an object of type `IRuleEvaluation` that has been created + */ + virtual std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const = 0; }; } diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.hpp index ce978d785b..2f77b0f73a 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.hpp @@ -37,6 +37,14 @@ namespace boosting { std::unique_ptr> create( const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; }; } diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.hpp index 3070877d6d..c80b0ce88e 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.hpp @@ -44,6 +44,14 @@ namespace boosting { std::unique_ptr> create( const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; }; } diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.hpp index 0349b71afe..b167404dc9 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.hpp @@ -55,6 +55,14 @@ namespace boosting { const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.hpp index d9e2b7986e..eabe812ffa 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.hpp @@ -62,6 +62,14 @@ namespace boosting { const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.hpp index b18cb78db4..67df86d949 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.hpp @@ -55,6 +55,14 @@ namespace boosting { const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.hpp index c378b69883..2a78325e09 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.hpp @@ -61,6 +61,14 @@ namespace boosting { const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.hpp index 8b8ea2466d..4b7bd42dc8 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.hpp @@ -39,6 +39,14 @@ namespace boosting { const DenseDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const override; + + std::unique_ptr> create( + const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const override; + std::unique_ptr> create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const override; diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization.hpp new file mode 100644 index 0000000000..a74154b824 --- /dev/null +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization.hpp @@ -0,0 +1,179 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/boosting/data/view_statistic_decomposable_bit.hpp" +#include "mlrl/boosting/data/view_statistic_non_decomposable_dense.hpp" +#include "mlrl/common/data/tuple.hpp" +#include "mlrl/common/data/view_matrix_c_contiguous.hpp" +#include "mlrl/common/data/view_matrix_sparse_set.hpp" +#include "mlrl/common/indices/index_vector_complete.hpp" +#include "mlrl/common/indices/index_vector_partial.hpp" + +#include +#include +#include + +namespace boosting { + + // Forward declarations + template + class IQuantizationMatrix; + + /** + * Defines an interface for all classes that implement a method for quantizing statistics about the quality of + * predictions for training examples. + */ + class IQuantization { + public: + + virtual ~IQuantization() {} + + /** + * A visitor function for handling quantization matrices that are backed by a view of the type + * `CContiguousView>`. + */ + typedef std::function>>>&)> + DenseDecomposableMatrixVisitor; + + /** + * A visitor function for handling quantization matrices that are backed by a view of the type + * `SparseSetView>`. + */ + typedef std::function>>>&)> + SparseDecomposableMatrixVisitor; + + /** + * A visitor function for handling quantization matrices that are backed by a view of the type + * `BitDecomposableStatisticView`. + */ + typedef std::function>&)> + BitDecomposableMatrixVisitor; + + /** + * A visitor function for handling quantization matrices that are backed by a view of the type + * `DenseNonDecomposableStatisticView`. + */ + typedef std::function>&)> + DenseNonDecomposableMatrixVisitor; + + /** + * Invokes one of the given visitor functions, depending on which one is able to handle the type of the + * matrix that is used for storing quantized scores. + * + * @param denseDecomposableMatrixVisitor An optional visitor function for handling quantization matrices + * that are backed by a view of the type + * `CContiguousView>` + * @param bitDecomposableMatrixVisitor An optional visitor function for handling quantization matrices + * that are backed by a view of the type + * `BitDecomposableStatisticView` + * @param sparseDecomposableMatrixVisitor An optional visitor function for handling quantization matrices + * that are backed by a view of the type + * `SparseSetView>` + * @param denseNonDecomposableMatrixVisitor An optional visitor function for handling quantization matrices + * that are backed by a view of the type + * `DenseNonDecomposableStatisticView` + */ + virtual void visitQuantizationMatrix( + std::optional denseDecomposableMatrixVisitor, + std::optional bitDecomposableMatrixVisitor, + std::optional sparseDecomposableMatrixVisitor, + std::optional denseNonDecomposableMatrixVisitor) = 0; + }; + + /** + * Defines an interface for all factories that allows to create instances of the type `IQuantization`. + */ + class IQuantizationFactory { + public: + + virtual ~IQuantizationFactory() {} + + /** + * Creates and returns a new object of type `IQuantization`. + * + * @param statisticMatrix A reference to an object of type `CContiguousView` that stores the statistics to + * be quantized + * @return An unique pointer to an object of type `IQuantization` that has been created + */ + virtual std::unique_ptr create( + const CContiguousView>& statisticMatrix) const = 0; + + /** + * Creates and returns a new object of type `IQuantization`. + * + * @param statisticMatrix A reference to an object of type `SparseSetView` that stores the statistics to + * be quantized + * @return An unique pointer to an object of type `IQuantization` that has been created + */ + virtual std::unique_ptr create( + const SparseSetView>& statisticMatrix) const = 0; + + /** + * Creates and returns a new object of type `IQuantization`. + * + * @param statisticMatrix A reference to an object of type `DenseNonDecomposableStatisticView` that stores + * the statistics to be quantized + * @return An unique pointer to an object of type `IQuantization` that has been created + */ + virtual std::unique_ptr create( + const DenseNonDecomposableStatisticView& statisticMatrix) const = 0; + }; + + /** + * Defines an interfaces for all matrices for storing quantized statistics that are backed by a view. + */ + template + class IQuantizationMatrix : public IQuantizationFactory { + public: + + virtual ~IQuantizationMatrix() override {} + + /** + * Quantifies all statistics that corresonds to the available outputs. + * + * @param outputIndices A reference to an object of type `ICompleteIndexVector` that stores the indices of + * the output for which the statistics should be quantized + */ + virtual void quantize(const CompleteIndexVector& outputIndices) = 0; + + /** + * Quantifies all statistics that correspond to a certain subset of the outputs. + * + * @param outputIndices A reference to an object of type `IPartialIndexVector` that stores the indices of + * the output for which the statistics should be quantized + */ + virtual void quantize(const PartialIndexVector& outputIndices) = 0; + + /** + * The type of the view, the matrix is backed by. + */ + typedef View view_type; + + /** + * Returns the view, the matrix is backed by. + * + * @return A reference to an object of type `view_type` + */ + virtual const view_type& getView() const = 0; + }; + + /** + * Defines an interface for all classes that allow to configure a method for quantizing statistics about the quality + * of predictions for training examples. + */ + class IQuantizationConfig { + public: + + virtual ~IQuantizationConfig() {} + + /** + * Creates and returns a new object of type `IQuantizationFactory` according to the specified configuration. + * + * @return An unique pointer to an object of type `IQuantizationFactory` that has been created + */ + virtual std::unique_ptr createQuantizationFactory() const = 0; + }; + +} diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_no.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_no.hpp new file mode 100644 index 0000000000..b0ba1f1643 --- /dev/null +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_no.hpp @@ -0,0 +1,22 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/boosting/statistics/quantization.hpp" + +#include + +namespace boosting { + + /** + * Defines an interface for all classes that allow to configure a method for quantizing statistics that does not + * actually perform any quantization. + */ + class NoQuantizationConfig final : public IQuantizationConfig { + public: + + std::unique_ptr createQuantizationFactory() const override; + }; + +} diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_stochastic.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_stochastic.hpp new file mode 100644 index 0000000000..b6478dfe52 --- /dev/null +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/quantization_stochastic.hpp @@ -0,0 +1,67 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/boosting/statistics/quantization.hpp" +#include "mlrl/common/random/rng.hpp" +#include "mlrl/common/util/properties.hpp" + +#include + +namespace boosting { + + /** + * Defines an interface for all classes that allow to configure a method for quantizing statistics that uses a + * stochastic rounding strategy. + */ + class IStochasticQuantizationConfig { + public: + + virtual ~IStochasticQuantizationConfig() {} + + /** + * Returns the number of bits that are used for quantized statistics. + * + * @return The number of bits that are used + */ + virtual uint32 getNumBits() const = 0; + + /** + * Sets the number of bits to be used for quantized statistics. + * + * @param numBits The number of bits to be used. Must be greater than 0 + * @return A reference to an object of type `IStochasticQuantizationConfig` that allows further + * configuration of the quantization method + */ + virtual IStochasticQuantizationConfig& setNumBits(uint32 numBits) = 0; + }; + + /** + * Defines an interface for all classes that allow to configure a method for quantizing statistics that uses a + * stochastic rounding strategy. + */ + class StochasticQuantizationConfig final : public IQuantizationConfig, + public IStochasticQuantizationConfig { + private: + + const ReadableProperty rngConfig_; + + uint32 numBits_; + + public: + + /** + * @param rngConfig A `ReadableProperty` that provides acccess the `RNGConfig` that stores the configuration + * of random number generators + */ + StochasticQuantizationConfig(ReadableProperty rngConfig); + + uint32 getNumBits() const override; + + IStochasticQuantizationConfig& setNumBits(uint32 numBits) override; + + std::unique_ptr createQuantizationFactory() const override; + }; + +} diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics.hpp index ce07fcf841..464321435e 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics.hpp @@ -8,6 +8,7 @@ #include "mlrl/common/statistics/statistics.hpp" #include +#include namespace boosting { @@ -34,11 +35,11 @@ namespace boosting { * Invokes one of the given visitor functions, depending on which one is able to handle the type of matrix * that is used to store the currently predicted scores. * - * @param denseVisitor The visitor function for handling objects of the type `CContiguousView` - * @param sparseVisitor The visitor function for handling objects of the type `SparseSetView` + * @param denseVisitor An optional visitor function for handling objects of the type `CContiguousView` + * @param sparseVisitor An optional visitor function for handling objects of the type `SparseSetView` */ - virtual void visitScoreMatrix(DenseScoreMatrixVisitor denseVisitor, - SparseScoreMatrixVisitor sparseVisitor) const = 0; + virtual void visitScoreMatrix(std::optional denseVisitor, + std::optional sparseVisitor) const = 0; }; } diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_dense.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_dense.hpp index 4218db5db7..81fd8f394f 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_dense.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_dense.hpp @@ -5,6 +5,7 @@ #pragma once #include "mlrl/boosting/losses/loss_decomposable.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/statistics/statistics_decomposable.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/statistics/statistics_provider.hpp" @@ -22,6 +23,8 @@ namespace boosting { : public IClassificationStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -37,6 +40,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `IDecomposableClassificationLossFactory` that allows to create * implementations of the loss function that should be used for @@ -62,6 +68,7 @@ namespace boosting { * parallel */ DenseDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, @@ -87,6 +94,8 @@ namespace boosting { class DenseDecomposableRegressionStatisticsProviderFactory final : public IRegressionStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -102,6 +111,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `IDecomposableRegressionLossFactory` that allows to create * implementations of the loss function that should be used for @@ -127,6 +139,7 @@ namespace boosting { * parallel */ DenseDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.hpp index 60f609fc10..ec2c62c164 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.hpp @@ -5,6 +5,7 @@ #include "mlrl/boosting/losses/loss_decomposable_sparse.hpp" #include "mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_sparse.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/statistics/statistics_decomposable.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/statistics/statistics_provider.hpp" @@ -22,6 +23,8 @@ namespace boosting { : public IClassificationStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -35,6 +38,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `ISparseDecomposableClassificationLossFactory` that allows to * create implementations of the loss function that should be used @@ -56,6 +62,7 @@ namespace boosting { * parallel */ SparseDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, diff --git a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.hpp b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.hpp index 57e6da1d52..95de22e6ca 100644 --- a/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.hpp +++ b/cpp/subprojects/boosting/include/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.hpp @@ -5,6 +5,7 @@ #pragma once #include "mlrl/boosting/losses/loss_non_decomposable.hpp" +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/statistics/statistics_non_decomposable.hpp" #include "mlrl/common/multi_threading/multi_threading.hpp" #include "mlrl/common/statistics/statistics_provider.hpp" @@ -22,6 +23,8 @@ namespace boosting { : public IClassificationStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -37,6 +40,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `INonDecomposableClassificationLossFactory` that allows to * create implementations of the loss function that should be used @@ -62,6 +68,7 @@ namespace boosting { * parallel */ DenseNonDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, @@ -87,6 +94,8 @@ namespace boosting { class DenseNonDecomposableRegressionStatisticsProviderFactory final : public IRegressionStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -102,6 +111,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `INonDecomposableRegressionLossFactory` that allows to create * implementations of the loss function that should be used for @@ -127,6 +139,7 @@ namespace boosting { * parallel */ DenseNonDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, @@ -155,6 +168,8 @@ namespace boosting { : public IClassificationStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -170,6 +185,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `INonDecomposableClassificationLossFactory` that allows to * create implementations of the loss function that should be used @@ -195,6 +213,7 @@ namespace boosting { * parallel */ DenseConvertibleNonDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, @@ -222,6 +241,8 @@ namespace boosting { : public IRegressionStatisticsProviderFactory { private: + const std::unique_ptr quantizationFactoryPtr_; + const std::unique_ptr lossFactoryPtr_; const std::unique_ptr evaluationMeasureFactoryPtr_; @@ -237,6 +258,9 @@ namespace boosting { public: /** + * @param quantizationFactoryPtr An unique pointer to an object of type `IQuantizationFactory` + * that allows to create implementations of the method that should + * be used for quantizing gradients and Hessians * @param lossFactoryPtr An unique pointer to an object of type * `INonDecomposableRegressionLossFactory` that allows to create * implementations of the loss function that should be used for @@ -262,6 +286,7 @@ namespace boosting { * parallel */ DenseConvertibleNonDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, diff --git a/cpp/subprojects/boosting/meson.build b/cpp/subprojects/boosting/meson.build index 2fffd1816f..d43affcb36 100644 --- a/cpp/subprojects/boosting/meson.build +++ b/cpp/subprojects/boosting/meson.build @@ -7,9 +7,11 @@ source_files = [ 'src/mlrl/boosting/binning/label_binning_no.cpp', 'src/mlrl/boosting/data/matrix_c_contiguous_numeric.cpp', 'src/mlrl/boosting/data/matrix_sparse_set_numeric.cpp', + 'src/mlrl/boosting/data/vector_statistic_decomposable_bit.cpp', 'src/mlrl/boosting/data/vector_statistic_decomposable_dense.cpp', 'src/mlrl/boosting/data/vector_statistic_decomposable_sparse.cpp', 'src/mlrl/boosting/data/vector_statistic_non_decomposable_dense.cpp', + 'src/mlrl/boosting/data/view_statistic_decomposable_bit.cpp', 'src/mlrl/boosting/data/view_statistic_non_decomposable_dense.cpp', 'src/mlrl/boosting/input/feature_binning_auto.cpp', 'src/mlrl/boosting/losses/loss_decomposable_logistic.cpp', @@ -62,6 +64,8 @@ source_files = [ 'src/mlrl/boosting/rule_evaluation/rule_evaluation_non_decomposable_partial_fixed_binned.cpp', 'src/mlrl/boosting/rule_model_assemblage/default_rule_auto.cpp', 'src/mlrl/boosting/sampling/partition_sampling_auto.cpp', + 'src/mlrl/boosting/statistics/quantization_no.cpp', + 'src/mlrl/boosting/statistics/quantization_stochastic.cpp', 'src/mlrl/boosting/statistics/statistic_format_auto.cpp', 'src/mlrl/boosting/statistics/statistic_format_dense.cpp', 'src/mlrl/boosting/statistics/statistic_format_sparse.cpp', diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_bit.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_bit.cpp new file mode 100644 index 0000000000..fc5c0dbcc5 --- /dev/null +++ b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_bit.cpp @@ -0,0 +1,143 @@ +#include "mlrl/boosting/data/vector_statistic_decomposable_bit.hpp" + +namespace boosting { + + static inline void copyInternally(const BitVector& firstView, BitVector& secondView) { + typename BitVector::const_iterator begin = firstView.cbegin(); + uint32 arraySize = firstView.cend() - begin; + util::copyView(begin, secondView.begin(), arraySize); + } + + static inline void addInternally(BitVector& firstView, const BitVector& secondView) { + typename BitVector::iterator begin = firstView.begin(); + uint32 arraySize = firstView.end() - begin; + util::addToView(begin, secondView.cbegin(), arraySize); + } + + static inline void addInternally(BitVector& firstView, const BitVector& secondView, + const PartialIndexVector& indices) { + uint32 numIndices = indices.getNumElements(); + + for (uint32 i = 0; i < numIndices; i++) { + uint32 index = indices[i]; + uint32 value = secondView[index]; + firstView.set(i, value); + } + } + + static inline void removeInternally(BitVector& firstView, const BitVector& secondView) { + typename BitVector::iterator begin = firstView.begin(); + uint32 arraySize = firstView.end() - begin; + util::removeFromView(begin, secondView.cbegin(), arraySize); + } + + static inline void differenceInternally(BitVector& firstView, const BitVector& secondView, + const BitVector& thirdView) { + typename BitVector::iterator begin = firstView.begin(); + uint32 arraySize = firstView.end() - begin; + util::setViewToDifference(begin, secondView.cbegin(), thirdView.cbegin(), arraySize); + } + + static inline void differenceInternally(BitVector& firstView, const BitVector& secondView, + const PartialIndexVector& indices, const BitVector& thirdView) { + uint32 numIndices = indices.getNumElements(); + + for (uint32 i = 0; i < numIndices; i++) { + uint32 index = indices[i]; + uint32 firstValue = secondView[index]; + uint32 secondValue = thirdView[i]; + firstView.set(i, firstValue - secondValue); + } + } + + BitDecomposableStatisticVector::BitDecomposableStatisticVector(const BitDecomposableStatisticView& view, + uint32 numElements, bool init) + : CompositeView, AllocatedBitVector>( + AllocatedBitVector(numElements, view.firstView.numBitsPerElement, init), + AllocatedBitVector(numElements, view.secondView.numBitsPerElement, init)) {} + + BitDecomposableStatisticVector::BitDecomposableStatisticVector(const BitDecomposableStatisticVector& other) + : CompositeView, AllocatedBitVector>( + AllocatedBitVector(other.firstView.numElements, other.firstView.numBitsPerElement), + AllocatedBitVector(other.secondView.numElements, other.secondView.numBitsPerElement)) { + copyInternally(other.firstView, this->firstView); + copyInternally(other.secondView, this->secondView); + } + + uint32 BitDecomposableStatisticVector::getNumElements() const { + return this->firstView.numElements; + } + + uint32 BitDecomposableStatisticVector::getNumBitsPerElement() const { + return this->firstView.numBitsPerElement; + } + + void BitDecomposableStatisticVector::add(const BitDecomposableStatisticVector& vector) { + addInternally(this->firstView, vector.firstView); + addInternally(this->secondView, vector.secondView); + } + + void BitDecomposableStatisticVector::add(const BitDecomposableStatisticView& view, uint32 row) { + addInternally(this->firstView, view.firstView[row]); + addInternally(this->secondView, view.secondView[row]); + } + + void BitDecomposableStatisticVector::add(const BitDecomposableStatisticView& view, uint32 row, float64 weight) { + // TODO Implement + throw std::runtime_error("not implemented"); + } + + void BitDecomposableStatisticVector::remove(const BitDecomposableStatisticView& view, uint32 row) { + removeInternally(this->firstView, view.firstView[row]); + removeInternally(this->secondView, view.secondView[row]); + } + + void BitDecomposableStatisticVector::remove(const BitDecomposableStatisticView& view, uint32 row, float64 weight) { + // TODO Implement + throw std::runtime_error("not implemented"); + } + + void BitDecomposableStatisticVector::addToSubset(const BitDecomposableStatisticView& view, uint32 row, + const CompleteIndexVector& indices) { + addInternally(this->firstView, view.firstView[row]); + addInternally(this->secondView, view.secondView[row]); + } + + void BitDecomposableStatisticVector::addToSubset(const BitDecomposableStatisticView& view, uint32 row, + const PartialIndexVector& indices) { + addInternally(this->firstView, view.firstView[row], indices); + addInternally(this->secondView, view.secondView[row], indices); + } + + void BitDecomposableStatisticVector::addToSubset(const BitDecomposableStatisticView& view, uint32 row, + const CompleteIndexVector& indices, float64 weight) { + // TODO Implement + throw std::runtime_error("not implemented"); + } + + void BitDecomposableStatisticVector::addToSubset(const BitDecomposableStatisticView& view, uint32 row, + const PartialIndexVector& indices, float64 weight) { + // TODO Implement + throw std::runtime_error("not implemented"); + } + + void BitDecomposableStatisticVector::difference(const BitDecomposableStatisticVector& first, + const CompleteIndexVector& firstIndices, + const BitDecomposableStatisticVector& second) { + differenceInternally(this->firstView, first.firstView, second.firstView); + differenceInternally(this->secondView, first.secondView, second.secondView); + } + + void BitDecomposableStatisticVector::difference(const BitDecomposableStatisticVector& first, + const PartialIndexVector& firstIndices, + const BitDecomposableStatisticVector& second) { + differenceInternally(this->firstView, first.firstView, firstIndices, second.firstView); + differenceInternally(this->secondView, first.secondView, firstIndices, second.secondView); + } + + void BitDecomposableStatisticVector::clear() { + this->firstView.clear(); + this->secondView.clear(); + } + +} diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_dense.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_dense.cpp index 0e6523558a..f0aab8efd7 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_dense.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_dense.cpp @@ -2,12 +2,14 @@ namespace boosting { - DenseDecomposableStatisticVector::DenseDecomposableStatisticVector(uint32 numElements, bool init) + DenseDecomposableStatisticVector::DenseDecomposableStatisticVector(const CContiguousView>& view, + uint32 numElements, bool init) : ClearableViewDecorator>>>( AllocatedVector>(numElements, init)) {} DenseDecomposableStatisticVector::DenseDecomposableStatisticVector(const DenseDecomposableStatisticVector& other) - : DenseDecomposableStatisticVector(other.getNumElements()) { + : ClearableViewDecorator>>>( + AllocatedVector>(other.getNumElements())) { util::copyView(other.cbegin(), this->begin(), this->getNumElements()); } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_sparse.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_sparse.cpp index 87786ce2c3..23faccd452 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_sparse.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_decomposable_sparse.cpp @@ -118,13 +118,15 @@ namespace boosting { return iterator_ - rhs.iterator_; } - SparseDecomposableStatisticVector::SparseDecomposableStatisticVector(uint32 numElements, bool init) + SparseDecomposableStatisticVector::SparseDecomposableStatisticVector(const SparseSetView>& view, + uint32 numElements, bool init) : ClearableViewDecorator>>>( AllocatedVector>(numElements, init)), sumOfWeights_(0) {} SparseDecomposableStatisticVector::SparseDecomposableStatisticVector(const SparseDecomposableStatisticVector& other) - : SparseDecomposableStatisticVector(other.getNumElements()) { + : ClearableViewDecorator>>>( + AllocatedVector>(other.getNumElements())) { util::copyView(other.view.cbegin(), this->view.begin(), this->getNumElements()); sumOfWeights_ = other.sumOfWeights_; } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_non_decomposable_dense.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_non_decomposable_dense.cpp index f3c9ce6f4d..d7a3de0a55 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_non_decomposable_dense.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/data/vector_statistic_non_decomposable_dense.cpp @@ -4,7 +4,8 @@ namespace boosting { - DenseNonDecomposableStatisticVector::DenseNonDecomposableStatisticVector(uint32 numGradients, bool init) + DenseNonDecomposableStatisticVector::DenseNonDecomposableStatisticVector( + const DenseNonDecomposableStatisticView& view, uint32 numGradients, bool init) : ClearableViewDecorator, AllocatedVector>>>( CompositeVector, AllocatedVector>( AllocatedVector(numGradients, init), @@ -12,7 +13,9 @@ namespace boosting { DenseNonDecomposableStatisticVector::DenseNonDecomposableStatisticVector( const DenseNonDecomposableStatisticVector& other) - : DenseNonDecomposableStatisticVector(other.getNumGradients()) { + : ClearableViewDecorator, AllocatedVector>>>( + CompositeVector, AllocatedVector>( + AllocatedVector(other.getNumGradients()), AllocatedVector(other.getNumHessians()))) { util::copyView(other.gradients_cbegin(), this->gradients_begin(), this->getNumGradients()); util::copyView(other.hessians_cbegin(), this->hessians_begin(), this->getNumHessians()); } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/data/view_statistic_decomposable_bit.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/data/view_statistic_decomposable_bit.cpp new file mode 100644 index 0000000000..008606bc62 --- /dev/null +++ b/cpp/subprojects/boosting/src/mlrl/boosting/data/view_statistic_decomposable_bit.cpp @@ -0,0 +1,15 @@ +#include "mlrl/boosting/data/view_statistic_decomposable_bit.hpp" + +#include "mlrl/boosting/util/math.hpp" + +namespace boosting { + + BitDecomposableStatisticView::BitDecomposableStatisticView(uint32 numRows, uint32 numCols, uint32 numBits) + : CompositeMatrix, AllocatedBitMatrix>( + AllocatedBitMatrix(numRows, numCols, numBits), + AllocatedBitMatrix(numRows, util::triangularNumber(numCols), numBits), numRows, numCols) {} + + BitDecomposableStatisticView::BitDecomposableStatisticView(BitDecomposableStatisticView&& other) + : CompositeMatrix, AllocatedBitMatrix>(std::move(other)) {} + +} diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_auto.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_auto.cpp index 2641c708ac..327e6632f4 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_auto.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_auto.cpp @@ -5,20 +5,22 @@ namespace boosting { - AutomaticHeadConfig::AutomaticHeadConfig(ReadableProperty lossConfig, + AutomaticHeadConfig::AutomaticHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty lossConfig, ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, ReadableProperty l2RegularizationConfig) - : lossConfig_(lossConfig), labelBinningConfig_(labelBinningConfig), multiThreadingConfig_(multiThreadingConfig), - l1RegularizationConfig_(l1RegularizationConfig), l2RegularizationConfig_(l2RegularizationConfig) {} + : quantizationConfig_(quantizationConfig), lossConfig_(lossConfig), labelBinningConfig_(labelBinningConfig), + multiThreadingConfig_(multiThreadingConfig), l1RegularizationConfig_(l1RegularizationConfig), + l2RegularizationConfig_(l2RegularizationConfig) {} std::unique_ptr AutomaticHeadConfig::createClassificationStatisticsProviderFactory( const IFeatureMatrix& featureMatrix, const IRowWiseLabelMatrix& labelMatrix, const IDecomposableClassificationLossConfig& lossConfig) const { - CompleteHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + CompleteHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createClassificationStatisticsProviderFactory(featureMatrix, labelMatrix, lossConfig); } @@ -27,12 +29,12 @@ namespace boosting { const IFeatureMatrix& featureMatrix, const IRowWiseLabelMatrix& labelMatrix, const ISparseDecomposableClassificationLossConfig& lossConfig) const { if (labelMatrix.getNumOutputs() > 1) { - SingleOutputHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + SingleOutputHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createClassificationStatisticsProviderFactory(featureMatrix, labelMatrix, lossConfig); } else { - CompleteHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + CompleteHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createClassificationStatisticsProviderFactory(featureMatrix, labelMatrix, lossConfig); } } @@ -41,8 +43,8 @@ namespace boosting { AutomaticHeadConfig::createClassificationStatisticsProviderFactory( const IFeatureMatrix& featureMatrix, const IRowWiseLabelMatrix& labelMatrix, const INonDecomposableClassificationLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { - CompleteHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + CompleteHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createClassificationStatisticsProviderFactory(featureMatrix, labelMatrix, lossConfig, blas, lapack); } @@ -51,8 +53,8 @@ namespace boosting { AutomaticHeadConfig::createRegressionStatisticsProviderFactory( const IFeatureMatrix& featureMatrix, const IRowWiseRegressionMatrix& regressionMatrix, const IDecomposableRegressionLossConfig& lossConfig) const { - CompleteHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + CompleteHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createRegressionStatisticsProviderFactory(featureMatrix, regressionMatrix, lossConfig); } @@ -60,8 +62,8 @@ namespace boosting { AutomaticHeadConfig::createRegressionStatisticsProviderFactory( const IFeatureMatrix& featureMatrix, const IRowWiseRegressionMatrix& regressionMatrix, const INonDecomposableRegressionLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { - CompleteHeadConfig headConfig(labelBinningConfig_, multiThreadingConfig_, l1RegularizationConfig_, - l2RegularizationConfig_); + CompleteHeadConfig headConfig(quantizationConfig_, labelBinningConfig_, multiThreadingConfig_, + l1RegularizationConfig_, l2RegularizationConfig_); return headConfig.createRegressionStatisticsProviderFactory(featureMatrix, regressionMatrix, lossConfig, blas, lapack); } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_complete.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_complete.cpp index f302bfcb2f..7b58d57150 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_complete.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_complete.cpp @@ -6,12 +6,14 @@ namespace boosting { - CompleteHeadConfig::CompleteHeadConfig(ReadableProperty labelBinningConfig, + CompleteHeadConfig::CompleteHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, ReadableProperty l2RegularizationConfig) - : labelBinningConfig_(labelBinningConfig), multiThreadingConfig_(multiThreadingConfig), - l1RegularizationConfig_(l1RegularizationConfig), l2RegularizationConfig_(l2RegularizationConfig) {} + : quantizationConfig_(quantizationConfig), labelBinningConfig_(labelBinningConfig), + multiThreadingConfig_(multiThreadingConfig), l1RegularizationConfig_(l1RegularizationConfig), + l2RegularizationConfig_(l2RegularizationConfig) {} std::unique_ptr CompleteHeadConfig::createClassificationStatisticsProviderFactory( @@ -21,6 +23,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -32,9 +36,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -51,6 +55,8 @@ namespace boosting { const INonDecomposableClassificationLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -62,9 +68,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = labelBinningConfig_.get().createNonDecomposableCompleteRuleEvaluationFactory(blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr CompleteHeadConfig::createRegressionStatisticsProviderFactory( @@ -74,6 +80,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -85,9 +93,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr CompleteHeadConfig::createRegressionStatisticsProviderFactory( @@ -95,6 +103,8 @@ namespace boosting { const INonDecomposableRegressionLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -106,9 +116,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = labelBinningConfig_.get().createNonDecomposableCompleteRuleEvaluationFactory(blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } bool CompleteHeadConfig::isPartial() const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.cpp index ad77009ca3..eb867d5e81 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_dynamic.cpp @@ -7,10 +7,11 @@ namespace boosting { - DynamicPartialHeadConfig::DynamicPartialHeadConfig(ReadableProperty labelBinningConfig, + DynamicPartialHeadConfig::DynamicPartialHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig) - : threshold_(0.02f), exponent_(2.0f), labelBinningConfig_(labelBinningConfig), - multiThreadingConfig_(multiThreadingConfig) {} + : threshold_(0.02f), exponent_(2.0f), quantizationConfig_(quantizationConfig), + labelBinningConfig_(labelBinningConfig), multiThreadingConfig_(multiThreadingConfig) {} float32 DynamicPartialHeadConfig::getThreshold() const { return threshold_; @@ -39,6 +40,8 @@ namespace boosting { const IDecomposableClassificationLossConfig& lossConfig) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -50,9 +53,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = labelBinningConfig_.get().createDecomposableDynamicPartialRuleEvaluationFactory(threshold_, exponent_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -61,6 +64,8 @@ namespace boosting { const ISparseDecomposableClassificationLossConfig& lossConfig) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createSparseDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -70,8 +75,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = labelBinningConfig_.get().createDecomposableDynamicPartialRuleEvaluationFactory(threshold_, exponent_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), - std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), + multiThreadingSettings); } std::unique_ptr @@ -80,6 +86,8 @@ namespace boosting { const INonDecomposableClassificationLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -93,9 +101,9 @@ namespace boosting { labelBinningConfig_.get().createNonDecomposableDynamicPartialRuleEvaluationFactory(threshold_, exponent_, blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -104,6 +112,8 @@ namespace boosting { const IDecomposableRegressionLossConfig& lossConfig) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -115,9 +125,9 @@ namespace boosting { std::unique_ptr pruningRuleEvaluationFactoryPtr = labelBinningConfig_.get().createDecomposableDynamicPartialRuleEvaluationFactory(threshold_, exponent_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -126,6 +136,8 @@ namespace boosting { const INonDecomposableRegressionLossConfig& lossConfig, const Blas& blas, const Lapack& lapack) const { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -139,9 +151,9 @@ namespace boosting { labelBinningConfig_.get().createNonDecomposableDynamicPartialRuleEvaluationFactory(threshold_, exponent_, blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } bool DynamicPartialHeadConfig::isPartial() const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_fixed.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_fixed.cpp index ca5f16ed0e..f4ad0a5fb5 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_fixed.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_partial_fixed.cpp @@ -23,10 +23,11 @@ namespace boosting { } } - FixedPartialHeadConfig::FixedPartialHeadConfig(ReadableProperty labelBinningConfig, + FixedPartialHeadConfig::FixedPartialHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig) - : outputRatio_(0.0f), minOutputs_(2), maxOutputs_(0), labelBinningConfig_(labelBinningConfig), - multiThreadingConfig_(multiThreadingConfig) {} + : outputRatio_(0.0f), minOutputs_(2), maxOutputs_(0), quantizationConfig_(quantizationConfig), + labelBinningConfig_(labelBinningConfig), multiThreadingConfig_(multiThreadingConfig) {} float32 FixedPartialHeadConfig::getOutputRatio() const { return outputRatio_; @@ -69,6 +70,8 @@ namespace boosting { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); float32 outputRatio = calculateOutputRatio(outputRatio_, labelMatrix); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -82,9 +85,9 @@ namespace boosting { labelBinningConfig_.get().createDecomposableFixedPartialRuleEvaluationFactory(outputRatio, minOutputs_, maxOutputs_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -94,6 +97,8 @@ namespace boosting { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); float32 outputRatio = calculateOutputRatio(outputRatio_, labelMatrix); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createSparseDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -105,8 +110,9 @@ namespace boosting { labelBinningConfig_.get().createDecomposableFixedPartialRuleEvaluationFactory(outputRatio, minOutputs_, maxOutputs_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), - std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), + multiThreadingSettings); } std::unique_ptr @@ -116,6 +122,8 @@ namespace boosting { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); float32 outputRatio = calculateOutputRatio(outputRatio_, labelMatrix); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -129,9 +137,9 @@ namespace boosting { labelBinningConfig_.get().createNonDecomposableFixedPartialRuleEvaluationFactory(outputRatio, minOutputs_, maxOutputs_, blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -141,6 +149,8 @@ namespace boosting { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); float32 outputRatio = calculateOutputRatio(outputRatio_, regressionMatrix); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -154,9 +164,9 @@ namespace boosting { labelBinningConfig_.get().createDecomposableFixedPartialRuleEvaluationFactory(outputRatio, minOutputs_, maxOutputs_); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -166,6 +176,8 @@ namespace boosting { MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); float32 outputRatio = calculateOutputRatio(outputRatio_, regressionMatrix); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -179,9 +191,9 @@ namespace boosting { labelBinningConfig_.get().createNonDecomposableFixedPartialRuleEvaluationFactory(outputRatio, minOutputs_, maxOutputs_, blas, lapack); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } bool FixedPartialHeadConfig::isPartial() const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_single.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_single.cpp index f3327de56e..3d7ac91273 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_single.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/head_type_single.cpp @@ -7,12 +7,14 @@ namespace boosting { - SingleOutputHeadConfig::SingleOutputHeadConfig(ReadableProperty labelBinningConfig, + SingleOutputHeadConfig::SingleOutputHeadConfig(ReadableProperty quantizationConfig, + ReadableProperty labelBinningConfig, ReadableProperty multiThreadingConfig, ReadableProperty l1RegularizationConfig, ReadableProperty l2RegularizationConfig) - : labelBinningConfig_(labelBinningConfig), multiThreadingConfig_(multiThreadingConfig), - l1RegularizationConfig_(l1RegularizationConfig), l2RegularizationConfig_(l2RegularizationConfig) {} + : quantizationConfig_(quantizationConfig), labelBinningConfig_(labelBinningConfig), + multiThreadingConfig_(multiThreadingConfig), l1RegularizationConfig_(l1RegularizationConfig), + l2RegularizationConfig_(l2RegularizationConfig) {} std::unique_ptr SingleOutputHeadConfig::createClassificationStatisticsProviderFactory( @@ -22,6 +24,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -35,9 +39,9 @@ namespace boosting { std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -48,6 +52,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createSparseDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -59,8 +65,9 @@ namespace boosting { std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), - std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), + multiThreadingSettings); } std::unique_ptr @@ -71,6 +78,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, labelMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableClassificationLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -84,9 +93,9 @@ namespace boosting { std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -97,6 +106,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -110,9 +121,9 @@ namespace boosting { std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } std::unique_ptr @@ -123,6 +134,8 @@ namespace boosting { float64 l2RegularizationWeight = l2RegularizationConfig_.get().getWeight(); MultiThreadingSettings multiThreadingSettings = multiThreadingConfig_.get().getSettings(featureMatrix, regressionMatrix.getNumOutputs()); + std::unique_ptr quantizationFactoryPtr = + quantizationConfig_.get().createQuantizationFactory(); std::unique_ptr lossFactoryPtr = lossConfig.createNonDecomposableRegressionLossFactory(); std::unique_ptr evaluationMeasureFactoryPtr = @@ -136,9 +149,9 @@ namespace boosting { std::make_unique(l1RegularizationWeight, l2RegularizationWeight); return std::make_unique( - std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), std::move(defaultRuleEvaluationFactoryPtr), - std::move(regularRuleEvaluationFactoryPtr), std::move(pruningRuleEvaluationFactoryPtr), - multiThreadingSettings); + std::move(quantizationFactoryPtr), std::move(lossFactoryPtr), std::move(evaluationMeasureFactoryPtr), + std::move(defaultRuleEvaluationFactoryPtr), std::move(regularRuleEvaluationFactoryPtr), + std::move(pruningRuleEvaluationFactoryPtr), multiThreadingSettings); } bool SingleOutputHeadConfig::isPartial() const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.cpp index 17635cda40..54a1c6286f 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete.cpp @@ -24,4 +24,16 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_); } + std::unique_ptr> DecomposableCompleteRuleEvaluationFactory::create( + const BitDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> DecomposableCompleteRuleEvaluationFactory::create( + const BitDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.cpp index b1baacec5e..0737a1480f 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_complete_binned.cpp @@ -28,4 +28,18 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_, std::move(labelBinningPtr)); } + std::unique_ptr> + DecomposableCompleteBinnedRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableCompleteBinnedRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.cpp index 967d3e9385..c2cf903c4f 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic.cpp @@ -107,6 +107,20 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_); } + std::unique_ptr> + DecomposableDynamicPartialRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableDynamicPartialRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + std::unique_ptr> DecomposableDynamicPartialRuleEvaluationFactory::create(const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.cpp index 98c149e026..cc1655361d 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_dynamic_binned.cpp @@ -115,6 +115,20 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_, std::move(labelBinningPtr)); } + std::unique_ptr> + DecomposableDynamicPartialBinnedRuleEvaluationFactory::create( + const BitDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableDynamicPartialBinnedRuleEvaluationFactory::create( + const BitDecomposableStatisticVector& statisticVector, const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + std::unique_ptr> DecomposableDynamicPartialBinnedRuleEvaluationFactory::create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.cpp index 35e5004354..f74fb030f1 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed.cpp @@ -99,6 +99,20 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_); } + std::unique_ptr> + DecomposableFixedPartialRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableFixedPartialRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + std::unique_ptr> DecomposableFixedPartialRuleEvaluationFactory::create(const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.cpp index 875953f9a3..ce56d0e935 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_partial_fixed_binned.cpp @@ -99,6 +99,20 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_, std::move(labelBinningPtr)); } + std::unique_ptr> + DecomposableFixedPartialBinnedRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableFixedPartialBinnedRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + std::unique_ptr> DecomposableFixedPartialBinnedRuleEvaluationFactory::create( const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.cpp index 4c4327f954..335556c1be 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/rule_evaluation/rule_evaluation_decomposable_single.cpp @@ -91,6 +91,20 @@ namespace boosting { indexVector, l1RegularizationWeight_, l2RegularizationWeight_); } + std::unique_ptr> + DecomposableSingleOutputRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const CompleteIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + + std::unique_ptr> + DecomposableSingleOutputRuleEvaluationFactory::create(const BitDecomposableStatisticVector& statisticVector, + const PartialIndexVector& indexVector) const { + // TODO Implement + return nullptr; + } + std::unique_ptr> DecomposableSingleOutputRuleEvaluationFactory::create(const SparseDecomposableStatisticVector& statisticVector, const CompleteIndexVector& indexVector) const { diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_no.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_no.cpp new file mode 100644 index 0000000000..61958c6e24 --- /dev/null +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_no.cpp @@ -0,0 +1,135 @@ +#include "mlrl/boosting/statistics/quantization_no.hpp" + +namespace boosting { + + class NoDenseDecomposableQuantization final : public IQuantization { + private: + + std::unique_ptr>>> quantizationMatrixPtr_; + + public: + + NoDenseDecomposableQuantization( + std::unique_ptr>>> quantizationMatrixPtr) + : quantizationMatrixPtr_(std::move(quantizationMatrixPtr)) {} + + void visitQuantizationMatrix( + std::optional denseDecomposableMatrixVisitor, + std::optional bitDecomposableMatrixVisitor, + std::optional sparseDecomposableMatrixVisitor, + std::optional denseNonDecomposableMatrixVisitor) + override { + if (denseDecomposableMatrixVisitor) { + (*denseDecomposableMatrixVisitor)(quantizationMatrixPtr_); + } + } + }; + + class NoSparseDecomposableQuantization final : public IQuantization { + private: + + std::unique_ptr>>> quantizationMatrixPtr_; + + public: + + NoSparseDecomposableQuantization( + std::unique_ptr>>> quantizationMatrixPtr) + : quantizationMatrixPtr_(std::move(quantizationMatrixPtr)) {} + + void visitQuantizationMatrix( + std::optional denseDecomposableMatrixVisitor, + std::optional bitDecomposableMatrixVisitor, + std::optional sparseDecomposableMatrixVisitor, + std::optional denseNonDecomposableMatrixVisitor) + override { + if (sparseDecomposableMatrixVisitor) { + (*sparseDecomposableMatrixVisitor)(quantizationMatrixPtr_); + } + } + }; + + class NoDenseNonDecomposableQuantization final : public IQuantization { + private: + + std::unique_ptr> quantizationMatrixPtr_; + + public: + + NoDenseNonDecomposableQuantization( + std::unique_ptr> quantizationMatrixPtr) + : quantizationMatrixPtr_(std::move(quantizationMatrixPtr)) {} + + void visitQuantizationMatrix( + std::optional denseDecomposableMatrixVisitor, + std::optional bitDecomposableMatrixVisitor, + std::optional sparseDecomposableMatrixVisitor, + std::optional denseNonDecomposableMatrixVisitor) + override { + if (denseNonDecomposableMatrixVisitor) { + (*denseNonDecomposableMatrixVisitor)(quantizationMatrixPtr_); + } + } + }; + + template + class NoQuantizationMatrix final : public IQuantizationMatrix { + private: + + const View& view_; + + public: + + NoQuantizationMatrix(const View& view) : view_(view) {} + + void quantize(const CompleteIndexVector& outputIndices) override {} + + void quantize(const PartialIndexVector& outputIndices) override {} + + const typename IQuantizationMatrix::view_type& getView() const override { + return view_; + } + + std::unique_ptr create( + const CContiguousView>& statisticMatrix) const override { + return std::make_unique( + std::make_unique>>>(statisticMatrix)); + } + + std::unique_ptr create(const SparseSetView>& statisticMatrix) const override { + return std::make_unique( + std::make_unique>>>(statisticMatrix)); + } + + std::unique_ptr create( + const DenseNonDecomposableStatisticView& statisticMatrix) const override { + return std::make_unique( + std::make_unique>(statisticMatrix)); + } + }; + + class NoQuantizationFactory final : public IQuantizationFactory { + public: + + std::unique_ptr create( + const CContiguousView>& statisticMatrix) const override { + return std::make_unique( + std::make_unique>>>(statisticMatrix)); + } + + std::unique_ptr create(const SparseSetView>& statisticMatrix) const override { + return std::make_unique( + std::make_unique>>>(statisticMatrix)); + } + + std::unique_ptr create( + const DenseNonDecomposableStatisticView& statisticMatrix) const override { + return std::make_unique( + std::make_unique>(statisticMatrix)); + } + }; + + std::unique_ptr NoQuantizationConfig::createQuantizationFactory() const { + return std::make_unique(); + } + +} diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_stochastic.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_stochastic.cpp new file mode 100644 index 0000000000..ac90bc4aaa --- /dev/null +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/quantization_stochastic.cpp @@ -0,0 +1,130 @@ +#include "mlrl/boosting/statistics/quantization_stochastic.hpp" + +#include "mlrl/boosting/data/view_statistic_decomposable_bit.hpp" +#include "mlrl/common/util/validation.hpp" + +namespace boosting { + + template + class StochasticQuantization final : public IQuantization { + private: + + std::unique_ptr> quantizationMatrixPtr_; + + public: + + StochasticQuantization( + std::unique_ptr> quantizationMatrixPtr) + : quantizationMatrixPtr_(std::move(quantizationMatrixPtr)) {} + + void visitQuantizationMatrix( + std::optional denseDecomposableMatrixVisitor, + std::optional bitDecomposableMatrixVisitor, + std::optional sparseDecomposableMatrixVisitor, + std::optional denseNonDecomposableMatrixVisitor) + override { + if (bitDecomposableMatrixVisitor) { + (*bitDecomposableMatrixVisitor)(quantizationMatrixPtr_); + } + } + }; + + template + class StochasticQuantizationMatrix final : public IQuantizationMatrix { + private: + + std::shared_ptr rngPtr_; + + const View& view_; + + BitDecomposableStatisticView quantizedView_; + + public: + + StochasticQuantizationMatrix(std::shared_ptr rngPtr, const View& view, uint32 numBits) + : rngPtr_(std::move(rngPtr)), view_(view), quantizedView_(view.numRows, view.numCols, numBits) {} + + void quantize(const CompleteIndexVector& outputIndices) override { + // TODO Implement + } + + void quantize(const PartialIndexVector& outputIndices) override { + // TODO Implement + } + + const typename IQuantizationMatrix::view_type& getView() const override { + return quantizedView_; + } + + std::unique_ptr create( + const CContiguousView>& statisticMatrix) const override { + return std::make_unique>>>( + std::make_unique>>>( + rngPtr_, statisticMatrix, quantizedView_.firstView.numBitsPerElement)); + } + + std::unique_ptr create(const SparseSetView>& statisticMatrix) const override { + return std::make_unique>>>( + std::make_unique>>>( + rngPtr_, statisticMatrix, quantizedView_.firstView.numBitsPerElement)); + } + + std::unique_ptr create( + const DenseNonDecomposableStatisticView& statisticMatrix) const override { + return std::make_unique>( + std::make_unique>( + rngPtr_, statisticMatrix, quantizedView_.firstView.numBitsPerElement)); + } + }; + + class StochasticQuantizationFactory final : public IQuantizationFactory { + private: + + const std::unique_ptr rngFactoryPtr_; + + uint32 numBits_; + + public: + + StochasticQuantizationFactory(std::unique_ptr rngFactoryPtr, uint32 numBits) + : rngFactoryPtr_(std::move(rngFactoryPtr)), numBits_(numBits) {} + + std::unique_ptr create( + const CContiguousView>& statisticMatrix) const override { + return std::make_unique>>>( + std::make_unique>>>( + rngFactoryPtr_->create(), statisticMatrix, numBits_)); + } + + std::unique_ptr create(const SparseSetView>& statisticMatrix) const override { + return std::make_unique>>>( + std::make_unique>>>( + rngFactoryPtr_->create(), statisticMatrix, numBits_)); + } + + std::unique_ptr create( + const DenseNonDecomposableStatisticView& statisticMatrix) const override { + return std::make_unique>( + std::make_unique>( + rngFactoryPtr_->create(), statisticMatrix, numBits_)); + } + }; + + StochasticQuantizationConfig::StochasticQuantizationConfig(ReadableProperty rngConfig) + : rngConfig_(rngConfig), numBits_(4) {} + + uint32 StochasticQuantizationConfig::getNumBits() const { + return numBits_; + } + + IStochasticQuantizationConfig& StochasticQuantizationConfig::setNumBits(uint32 numBits) { + util::assertGreater("numBits", numBits, 0); + numBits_ = numBits; + return *this; + } + + std::unique_ptr StochasticQuantizationConfig::createQuantizationFactory() const { + return std::make_unique(rngConfig_.get().createRNGFactory(), numBits_); + } + +} diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_common.hpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_common.hpp index 4b3f9c049d..f0bb3db6a6 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_common.hpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_common.hpp @@ -3,6 +3,7 @@ */ #pragma once +#include "mlrl/boosting/statistics/quantization.hpp" #include "mlrl/boosting/statistics/statistics.hpp" #include @@ -97,8 +98,8 @@ namespace boosting { */ StatisticsSubset(const StatisticView& statisticView, const RuleEvaluationFactory& ruleEvaluationFactory, const WeightVector& weights, const IndexVector& outputIndices) - : sumVector_(outputIndices.getNumElements(), true), statisticView_(statisticView), weights_(weights), - outputIndices_(outputIndices), + : sumVector_(statisticView, outputIndices.getNumElements(), true), statisticView_(statisticView), + weights_(weights), outputIndices_(outputIndices), ruleEvaluationPtr_(ruleEvaluationFactory.create(sumVector_, outputIndices)) {} /** @@ -181,7 +182,8 @@ namespace boosting { : StatisticsSubset(statistics.statisticView_, statistics.ruleEvaluationFactory_, statistics.weights_, outputIndices), - tmpVector_(outputIndices.getNumElements()), totalSumVector_(&totalSumVector) {} + tmpVector_(statistics.statisticView_, outputIndices.getNumElements()), + totalSumVector_(&totalSumVector) {} /** * @see `IResettableStatisticsSubset::resetSubset` @@ -391,7 +393,7 @@ namespace boosting { const WeightVector& weights) : AbstractWeightedStatistics( statisticView, ruleEvaluationFactory, weights), - totalSumVectorPtr_(std::make_unique(statisticView.numCols, true)) { + totalSumVectorPtr_(std::make_unique(statisticView, statisticView.numCols, true)) { uint32 numStatistics = weights.getNumElements(); for (uint32 i = 0; i < numStatistics; i++) { @@ -456,26 +458,13 @@ namespace boosting { } }; - template - static inline void applyPredictionInternally(uint32 statisticIndex, const Prediction& prediction, - ScoreMatrix& scoreMatrix) { - scoreMatrix.addToRowFromSubset(statisticIndex, prediction.values_cbegin(), prediction.values_cend(), - prediction.indices_cbegin(), prediction.indices_cend()); - } - - template - static inline void revertPredictionInternally(uint32 statisticIndex, const Prediction& prediction, - ScoreMatrix& scoreMatrix) { - scoreMatrix.removeFromRowFromSubset(statisticIndex, prediction.values_cbegin(), prediction.values_cend(), - prediction.indices_cbegin(), prediction.indices_cend()); - } - /** * An abstract base class for all statistics that provide access to gradients and Hessians that are calculated * according to a loss function. * * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training * examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients and Hessians * @tparam StatisticVector The type of the vectors that are used to store gradients and Hessians * @tparam StatisticMatrix The type of the matrix that provides access to the gradients and Hessians * @tparam ScoreMatrix The type of the matrices that are used to store predicted scores @@ -486,8 +475,8 @@ namespace boosting { * used for calculating the predictions of rules, as well as corresponding quality * scores */ - template + template class AbstractStatistics : virtual public IBoostingStatistics { private: @@ -514,18 +503,31 @@ namespace boosting { : statistics_(statistics), prediction_(prediction) {} void applyPrediction(uint32 statisticIndex) override { - applyPredictionInternally(statisticIndex, prediction_, *statistics_.scoreMatrixPtr_); + statistics_.scoreMatrixPtr_->addToRowFromSubset( + statisticIndex, prediction_.values_cbegin(), prediction_.values_cend(), + prediction_.indices_cbegin(), prediction_.indices_cend()); statistics_.updateStatistics(statisticIndex, prediction_); } void revertPrediction(uint32 statisticIndex) override { - revertPredictionInternally(statisticIndex, prediction_, *statistics_.scoreMatrixPtr_); + statistics_.scoreMatrixPtr_->removeFromRowFromSubset( + statisticIndex, prediction_.values_cbegin(), prediction_.values_cend(), + prediction_.indices_cbegin(), prediction_.indices_cend()); statistics_.updateStatistics(statisticIndex, prediction_); } + + void commit() override { + statistics_.quantizationMatrixPtr_->quantize(prediction_.getIndexVector()); + } }; protected: + /** + * An unique pointer to the matrix that provides access to quantized gradients and Hessians. + */ + std::unique_ptr quantizationMatrixPtr_; + /** * An unique pointer to the loss function that should be used for calculating gradients and Hessians. */ @@ -561,18 +563,28 @@ namespace boosting { /** * Must be implemented by subclasses in order to update the statistics for all available outputs at a * specific index. + * + * @param statisticIndex The index of the statistics that should be updated + * @param prediction A reference to an object of type `CompletePrediction` that stores the + * predictions according to which the statistics should be updated */ virtual void updateStatistics(uint32 statisticIndex, const CompletePrediction& prediction) = 0; /** * Must be implemented by subclasses in order to update the statistics for a subset of the available outputs * at a specific index. + * + * @param statisticIndex The index of the statistics that should be updated + * @param prediction A reference to an object of type `PartialPrediction` that stores the predictions + * according to which the statistics should be updated */ virtual void updateStatistics(uint32 statisticIndex, const PartialPrediction& prediction) = 0; public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `LossFunction` that * implements the loss function that should be used for calculating gradients * and Hessians @@ -589,12 +601,14 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of template type `ScoreMatrix` that stores * the currently predicted scores */ - AbstractStatistics(std::unique_ptr lossPtr, + AbstractStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const RuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticMatrixPtr, std::unique_ptr scoreMatrixPtr) - : lossPtr_(std::move(lossPtr)), evaluationMeasurePtr_(std::move(evaluationMeasurePtr)), + : quantizationMatrixPtr_(std::move(quantizationMatrixPtr)), lossPtr_(std::move(lossPtr)), + evaluationMeasurePtr_(std::move(evaluationMeasurePtr)), ruleEvaluationFactory_(&ruleEvaluationFactory), outputMatrix_(outputMatrix), statisticMatrixPtr_(std::move(statisticMatrixPtr)), scoreMatrixPtr_(std::move(scoreMatrixPtr)) {} @@ -639,9 +653,9 @@ namespace boosting { std::unique_ptr createSubset(const CompleteIndexVector& outputIndices, const EqualWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -649,9 +663,9 @@ namespace boosting { */ std::unique_ptr createSubset(const PartialIndexVector& outputIndices, const EqualWeightVector& weights) const override final { - return std::make_unique>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -659,9 +673,9 @@ namespace boosting { */ std::unique_ptr createSubset(const CompleteIndexVector& outputIndices, const BitWeightVector& weights) const override final { - return std::make_unique>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -669,9 +683,9 @@ namespace boosting { */ std::unique_ptr createSubset(const PartialIndexVector& outputIndices, const BitWeightVector& weights) const override final { - return std::make_unique>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -680,9 +694,9 @@ namespace boosting { std::unique_ptr createSubset( const CompleteIndexVector& outputIndices, const DenseWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, CompleteIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -691,9 +705,9 @@ namespace boosting { std::unique_ptr createSubset( const PartialIndexVector& outputIndices, const DenseWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, PartialIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -703,9 +717,9 @@ namespace boosting { const CompleteIndexVector& outputIndices, const OutOfSampleWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, CompleteIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -715,9 +729,9 @@ namespace boosting { const PartialIndexVector& outputIndices, const OutOfSampleWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, PartialIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -727,9 +741,9 @@ namespace boosting { const CompleteIndexVector& outputIndices, const OutOfSampleWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, CompleteIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -739,9 +753,9 @@ namespace boosting { const PartialIndexVector& outputIndices, const OutOfSampleWeightVector& weights) const override final { return std::make_unique< - StatisticsSubset, PartialIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -751,9 +765,9 @@ namespace boosting { const CompleteIndexVector& outputIndices, const OutOfSampleWeightVector>& weights) const override final { return std::make_unique< - StatisticsSubset>, CompleteIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -763,9 +777,9 @@ namespace boosting { const PartialIndexVector& outputIndices, const OutOfSampleWeightVector>& weights) const override final { return std::make_unique< - StatisticsSubset>, PartialIndexVector>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights, outputIndices); } /** @@ -773,9 +787,9 @@ namespace boosting { */ std::unique_ptr createWeightedStatistics( const EqualWeightVector& weights) const override final { - return std::make_unique>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); } /** @@ -783,9 +797,9 @@ namespace boosting { */ std::unique_ptr createWeightedStatistics( const BitWeightVector& weights) const override final { - return std::make_unique>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); } /** @@ -793,9 +807,9 @@ namespace boosting { */ std::unique_ptr createWeightedStatistics( const DenseWeightVector& weights) const override final { - return std::make_unique>>( - statisticMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); + quantizationMatrixPtr_->getView(), *ruleEvaluationFactory_, weights); } }; diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_common.hpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_common.hpp index 9816501de8..a544127ad0 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_common.hpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_common.hpp @@ -28,6 +28,7 @@ namespace boosting { * * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training * examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients and Hessians * @tparam StatisticVector The type of the vectors that are used to store gradients and Hessians * @tparam StatisticMatrix The type of the matrix that provides access to the gradients and Hessians * @tparam ScoreMatrix The type of the matrices that are used to store predicted scores @@ -38,11 +39,11 @@ namespace boosting { * used for calculating the predictions of rules, as well as corresponding quality * scores */ - template + template class AbstractDecomposableStatistics - : public AbstractStatistics, + : public AbstractStatistics, virtual public IDecomposableStatistics { protected: @@ -61,6 +62,8 @@ namespace boosting { public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `LossFunction` that * implements the loss function that should be used for calculating gradients * and Hessians @@ -77,16 +80,17 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of template type `ScoreMatrix` that stores * the currently predicted scores */ - AbstractDecomposableStatistics(std::unique_ptr lossPtr, + AbstractDecomposableStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const RuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticMatrixPtr, std::unique_ptr scoreMatrixPtr) - : AbstractStatistics( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} + : AbstractStatistics( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} /** * @see `IDecomposableStatistics::setRuleEvaluationFactory` diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_dense.hpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_dense.hpp index e3125d669d..0a178822f0 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_dense.hpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_decomposable_dense.hpp @@ -52,16 +52,21 @@ namespace boosting { * @tparam Loss The type of the loss function * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training * examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients and Hessians + * @tparam StatisticVector The type of the vectors that are used to store gradients and Hessians * @tparam EvaluationMeasure The type of the evaluation that should be used to access the quality of predictions */ - template + template class DenseDecomposableStatistics final - : public AbstractDecomposableStatistics, Loss, EvaluationMeasure, IDecomposableRuleEvaluationFactory> { public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `Loss` that implements the * loss function that should be used for calculating gradients and Hessians * @param evaluationMeasurePtr An unique pointer to an object of template type `EvaluationMeasure` that @@ -77,24 +82,28 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of type `NumericCContiguousMatrix` that * stores the currently predicted scores */ - DenseDecomposableStatistics(std::unique_ptr lossPtr, + DenseDecomposableStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const IDecomposableRuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticMatrixPtr, std::unique_ptr> scoreMatrixPtr) - : AbstractDecomposableStatistics, Loss, EvaluationMeasure, IDecomposableRuleEvaluationFactory>( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} /** * @see `IBoostingStatistics::visitScoreMatrix` */ - void visitScoreMatrix(IBoostingStatistics::DenseScoreMatrixVisitor denseVisitor, - IBoostingStatistics::SparseScoreMatrixVisitor sparseVisitor) const override { - denseVisitor(this->scoreMatrixPtr_->getView()); + void visitScoreMatrix( + std::optional denseVisitor, + std::optional sparseVisitor) const override { + if (denseVisitor) { + (*denseVisitor)(this->scoreMatrixPtr_->getView()); + } } }; diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_non_decomposable_common.hpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_non_decomposable_common.hpp index 8f7af8c6b4..4b60ed524d 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_non_decomposable_common.hpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_non_decomposable_common.hpp @@ -26,6 +26,8 @@ namespace boosting { * * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of * the training examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients + * and Hessians * @tparam StatisticVector The type of the vectors that are used to store gradients and * Hessians * @tparam StatisticMatrix The type of the matrix that stores the gradients and Hessians @@ -43,12 +45,12 @@ namespace boosting { * their overall quality, based on gradients and Hessians that have * been calculated according to a decomposable loss function */ - template + template class AbstractNonDecomposableStatistics - : public AbstractStatistics, + : public AbstractStatistics, virtual public INonDecomposableStatistics { protected: @@ -68,6 +70,8 @@ namespace boosting { public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `LossFunction` that * implements the loss function that should be used for calculating gradients * and Hessians @@ -85,16 +89,17 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of template type `ScoreMatrix` that stores * the currently predicted scores */ - AbstractNonDecomposableStatistics(std::unique_ptr lossPtr, + AbstractNonDecomposableStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const NonDecomposableRuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticMatrixPtr, std::unique_ptr scoreMatrixPtr) - : AbstractStatistics( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} + : AbstractStatistics( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} /** * @see `INonDecomposableStatistics::setRuleEvaluationFactory` diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_dense.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_dense.cpp index 05a67b565f..b0db2287ba 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_dense.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_dense.cpp @@ -9,12 +9,13 @@ namespace boosting { template static inline std::unique_ptr> createStatistics( std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, - const IDecomposableRuleEvaluationFactory& ruleEvaluationFactory, MultiThreadingSettings multiThreadingSettings, - const OutputMatrix& outputMatrix) { + const IQuantizationFactory& quantizationFactory, const IDecomposableRuleEvaluationFactory& ruleEvaluationFactory, + MultiThreadingSettings multiThreadingSettings, const OutputMatrix& outputMatrix) { uint32 numExamples = outputMatrix.numRows; uint32 numOutputs = outputMatrix.numCols; std::unique_ptr statisticMatrixPtr = std::make_unique(numExamples, numOutputs); + std::unique_ptr quantizationPtr = quantizationFactory.create(statisticMatrixPtr->getView()); std::unique_ptr> scoreMatrixPtr = std::make_unique>(numExamples, numOutputs, true); const Loss* lossRawPtr = lossPtr.get(); @@ -32,19 +33,36 @@ namespace boosting { IndexIterator(outputMatrixPtr->numCols), *statisticMatrixRawPtr); } - return std::make_unique>( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + std::unique_ptr> statisticsPtr; + auto denseDecomposableMatrixVisitor = + [&](std::unique_ptr>>>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique< + DenseDecomposableStatistics>>, + DenseDecomposableStatisticVector, EvaluationMeasure>>( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + }; + auto bitDecomposableMatrixVisitor = + [&](std::unique_ptr>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique< + DenseDecomposableStatistics, + BitDecomposableStatisticVector, EvaluationMeasure>>( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + }; + quantizationPtr->visitQuantizationMatrix(denseDecomposableMatrixVisitor, bitDecomposableMatrixVisitor, {}, {}); + return statisticsPtr; } DenseDecomposableClassificationStatisticsProviderFactory::DenseDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -58,8 +76,8 @@ namespace boosting { std::unique_ptr evaluationMeasurePtr = evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, labelMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } @@ -71,20 +89,21 @@ namespace boosting { std::unique_ptr evaluationMeasurePtr = evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, labelMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } DenseDecomposableRegressionStatisticsProviderFactory::DenseDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -97,8 +116,8 @@ namespace boosting { std::unique_ptr evaluationMeasurePtr = evaluationMeasureFactoryPtr_->createRegressionEvaluationMeasure(); std::unique_ptr> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } @@ -109,8 +128,8 @@ namespace boosting { std::unique_ptr evaluationMeasurePtr = evaluationMeasureFactoryPtr_->createRegressionEvaluationMeasure(); std::unique_ptr> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.cpp index 0a535690c2..491e8ba44f 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_decomposable_sparse.cpp @@ -27,17 +27,21 @@ namespace boosting { * Provides access to gradients and Hessians that have been calculated according to a decomposable loss function * and are stored using sparse data structures. * - * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training examples + * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training + * examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients and Hessians */ - template + template class SparseDecomposableStatistics final - : public AbstractDecomposableStatistics, ISparseDecomposableClassificationLoss, ISparseEvaluationMeasure, ISparseDecomposableRuleEvaluationFactory> { public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `LossFunction` that * implements the loss function that should be used for calculating gradients * and Hessians @@ -54,31 +58,35 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of type `NumericSparseSetMatrix` that stores * the currently predicted scores */ - SparseDecomposableStatistics(std::unique_ptr lossPtr, + SparseDecomposableStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const ISparseDecomposableRuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticViewPtr, std::unique_ptr> scoreMatrixPtr) - : AbstractDecomposableStatistics, ISparseDecomposableClassificationLoss, ISparseEvaluationMeasure, ISparseDecomposableRuleEvaluationFactory>( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticViewPtr), std::move(scoreMatrixPtr)) {} + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticViewPtr), std::move(scoreMatrixPtr)) {} /** * @see `IBoostingStatistics::visitScoreMatrix` */ - void visitScoreMatrix(IBoostingStatistics::DenseScoreMatrixVisitor denseVisitor, - IBoostingStatistics::SparseScoreMatrixVisitor sparseVisitor) const override { - sparseVisitor(this->scoreMatrixPtr_->getView()); + void visitScoreMatrix( + std::optional denseVisitor, + std::optional sparseVisitor) const override { + if (sparseVisitor) { + (*sparseVisitor)(this->scoreMatrixPtr_->getView()); + } } }; template static inline std::unique_ptr> createStatistics( - const ISparseDecomposableClassificationLossFactory& lossFactory, + const IQuantizationFactory& quantizationFactory, const ISparseDecomposableClassificationLossFactory& lossFactory, const ISparseEvaluationMeasureFactory& evaluationMeasureFactory, const ISparseDecomposableRuleEvaluationFactory& ruleEvaluationFactory, MultiThreadingSettings multiThreadingSettings, const OutputMatrix& outputMatrix) { @@ -90,6 +98,7 @@ namespace boosting { evaluationMeasureFactory.createSparseEvaluationMeasure(); std::unique_ptr statisticMatrixPtr = std::make_unique(numExamples, numOutputs); + std::unique_ptr quantizationPtr = quantizationFactory.create(statisticMatrixPtr->getView()); std::unique_ptr> scoreMatrixPtr = std::make_unique>(numExamples, numOutputs); const ISparseDecomposableClassificationLoss* lossRawPtr = lossPtr.get(); @@ -107,19 +116,27 @@ namespace boosting { IndexIterator(outputMatrixPtr->numCols), *statisticMatrixRawPtr); } - return std::make_unique>( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + std::unique_ptr> statisticsPtr; + auto sparseDecomposableMatrixVisitor = + [&](std::unique_ptr>>>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique< + SparseDecomposableStatistics>>>>( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + }; + quantizationPtr->visitQuantizationMatrix({}, {}, sparseDecomposableMatrixVisitor, {}); + return statisticsPtr; } SparseDecomposableClassificationStatisticsProviderFactory:: SparseDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), pruningRuleEvaluationFactoryPtr_(std::move(pruningRuleEvaluationFactoryPtr)), @@ -128,8 +145,8 @@ namespace boosting { std::unique_ptr SparseDecomposableClassificationStatisticsProviderFactory::create( const CContiguousView& labelMatrix) const { std::unique_ptr> statisticsPtr = - createStatistics(*lossFactoryPtr_, *evaluationMeasureFactoryPtr_, *regularRuleEvaluationFactoryPtr_, - multiThreadingSettings_, labelMatrix); + createStatistics(*quantizationFactoryPtr_, *lossFactoryPtr_, *evaluationMeasureFactoryPtr_, + *regularRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } @@ -137,8 +154,8 @@ namespace boosting { std::unique_ptr SparseDecomposableClassificationStatisticsProviderFactory::create( const BinaryCsrView& labelMatrix) const { std::unique_ptr> statisticsPtr = - createStatistics(*lossFactoryPtr_, *evaluationMeasureFactoryPtr_, *regularRuleEvaluationFactoryPtr_, - multiThreadingSettings_, labelMatrix); + createStatistics(*quantizationFactoryPtr_, *lossFactoryPtr_, *evaluationMeasureFactoryPtr_, + *regularRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } diff --git a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.cpp b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.cpp index 11980bf279..50f8a75348 100644 --- a/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.cpp +++ b/cpp/subprojects/boosting/src/mlrl/boosting/statistics/statistics_provider_non_decomposable_dense.cpp @@ -54,18 +54,21 @@ namespace boosting { * @tparam Loss The type of the non-decomposable loss function * @tparam OutputMatrix The type of the matrix that provides access to the ground truth of the training * examples + * @tparam QuantizationMatrix The type of the matrix that provides access to quantized gradients and Hessians * @tparam EvaluationMeasure The type of the evaluation measure that should be used to access the quality of * predictions */ - template + template class DenseNonDecomposableStatistics final : public AbstractNonDecomposableStatistics< - OutputMatrix, DenseNonDecomposableStatisticVector, DenseNonDecomposableStatisticMatrix, + OutputMatrix, QuantizationMatrix, DenseNonDecomposableStatisticVector, DenseNonDecomposableStatisticMatrix, NumericCContiguousMatrix, Loss, EvaluationMeasure, INonDecomposableRuleEvaluationFactory, IDecomposableRuleEvaluationFactory> { public: /** + * @param quantizationMatrixPtr An unique pointer to an object of template type `QuantizationMatrix` that + * provides access to quantized gradients and Hessians * @param lossPtr An unique pointer to an object of template type `Loss` that implements the * loss function to be used for calculating gradients and Hessians * @param evaluationMeasurePtr An unique pointer to an object of template type `EvaluationMeasure` that @@ -81,25 +84,29 @@ namespace boosting { * @param scoreMatrixPtr An unique pointer to an object of type `NumericCContiguousMatrix` that * stores the currently predicted scores */ - DenseNonDecomposableStatistics(std::unique_ptr lossPtr, + DenseNonDecomposableStatistics(std::unique_ptr quantizationMatrixPtr, + std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, const INonDecomposableRuleEvaluationFactory& ruleEvaluationFactory, const OutputMatrix& outputMatrix, std::unique_ptr statisticMatrixPtr, std::unique_ptr> scoreMatrixPtr) : AbstractNonDecomposableStatistics< - OutputMatrix, DenseNonDecomposableStatisticVector, DenseNonDecomposableStatisticMatrix, - NumericCContiguousMatrix, Loss, EvaluationMeasure, INonDecomposableRuleEvaluationFactory, - IDecomposableRuleEvaluationFactory>(std::move(lossPtr), std::move(evaluationMeasurePtr), - ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} + OutputMatrix, QuantizationMatrix, DenseNonDecomposableStatisticVector, + DenseNonDecomposableStatisticMatrix, NumericCContiguousMatrix, Loss, EvaluationMeasure, + INonDecomposableRuleEvaluationFactory, IDecomposableRuleEvaluationFactory>( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)) {} /** * @see `IBoostingStatistics::visitScoreMatrix` */ - void visitScoreMatrix(IBoostingStatistics::DenseScoreMatrixVisitor denseVisitor, - IBoostingStatistics::SparseScoreMatrixVisitor sparseVisitor) const override { - denseVisitor(this->scoreMatrixPtr_->getView()); + void visitScoreMatrix( + std::optional denseVisitor, + std::optional sparseVisitor) const override { + if (denseVisitor) { + (*denseVisitor)(this->scoreMatrixPtr_->getView()); + } } /** @@ -137,9 +144,30 @@ namespace boosting { } } - return std::make_unique>( - std::move(this->lossPtr_), std::move(this->evaluationMeasurePtr_), ruleEvaluationFactory, - this->outputMatrix_, std::move(decomposableStatisticMatrixPtr), std::move(this->scoreMatrixPtr_)); + std::unique_ptr quantizationPtr = + this->quantizationMatrixPtr_->create(*decomposableStatisticMatrixRawPtr); + std::unique_ptr> statisticsPtr; + auto denseDecomposableMatrixVisitor = + [&](std::unique_ptr>>>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique>>, + DenseDecomposableStatisticVector, EvaluationMeasure>>( + std::move(quantizationMatrixPtr), std::move(this->lossPtr_), + std::move(this->evaluationMeasurePtr_), ruleEvaluationFactory, this->outputMatrix_, + std::move(decomposableStatisticMatrixPtr), std::move(this->scoreMatrixPtr_)); + }; + auto bitDecomposableMatrixVisitor = + [&](std::unique_ptr>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique< + DenseDecomposableStatistics, + BitDecomposableStatisticVector, EvaluationMeasure>>( + std::move(quantizationMatrixPtr), std::move(this->lossPtr_), + std::move(this->evaluationMeasurePtr_), ruleEvaluationFactory, this->outputMatrix_, + std::move(decomposableStatisticMatrixPtr), std::move(this->scoreMatrixPtr_)); + }; + quantizationPtr->visitQuantizationMatrix(denseDecomposableMatrixVisitor, bitDecomposableMatrixVisitor, + {}, {}); + return statisticsPtr; } }; @@ -147,12 +175,14 @@ namespace boosting { static inline std::unique_ptr< INonDecomposableStatistics> createStatistics(std::unique_ptr lossPtr, std::unique_ptr evaluationMeasurePtr, + const IQuantizationFactory& quantizationFactory, const INonDecomposableRuleEvaluationFactory& ruleEvaluationFactory, MultiThreadingSettings multiThreadingSettings, const OutputMatrix& outputMatrix) { uint32 numExamples = outputMatrix.numRows; uint32 numOutputs = outputMatrix.numCols; std::unique_ptr statisticMatrixPtr = std::make_unique(numExamples, numOutputs); + std::unique_ptr quantizationPtr = quantizationFactory.create(statisticMatrixPtr->getView()); std::unique_ptr> scoreMatrixPtr = std::make_unique>(numExamples, numOutputs, true); const Loss* lossRawPtr = lossPtr.get(); @@ -169,20 +199,30 @@ namespace boosting { *statisticMatrixRawPtr); } - return std::make_unique>( - std::move(lossPtr), std::move(evaluationMeasurePtr), ruleEvaluationFactory, outputMatrix, - std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + std::unique_ptr< + INonDecomposableStatistics> + statisticsPtr; + auto denseNonDecomposableMatrixVisitor = + [&](std::unique_ptr>& quantizationMatrixPtr) { + statisticsPtr = std::make_unique, EvaluationMeasure>>( + std::move(quantizationMatrixPtr), std::move(lossPtr), std::move(evaluationMeasurePtr), + ruleEvaluationFactory, outputMatrix, std::move(statisticMatrixPtr), std::move(scoreMatrixPtr)); + }; + quantizationPtr->visitQuantizationMatrix({}, {}, {}, denseNonDecomposableMatrixVisitor); + return statisticsPtr; } DenseNonDecomposableClassificationStatisticsProviderFactory:: DenseNonDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -197,8 +237,9 @@ namespace boosting { evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr< INonDecomposableStatistics> - statisticsPtr = createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), - *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); + statisticsPtr = + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique< NonDecomposableStatisticsProvider>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); @@ -212,21 +253,23 @@ namespace boosting { evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr< INonDecomposableStatistics> - statisticsPtr = createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), - *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); + statisticsPtr = + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique< NonDecomposableStatisticsProvider>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); } DenseNonDecomposableRegressionStatisticsProviderFactory::DenseNonDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -242,8 +285,8 @@ namespace boosting { std::unique_ptr< INonDecomposableStatistics> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique< NonDecomposableStatisticsProvider>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); @@ -258,8 +301,8 @@ namespace boosting { std::unique_ptr< INonDecomposableStatistics> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique< NonDecomposableStatisticsProvider>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr)); @@ -267,13 +310,14 @@ namespace boosting { DenseConvertibleNonDecomposableClassificationStatisticsProviderFactory:: DenseConvertibleNonDecomposableClassificationStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -288,8 +332,9 @@ namespace boosting { evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr< INonDecomposableStatistics> - statisticsPtr = createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), - *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); + statisticsPtr = + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr), @@ -304,8 +349,9 @@ namespace boosting { evaluationMeasureFactoryPtr_->createClassificationEvaluationMeasure(); std::unique_ptr< INonDecomposableStatistics> - statisticsPtr = createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), - *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); + statisticsPtr = + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, labelMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr), @@ -314,13 +360,14 @@ namespace boosting { DenseConvertibleNonDecomposableRegressionStatisticsProviderFactory:: DenseConvertibleNonDecomposableRegressionStatisticsProviderFactory( + std::unique_ptr quantizationFactoryPtr, std::unique_ptr lossFactoryPtr, std::unique_ptr evaluationMeasureFactoryPtr, std::unique_ptr defaultRuleEvaluationFactoryPtr, std::unique_ptr regularRuleEvaluationFactoryPtr, std::unique_ptr pruningRuleEvaluationFactoryPtr, MultiThreadingSettings multiThreadingSettings) - : lossFactoryPtr_(std::move(lossFactoryPtr)), + : quantizationFactoryPtr_(std::move(quantizationFactoryPtr)), lossFactoryPtr_(std::move(lossFactoryPtr)), evaluationMeasureFactoryPtr_(std::move(evaluationMeasureFactoryPtr)), defaultRuleEvaluationFactoryPtr_(std::move(defaultRuleEvaluationFactoryPtr)), regularRuleEvaluationFactoryPtr_(std::move(regularRuleEvaluationFactoryPtr)), @@ -336,8 +383,8 @@ namespace boosting { std::unique_ptr< INonDecomposableStatistics> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr), @@ -353,8 +400,8 @@ namespace boosting { std::unique_ptr< INonDecomposableStatistics> statisticsPtr = - createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *defaultRuleEvaluationFactoryPtr_, - multiThreadingSettings_, regressionMatrix); + createStatistics(std::move(lossPtr), std::move(evaluationMeasurePtr), *quantizationFactoryPtr_, + *defaultRuleEvaluationFactoryPtr_, multiThreadingSettings_, regressionMatrix); return std::make_unique>( *regularRuleEvaluationFactoryPtr_, *pruningRuleEvaluationFactoryPtr_, std::move(statisticsPtr), diff --git a/cpp/subprojects/common/include/mlrl/common/data/vector_bit.hpp b/cpp/subprojects/common/include/mlrl/common/data/vector_bit.hpp deleted file mode 100644 index 91742b6b98..0000000000 --- a/cpp/subprojects/common/include/mlrl/common/data/vector_bit.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * @author Michael Rapp (michael.rapp.ml@gmail.com) - */ -#pragma once - -#include "mlrl/common/data/view_vector.hpp" - -/** - * An one-dimension vector that stores binary data in a space-efficient way. - */ -class BitVector final : public ClearableViewDecorator>> { - private: - - const uint32 numElements_; - - public: - - /** - * @param numElements The number of elements in the vector - * @param init True, if all elements in the vector should be value-initialized, false otherwise - */ - BitVector(uint32 numElements, bool init = false); - - /** - * Returns the value of the element at a specific position. - * - * @param pos The position of the element - * @return The value of the specified element - */ - bool operator[](uint32 pos) const; - - /** - * Sets a value to the element at a specific position. - * - * @param pos The position of the element - * @param value The value to be set - */ - void set(uint32 pos, bool value); - - /** - * Returns the number of elements in the vector. - * - * @return The number of elements in the vector - */ - uint32 getNumElements() const; -}; diff --git a/cpp/subprojects/common/include/mlrl/common/data/vector_bit_binary.hpp b/cpp/subprojects/common/include/mlrl/common/data/vector_bit_binary.hpp new file mode 100644 index 0000000000..d27aab2681 --- /dev/null +++ b/cpp/subprojects/common/include/mlrl/common/data/vector_bit_binary.hpp @@ -0,0 +1,22 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/common/data/view_vector_bit.hpp" + +/** + * An one-dimensional vector that stores binary data in a space-efficient way. + */ +class BinaryBitVector final + : public ClearableViewDecorator>>> { + public: + + /** + * @param numElements The number of elements in the vector + * @param init True, if all elements in the vector should be value-initialized, false otherwise + */ + BinaryBitVector(uint32 numElements, bool init = false) + : ClearableViewDecorator>>>( + AllocatedBitVector(numElements, 1, init)) {} +}; diff --git a/cpp/subprojects/common/include/mlrl/common/data/view_bit.hpp b/cpp/subprojects/common/include/mlrl/common/data/view_bit.hpp new file mode 100644 index 0000000000..994e031b02 --- /dev/null +++ b/cpp/subprojects/common/include/mlrl/common/data/view_bit.hpp @@ -0,0 +1,50 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/common/data/view.hpp" + +#include + +/** + * A view that provides random access to integer values, each with a specific number of bits, stored in a pre-allocated + * array of a specific size. + */ +class MLRLCOMMON_API BitView : public BaseView { + public: + + /** + * The number of bits per element in the view. + */ + uint32 numBitsPerElement; + + /** + * @param array A pointer to an array of type `uint32` that stores the values, the view should provide + * access to + * @param dimensions The number of elements in each dimension of the view + */ + BitView(uint32* array, std::initializer_list dimensions) + : BaseView(array), numBitsPerElement(dimensions.begin()[1]) {} + + /** + * @param array A pointer to an array of type `uint32` that stores the values, the view should + * provide access to + * @param numElements The number of elements in the view + * @param numBitsPerElement The number of bits per element in the view + */ + BitView(uint32* array, uint32 numElements, uint32 numBitsPerElement) + : BaseView(array), numBitsPerElement(numBitsPerElement) {} + + /** + * @param other A const reference to an object of type `BitView` that should be copied + */ + BitView(const BitView& other) : BaseView(other), numBitsPerElement(other.numBitsPerElement) {} + + /** + * @param other A reference to an object of type `BitView` that should be moved + */ + BitView(BitView&& other) : BaseView(std::move(other)), numBitsPerElement(other.numBitsPerElement) {} + + virtual ~BitView() override {} +}; diff --git a/cpp/subprojects/common/include/mlrl/common/data/view_matrix_bit.hpp b/cpp/subprojects/common/include/mlrl/common/data/view_matrix_bit.hpp new file mode 100644 index 0000000000..96b7063e77 --- /dev/null +++ b/cpp/subprojects/common/include/mlrl/common/data/view_matrix_bit.hpp @@ -0,0 +1,129 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/common/data/view_matrix.hpp" +#include "mlrl/common/data/view_vector_bit.hpp" +#include "mlrl/common/util/bit_functions.hpp" + +#include + +/** + * A two-dimensional view that provides random access to integer values, each with a specific number of bits, stored in + * a dense matrix of a specific size. + * + * @tparam T The type of the integer values, the view provides access to + */ +template +class MLRLCOMMON_API BitMatrix : public BitView, + public Matrix { + private: + + uint32 numElementsPerRow; + + public: + + /** + * @param array A pointer to an array of type `uint32` that stores the values, the view should + * provide access to + * @param numRows The number of rows in the view + * @param numCols The number of columns in the view + * @param numBitsPerElement The number of bits per element in the view + */ + BitMatrix(uint32* array, uint32 numRows, uint32 numCols, uint32 numBitsPerElement) + : BitView(array, numRows * numCols, numBitsPerElement), Matrix(numRows, numCols), + numElementsPerRow(util::getBitArraySize(numCols, numBitsPerElement)) {} + + /** + * @param other A const reference to an object of type `BitMatrix` that should be copied + */ + BitMatrix(const BitMatrix& other) : BitView(other), Matrix(other) {} + + /** + * @param other A reference to an object of type `BitMatrix` that should be moved + */ + BitMatrix(BitMatrix&& other) : BitView(std::move(other)), Matrix(std::move(other)) {} + + virtual ~BitMatrix() override {} + + /** + * Provides read-only access to an individual row in the view. + */ + typedef const BitVector const_row; + + /** + * Provides access to an individual row in the view and allows to modify it. + */ + typedef BitVector row; + + /** + * Creates and returns a view that provides read-only access to a specific row in the view. + * + * @param row The index of the row + * @return A `const_row` + */ + const_row operator[](uint32 row) const { + return BitVector(&BaseView::array[numElementsPerRow * row], numElementsPerRow, + BitView::numBitsPerElement); + } + + /** + * Creates and returns a view that provides access to a specific row in the view and allows to modify it. + * + * @param row The index of the row + * @return A `row` + */ + row operator[](uint32 row) { + return BitVector(&BaseView::array[numElementsPerRow * row], numElementsPerRow, + BitView::numBitsPerElement); + } +}; + +/** + * Allocates the memory, a `BitMatrix` provides access to. + * + * @tparam BitMatrix The type of the bit matrix + */ +template +class MLRLCOMMON_API BitMatrixAllocator : public BitMatrix { + public: + + /** + * @param numRows The number of rows in the bit matrix + * @param numCols The number of columns in the bit matrix + * @param numBitsPerElement The number of bits per element in the bit matrix + * @param init True, if all elements in the bit matrix should be value-initialized, false otherwise + */ + explicit BitMatrixAllocator(uint32 numRows, uint32 numCols, uint32 numBitsPerElement, bool init = false) + : BitMatrix( + util::allocateMemory( + util::getBitArraySize(numCols, numBitsPerElement) * numRows, init), + numRows, numCols, numBitsPerElement) {} + + /** + * @param other A reference to an object of type `BitMatrixAllocator` that should be copied + */ + BitMatrixAllocator(const BitMatrixAllocator& other) : BitMatrix(other) { + throw std::runtime_error("Objects of type BitMatrixAllocator cannot be copied"); + } + + /** + * @param other A reference to an object of type `BitMatrixAllocator` that should be moved + */ + BitMatrixAllocator(BitMatrixAllocator&& other) : BitMatrix(std::move(other)) { + other.release(); + } + + virtual ~BitMatrixAllocator() override { + util::freeMemory(BitMatrix::array); + } +}; + +/** + * Allocates the memory, a `BitMatrix` provides access to. + * + * @tparam T The type of the integer values, the view provides access to + */ +template +using AllocatedBitMatrix = BitMatrixAllocator>; diff --git a/cpp/subprojects/common/include/mlrl/common/data/view_vector_bit.hpp b/cpp/subprojects/common/include/mlrl/common/data/view_vector_bit.hpp new file mode 100644 index 0000000000..f5d2bf034e --- /dev/null +++ b/cpp/subprojects/common/include/mlrl/common/data/view_vector_bit.hpp @@ -0,0 +1,253 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/common/data/view_bit.hpp" +#include "mlrl/common/data/view_vector.hpp" +#include "mlrl/common/util/bit_functions.hpp" + +#include + +/** + * A one-dimensional vector that provides random access to integer values, each with a specific number of bits, stored + * in a pre-allocated array of a specific size. + * + * @param T The type of the integer values, the view provides access to + */ +template +class MLRLCOMMON_API BitVector : public BitView { + private: + + static inline constexpr uint32 NUM_BITS = util::bits(); + + inline constexpr uint32 getOffset(uint32 pos) const { + return pos / (NUM_BITS / BitView::numBitsPerElement); + } + + inline constexpr uint32 getNumShifts(uint32 pos) const { + uint32 numIntegersPerElement = NUM_BITS / numBitsPerElement; + return NUM_BITS - ((pos % numIntegersPerElement) * numBitsPerElement) - numBitsPerElement; + } + + inline constexpr uint32 getBitMask(uint32 numShifts) const { + uint32 ones = util::getNumBitCombinations(numBitsPerElement) - 1; + return ones << numShifts; + } + + public: + + /** + * The number of elements in the bit vector. + */ + uint32 numElements; + + /** + * @param array A pointer to an array of type `uint32` that stores the values, the bit vector should + * provide access to + * @param dimensions The number of elements in each dimension of the bit vector + */ + BitVector(uint32* array, std::initializer_list dimensions) + : BitView(array, dimensions), numElements(dimensions.begin()[0]) {} + + /** + * @param array A pointer to an array of type `uint32` that stores the values, the bit vector should + * provide access to + * @param numElements The number of elements in the bit vector + * @param numBitsPerElement The number of bits per element in the bit vector + */ + BitVector(uint32* array, uint32 numElements, uint32 numBitsPerElement) + : BitView(array, numElements, numBitsPerElement), numElements(numElements) {} + + /** + * @param other A const reference to an object of type `BitVector` that should be copied + */ + BitVector(const BitVector& other) : BitView(other), numElements(other.numElements) {} + + /** + * @param other A reference to an object of type `BitVector` that should be moved + */ + BitVector(BitVector&& other) : BitView(std::move(other)), numElements(other.numElements) {} + + virtual ~BitVector() override {} + + /** + * The type of the integer values, the view provides access to + */ + typedef T type; + + /** + * An iterator that provides read-only access to the view's underlying array. + */ + typedef const typename BaseView::value_type* const_iterator; + + /** + * An iterator that provides access to the view's underlying array and allows to modify it. + */ + typedef typename BaseView::value_type* iterator; + + /** + * Returns a `const_iterator` to the beginning of the view's underlying array. + * + * @return A `const_iterator` to the beginning + */ + const_iterator cbegin() const { + return BaseView::array; + } + + /** + * Returns a `const_iterator` to the end of the view's underlying array. + * + * @return A `const_iterator` to the end + */ + const_iterator cend() const { + return &BaseView::array[util::getBitArraySize(numElements, BitView::numBitsPerElement)]; + } + + /** + * Returns an `iterator` to the beginning of the view's underlying array. + * + * @return An `iterator` to the beginning + */ + iterator begin() { + return BaseView::array; + } + + /** + * Returns an `iterator` to the end of the view's underlying array. + * + * @return An `iterator` to the end + */ + iterator end() { + return &BaseView::array[util::getBitArraySize(numElements, BitView::numBitsPerElement)]; + } + + /** + * Returns the value of the element at a specific position. + * + * @param pos The position of the element + * @return The value of the specified element + */ + type operator[](uint32 pos) const { + uint32 offset = this->getOffset(pos); + uint32 numShifts = this->getNumShifts(pos); + uint32 bitMask = this->getBitMask(numShifts); + uint32 value = BaseView::array[offset]; + return static_cast((value & bitMask) >> numShifts); + } + + /** + * Sets a value to the element at a specific position. + * + * @param pos The position of the element + * @param value The value to be set + */ + void set(uint32 pos, type value) { + uint32 offset = this->getOffset(pos); + uint32 numShifts = this->getNumShifts(pos); + uint32 bitMask = this->getBitMask(numShifts); + BaseView::array[offset] &= ~bitMask; + BaseView::array[offset] |= value << numShifts; + } + + /** + * Sets all values stored in the bit vector to zero. + */ + void clear() { + iterator begin = this->begin(); + uint32 arraySize = util::getBitArraySize(numElements, BitView::numBitsPerElement); + util::setViewToZeros(begin, arraySize); + } +}; + +/** + * Allocates the memory, a `BitVector` provides access to. + * + * @tparam BitVector The type of the bit vector + */ +template +class MLRLCOMMON_API BitVectorAllocator : public BitVector { + public: + + /** + * @param numElements The number of elements in the bit vector + * @param numBitsPerElement The number of bits per element in the bit vector + * @param init True, if all elements in the bit vector should be value-initialized, false otherwise + */ + explicit BitVectorAllocator(uint32 numElements, uint32 numBitsPerElement, bool init = false) + : BitVector(util::allocateMemory( + util::getBitArraySize(numElements, numBitsPerElement), init), + {numElements, numBitsPerElement}) {} + + /** + * @param other A reference to an object of type `BitVectorAllocator` that should be copied + */ + BitVectorAllocator(const BitVectorAllocator& other) : BitVector(other) { + throw std::runtime_error("Objects of type BitVectorAllocator cannot be copied"); + } + + /** + * @param other A reference to an object of type `BitVectorAllocator` that should be moved + */ + BitVectorAllocator(BitVectorAllocator&& other) : BitVector(std::move(other)) { + other.release(); + } + + virtual ~BitVectorAllocator() override { + util::freeMemory(BitVector::array); + } +}; + +/** + * Allocates the memory, a `BitVector` provides access to. + * + * @tparam T The type of the integer values, the view provides access to + */ +template +using AllocatedBitVector = BitVectorAllocator>; + +/** + * Provides random read and write access to integer values stored in a bit vector. + * + * @tparam BitVector The type of view, the bit vector is backed by + */ +template +class BitVectorDecorator : public BitVector { + public: + + /** + * @param view The view, the bit vector should be backed by + */ + explicit BitVectorDecorator(typename BitVector::view_type&& view) : BitVector(std::move(view)) {} + + virtual ~BitVectorDecorator() override {} + + /** + * Returns the number of bits per element in the bit vector. + * + * @return The number of bits per element + */ + uint32 getNumBitsPerElement() const { + return this->view.numBitsPerElement; + } + + /** + * Returns the value of the element at a specific position. + * + * @param pos The position of the element + * @return The value of the specified element + */ + typename BitVector::view_type::type operator[](uint32 pos) const { + return this->view[pos]; + } + + /** + * Sets a value to the element at a specific position. + * + * @param pos The position of the element + * @param value The value to be set + */ + void set(uint32 pos, typename BitVector::view_type::type value) { + this->view.set(pos, value); + } +}; diff --git a/cpp/subprojects/common/include/mlrl/common/model/body.hpp b/cpp/subprojects/common/include/mlrl/common/model/body.hpp index e9d4c426b7..f59adba22e 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/body.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/body.hpp @@ -6,6 +6,7 @@ #include "mlrl/common/data/view.hpp" #include +#include // Forward declarations class EmptyBody; @@ -74,8 +75,10 @@ class MLRLCOMMON_API IBody : public IConditional { * Invokes one of the given visitor functions, depending on which one is able to handle this particular type of * body. * - * @param emptyBodyVisitor The visitor function for handling objects of the type `EmptyBody` - * @param conjunctiveBodyVisitor The visitor function for handling objects of the type `ConjunctiveBody` + * @param emptyBodyVisitor An optional visitor function for handling objects of the type `EmptyBody` + * @param conjunctiveBodyVisitor An optional visitor function for handling objects of the type + * `ConjunctiveBody` */ - virtual void visit(EmptyBodyVisitor emptyBodyVisitor, ConjunctiveBodyVisitor conjunctiveBodyVisitor) const = 0; + virtual void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor) const = 0; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/body_conjunctive.hpp b/cpp/subprojects/common/include/mlrl/common/model/body_conjunctive.hpp index 6cf22f6847..df78dca5e3 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/body_conjunctive.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/body_conjunctive.hpp @@ -668,5 +668,6 @@ class MLRLCOMMON_API ConjunctiveBody final : public IBody { float32 sparseValue, View::iterator tmpArray1, View::iterator tmpArray2, uint32 n) const override; - void visit(EmptyBodyVisitor emptyBodyVisitor, ConjunctiveBodyVisitor conjunctiveBodyVisitor) const override; + void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor) const override; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/body_empty.hpp b/cpp/subprojects/common/include/mlrl/common/model/body_empty.hpp index f9ada75b75..686c50f04b 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/body_empty.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/body_empty.hpp @@ -18,5 +18,6 @@ class MLRLCOMMON_API EmptyBody final : public IBody { float32 sparseValue, View::iterator tmpArray1, View::iterator tmpArray2, uint32 n) const override; - void visit(EmptyBodyVisitor emptyBodyVisitor, ConjunctiveBodyVisitor conjunctiveBodyVisitor) const override; + void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor) const override; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/head.hpp b/cpp/subprojects/common/include/mlrl/common/model/head.hpp index 31ca14fa64..3a06cd7cfe 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/head.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/head.hpp @@ -4,6 +4,7 @@ #pragma once #include +#include // Forward declarations class CompleteHead; @@ -31,8 +32,9 @@ class MLRLCOMMON_API IHead { * Invokes one of the given visitor functions, depending on which one is able to handle this particular type of * head. * - * @param completeHeadVisitor The visitor function for handling objects of the type `CompleteHead` - * @param partialHeadVisitor The visitor function for handling objects of the type `PartialHead` + * @param completeHeadVisitor An optional visitor function for handling objects of the type `CompleteHead` + * @param partialHeadVisitor An optional visitor function for handling objects of the type `PartialHead` */ - virtual void visit(CompleteHeadVisitor completeHeadVisitor, PartialHeadVisitor partialHeadVisitor) const = 0; + virtual void visit(std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const = 0; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/head_complete.hpp b/cpp/subprojects/common/include/mlrl/common/model/head_complete.hpp index be5e69f18d..d06799209d 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/head_complete.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/head_complete.hpp @@ -56,5 +56,6 @@ class MLRLCOMMON_API CompleteHead final : public VectorDecorator completeHeadVisitor, + std::optional partialHeadVisitor) const override; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/head_partial.hpp b/cpp/subprojects/common/include/mlrl/common/model/head_partial.hpp index 81f635ca83..0fe106cab9 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/head_partial.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/head_partial.hpp @@ -19,5 +19,6 @@ class MLRLCOMMON_API PartialHead final */ PartialHead(uint32 numElements); - void visit(CompleteHeadVisitor completeHeadVisitor, PartialHeadVisitor partialHeadVisitor) const override; + void visit(std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const override; }; diff --git a/cpp/subprojects/common/include/mlrl/common/model/rule_list.hpp b/cpp/subprojects/common/include/mlrl/common/model/rule_list.hpp index 74f9cecd79..209a1a0986 100644 --- a/cpp/subprojects/common/include/mlrl/common/model/rule_list.hpp +++ b/cpp/subprojects/common/include/mlrl/common/model/rule_list.hpp @@ -52,29 +52,31 @@ class MLRLCOMMON_API IRuleList : public IRuleModel { * Invokes some of the given visitor functions, depending on which ones are able to handle the bodies and heads * of all rules that are contained in this model, including the default rule, if available. * - * @param emptyBodyVisitor The visitor function for handling objects of the type `EmptyBody` - * @param conjunctiveBodyVisitor The visitor function for handling objects of the type `ConjunctiveBody` - * @param completeHeadVisitor The visitor function for handling objects of the type `CompleteHead` - * @param partialHeadVisitor The visitor function for handling objects of the type `PartialHead` + * @param emptyBodyVisitor An optional visitor function for handling objects of the type `EmptyBody` + * @param conjunctiveBodyVisitor An optional visitor function for handling objects of the type + * `ConjunctiveBody` + * @param completeHeadVisitor An optional visitor function for handling objects of the type `CompleteHead` + * @param partialHeadVisitor An optional visitor function for handling objects of the type `PartialHead` */ - virtual void visit(IBody::EmptyBodyVisitor emptyBodyVisitor, - IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const = 0; + virtual void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const = 0; /** * Invokes some of the given visitor functions, depending on which ones are able to handle the bodies and heads * of all used rules that are contained in this model, including the default rule, if available. * - * @param emptyBodyVisitor The visitor function for handling objects of the type `EmptyBody` - * @param conjunctiveBodyVisitor The visitor function for handling objects of the type `ConjunctiveBody` - * @param completeHeadVisitor The visitor function for handling objects of the type `CompleteHead` - * @param partialHeadVisitor The visitor function for handling objects of the type `PartialHead` + * @param emptyBodyVisitor An optional visitor function for handling objects of the type `EmptyBody` + * @param conjunctiveBodyVisitor An optional visitor function for handling objects of the type + * `ConjunctiveBody` + * @param completeHeadVisitor An optional visitor function for handling objects of the type `CompleteHead` + * @param partialHeadVisitor An optional visitor function for handling objects of the type `PartialHead` */ - virtual void visitUsed(IBody::EmptyBodyVisitor emptyBodyVisitor, - IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const = 0; + virtual void visitUsed(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const = 0; }; /** @@ -120,15 +122,19 @@ class RuleList final : public IRuleList { * Invokes some of the given visitor functions, depending on which ones are able to handle the rule's * particular type of body and head. * - * @param emptyBodyVisitor The visitor function for handling objects of type `EmptyBody` - * @param conjunctiveBodyVisitor The visitor function for handling objects of type `ConjunctiveBody` - * @param completeHeadVisitor The visitor function for handling objects of type `CompleteHead` - * @param partialHeadVisitor The visitor function for handling objects of type `PartialHead` + * @param emptyBodyVisitor An optional visitor function for handling objects of type + * `EmptyBody` + * @param conjunctiveBodyVisitor An optional visitor function for handling objects of type + * `ConjunctiveBody` + * @param completeHeadVisitor An optional visitor function for handling objects of type + * `CompleteHead` + * @param partialHeadVisitor An optional visitor function for handling objects of type + * `PartialHead` */ - void visit(IBody::EmptyBodyVisitor emptyBodyVisitor, - IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const; + void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const; }; private: @@ -317,13 +323,15 @@ class RuleList final : public IRuleList { bool isDefaultRuleTakingPrecedence() const override; - void visit(IBody::EmptyBodyVisitor emptyBodyVisitor, IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const override; + void visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const override; - void visitUsed(IBody::EmptyBodyVisitor emptyBodyVisitor, IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const override; + void visitUsed(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const override; std::unique_ptr createBinaryPredictor( const IBinaryPredictorFactory& factory, const CContiguousView& featureMatrix, diff --git a/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_complete.hpp b/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_complete.hpp index 96c7d5992d..472ad22f90 100644 --- a/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_complete.hpp +++ b/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_complete.hpp @@ -82,6 +82,14 @@ class CompletePrediction final : public VectorDecorator */ index_const_iterator indices_cend() const; + /** + * Returns a reference to the `CompleteIndexVector` that stores the indices for which the rule predicts. + * + * @return A reference to an object of type `CompleteIndexVector` that stores the indices for which the rule + * predicts + */ + const CompleteIndexVector& getIndexVector() const; + uint32 getNumElements() const override; void sort() override; diff --git a/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_partial.hpp b/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_partial.hpp index 85745009aa..944dc90e6d 100644 --- a/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_partial.hpp +++ b/cpp/subprojects/common/include/mlrl/common/rule_refinement/prediction_partial.hpp @@ -105,6 +105,14 @@ class PartialPrediction final : public ResizableVectorDecorator /** - * An one-dimensional vector that provides random access to a fixed number of binary weights stored in a `BitVector`. + * An one-dimensional vector that provides random access to a fixed number of binary weights stored in a + * `BinaryBitVector`. */ class BitWeightVector final : public IWeightVector { private: - BitVector vector_; + BinaryBitVector vector_; uint32 numNonZeroWeights_; diff --git a/cpp/subprojects/common/include/mlrl/common/statistics/statistics.hpp b/cpp/subprojects/common/include/mlrl/common/statistics/statistics.hpp index 2a6ea33b49..cb8d18bf88 100644 --- a/cpp/subprojects/common/include/mlrl/common/statistics/statistics.hpp +++ b/cpp/subprojects/common/include/mlrl/common/statistics/statistics.hpp @@ -39,6 +39,11 @@ class IStatisticsUpdate { * @param statisticIndex The index of the statistic that should be updated */ virtual void revertPrediction(uint32 statisticIndex) = 0; + + /** + * Commits the update. + */ + virtual void commit() = 0; }; /** diff --git a/cpp/subprojects/common/include/mlrl/common/util/bit_functions.hpp b/cpp/subprojects/common/include/mlrl/common/util/bit_functions.hpp new file mode 100644 index 0000000000..f3a8de6811 --- /dev/null +++ b/cpp/subprojects/common/include/mlrl/common/util/bit_functions.hpp @@ -0,0 +1,47 @@ +/* + * @author Michael Rapp (michael.rapp.ml@gmail.com) + */ +#pragma once + +#include "mlrl/common/data/types.hpp" + +#include + +namespace util { + + /** + * Returns the number of bits used by a certain type. + * + * @tparam T The type + * @return The number of bits + */ + template + static inline constexpr uint32 bits() { + return static_cast(CHAR_BIT * sizeof(T)); + } + + /** + * Returns the number of elements needed by an array of a specific type for storing a given number of integers, each + * with a specific number of bits. + * + * @tparam T The type of the array + * @param numIntegers The number of integers to be stored + * @param numBitsPerInteger The number of bits per integer + * @return The number of elements needed + */ + template + static inline constexpr uint32 getBitArraySize(uint32 numIntegers, uint32 numBitsPerInteger) { + uint32 numIntegersPerElement = bits() / numBitsPerInteger; + return numIntegers / numIntegersPerElement + (numIntegers % numIntegersPerElement != 0); + } + + /** + * Returns the number of values representable by a given number of bits. + * + * @param numBits The number of bits + * @return The number of representable values + */ + static inline uint32 getNumBitCombinations(uint32 numBits) { + return static_cast(std::pow(2, numBits)); + } +} diff --git a/cpp/subprojects/common/meson.build b/cpp/subprojects/common/meson.build index 1503ce9b1a..fc5a9d99f6 100644 --- a/cpp/subprojects/common/meson.build +++ b/cpp/subprojects/common/meson.build @@ -2,7 +2,6 @@ project('common', 'cpp') # Source files source_files = [ - 'src/mlrl/common/data/vector_bit.cpp', 'src/mlrl/common/iterator/iterator_index.cpp', 'src/mlrl/common/indices/index_vector_complete.cpp', 'src/mlrl/common/indices/index_vector_partial.cpp', @@ -102,8 +101,9 @@ source_files = [ # Test files test_files = [ 'test/mlrl/common/data/array.cpp', - 'test/mlrl/common/data/vector_bit.cpp', + 'test/mlrl/common/data/vector_bit_binary.cpp', 'test/mlrl/common/data/vector_dense.cpp', + 'test/mlrl/common/data/view_vector_bit.cpp', 'test/mlrl/common/input/feature_binning_equal_frequency.cpp', 'test/mlrl/common/input/feature_binning_equal_width.cpp', 'test/mlrl/common/input/feature_type_nominal.cpp', diff --git a/cpp/subprojects/common/src/mlrl/common/data/vector_bit.cpp b/cpp/subprojects/common/src/mlrl/common/data/vector_bit.cpp deleted file mode 100644 index 4b5e50515c..0000000000 --- a/cpp/subprojects/common/src/mlrl/common/data/vector_bit.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "mlrl/common/data/vector_bit.hpp" - -#include - -static inline constexpr uint32 UINT32_SIZE = static_cast(CHAR_BIT * sizeof(uint32)); - -static inline constexpr uint32 size(uint32 numElements) { - return numElements / UINT32_SIZE + (numElements % UINT32_SIZE != 0); -} - -static inline constexpr uint32 index(uint32 pos) { - return pos / UINT32_SIZE; -} - -static inline constexpr uint32 mask(uint32 pos) { - return 1U << (pos % UINT32_SIZE); -} - -BitVector::BitVector(uint32 numElements, bool init) - : ClearableViewDecorator>>( - AllocatedVector(size(numElements), init)), - numElements_(numElements) {} - -bool BitVector::operator[](uint32 pos) const { - return this->view.array[index(pos)] & mask(pos); -} - -void BitVector::set(uint32 pos, bool value) { - if (value) { - this->view.array[index(pos)] |= mask(pos); - } else { - this->view.array[index(pos)] &= ~mask(pos); - } -} - -uint32 BitVector::getNumElements() const { - return numElements_; -} diff --git a/cpp/subprojects/common/src/mlrl/common/input/feature_info_mixed.cpp b/cpp/subprojects/common/src/mlrl/common/input/feature_info_mixed.cpp index d8246326ac..3b87834ca0 100644 --- a/cpp/subprojects/common/src/mlrl/common/input/feature_info_mixed.cpp +++ b/cpp/subprojects/common/src/mlrl/common/input/feature_info_mixed.cpp @@ -1,20 +1,20 @@ #include "mlrl/common/input/feature_info_mixed.hpp" -#include "mlrl/common/data/vector_bit.hpp" +#include "mlrl/common/data/vector_bit_binary.hpp" #include "mlrl/common/input/feature_type_nominal.hpp" #include "mlrl/common/input/feature_type_numerical.hpp" #include "mlrl/common/input/feature_type_ordinal.hpp" /** - * An implementation of the type `IMixedFeatureInfo` that uses `BitVector`s to store whether individual features are - * ordinal, nominal or numerical. + * An implementation of the type `IMixedFeatureInfo` that uses `BinaryBitVector`s to store whether individual features + * are ordinal, nominal or numerical. */ class BitFeatureInfo final : public IMixedFeatureInfo { private: - BitVector ordinalBitVector_; + BinaryBitVector ordinalBitVector_; - BitVector nominalBitVector_; + BinaryBitVector nominalBitVector_; public: diff --git a/cpp/subprojects/common/src/mlrl/common/model/body_conjunctive.cpp b/cpp/subprojects/common/src/mlrl/common/model/body_conjunctive.cpp index 441136a4e7..e055c8fefb 100644 --- a/cpp/subprojects/common/src/mlrl/common/model/body_conjunctive.cpp +++ b/cpp/subprojects/common/src/mlrl/common/model/body_conjunctive.cpp @@ -304,6 +304,9 @@ bool ConjunctiveBody::covers(View::const_iterator indicesBegin, View emptyBodyVisitor, + std::optional conjunctiveBodyVisitor) const { + if (conjunctiveBodyVisitor) { + (*conjunctiveBodyVisitor)(*this); + } } diff --git a/cpp/subprojects/common/src/mlrl/common/model/body_empty.cpp b/cpp/subprojects/common/src/mlrl/common/model/body_empty.cpp index b6a4ab842f..bdfe820e2a 100644 --- a/cpp/subprojects/common/src/mlrl/common/model/body_empty.cpp +++ b/cpp/subprojects/common/src/mlrl/common/model/body_empty.cpp @@ -10,6 +10,9 @@ bool EmptyBody::covers(View::const_iterator indicesBegin, View:: return true; } -void EmptyBody::visit(EmptyBodyVisitor emptyBodyVisitor, ConjunctiveBodyVisitor conjunctiveBodyVisitor) const { - emptyBodyVisitor(*this); +void EmptyBody::visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor) const { + if (emptyBodyVisitor) { + (*emptyBodyVisitor)(*this); + } } diff --git a/cpp/subprojects/common/src/mlrl/common/model/head_complete.cpp b/cpp/subprojects/common/src/mlrl/common/model/head_complete.cpp index e52eb8ee5c..de2f21f846 100644 --- a/cpp/subprojects/common/src/mlrl/common/model/head_complete.cpp +++ b/cpp/subprojects/common/src/mlrl/common/model/head_complete.cpp @@ -19,6 +19,9 @@ CompleteHead::value_const_iterator CompleteHead::values_cend() const { return this->view.cend(); } -void CompleteHead::visit(CompleteHeadVisitor completeHeadVisitor, PartialHeadVisitor partialHeadVisitor) const { - completeHeadVisitor(*this); +void CompleteHead::visit(std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const { + if (completeHeadVisitor) { + (*completeHeadVisitor)(*this); + } } diff --git a/cpp/subprojects/common/src/mlrl/common/model/head_partial.cpp b/cpp/subprojects/common/src/mlrl/common/model/head_partial.cpp index 5b1e83fa84..8eba41781e 100644 --- a/cpp/subprojects/common/src/mlrl/common/model/head_partial.cpp +++ b/cpp/subprojects/common/src/mlrl/common/model/head_partial.cpp @@ -5,6 +5,9 @@ PartialHead::PartialHead(uint32 numElements) CompositeVector, AllocatedVector>(AllocatedVector(numElements), AllocatedVector(numElements))) {} -void PartialHead::visit(CompleteHeadVisitor completeHeadVisitor, PartialHeadVisitor partialHeadVisitor) const { - partialHeadVisitor(*this); +void PartialHead::visit(std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const { + if (partialHeadVisitor) { + (*partialHeadVisitor)(*this); + } } diff --git a/cpp/subprojects/common/src/mlrl/common/model/rule_list.cpp b/cpp/subprojects/common/src/mlrl/common/model/rule_list.cpp index 9fd9426da2..0f9cb3a36e 100644 --- a/cpp/subprojects/common/src/mlrl/common/model/rule_list.cpp +++ b/cpp/subprojects/common/src/mlrl/common/model/rule_list.cpp @@ -17,10 +17,10 @@ const IHead& RuleList::Rule::getHead() const { return *headPtr_; } -void RuleList::Rule::visit(IBody::EmptyBodyVisitor emptyBodyVisitor, - IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const { +void RuleList::Rule::visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const { bodyPtr_->visit(emptyBodyVisitor, conjunctiveBodyVisitor); headPtr_->visit(completeHeadVisitor, partialHeadVisitor); } @@ -131,18 +131,20 @@ bool RuleList::isDefaultRuleTakingPrecedence() const { return defaultRuleTakesPrecedence_; } -void RuleList::visit(IBody::EmptyBodyVisitor emptyBodyVisitor, IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const { +void RuleList::visit(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const { for (auto it = this->cbegin(); it != this->cend(); it++) { const Rule& rule = *it; rule.visit(emptyBodyVisitor, conjunctiveBodyVisitor, completeHeadVisitor, partialHeadVisitor); } } -void RuleList::visitUsed(IBody::EmptyBodyVisitor emptyBodyVisitor, IBody::ConjunctiveBodyVisitor conjunctiveBodyVisitor, - IHead::CompleteHeadVisitor completeHeadVisitor, - IHead::PartialHeadVisitor partialHeadVisitor) const { +void RuleList::visitUsed(std::optional emptyBodyVisitor, + std::optional conjunctiveBodyVisitor, + std::optional completeHeadVisitor, + std::optional partialHeadVisitor) const { for (auto it = this->used_cbegin(); it != this->used_cend(); it++) { const Rule& rule = *it; rule.visit(emptyBodyVisitor, conjunctiveBodyVisitor, completeHeadVisitor, partialHeadVisitor); diff --git a/cpp/subprojects/common/src/mlrl/common/rule_induction/rule_induction_common.hpp b/cpp/subprojects/common/src/mlrl/common/rule_induction/rule_induction_common.hpp index 0be83e5748..4de065a007 100644 --- a/cpp/subprojects/common/src/mlrl/common/rule_induction/rule_induction_common.hpp +++ b/cpp/subprojects/common/src/mlrl/common/rule_induction/rule_induction_common.hpp @@ -97,6 +97,7 @@ class AbstractRuleInduction : public IRuleInduction { statisticsUpdatePtr->applyPrediction(i); } + statisticsUpdatePtr->commit(); modelBuilder.setDefaultRule(defaultPredictionPtr); } diff --git a/cpp/subprojects/common/src/mlrl/common/rule_refinement/feature_space_tabular.cpp b/cpp/subprojects/common/src/mlrl/common/rule_refinement/feature_space_tabular.cpp index 9b74db1e7f..32156fd4b2 100644 --- a/cpp/subprojects/common/src/mlrl/common/rule_refinement/feature_space_tabular.cpp +++ b/cpp/subprojects/common/src/mlrl/common/rule_refinement/feature_space_tabular.cpp @@ -287,6 +287,8 @@ class TabularFeatureSpace final : public IFeatureSpace { statisticsUpdateRawPtr->applyPrediction(i); } } + + statisticsUpdatePtr->commit(); } void revertPrediction(const IPrediction& prediction) override { @@ -307,6 +309,8 @@ class TabularFeatureSpace final : public IFeatureSpace { statisticsUpdateRawPtr->revertPrediction(i); } } + + statisticsUpdatePtr->commit(); } }; diff --git a/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_complete.cpp b/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_complete.cpp index 294deaa4a2..793c96e782 100644 --- a/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_complete.cpp +++ b/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_complete.cpp @@ -32,6 +32,10 @@ CompletePrediction::index_const_iterator CompletePrediction::indices_cend() cons return indexVector_.cend(); } +const CompleteIndexVector& CompletePrediction::getIndexVector() const { + return indexVector_; +} + uint32 CompletePrediction::getNumElements() const { return VectorDecorator>::getNumElements(); } diff --git a/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_partial.cpp b/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_partial.cpp index b31fb476fb..12c54471d7 100644 --- a/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_partial.cpp +++ b/cpp/subprojects/common/src/mlrl/common/rule_refinement/prediction_partial.cpp @@ -42,6 +42,10 @@ PartialPrediction::index_const_iterator PartialPrediction::indices_cend() const return indexVector_.cend(); } +const PartialIndexVector& PartialPrediction::getIndexVector() const { + return indexVector_; +} + uint32 PartialPrediction::getNumElements() const { return ResizableVectorDecorator>>::getNumElements(); } diff --git a/cpp/subprojects/common/src/mlrl/common/sampling/stratified_sampling_output_wise.cpp b/cpp/subprojects/common/src/mlrl/common/sampling/stratified_sampling_output_wise.cpp index 446b272f94..522cc76403 100644 --- a/cpp/subprojects/common/src/mlrl/common/sampling/stratified_sampling_output_wise.cpp +++ b/cpp/subprojects/common/src/mlrl/common/sampling/stratified_sampling_output_wise.cpp @@ -262,7 +262,7 @@ class StratificationMatrix final : public AllocatedBinaryCscView { // Create a boolean array that stores whether individual examples remain to be processed (1) or not (0)... uint32 numTotalExamples = columnWiseLabelMatrix.numRows; - BitVector mask(numTotalExamples, true); + BinaryBitVector mask(numTotalExamples, true); for (uint32 i = 0; i < Matrix::numRows; i++) { uint32 exampleIndex = indicesBegin[i]; diff --git a/cpp/subprojects/common/test/mlrl/common/data/vector_bit.cpp b/cpp/subprojects/common/test/mlrl/common/data/vector_bit_binary.cpp similarity index 62% rename from cpp/subprojects/common/test/mlrl/common/data/vector_bit.cpp rename to cpp/subprojects/common/test/mlrl/common/data/vector_bit_binary.cpp index b1402d7828..aee0707a48 100644 --- a/cpp/subprojects/common/test/mlrl/common/data/vector_bit.cpp +++ b/cpp/subprojects/common/test/mlrl/common/data/vector_bit_binary.cpp @@ -1,25 +1,25 @@ -#include "mlrl/common/data/vector_bit.hpp" +#include "mlrl/common/data/vector_bit_binary.hpp" #include -TEST(BitVectorTest, getNumElements) { +TEST(BinaryBitVectorTest, getNumElements) { uint32 numElements = 270; - BitVector vector(numElements); + BinaryBitVector vector(numElements); EXPECT_EQ(vector.getNumElements(), numElements); } -TEST(BitVectorTest, defaultInitialization) { +TEST(BinaryBitVectorTest, defaultInitialization) { uint32 numElements = 270; - BitVector vector(numElements, true); + BinaryBitVector vector(numElements, true); for (uint32 i = 0; i < numElements; i++) { EXPECT_FALSE(vector[i]); } } -TEST(BitVectorTest, set) { +TEST(BinaryBitVectorTest, set) { uint32 numElements = 270; - BitVector vector(numElements, false); + BinaryBitVector vector(numElements, false); for (uint32 i = 0; i < numElements; i++) { vector.set(i, false); @@ -27,9 +27,9 @@ TEST(BitVectorTest, set) { } } -TEST(BitVectorTest, clear) { +TEST(BinaryBitVectorTest, clear) { uint32 numElements = 270; - BitVector vector(numElements); + BinaryBitVector vector(numElements); for (uint32 i = 0; i < numElements; i++) { vector.set(i, true); diff --git a/cpp/subprojects/common/test/mlrl/common/data/view_vector_bit.cpp b/cpp/subprojects/common/test/mlrl/common/data/view_vector_bit.cpp new file mode 100644 index 0000000000..1929efd620 --- /dev/null +++ b/cpp/subprojects/common/test/mlrl/common/data/view_vector_bit.cpp @@ -0,0 +1,78 @@ +#include "mlrl/common/data/view_vector_bit.hpp" + +#include + +TEST(BitVectorTest, constructor) { + uint32 numElements = 256; + uint32 numBitsPerElement = 4; + AllocatedBitVector vector(numElements, numBitsPerElement); + EXPECT_EQ(vector.numElements, numElements); + EXPECT_EQ(vector.numBitsPerElement, numBitsPerElement); +} + +TEST(BitVectorTest, defaultInitialization) { + uint32 numElements = 256; + AllocatedBitVector vector(numElements, 4, true); + + for (uint32 i = 0; i < numElements; i++) { + EXPECT_EQ(vector[i], (uint32) 0); + } +} + +TEST(BitVectorTest, set1) { + uint32 numElements = 256; + uint32 numBitsPerElement = 4; + uint32 numValuesPerElement = util::getNumBitCombinations(numBitsPerElement); + AllocatedBitVector vector(numElements, numBitsPerElement, false); + uint32 i = 0; + + while (i < numElements) { + for (uint32 j = 0; i < numElements && j < numValuesPerElement; j++) { + vector.set(i, j); + i++; + } + } + + i = 0; + + while (i < numElements) { + for (uint32 j = 0; i < numElements && j < numValuesPerElement; j++) { + EXPECT_EQ(vector[i], (uint32) j); + i++; + } + } +} + +TEST(BitVectorTest, set2) { + uint32 numElements = 256; + uint32 numBitsPerElement = 3; + uint32 numValuesPerElement = util::getNumBitCombinations(numBitsPerElement); + AllocatedBitVector vector(numElements, numBitsPerElement, false); + uint32 i = 0; + + while (i < numElements) { + for (uint32 j = 0; i < numElements && j < numValuesPerElement; j++) { + vector.set(i, j); + i++; + } + } + + i = 0; + + while (i < numElements) { + for (uint32 j = 0; i < numElements && j < numValuesPerElement; j++) { + EXPECT_EQ(vector[i], (uint32) j); + i++; + } + } +} + +TEST(BitVectorTest, clear) { + uint32 numElements = 256; + AllocatedBitVector vector(numElements, 4, false); + vector.clear(); + + for (uint32 i = 0; i < numElements; i++) { + EXPECT_EQ(vector[i], (uint32) 0); + } +} diff --git a/cpp/subprojects/seco/src/mlrl/seco/prediction/predictor_binary_output_wise.cpp b/cpp/subprojects/seco/src/mlrl/seco/prediction/predictor_binary_output_wise.cpp index 8dbb49bf61..943bdecdd4 100644 --- a/cpp/subprojects/seco/src/mlrl/seco/prediction/predictor_binary_output_wise.cpp +++ b/cpp/subprojects/seco/src/mlrl/seco/prediction/predictor_binary_output_wise.cpp @@ -1,7 +1,7 @@ #include "mlrl/seco/prediction/predictor_binary_output_wise.hpp" #include "mlrl/common/data/array.hpp" -#include "mlrl/common/data/vector_bit.hpp" +#include "mlrl/common/data/vector_bit_binary.hpp" #include "mlrl/common/iterator/iterator_forward_non_zero_index.hpp" #include "mlrl/common/iterator/iterator_index.hpp" #include "mlrl/common/model/head_complete.hpp" @@ -10,7 +10,7 @@ namespace seco { - static inline void applyHead(const CompleteHead& head, View::iterator iterator, BitVector& mask) { + static inline void applyHead(const CompleteHead& head, View::iterator iterator, BinaryBitVector& mask) { CompleteHead::value_const_iterator valueIterator = head.values_cbegin(); uint32 numElements = head.getNumElements(); @@ -23,7 +23,7 @@ namespace seco { } } - static inline void applyHead(const PartialHead& head, View::iterator iterator, BitVector& mask) { + static inline void applyHead(const PartialHead& head, View::iterator iterator, BinaryBitVector& mask) { PartialHead::value_const_iterator valueIterator = head.values_cbegin(); PartialHead::index_const_iterator indexIterator = head.indices_cbegin(); uint32 numElements = head.getNumElements(); @@ -39,7 +39,7 @@ namespace seco { } } - static inline void applyHead(const IHead& head, View::iterator scoreIterator, BitVector& mask) { + static inline void applyHead(const IHead& head, View::iterator scoreIterator, BinaryBitVector& mask) { auto completeHeadVisitor = [&](const CompleteHead& head) { applyHead(head, scoreIterator, mask); }; @@ -54,7 +54,7 @@ namespace seco { RuleList::const_iterator rulesEnd, CContiguousView& predictionMatrix, uint32 exampleIndex, uint32 predictionIndex) { - BitVector mask(predictionMatrix.numCols, true); + BinaryBitVector mask(predictionMatrix.numCols, true); for (; rulesBegin != rulesEnd; rulesBegin++) { const RuleList::Rule& rule = *rulesBegin; @@ -72,7 +72,7 @@ namespace seco { RuleList::const_iterator rulesEnd, CContiguousView& predictionMatrix, uint32 exampleIndex, uint32 predictionIndex) { - BitVector mask(predictionMatrix.numCols, true); + BinaryBitVector mask(predictionMatrix.numCols, true); uint32 numFeatures = featureMatrix.numCols; Array tmpArray1(numFeatures); Array tmpArray2(numFeatures, true); diff --git a/cpp/subprojects/seco/src/mlrl/seco/statistics/statistics_common.hpp b/cpp/subprojects/seco/src/mlrl/seco/statistics/statistics_common.hpp index be77d58ee8..93e3882c03 100644 --- a/cpp/subprojects/seco/src/mlrl/seco/statistics/statistics_common.hpp +++ b/cpp/subprojects/seco/src/mlrl/seco/statistics/statistics_common.hpp @@ -617,6 +617,8 @@ namespace seco { statistics_.majorityLabelVectorPtr_->cbegin(), statistics_.majorityLabelVectorPtr_->cend()); } + + void commit() override {} }; const LabelMatrix& labelMatrix_; diff --git a/doc/user_guide/boosting/parameters.md b/doc/user_guide/boosting/parameters.md index c1ccbcc8b4..4e20f1cd31 100644 --- a/doc/user_guide/boosting/parameters.md +++ b/doc/user_guide/boosting/parameters.md @@ -598,6 +598,22 @@ The following parameters can be used to control various approximation and optimi A sparse format is used for the representation of gradients and Hessians, if supported by the loss function. ``` +### `quantization` + +> *Default value = `'none'`.* + +```{glossary} +`'none'` + No quantization is used. + +`'stochastic'` + Gradients and Hessians are quantized using a stochastic rounding strategy. The following options may be provided using the {ref}`bracket notation`: + + - `num_bits` *(Default value = `4`)* + + The number of bits to be used for quantized gradients and Hessians. The given value must be at least 1. +``` + ## Probability Calibration The following parameters enable to learn calibration models that should be included in a model and may result in more accurate probability estimates being predicted. diff --git a/python/subprojects/boosting/meson.build b/python/subprojects/boosting/meson.build index 02bfec7ab9..f76cb4d24c 100644 --- a/python/subprojects/boosting/meson.build +++ b/python/subprojects/boosting/meson.build @@ -12,6 +12,7 @@ cython_module_names = [ 'post_processor', 'prediction', 'probability_calibration', + 'quantization', 'regularization' ] diff --git a/python/subprojects/boosting/mlrl/boosting/boosting_learners.py b/python/subprojects/boosting/mlrl/boosting/boosting_learners.py index 93d799b170..95ce491018 100644 --- a/python/subprojects/boosting/mlrl/boosting/boosting_learners.py +++ b/python/subprojects/boosting/mlrl/boosting/boosting_learners.py @@ -48,6 +48,7 @@ def __init__(self, shrinkage: Optional[float] = 0.3, l1_regularization_weight: Optional[float] = None, l2_regularization_weight: Optional[float] = None, + quantization: Optional[str] = None, parallel_rule_refinement: Optional[str] = None, parallel_statistic_update: Optional[str] = None, parallel_prediction: Optional[str] = None): @@ -132,6 +133,9 @@ def __init__(self, used to shrink the weight of individual rules. Must be in (0, 1] :param l1_regularization_weight: The weight of the L1 regularization. Must be at least 0 :param l2_regularization_weight: The weight of the L2 regularization. Must be at least 0 + :param quantization: The method that should be used for quantizing gradients and + Hessians. Must be one 'stochastic' or 'none', if no quantization + should be used :param parallel_rule_refinement: Whether potential refinements of rules should be searched for in parallel or not. Must be 'true', 'false' or 'auto', if the most suitable strategy should be chosen automatically depending on the @@ -170,6 +174,7 @@ def __init__(self, self.shrinkage = shrinkage self.l1_regularization_weight = l1_regularization_weight self.l2_regularization_weight = l2_regularization_weight + self.quantization = quantization self.parallel_rule_refinement = parallel_rule_refinement self.parallel_statistic_update = parallel_statistic_update self.parallel_prediction = parallel_prediction diff --git a/python/subprojects/boosting/mlrl/boosting/config.py b/python/subprojects/boosting/mlrl/boosting/config.py index cc27461cd1..c261a86fcb 100644 --- a/python/subprojects/boosting/mlrl/boosting/config.py +++ b/python/subprojects/boosting/mlrl/boosting/config.py @@ -16,7 +16,7 @@ AutomaticParallelStatisticUpdateMixin, CompleteHeadMixin, ConstantShrinkageMixin, \ DecomposableSquaredErrorLossMixin, DynamicPartialHeadMixin, FixedPartialHeadMixin, L1RegularizationMixin, \ L2RegularizationMixin, NoL1RegularizationMixin, NoL2RegularizationMixin, NonDecomposableSquaredErrorLossMixin, \ - SingleOutputHeadMixin + NoQuantizationMixin, SingleOutputHeadMixin, StochasticQuantizationMixin from mlrl.boosting.cython.learner_classification import AutomaticBinaryPredictorMixin, AutomaticDefaultRuleMixin, \ AutomaticLabelBinningMixin, AutomaticPartitionSamplingMixin, AutomaticProbabilityPredictorMixin, \ AutomaticStatisticsMixin, DecomposableLogisticLossMixin, DecomposableSquaredHingeLossMixin, DenseStatisticsMixin, \ @@ -211,6 +211,30 @@ def _configure(self, config, value: str, _: Optional[Options]): config.use_automatic_statistics() +class QuantizationParameter(NominalParameter): + """ + A parameter that allows to configure the method to be used for quantizing gradients and Hessians. + """ + + QUANTIZATION_STOCHASTIC = 'stochastic' + + OPTION_NUM_BITS = 'num_bits' + + def __init__(self): + super().__init__(name='quantization', description='The method to be used for quantizing gradients and Hessians') + self.add_value(name=NONE, mixin=NoQuantizationMixin) + self.add_value(name=self.QUANTIZATION_STOCHASTIC, + mixin=StochasticQuantizationMixin, + options={self.OPTION_NUM_BITS}) + + def _configure(self, config, value: str, options: Optional[Options]): + if value == NONE: + config.use_no_quantization() + elif value == self.QUANTIZATION_STOCHASTIC: + conf = config.use_stochastic_quantization() + conf.set_num_bits(options.get_int(self.OPTION_NUM_BITS, conf.get_num_bits())) + + class LabelBinningParameter(NominalParameter): """ A parameter that allows to configure the strategy to be used for gradient-based label binning (GBLB). @@ -489,6 +513,7 @@ def _configure(self, config, value: str, options: Optional[Options]): L2RegularizationParameter(), DefaultRuleParameter(), StatisticFormatParameter(), + QuantizationParameter(), LabelBinningParameter(), ClassificationLossParameter(), HeadTypeParameter(), diff --git a/python/subprojects/boosting/mlrl/boosting/cython/learner.pxd b/python/subprojects/boosting/mlrl/boosting/cython/learner.pxd index 5a4139c164..0169888d72 100644 --- a/python/subprojects/boosting/mlrl/boosting/cython/learner.pxd +++ b/python/subprojects/boosting/mlrl/boosting/cython/learner.pxd @@ -1,5 +1,6 @@ from mlrl.boosting.cython.head_type cimport IDynamicPartialHeadConfig, IFixedPartialHeadConfig from mlrl.boosting.cython.post_processor cimport IConstantShrinkageConfig +from mlrl.boosting.cython.quantization cimport IStochasticQuantizationConfig from mlrl.boosting.cython.regularization cimport IManualRegularizationConfig ctypedef double (*DdotFunction)(int* n, double* dx, int* incx, double* dy, int* incy) @@ -41,6 +42,19 @@ cdef extern from "mlrl/boosting/learner.hpp" namespace "boosting" nogil: IConstantShrinkageConfig& useConstantShrinkagePostProcessor() + cdef cppclass INoQuantizationMixin: + + # Functions: + + void useNoQuantization() + + cdef cppclass IStochasticQuantizationMixin: + + # Functions: + + IStochasticQuantizationConfig& useStochasticQuantization() + + cdef cppclass INoL1RegularizationMixin: # Functions: diff --git a/python/subprojects/boosting/mlrl/boosting/cython/learner.pyx b/python/subprojects/boosting/mlrl/boosting/cython/learner.pyx index d5a4da062d..cb5ef5d1a0 100644 --- a/python/subprojects/boosting/mlrl/boosting/cython/learner.pyx +++ b/python/subprojects/boosting/mlrl/boosting/cython/learner.pyx @@ -5,6 +5,7 @@ from abc import ABC, abstractmethod from mlrl.boosting.cython.head_type import DynamicPartialHeadConfig, FixedPartialHeadConfig from mlrl.boosting.cython.post_processor import ConstantShrinkageConfig +from mlrl.boosting.cython.quantization import StochasticQuantizationConfig from mlrl.boosting.cython.regularization import ManualRegularizationConfig @@ -126,6 +127,37 @@ class L2RegularizationMixin(ABC): pass +class NoQuantizationMixin(ABC): + """ + Allows to configure a rule learner to not quantize statistics about the quality of predictions for the training + examples. + """ + + @abstractmethod + def use_no_quantization(self): + """ + Configures the rule learner to not quantize statistics about the quality of predictions for the training + examples. + """ + pass + + +class StochasticQuantizationMixin(ABC): + """ + Allows to configure a rule learner to quantize statistics using a stochastic rounding strategy. + """ + + @abstractmethod + def use_stochastic_quantization(self) -> StochasticQuanizationConfig: + """ + Configures the rule learner to quantize statistics about the quality of predictions for the training examples + using a stochastic rounding strategy. + + :return: A `StochasticQuantizationConfig` that allows further configuration of the quantization method + """ + pass + + class CompleteHeadMixin(ABC): """ Allows to configure a rule learner to induce rules with complete heads that predict for all available outputs. diff --git a/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pxd b/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pxd index 9c9c192b2c..6c3ee59d77 100644 --- a/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pxd +++ b/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pxd @@ -22,8 +22,8 @@ from mlrl.boosting.cython.learner cimport DdotFunction, DspmvFunction, DsysvFunc IAutomaticHeadMixin, IAutomaticParallelRuleRefinementMixin, IAutomaticParallelStatisticUpdateMixin, \ ICompleteHeadMixin, IConstantShrinkageMixin, IDecomposableSquaredErrorLossMixin, IDynamicPartialHeadMixin, \ IFixedPartialHeadMixin, IL1RegularizationMixin, IL2RegularizationMixin, INoL1RegularizationMixin, \ - INoL2RegularizationMixin, INonDecomposableSquaredErrorLossMixin, IOutputWiseScorePredictorMixin, \ - ISingleOutputHeadMixin + INoL2RegularizationMixin, INonDecomposableSquaredErrorLossMixin, INoQuantizationMixin, \ + IOutputWiseScorePredictorMixin, ISingleOutputHeadMixin, IStochasticQuantizationMixin from mlrl.boosting.cython.learner_classification cimport IAutomaticBinaryPredictorMixin, IAutomaticDefaultRuleMixin, \ IAutomaticLabelBinningMixin, IAutomaticPartitionSamplingMixin, IAutomaticProbabilityPredictorMixin, \ IAutomaticStatisticsMixin, IDecomposableLogisticLossMixin, IDecomposableSquaredHingeLossMixin, \ @@ -47,6 +47,8 @@ cdef extern from "mlrl/boosting/learner_boomer_classifier.hpp" namespace "boosti IL1RegularizationMixin, INoL2RegularizationMixin, IL2RegularizationMixin, + INoQuantizationMixin, + IStochasticQuantizationMixin, INoDefaultRuleMixin, IDefaultRuleMixin, IAutomaticDefaultRuleMixin, @@ -144,6 +146,8 @@ cdef extern from "mlrl/boosting/learner_boomer_regressor.hpp" namespace "boostin IL1RegularizationMixin, INoL2RegularizationMixin, IL2RegularizationMixin, + INoQuantizationMixin, + IStochasticQuantizationMixin, INoDefaultRuleMixin, IDefaultRuleMixin, IAutomaticDefaultRuleMixin, diff --git a/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pyx b/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pyx index 34a701d946..ecddc1f556 100644 --- a/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pyx +++ b/python/subprojects/boosting/mlrl/boosting/cython/learner_boomer.pyx @@ -39,6 +39,7 @@ from mlrl.boosting.cython.prediction cimport ExampleWiseBinaryPredictorConfig, G from mlrl.boosting.cython.probability_calibration cimport IIsotonicJointProbabilityCalibratorConfig, \ IIsotonicMarginalProbabilityCalibratorConfig, IsotonicJointProbabilityCalibratorConfig, \ IsotonicMarginalProbabilityCalibratorConfig +from mlrl.boosting.cython.quantization cimport IStochasticQuantizationConfig, StochasticQuantizationConfig from mlrl.boosting.cython.regularization cimport IManualRegularizationConfig, ManualRegularizationConfig from mlrl.common.cython.learner import BeamSearchTopDownRuleInductionMixin, DefaultRuleMixin, \ @@ -61,7 +62,8 @@ from mlrl.boosting.cython.learner import AutomaticFeatureBinningMixin, Automatic AutomaticParallelRuleRefinementMixin, AutomaticParallelStatisticUpdateMixin, CompleteHeadMixin, \ ConstantShrinkageMixin, DecomposableSquaredErrorLossMixin, DynamicPartialHeadMixin, FixedPartialHeadMixin, \ L1RegularizationMixin, L2RegularizationMixin, NoL1RegularizationMixin, NoL2RegularizationMixin, \ - NonDecomposableSquaredErrorLossMixin, OutputWiseScorePredictorMixin, SingleOutputHeadMixin + NonDecomposableSquaredErrorLossMixin, NoQuantizationMixin, OutputWiseScorePredictorMixin, SingleOutputHeadMixin, \ + StochasticQuantizationMixin from mlrl.boosting.cython.learner_classification import AutomaticBinaryPredictorMixin, AutomaticDefaultRuleMixin, \ AutomaticLabelBinningMixin, AutomaticPartitionSamplingMixin, AutomaticProbabilityPredictorMixin, \ AutomaticStatisticsMixin, DecomposableLogisticLossMixin, DecomposableSquaredHingeLossMixin, DenseStatisticsMixin, \ @@ -83,6 +85,8 @@ cdef class BoomerClassifierConfig(RuleLearnerConfig, L1RegularizationMixin, NoL2RegularizationMixin, L2RegularizationMixin, + NoQuantizationMixin, + StochasticQuantizationMixin, NoDefaultRuleMixin, DefaultRuleMixin, AutomaticDefaultRuleMixin, @@ -462,6 +466,15 @@ cdef class BoomerClassifierConfig(RuleLearnerConfig, config.config_ptr = config_ptr return config + def use_no_quantization(self): + self.config_ptr.get().useNoQuantization() + + def use_stochastic_quantization(self) -> StochasticQuantizationConfig: + cdef IStochasticQuantizationConfig* config_ptr = &self.config_ptr.get().useStochasticQuantization() + cdef StochasticQuantizationConfig config = StochasticQuantizationConfig.__new__(StochasticQuantizationConfig) + config.config_ptr = config_ptr + return config + def use_non_decomposable_logistic_loss(self): self.config_ptr.get().useNonDecomposableLogisticLoss() @@ -586,6 +599,8 @@ cdef class BoomerRegressorConfig(RuleLearnerConfig, L1RegularizationMixin, NoL2RegularizationMixin, L2RegularizationMixin, + NoQuantizationMixin, + StochasticQuantizationMixin, NoDefaultRuleMixin, DefaultRuleMixin, AutomaticDefaultRuleMixin, @@ -886,6 +901,15 @@ cdef class BoomerRegressorConfig(RuleLearnerConfig, config.config_ptr = config_ptr return config + def use_no_quantization(self): + self.config_ptr.get().useNoQuantization() + + def use_stochastic_quantization(self) -> StochasticQuantizationConfig: + cdef IStochasticQuantizationConfig* config_ptr = &self.config_ptr.get().useStochasticQuantization() + cdef StochasticQuantizationConfig config = StochasticQuantizationConfig.__new__(StochasticQuantizationConfig) + config.config_ptr = config_ptr + return config + def use_non_decomposable_squared_error_loss(self): self.config_ptr.get().useNonDecomposableSquaredErrorLoss() diff --git a/python/subprojects/boosting/mlrl/boosting/cython/quantization.pxd b/python/subprojects/boosting/mlrl/boosting/cython/quantization.pxd new file mode 100644 index 0000000000..d4cbc8dbc0 --- /dev/null +++ b/python/subprojects/boosting/mlrl/boosting/cython/quantization.pxd @@ -0,0 +1,19 @@ +from mlrl.common.cython._types cimport uint32 + + +cdef extern from "mlrl/boosting/statistics/quantization_stochastic.hpp" namespace "boosting" nogil: + + cdef cppclass IStochasticQuantizationConfig: + + # Functions: + + uint32 getNumBits() const + + IStochasticQuantizationConfig& setNumBits(uint32 numBits) except + + + +cdef class StochasticQuantizationConfig: + + # Attributes: + + cdef IStochasticQuantizationConfig* config_ptr diff --git a/python/subprojects/boosting/mlrl/boosting/cython/quantization.pyx b/python/subprojects/boosting/mlrl/boosting/cython/quantization.pyx new file mode 100644 index 0000000000..f4437e064f --- /dev/null +++ b/python/subprojects/boosting/mlrl/boosting/cython/quantization.pyx @@ -0,0 +1,30 @@ +""" +@author: Michael Rapp (michael.rapp.ml@gmail.com) +""" +from mlrl.common.cython.validation import assert_greater + + +cdef class StochasticQuantizationConfig: + """ + Allows to configure a method for quantizing statistics that uses a stochastic rounding strategy. + """ + + def get_num_bits(self) -> int: + """ + Returns the number of bits that are used used for quantized statistics. + + :return: The number of bits that are used + """ + return self.config_ptr.getNumBits() + + def set_num_bits(self, num_bits: int) -> StochasticQuantizationConfig: + """ + Sets the number of bits to be used for quantized statistics. + + :param num_bits: The number of bits to be used. Must be greater than 0 + :return: An `StochasticQuantizationConfig` that allows further configuration of the quantization + method + """ + assert_greater('num_bits', num_bits, 0) + self.config_ptr.setNumBits(num_bits) + return self