// // calibration.hpp // MNN // // Created by MNN on 2019/04/23. // Copyright © 2018, Alibaba Group Holding Limited // #ifndef CALIBRATION_HPP #define CALIBRATION_HPP #include #include #include #include "TensorStatistic.hpp" #include "core/TensorUtils.hpp" #include #include "MNN_generated.h" #include "Helper.hpp" #include "logkit.h" // Calibration find the optimal threshold according to KL-divergence // process: the below process is applied on the whole Conv|DepthwiseConv layers // 1. run the model on the batch samples, update the max(abs(feature_maps)) when the op is Convolution|Depthwise // 2. cut the max(abs(feature_maps)) into 2048 slices // 3. run the model on the batch samples again, update the distribution of feature maps every Conv|DepthwiseConv layer // 4. apply Calibration on every distribution to get the optimal thereshold // 5. compute the (input_scale * weight_scale) / output_scale, update the scale of symmetricQuan in Convolution Paramter struct WeakPtrCompare { template bool operator()(const std::weak_ptr& a, const std::weak_ptr& b) const { // owner_before 比较的是底层控制块的地址,提供了一个稳定的排序依据 return a.owner_before(b); } }; class Calibration { public: Calibration(MNN::NetT* model, const uint8_t* modelBuffer, const int bufferSize, const std::string& configPath, std::string originalModelFile, std::string dstModelFile); void runQuantizeModel(); void dumpTensorScales(const std::string& modelFile); void ComputeUnaryBuffer(MNN::NetT* net); bool valid() const { return mValid; } private: Calibration(); MNN::NetT* _originalModel; std::shared_ptr _process; std::map> _tensorDescribes; bool mValid = true; const int _binNums = 2048; int _calibrationFileNum = 0; int _width = 1; int _height = 1; int _channels; int _batch = 32; bool _batchSetByUser = false; int _quant_bits = 8; bool _winogradOpt = false; Helper::PreprocessConfig _preprocessConfig; Helper::InputType _inputType; std::string _calibrationFilePath; std::string _originalModelFile; std::string _destModelFile; MNN::CV::ImageProcess::Config _imageProcessConfig; std::vector _calibrationFiles; std::vector mCalibrationDatasetDir; std::vector mInputNames; std::vector mOutputNames; std::map mInputInfo; std::map> mInputShape; std::vector mInputs; std::shared_ptr mBackend; // Tensor and Info std::map, std::shared_ptr, WeakPtrCompare> _featureInfo; std::map, std::shared_ptr, WeakPtrCompare> _featureInfoOrigin; std::map, const MNN::Tensor*>> _tensorMap; // The scale results std::map, std::pair, WeakPtrCompare> _scales; // {opName, {outputDes, inputDes}} std::map, std::vector>>> _rasterTensors; std::map, std::vector>>> _poolTensors; // keep mnn forward information std::vector mInputTensors; std::vector _inputTensorDims; std::shared_ptr _module; std::shared_ptr _moduleOrigin; std::string _featureQuantizeMethod = "KL"; std::string _weightQuantizeMethod = "MAX_ABS"; float _featureClampValue = 127.0f; float _weightClampValue = 127.0f; std::vector _skip_quant_ops; bool _debug = false; std::vector _getInputShape(std::string filename); void _resizeIfNeeded(std::string filename, bool force = false); void _initMNNSession(const uint8_t* modelBuffer, const int bufferSize); // compute min/max value for every Tensor void _computeFeatureMapsRange(); void _collectFeatureMapsDistribution(); void _computeFeatureScaleKL(); void _computeFeatureScaleADMM(); void _quantizeModelEMA(); void _computeFeatureScaleMoving(); void _fake_quant_weights(); void _computeQuantError(); void _insertScale(); }; int quant_main(int argc, const char* argv[]); #endif // CALIBRATION_HPP