| #pragma once |
| |
| #include "caffe2/core/observer.h" |
| #include "caffe2/core/operator.h" |
| #include "caffe2/quantization/server/dnnlowp.h" |
| #include "caffe2/quantization/server/dynamic_histogram.h" |
| |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| namespace caffe2 { |
| |
| class OutputMinMaxObserver final : public ObserverBase<OperatorBase> { |
| public: |
| explicit OutputMinMaxObserver(OperatorBase* op); |
| ~OutputMinMaxObserver(); |
| |
| struct TensorInfo { |
| explicit TensorInfo(const std::string& name) |
| : min(std::numeric_limits<float>::max()), |
| max(std::numeric_limits<float>::lowest()), |
| total_min(std::numeric_limits<float>::max()), |
| total_max(std::numeric_limits<float>::lowest()), |
| name(name) {} |
| |
| void Update(float cur_min, float cur_max) { |
| min = std::min(min, cur_min); |
| max = std::max(max, cur_max); |
| total_min = std::min(total_min, cur_min); |
| total_max = std::max(total_max, cur_max); |
| } |
| |
| float min, max; |
| float total_min, total_max; |
| std::string name; |
| }; |
| |
| struct OperatorInfo { |
| std::vector<TensorInfo> tensor_infos; |
| std::string type; |
| }; |
| |
| // OutputMinMaxObserver is assumed to be used together with |
| // OutputMinMaxNetObserver and the information shared via shared_ptr to be |
| // prepared for the case when OutputMinMaxObserver is destroyed before |
| // OutputMinMaxNetObserver |
| std::shared_ptr<OperatorInfo> GetInfo() { |
| return info_; |
| } |
| |
| private: |
| void Stop() override; |
| |
| std::shared_ptr<OperatorInfo> info_; |
| bool warning_printed_ = false; |
| }; // class OutputMinMaxObserver |
| |
| class OutputMinMaxNetObserver final : public NetObserver { |
| public: |
| /// @params dump_freq Print out only once in destructor if -1. |
| // Otherwise, print out every dum_freq invocations |
| explicit OutputMinMaxNetObserver( |
| NetBase* subject, |
| const std::string& out_file_name, |
| int dump_freq = -1, |
| string delimiter = " "); |
| ~OutputMinMaxNetObserver(); |
| |
| private: |
| void Stop() override; |
| void DumpAndReset_( |
| const std::string& out_file_name, |
| bool print_total_min_max = false); |
| |
| int dump_freq_, cnt_; |
| const std::string out_file_name_; |
| std::string delimiter_; |
| std::vector<std::shared_ptr<OutputMinMaxObserver::OperatorInfo>> |
| min_max_infos_; |
| }; |
| |
| /** |
| * Given min/max, collect histogram |
| */ |
| class HistogramObserver final : public ObserverBase<OperatorBase> { |
| public: |
| struct Info { |
| std::vector<dnnlowp::DynamicHistogram> histograms; |
| std::vector<dnnlowp::DynamicHistogram> total_histograms; |
| OutputMinMaxObserver::OperatorInfo min_max_info; |
| }; |
| |
| explicit HistogramObserver(OperatorBase* op, std::shared_ptr<Info> info); |
| |
| private: |
| void Stop() override; |
| |
| std::shared_ptr<Info> info_; |
| bool warning_printed_ = false; |
| }; // class HistogramObserver |
| |
| /** |
| * Given min/max, collect histogram of the max value of each column of tensor |
| */ |
| class OutputColumnMaxHistogramObserver final |
| : public ObserverBase<OperatorBase> { |
| public: |
| explicit OutputColumnMaxHistogramObserver( |
| OperatorBase* op, |
| const std::string& col_max_blob_name, |
| int nbins, |
| std::shared_ptr<HistogramObserver::Info> info); |
| |
| private: |
| void Stop() override; |
| |
| std::string col_max_blob_name_; |
| int nbins_; |
| std::shared_ptr<HistogramObserver::Info> info_; |
| bool warning_printed_ = false; |
| int col_max_blob_idx_ = -1; |
| int num_columns_ = -1; |
| }; // class OutputColumnMaxHistogramObserver |
| |
| class HistogramNetObserver final : public NetObserver { |
| public: |
| /** |
| * @params mul_nets true if we expect multiple nets with the same name so |
| * we include extra information in the file name to |
| * distinghuish them |
| * @params dump_freq if not -1 we dump histogram every dump_freq invocation |
| * of the net |
| */ |
| explicit HistogramNetObserver( |
| NetBase* subject, |
| const std::string& out_file_name, |
| int nbins, |
| int dump_freq = -1, |
| bool mul_nets = false, |
| string op_filter = "", |
| string delimiter = " "); |
| ~HistogramNetObserver(); |
| void DumpHistogramFile() { |
| DumpAndReset_(out_file_name_, false); |
| } |
| |
| private: |
| void Stop() override; |
| void DumpAndReset_( |
| const std::string& out_file_name, |
| bool print_total_min_max = false); |
| |
| int dump_freq_, cnt_; |
| |
| /** If multiple nets exist and are attached with the observers, the histogram |
| * files for the nets will be appended with netbase addresses. |
| */ |
| bool mul_nets_; |
| string net_name_; |
| string op_filter_; |
| string delimiter_; |
| const std::string out_file_name_; |
| std::vector<std::shared_ptr<HistogramObserver::Info>> hist_infos_; |
| }; |
| |
| class OutputColumnMaxHistogramNetObserver final : public NetObserver { |
| public: |
| explicit OutputColumnMaxHistogramNetObserver( |
| NetBase* subject, |
| const std::string& out_file_name, |
| const std::vector<std::string>& observe_column_max_for_blobs, |
| int nbins, |
| int dump_freq = -1, |
| bool mul_nets = false, |
| string delimiter = " "); |
| ~OutputColumnMaxHistogramNetObserver(); |
| void DumpOutputColumnMaxHistogramFile() { |
| DumpAndReset_(out_file_name_, false); |
| } |
| |
| private: |
| void Stop() override; |
| void DumpAndReset_( |
| const std::string& out_file_name, |
| bool print_total_min_max = false); |
| int dump_freq_, cnt_; |
| bool mul_nets_; |
| const std::string out_file_name_; |
| std::string delimiter_; |
| std::unordered_set<std::string> col_max_blob_names_; |
| |
| // {op_idx: {output_index: col_hists}} |
| std::unordered_map< |
| int, |
| std::unordered_map<int, std::shared_ptr<HistogramObserver::Info>>> |
| hist_infos_; |
| }; |
| |
| /** |
| * Set quantization parameters of operators based on min/max |
| * collected from OutputMinMaxObserver |
| */ |
| class RegisterQuantizationParamsNetObserver final : public NetObserver { |
| public: |
| explicit RegisterQuantizationParamsNetObserver( |
| NetBase* subject, |
| const std::string& min_max_file_name, |
| bool is_weight = false, |
| const std::string& qparams_output_file_name = ""); |
| }; |
| |
| /** |
| * Set quantization parameters of operators based on min/max |
| * collected from OutputMinMaxObserver |
| */ |
| class RegisterQuantizationParamsWithHistogramNetObserver final |
| : public NetObserver { |
| public: |
| explicit RegisterQuantizationParamsWithHistogramNetObserver( |
| NetBase* subject, |
| const std::string& histogram_file_name, |
| bool is_weight = false, |
| const std::string& qparams_output_file_name = ""); |
| }; |
| |
| #ifdef _MSC_VER |
| struct tm* localtime_r(time_t* _clock, struct tm* _result) { |
| struct tm* candidate_result = localtime(_clock); |
| if (candidate_result) { |
| *(_result) = *candidate_result; |
| } |
| return candidate_result; |
| } |
| #endif |
| |
| } // namespace caffe2 |