From f0f1481fb67bf4bc928f52943f4dc1df61e00019 Mon Sep 17 00:00:00 2001 From: NAUD Maxence <maxence.naud@cea.fr> Date: Wed, 29 Jan 2025 13:57:41 +0000 Subject: [PATCH 1/2] Add standardization to some C++ files - Standardize #ifndef preprocessor directives in many files - remove some unused includes - add used includes - remove edn-of-line spaces - add doxygen to 'DoReFa.hpp' - add log to 'CLE.cpp' - move functions from hpp to cpp file in DoReFa, FixedQ and TanhClamp operators - change size_t for std::size_t --- aidge_quantization/unit_tests/test_ptq.py | 22 +++--- include/aidge/operator/FixedQ.hpp | 43 ++++++------ include/aidge/operator/LSQ.hpp | 6 +- include/aidge/operator/SAT/DoReFa.hpp | 67 ++++++++++++------- include/aidge/operator/SAT/TanhClamp.hpp | 33 +++------ include/aidge/quantization/PTQ/CLE.hpp | 30 +++++---- include/aidge/quantization/PTQ/Clipping.hpp | 22 +++--- include/aidge/quantization/PTQ/PTQ.hpp | 27 ++++---- include/aidge/quantization/PTQ/PTQMetaOps.hpp | 18 ++--- include/aidge/quantization/QAT/QAT_FixedQ.hpp | 10 +-- include/aidge/quantization/QAT/QAT_LSQ.hpp | 20 +++--- src/PTQ/CLE.cpp | 40 +++++++---- src/PTQ/PTQMetaOps.cpp | 22 +++--- src/operator/FixedQ.cpp | 20 ++++++ src/operator/SAT/DoReFa.cpp | 33 +++++++-- src/operator/SAT/TanhClamp.cpp | 22 +++++- 16 files changed, 259 insertions(+), 176 deletions(-) diff --git a/aidge_quantization/unit_tests/test_ptq.py b/aidge_quantization/unit_tests/test_ptq.py index dfdedd8..56080bf 100644 --- a/aidge_quantization/unit_tests/test_ptq.py +++ b/aidge_quantization/unit_tests/test_ptq.py @@ -21,7 +21,7 @@ ACCURACIES = (95.4, 94.4) # (97.9, 97.7) NB_BITS = 4 # -------------------------------------------------------------- -# UTILS +# UTILS # -------------------------------------------------------------- def propagate(model, scheduler, sample): @@ -50,7 +50,7 @@ def compute_accuracy(model, samples, labels): # -------------------------------------------------------------- class test_ptq(unittest.TestCase): - + def setUp(self): # load the samples / labels (numpy) @@ -70,19 +70,20 @@ class test_ptq(unittest.TestCase): def tearDown(self): pass - + def test_model(self): Log.set_console_level(Level.Info) # compute the base accuracy accuracy = compute_accuracy(self.model, self.samples[0:NB_SAMPLES], self.labels) self.assertAlmostEqual(accuracy * 100, ACCURACIES[0], msg='base accuracy does not meet the baseline !', delta=0.1) - + def test_quant_model(self): - Log.set_console_level(Level.Info) + Log.set_console_level(Level.Debug) # create the calibration dataset + tensors = [] for sample in self.samples[0:NB_SAMPLES]: sample = prepare_sample(sample) @@ -91,14 +92,13 @@ class test_ptq(unittest.TestCase): # quantize the model - aidge_quantization.quantize_network( - self.model, - NB_BITS, - tensors, - clipping_mode=aidge_quantization.Clipping.MSE, + self.model, + NB_BITS, + tensors, + clipping_mode=aidge_quantization.Clipping.MSE, no_quantization=False, - optimize_signs=True, + optimize_signs=True, single_shift=False ) diff --git a/include/aidge/operator/FixedQ.hpp b/include/aidge/operator/FixedQ.hpp index 96a52b4..3d46dcf 100644 --- a/include/aidge/operator/FixedQ.hpp +++ b/include/aidge/operator/FixedQ.hpp @@ -9,11 +9,12 @@ * ********************************************************************************/ -#ifndef AIDGE_CORE_OPERATOR_FIXEDQ_H_ -#define AIDGE_CORE_OPERATOR_FIXEDQ_H_ +#ifndef AIDGE_QUANTIZATION_OPERATOR_FIXEDQ_H_ +#define AIDGE_QUANTIZATION_OPERATOR_FIXEDQ_H_ -#include <cassert> +#include <cstddef> // std::size_t #include <memory> +#include <string> #include <vector> #include "aidge/backend/OperatorImpl.hpp" @@ -21,8 +22,8 @@ #include "aidge/operator/OperatorTensor.hpp" #include "aidge/utils/ErrorHandling.hpp" #include "aidge/utils/Registrar.hpp" -#include "aidge/utils/Types.h" #include "aidge/utils/StaticAttributes.hpp" +#include "aidge/utils/Types.h" namespace Aidge { @@ -43,24 +44,20 @@ private: public: - FixedQ_Op(std::size_t nbBits, float span, bool isOutputUnsigned) : - OperatorTensor(Type, {InputCategory::Data}, 1), - mAttributes(std::make_shared<Attributes_>(attr<FixedQAttr::NbBits>(nbBits), attr<FixedQAttr::Span>(span), attr<FixedQAttr::IsOutputUnsigned>(isOutputUnsigned))) + FixedQ_Op(std::size_t nbBits = 8, float span = 4.0f, bool isOutputUnsigned = false) : + OperatorTensor(Type, {InputCategory::Data}, 1), + mAttributes(std::make_shared<Attributes_>( + attr<FixedQAttr::NbBits>(nbBits), + attr<FixedQAttr::Span>(span), + attr<FixedQAttr::IsOutputUnsigned>(isOutputUnsigned))) {} /** - * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). + * @brief Copy-constructor. Copy the operator attributes and its output + * tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - FixedQ_Op(const FixedQ_Op& op) - : OperatorTensor(op), mAttributes(op.mAttributes) - { - if (op.mImpl){ - SET_IMPL_MACRO(FixedQ_Op, *this, op.backend()); - }else{ - mImpl = nullptr; - } - } + FixedQ_Op(const FixedQ_Op& op); /** * @brief Clone the operator using its copy-constructor. @@ -88,14 +85,16 @@ public: }; -inline std::shared_ptr<Node> FixedQ(std::size_t nbBits = 8, float span = 4.0f, bool isOutputUnsigned = false, const std::string& name = "") { - return std::make_shared<Node>(std::make_shared<FixedQ_Op>(nbBits, span, isOutputUnsigned), name); -} -} +std::shared_ptr<Node> FixedQ(std::size_t nbBits = 8, + float span = 4.0f, + bool isOutputUnsigned = false, + const std::string& name = ""); + +} // namespace Aidge namespace { template <> const char* const EnumStrings<Aidge::FixedQAttr>::data[] = {"nb_bits", "span", "is_output_unsigned"}; } -#endif /* AIDGE_CORE_OPERATOR_FIXEDQ_H_ */ +#endif /* AIDGE_QUANTIZATION_OPERATOR_FIXEDQ_H_ */ diff --git a/include/aidge/operator/LSQ.hpp b/include/aidge/operator/LSQ.hpp index eb266bc..970c476 100644 --- a/include/aidge/operator/LSQ.hpp +++ b/include/aidge/operator/LSQ.hpp @@ -9,8 +9,8 @@ * ********************************************************************************/ -#ifndef AIDGE_CORE_OPERATOR_LSQ_H_ -#define AIDGE_CORE_OPERATOR_LSQ_H_ +#ifndef AIDGE_QUANTIZATION_OPERATOR_LSQ_H_ +#define AIDGE_QUANTIZATION_OPERATOR_LSQ_H_ #include <cassert> #include <memory> @@ -105,4 +105,4 @@ template <> const char *const EnumStrings<Aidge::LSQAttr>::data[] = {"range"}; } -#endif /* AIDGE_CORE_OPERATOR_LSQ_H_ */ +#endif /* AIDGE_QUANTIZATION_OPERATOR_LSQ_H_ */ diff --git a/include/aidge/operator/SAT/DoReFa.hpp b/include/aidge/operator/SAT/DoReFa.hpp index 92ce167..d168c38 100644 --- a/include/aidge/operator/SAT/DoReFa.hpp +++ b/include/aidge/operator/SAT/DoReFa.hpp @@ -9,17 +9,15 @@ * ********************************************************************************/ -#ifndef AIDGE_CORE_OPERATOR_DOREFA_H_ -#define AIDGE_CORE_OPERATOR_DOREFA_H_ +#ifndef AIDGE_QUANTIZATION_OPERATOR_SAT_DOREFA_H_ +#define AIDGE_QUANTIZATION_OPERATOR_SAT_DOREFA_H_ -#include <cassert> #include <memory> #include <vector> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/graph/Node.hpp" #include "aidge/operator/OperatorTensor.hpp" -#include "aidge/utils/ErrorHandling.hpp" #include "aidge/utils/Registrar.hpp" #include "aidge/utils/StaticAttributes.hpp" #include "aidge/utils/Types.h" @@ -43,12 +41,17 @@ public: static const std::string Type; private: - using Attributes_ = StaticAttributes<DoReFaAttr, size_t, DoReFaMode>; + using Attributes_ = StaticAttributes<DoReFaAttr, std::size_t, DoReFaMode>; template <DoReFaAttr e> using attr = typename Attributes_::template attr<e>; const std::shared_ptr<Attributes_> mAttributes; public: - DoReFa_Op(size_t range = 255, DoReFaMode mode = DoReFaMode::Default) + /** + * @brief Constructor for DoReFa_Op + * @param range The quantization range (default: 255) + * @param mode The quantization mode (default: Default) + */ + DoReFa_Op(std::size_t range = 255, DoReFaMode mode = DoReFaMode::Default) : OperatorTensor(Type, {InputCategory::Param}, 1), mAttributes(std::make_shared<Attributes_>( attr<DoReFaAttr::Range>(range), @@ -59,30 +62,34 @@ public: * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - DoReFa_Op(const DoReFa_Op& op) - : OperatorTensor(op), - mAttributes(op.mAttributes) - { - if (op.mImpl){ - SET_IMPL_MACRO(DoReFa_Op, *this, op.backend()); - }else{ - mImpl = nullptr; - } - } + DoReFa_Op(const DoReFa_Op& op); /** * @brief Clone the operator using its copy-constructor. * @see Operator::DoReFa_Op + * @return std::shared_ptr<Operator> A deep copy of the operator */ - std::shared_ptr<Operator> clone() const override { - return std::make_shared<DoReFa_Op>(*this); - } + std::shared_ptr<Operator> clone() const override; + /** + * @brief Get available backends for this operator + * @return std::set<std::string> Set of supported backend names + */ std::set<std::string> getAvailableBackends() const override final; + + /** + * @brief Set the backend for this operator + * @param name Backend name + * @param device Device index (default: 0) + */ void setBackend(const std::string& name, DeviceIdx_t device = 0) override final; + /** + * @brief Get operator attributes + * @return std::shared_ptr<Attributes> Shared pointer to operator attributes + */ inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; } - inline size_t& range() const noexcept { return mAttributes->getAttr<DoReFaAttr::Range>(); } + inline std::size_t& range() const noexcept { return mAttributes->getAttr<DoReFaAttr::Range>(); } inline DoReFaMode& mode() const noexcept { return mAttributes->getAttr<DoReFaAttr::Mode>(); } static const std::vector<std::string> getInputsName(){ @@ -93,10 +100,20 @@ public: } }; -inline std::shared_ptr<Node> DoReFa(size_t range = 255, DoReFaMode mode = DoReFaMode::Default, const std::string& name = "") { - return std::make_shared<Node>(std::make_shared<DoReFa_Op>(range, mode), name); -} -} +/** + * @brief Factory function to create a DoReFa operator node + * + * @param range Quantization range (default: 255) + * @param mode Quantization mode (default: Default) + * @param name Node name (default: empty) + * + * @return std::shared_ptr<Node> Shared pointer to the created node + */ +std::shared_ptr<Node> DoReFa(std::size_t range = 255, + DoReFaMode mode = DoReFaMode::Default, + const std::string& name = ""); + +} // namespace Aidge namespace { template <> @@ -106,4 +123,4 @@ template <> const char *const EnumStrings<Aidge::DoReFaMode>::data[] = {"default", "symmetric", "asymmetric", "full_range"}; } -#endif /* AIDGE_CORE_OPERATOR_DOREFA_H_ */ +#endif /* AIDGE_QUANTIZATION_OPERATOR_SAT_DOREFA_H_ */ diff --git a/include/aidge/operator/SAT/TanhClamp.hpp b/include/aidge/operator/SAT/TanhClamp.hpp index def43b8..9d99d70 100644 --- a/include/aidge/operator/SAT/TanhClamp.hpp +++ b/include/aidge/operator/SAT/TanhClamp.hpp @@ -9,20 +9,18 @@ * ********************************************************************************/ -#ifndef AIDGE_CORE_OPERATOR_TANHCLAMP_H_ -#define AIDGE_CORE_OPERATOR_TANHCLAMP_H_ +#ifndef AIDGE_QUANTIZATION_OPERATOR_SAT_TANHCLAMP_H_ +#define AIDGE_QUANTIZATION_OPERATOR_SAT_TANHCLAMP_H_ -#include <cassert> #include <memory> +#include <set> +#include <string> #include <vector> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/graph/Node.hpp" #include "aidge/operator/OperatorTensor.hpp" -#include "aidge/operator/Producer.hpp" -#include "aidge/utils/ErrorHandling.hpp" #include "aidge/utils/Registrar.hpp" -#include "aidge/utils/StaticAttributes.hpp" #include "aidge/utils/Types.h" namespace Aidge { @@ -44,23 +42,13 @@ public: * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - TanhClamp_Op(const TanhClamp_Op& op) - : OperatorTensor(op) - { - if (op.mImpl){ - SET_IMPL_MACRO(TanhClamp_Op, *this, op.backend()); - }else{ - mImpl = nullptr; - } - } + TanhClamp_Op(const TanhClamp_Op& op); /** * @brief Clone the operator using its copy-constructor. * @see Operator::TanhClamp_Op */ - std::shared_ptr<Operator> clone() const override { - return std::make_shared<TanhClamp_Op>(*this); - } + std::shared_ptr<Operator> clone() const override; bool forwardDims(bool allowDataDependency = false) override final; std::set<std::string> getAvailableBackends() const override final; @@ -75,9 +63,8 @@ public: } }; -inline std::shared_ptr<Node> TanhClamp(const std::string& name = "") { - return std::make_shared<Node>(std::make_shared<TanhClamp_Op>(), name); -} -} +std::shared_ptr<Node> TanhClamp(const std::string& name = ""); + +} // namespace Aidge -#endif /* AIDGE_CORE_OPERATOR_TANHCLAMP_H_ */ +#endif /* AIDGE_QUANTIZATION_OPERATOR_SAT_TANHCLAMP_H_ */ diff --git a/include/aidge/quantization/PTQ/CLE.hpp b/include/aidge/quantization/PTQ/CLE.hpp index 77eaf7f..f4dc073 100644 --- a/include/aidge/quantization/PTQ/CLE.hpp +++ b/include/aidge/quantization/PTQ/CLE.hpp @@ -9,29 +9,33 @@ * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_PTQ_CLE_H_ -#define AIDGE_QUANTIZATION_PTQ_CLE_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLE_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLE_H_ -//#include <cstdint> -//#include <map> -//#include <memory> -//#include <string> -//#include <vector> +#include <memory> -#include "aidge/data/Tensor.hpp" #include "aidge/graph/GraphView.hpp" namespace Aidge { /** - * @brief Equalize the ranges of the nodes parameters by proceding iteratively. - * Can only be applied to single branch networks (otherwise does not edit the graphView). + * @brief Equalize the ranges of the nodes parameters by proceding iteratively. + * Can only be applied to single branch networks (otherwise does not edit the GraphView). + * + * Cross Layer Equalization (CLE) is used to balance the weights between consecutive + * layers to improve quantization performance. It works by iteratively scaling weights + * and biases of adjacent layers while preserving the overall function of the network. + * + * @note The operation modifies weights and biases in-place but preserves the mathematical + * function computed by the network. + * * @param graphView The GraphView to process. - * @param targetDelta the stopping criterion (typical value : 0.01) + * @param targetDelta the stopping criterion (typical value : 0.01). Smaller values lead + * to more precise equalization but may require more iterations. */ void crossLayerEqualization(std::shared_ptr<GraphView> graphView, double targetDelta = 0.01); -} +} // namespace Aidge -#endif /* AIDGE_QUANTIZATION_PTQ_CLE_H_ */ \ No newline at end of file +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLE_H_ */ diff --git a/include/aidge/quantization/PTQ/Clipping.hpp b/include/aidge/quantization/PTQ/Clipping.hpp index d0622f4..3f65c42 100644 --- a/include/aidge/quantization/PTQ/Clipping.hpp +++ b/include/aidge/quantization/PTQ/Clipping.hpp @@ -9,14 +9,14 @@ * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_PTQ_CLIP_H_ -#define AIDGE_QUANTIZATION_PTQ_CLIP_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLIP_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLIP_H_ -//#include <cstdint> -//#include <map> -//#include <memory> -//#include <string> -//#include <vector> +#include <cstdint> // std::uint8_t +#include <map> +#include <memory> +#include <string> +#include <vector> #include "aidge/data/Tensor.hpp" #include "aidge/graph/GraphView.hpp" @@ -56,9 +56,9 @@ namespace Aidge double computeKLClipping(std::vector<int> histogram, std::uint8_t nbBits); /** - * @brief Return a corrected map of the provided activation ranges. - * To do so compute the optimal clipping values for every node and multiply the input ranges by those values. - * The method used to compute the clippings can be eihter 'MSE', 'AA', 'KL' or 'MAX'. + * @brief Return a corrected map of the provided activation ranges. + * To do so compute the optimal clipping values for every node and multiply the input ranges by those values. + * The method used to compute the clippings can be eihter 'MSE', 'AA', 'KL' or 'MAX'. * @param clippingMode The method used to compute the optimal clippings. * @param valueRanges The map associating each affine node to its output range. * @param nbBits The quantization number of bits. @@ -71,5 +71,5 @@ namespace Aidge } -#endif /* AIDGE_QUANTIZATION_PTQ_CLIP_H_ */ +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_PTQ_CLIP_H_ */ diff --git a/include/aidge/quantization/PTQ/PTQ.hpp b/include/aidge/quantization/PTQ/PTQ.hpp index d2b8b7f..4fc38bc 100644 --- a/include/aidge/quantization/PTQ/PTQ.hpp +++ b/include/aidge/quantization/PTQ/PTQ.hpp @@ -9,16 +9,19 @@ * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_PTQ_PTQ_H_ -#define AIDGE_QUANTIZATION_PTQ_PTQ_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQ_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQ_H_ -//#include <cstdint> -//#include <map> -//#include <memory> -//#include <string> -//#include <vector> +#include <cstdint> // std::uint8_t +#include <map> +#include <memory> +#include <set> +#include <string> +#include <utility> // std::pair +#include <vector> #include "aidge/data/Tensor.hpp" +#include "aidge/quantization/PTQ/Clipping.hpp" #include "aidge/graph/GraphView.hpp" namespace Aidge { @@ -104,12 +107,12 @@ namespace Aidge { * @brief Normalize the activations of each affine node so that they fit in the [-1:1] range. * This is done by reconfiguring the scaling nodes, as well as rescaling the weights and biases tensors. * @param graphView The GraphView containing the affine nodes. - * @param valueRanges The node output value ranges computed over the calibration dataset. + * @param valueRanges The node output value ranges computed over the calibration dataset. */ void normalizeActivations(std::shared_ptr<GraphView> graphView, std::map<std::string, double> valueRanges); /** - * @brief For each node, compute the sign of its input and output values. + * @brief For each node, compute the sign of its input and output values. * The goal of the routine is to maximize the number of unsigned IOs in order to double the value resolution when possible. * @param graphView The GraphView to analyze. * @param verbose Whether to print the sign map or not. @@ -135,7 +138,7 @@ namespace Aidge { * @param clippingMode: Type of the clipping optimization. Can be either 'MAX', 'MSE', 'AA' or 'KL'. * @param applyRounding Whether to apply the rounding operations or not. * @param optimizeSigns Whether to take account of the IO signs of the operators or not. - * @param singleShift Whether to convert the scaling factors into powers of two. If true the approximations are compensated using the previous nodes weights. + * @param singleShift Whether to convert the scaling factors into powers of two. If true the approximations are compensated using the previous nodes weights. * @param verbose Whether to print internal informations about the quantization process. */ void quantizeNetwork(std::shared_ptr<GraphView> graphView, std::uint8_t nbBits, std::vector<std::shared_ptr<Tensor>> inputDataSet, Clipping clippingMode, bool applyRounding, bool optimizeSigns, bool singleShift, bool useCuda, bool verbose); @@ -157,8 +160,8 @@ namespace Aidge { * @brief Developement and test routine. * @param graphView The GraphView under test. */ - void devPTQ(std::shared_ptr<GraphView> graphView); + void devPTQ(std::shared_ptr<GraphView> graphView); } -#endif /* AIDGE_QUANTIZATION_PTQ_PTQ_H_ */ +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQ_H_ */ diff --git a/include/aidge/quantization/PTQ/PTQMetaOps.hpp b/include/aidge/quantization/PTQ/PTQMetaOps.hpp index 62fac87..b9bad0d 100644 --- a/include/aidge/quantization/PTQ/PTQMetaOps.hpp +++ b/include/aidge/quantization/PTQ/PTQMetaOps.hpp @@ -8,22 +8,14 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_PTQ_PTQMETAOPS_H_ -#define AIDGE_QUANTIZATION_PTQ_PTQMETAOPS_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQMETAOPS_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQMETAOPS_H_ -#include <array> #include <memory> #include <string> -#include <utility> - -#include "aidge/operator/Clip.hpp" -#include "aidge/operator/Mul.hpp" -#include "aidge/operator/Round.hpp" #include "aidge/graph/GraphView.hpp" #include "aidge/graph/Node.hpp" -#include "aidge/graph/OpArgs.hpp" // Sequential -#include "aidge/operator/MetaOperator.hpp" namespace Aidge { @@ -55,7 +47,7 @@ std::shared_ptr<Aidge::Node> Scaling(double scalingFactor, const std::string& na void updateScalingFactor(std::shared_ptr<Aidge::Node> MetaOpNode, double newScalingFactor); /// @brief Retrieves the current scaling factor of a PTQ meta-operator node. -/// This function returns the scaling factor associated with the specified PTQ meta-operator node, +/// This function returns the scaling factor associated with the specified PTQ meta-operator node, /// allowing inspection of the current scalar applied in the [Mul] operation. /// /// @param MetaOpNode A shared pointer to the PTQ meta-operator node whose scaling factor is being queried. @@ -66,7 +58,7 @@ double getScalingFactor(std::shared_ptr<Aidge::Node> MetaOpNode); /// This function modifies the clip range of a Quantizer node, allowing adjustment of the range within which values are clipped /// in the [Clip] operation of the Quantizer sequence. /// -/// @param QuantizerNode A shared pointer to the Quantizer node whose clip range is being set. +/// @param QuantizerNode A shared pointer to the Quantizer node whose clip range is being set. /// This node should have been created using the Quantizer function. /// @param min The minimum value for the clip range. Values below this will be clipped to this minimum. /// @param max The maximum value for the clip range. Values above this will be clipped to this maximum. @@ -75,4 +67,4 @@ void setClipRange(std::shared_ptr<Aidge::Node> QuantizerNode, double min, double } -#endif /* AIDGE_QUANTIZATION_PTQ_PTQMETAOPS_H_ */ +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_PTQ_PTQMETAOPS_H_ */ diff --git a/include/aidge/quantization/QAT/QAT_FixedQ.hpp b/include/aidge/quantization/QAT/QAT_FixedQ.hpp index ecbe742..6a2aa24 100644 --- a/include/aidge/quantization/QAT/QAT_FixedQ.hpp +++ b/include/aidge/quantization/QAT/QAT_FixedQ.hpp @@ -9,8 +9,10 @@ * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_QAT_FIXEDQ_H_ -#define AIDGE_QUANTIZATION_QAT_FIXEDQ_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_QAT_FIXEDQ_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_QAT_FIXEDQ_H_ + +#include <memory> #include "aidge/graph/Node.hpp" #include "aidge/graph/GraphView.hpp" @@ -41,10 +43,10 @@ void insertAndInitQuantizers(std::shared_ptr<GraphView> graphView, size_t nbBits * @brief Developement and test routine. * @param graphView The GraphView under test. */ -void devQAT(std::shared_ptr<GraphView> graphView); +void devQAT(std::shared_ptr<GraphView> graphView); } } -#endif /* AIDGE_QUANTIZATION_QAT_FIXEDQ_H_ */ +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_QAT_FIXEDQ_H_ */ diff --git a/include/aidge/quantization/QAT/QAT_LSQ.hpp b/include/aidge/quantization/QAT/QAT_LSQ.hpp index 4970be0..a44c71b 100644 --- a/include/aidge/quantization/QAT/QAT_LSQ.hpp +++ b/include/aidge/quantization/QAT/QAT_LSQ.hpp @@ -9,12 +9,14 @@ * ********************************************************************************/ -#ifndef AIDGE_QUANTIZATION_QAT_LSQ_H_ -#define AIDGE_QUANTIZATION_QAT_LSQ_H_ +#ifndef AIDGE_QUANTIZATION_QUANTIZATION_QAT_LSQ_H_ +#define AIDGE_QUANTIZATION_QUANTIZATION_QAT_LSQ_H_ + +#include <cstddef> // std::size_t +#include <memory> -#include "aidge/graph/Node.hpp" -#include "aidge/graph/GraphView.hpp" #include "aidge/data/Tensor.hpp" +#include "aidge/graph/GraphView.hpp" namespace Aidge { namespace QuantLSQ { @@ -25,7 +27,7 @@ namespace QuantLSQ { * @param nbBits Number of quantization bits. * @param span Fixed output span of the quantizers. */ -void insertQuantizers(std::shared_ptr<GraphView> graphView, size_t nbBits, float step_size); +void insertQuantizers(std::shared_ptr<GraphView> graphView, std::size_t nbBits, float step_size); /** * @brief Given a GraphView with parameters properly initialized and some calibration data, @@ -35,10 +37,10 @@ void insertQuantizers(std::shared_ptr<GraphView> graphView, size_t nbBits, float * @param calibrationData Calibration data used to adjust the spans. * @param scale Multiplicative constant applied to the spans. */ -void insertAndInitQuantizers(std::shared_ptr<GraphView> graphView, size_t nbBits, std::shared_ptr<Tensor> calibrationData); +void insertAndInitQuantizers(std::shared_ptr<GraphView> graphView, std::size_t nbBits, std::shared_ptr<Tensor> calibrationData); -} -} +} // namespace QuantLSQ +} // namespace Aidge -#endif /* AIDGE_QUANTIZATION_QAT_LSQ_H_ */ +#endif /* AIDGE_QUANTIZATION_QUANTIZATION_QAT_LSQ_H_ */ diff --git a/src/PTQ/CLE.cpp b/src/PTQ/CLE.cpp index 2c81815..5265d9c 100644 --- a/src/PTQ/CLE.cpp +++ b/src/PTQ/CLE.cpp @@ -10,14 +10,19 @@ ********************************************************************************/ #include "aidge/quantization/PTQ/CLE.hpp" + +#include <cmath> // std::abs, std::fabs, std::sqrt +#include <cstddef> // std::size_t +#include <memory> +#include <vector> + #include "aidge/quantization/PTQ/Clipping.hpp" -#include "aidge/quantization/PTQ/PTQ.hpp" +#include "aidge/quantization/PTQ/PTQ.hpp" // retrieveNodeVector #include "aidge/graph/GraphView.hpp" -#include "aidge/scheduler/SequentialScheduler.hpp" -#include "aidge/scheduler/Scheduler.hpp" -#include "aidge/utils/Log.hpp" +#include "aidge/graph/Node.hpp" #include "aidge/operator/OperatorTensor.hpp" +#include "aidge/utils/Log.hpp" namespace Aidge { @@ -42,13 +47,13 @@ static void rescaleTensor(std::shared_ptr<Tensor> tensor, double scaling) castedTensor[i] *= scaling; } -static double getTensorAbsoluteMax(std::shared_ptr <Tensor> tensor) +static double getTensorAbsoluteMax(std::shared_ptr<Tensor> tensor) { // Get the tensor data pointer and edit it double * castedTensor = static_cast<double*> (tensor->getImpl()->rawPtr()); // Get the tensor absolute max value - double maxValue = 0.0f; + double maxValue = 0.0; for(std::size_t i = 0; i < tensor->size(); ++i) { if(std::fabs(castedTensor[i]) > maxValue) { maxValue = std::fabs(castedTensor[i]); @@ -62,15 +67,14 @@ void crossLayerEqualization(std::shared_ptr<GraphView> graphView, double targetD std::vector<std::shared_ptr<Node>> nodeVector = retrieveNodeVector(graphView); // Check if the CLE can be applied ... - for (std::shared_ptr<Node> node : nodeVector) if (node->getChildren().size() > 1) { - Log::info(" Network have multiple branches, skipping the CLE ... "); + Log::notice("Network have multiple branches, skipping the CLE ... "); return; - } + } - Log::info(" Applying the Cross-Layer Equalization ... "); + Log::info("Applying the Cross-Layer Equalization ... "); // Get the vector of affine nodes @@ -79,17 +83,22 @@ void crossLayerEqualization(std::shared_ptr<GraphView> graphView, double targetD if (isAffine(node)) affineNodeVector.push_back(node); + if (affineNodeVector.empty()) { + Log::notice("No affine nodes found in the network. CLE cannot be applied."); + return; + } double maxRangeDelta; + int iteration = 0; - do + do { + ++iteration; maxRangeDelta = 0.0; - //std::cout << " ----- " << std::endl; //for (std::shared_ptr<Node> node : affineNodeVector) // std::cout << getTensorAbsoluteMax(getWeightTensor(node)) << std::endl; - - for (size_t i = 0; i < (affineNodeVector.size() - 1); i++) + + for (std::size_t i = 0; i < (affineNodeVector.size() - 1); i++) { std::shared_ptr<Node> n1 = affineNodeVector[i]; std::shared_ptr<Node> n2 = affineNodeVector[i+1]; @@ -111,6 +120,9 @@ void crossLayerEqualization(std::shared_ptr<GraphView> graphView, double targetD } } while (maxRangeDelta > targetDelta); + + Log::notice("CLE completed after {} iterations. Final max range delta: {:.6f}", + iteration, maxRangeDelta); } } \ No newline at end of file diff --git a/src/PTQ/PTQMetaOps.cpp b/src/PTQ/PTQMetaOps.cpp index 527d853..77018c2 100644 --- a/src/PTQ/PTQMetaOps.cpp +++ b/src/PTQ/PTQMetaOps.cpp @@ -11,8 +11,8 @@ #include "aidge/quantization/PTQ/PTQMetaOps.hpp" -#include <array> #include <memory> +#include <string> #include <utility> //Operator @@ -32,7 +32,7 @@ #include "aidge/utils/Log.hpp" -namespace Aidge +namespace Aidge { std::shared_ptr<Node> Quantizer(double scalingFactor, double clipMin, double clipMax, const std::string& name) @@ -46,19 +46,19 @@ std::shared_ptr<Node> Quantizer(double scalingFactor, double clipMin, double cli // connect the scaling factor producer std::shared_ptr<Tensor> scalingFactorTensor = std::make_shared<Tensor>(Array1D<double, 1> {scalingFactor}); - std::shared_ptr<Node> scalingFactorProducer = addProducer<1>(mulNode, 1, {1}, "ScalingFactor"); + std::shared_ptr<Node> scalingFactorProducer = addProducer<1>(mulNode, 1, {1}, "ScalingFactor"); scalingFactorProducer->getOperator()->setOutput(0, scalingFactorTensor); - + // create the metaop graph std::shared_ptr<GraphView> graphView = Sequential({mulNode, roundNode, clipNode}); std::shared_ptr<GraphView> connectedGraphView = getConnectedGraphView(mulNode); // XXX why not use the graphView ??? - // return the metaop + // return the metaop std::shared_ptr<Node> metaopNode = MetaOperator("Quantizer", connectedGraphView, {}, name); // XXX alternative prototype - return metaopNode; + return metaopNode; } std::shared_ptr<Node> Scaling(double scalingFactor, const std::string& name) @@ -67,7 +67,7 @@ std::shared_ptr<Node> Scaling(double scalingFactor, const std::string& name) std::shared_ptr<Node> mulNode = Mul((!name.empty()) ? name + "_Scaling" : ""); - std::shared_ptr<Node> scalingFactorProducer = addProducer<1>(mulNode, 1, {1}, "ScalingFactor"); + std::shared_ptr<Node> scalingFactorProducer = addProducer<1>(mulNode, 1, {1}, "ScalingFactor"); scalingFactorProducer->getOperator()->setOutput(0, scalingFactorTensor); std::shared_ptr<GraphView> graphView = Sequential({mulNode}); @@ -96,7 +96,7 @@ void updateScalingFactor(std::shared_ptr<Node> metaOpNode, double scalingFactor) std::shared_ptr<Tensor> scalingFactorTensor = std::make_shared<Tensor>(Array1D<double, 1> {scalingFactor}); std::shared_ptr<MetaOperator_Op> metaOp = std::static_pointer_cast<MetaOperator_Op>(metaOpNode->getOperator()); - + std::shared_ptr<Node> mulNode = getSubNode(metaOp->getMicroGraph(), "Mul"); if (!mulNode) @@ -113,7 +113,7 @@ double getScalingFactor(std::shared_ptr<Node> MetaOpNode) } std::shared_ptr<MetaOperator_Op> metaOp = std::static_pointer_cast<MetaOperator_Op>(MetaOpNode->getOperator()); - + std::shared_ptr<Node> mulNode = getSubNode(metaOp->getMicroGraph(), "Mul"); if (!mulNode) { @@ -123,8 +123,8 @@ double getScalingFactor(std::shared_ptr<Node> MetaOpNode) auto scalingFactorTensor = std::static_pointer_cast<OperatorTensor>(mulNode->getOperator())->getInput(1); std::shared_ptr<Tensor> fallback; - const Tensor& localTensor = scalingFactorTensor->refCastFrom(fallback, DataType::Float64, "cpu"); - + const Tensor& localTensor = scalingFactorTensor->refCastFrom(fallback, DataType::Float64, "cpu"); + return localTensor.get<double>(0); } diff --git a/src/operator/FixedQ.cpp b/src/operator/FixedQ.cpp index 8791740..9828ce9 100644 --- a/src/operator/FixedQ.cpp +++ b/src/operator/FixedQ.cpp @@ -20,6 +20,17 @@ const std::string Aidge::FixedQ_Op::Type = "FixedQ"; +Aidge::FixedQ_Op::FixedQ_Op(const Aidge::FixedQ_Op& op) + : OperatorTensor(op), + mAttributes(op.mAttributes) +{ + if (op.mImpl){ + SET_IMPL_MACRO(FixedQ_Op, *this, op.backend()); + }else{ + mImpl = nullptr; + } +} + std::set<std::string> Aidge::FixedQ_Op::getAvailableBackends() const { return Registrar<FixedQ_Op>::getKeys(); } @@ -28,3 +39,12 @@ void Aidge::FixedQ_Op::setBackend(const std::string& name, DeviceIdx_t device) { SET_IMPL_MACRO(FixedQ_Op, *this, name); mOutputs[0]->setBackend(name, device); } + +//////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr<Aidge::Node> Aidge::FixedQ(std::size_t nbBits, + float span, + bool isOutputUnsigned, + const std::string& name) { + return std::make_shared<Node>(std::make_shared<FixedQ_Op>(nbBits, span, isOutputUnsigned), name); +} \ No newline at end of file diff --git a/src/operator/SAT/DoReFa.cpp b/src/operator/SAT/DoReFa.cpp index b6124ba..426e330 100644 --- a/src/operator/SAT/DoReFa.cpp +++ b/src/operator/SAT/DoReFa.cpp @@ -17,13 +17,38 @@ #include "aidge/data/Tensor.hpp" #include "aidge/utils/Types.h" -const std::string Aidge::DoReFa_Op::Type = "DoReFa"; +namespace Aidge { -std::set<std::string> Aidge::DoReFa_Op::getAvailableBackends() const { +const std::string DoReFa_Op::Type = "DoReFa"; + +DoReFa_Op::DoReFa_Op(const DoReFa_Op& op) + : OperatorTensor(op), + mAttributes(op.mAttributes) +{ + if (op.mImpl) { + SET_IMPL_MACRO(DoReFa_Op, *this, op.backend()); + } else { + mImpl = nullptr; + } +} + +std::shared_ptr<Operator> DoReFa_Op::clone() const { + return std::make_shared<DoReFa_Op>(*this); +} + +std::set<std::string> DoReFa_Op::getAvailableBackends() const { return Registrar<DoReFa_Op>::getKeys(); } -void Aidge::DoReFa_Op::setBackend(const std::string& name, DeviceIdx_t device) { +void DoReFa_Op::setBackend(const std::string& name, DeviceIdx_t device) { SET_IMPL_MACRO(DoReFa_Op, *this, name); mOutputs[0]->setBackend(name, device); -} \ No newline at end of file +} + +//////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr<Node> DoReFa(size_t range, DoReFaMode mode, const std::string& name) { + return std::make_shared<Node>(std::make_shared<DoReFa_Op>(range, mode), name); +} + +} // namespace Aidge \ No newline at end of file diff --git a/src/operator/SAT/TanhClamp.cpp b/src/operator/SAT/TanhClamp.cpp index 2b8d63d..5f7e441 100644 --- a/src/operator/SAT/TanhClamp.cpp +++ b/src/operator/SAT/TanhClamp.cpp @@ -20,6 +20,20 @@ const std::string Aidge::TanhClamp_Op::Type = "TanhClamp"; +Aidge::TanhClamp_Op::TanhClamp_Op(const Aidge::TanhClamp_Op& op) + : OperatorTensor(op) +{ + if (op.mImpl) { + SET_IMPL_MACRO(TanhClamp_Op, *this, op.backend()); + } else { + mImpl = nullptr; + } +} + +std::shared_ptr<Aidge::Operator> Aidge::TanhClamp_Op::clone() const { + return std::make_shared<TanhClamp_Op>(*this); +} + bool Aidge::TanhClamp_Op::forwardDims(bool /*allowDataDependency*/) { if (inputsAssociated()) { @@ -40,5 +54,11 @@ void Aidge::TanhClamp_Op::setBackend(const std::string& name, DeviceIdx_t device mOutputs[0]->setBackend(name, device); // Scale output is always on CPU for now - mOutputs[1]->setBackend("cpu"); // XXX why ? + mOutputs[1]->setBackend("cpu"); // XXX why ? +} + +//////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr<Aidge::Node> Aidge::TanhClamp(const std::string& name = "") { + return std::make_shared<Node>(std::make_shared<TanhClamp_Op>(), name); } \ No newline at end of file -- GitLab From 8c19ba8037f931efda7ca38b57a5ec1ce15ee322 Mon Sep 17 00:00:00 2001 From: NAUD Maxence <maxence.naud@cea.fr> Date: Wed, 29 Jan 2025 16:14:18 +0000 Subject: [PATCH 2/2] Fix factory declaration in 'TanhClamp.cpp' --- src/operator/SAT/TanhClamp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operator/SAT/TanhClamp.cpp b/src/operator/SAT/TanhClamp.cpp index 5f7e441..a03fc7d 100644 --- a/src/operator/SAT/TanhClamp.cpp +++ b/src/operator/SAT/TanhClamp.cpp @@ -59,6 +59,6 @@ void Aidge::TanhClamp_Op::setBackend(const std::string& name, DeviceIdx_t device //////////////////////////////////////////////////////////////////////////////// -std::shared_ptr<Aidge::Node> Aidge::TanhClamp(const std::string& name = "") { +std::shared_ptr<Aidge::Node> Aidge::TanhClamp(const std::string& name) { return std::make_shared<Node>(std::make_shared<TanhClamp_Op>(), name); } \ No newline at end of file -- GitLab