2 * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "MinMaxRecorder.h"
19 #include "backend/ITensor.h"
29 MinMaxRecorder::MinMaxRecorder(const std::string &minmax_filepath, const ir::Graph &graph,
30 const backend::BackendContexts &backend_contexts)
31 : _graph{graph}, _backend_contexts{backend_contexts}, _h5dumper(minmax_filepath)
35 void MinMaxRecorder::handleJobEnd(IExecutor *, ir::SubgraphIndex subg_idx,
36 ir::OperationIndex op_idx, const backend::Backend *backend)
38 const auto &tensor_reg = _backend_contexts.at(backend)->tensor_registry;
39 const auto &op = _graph.operations().at(op_idx);
40 const auto &outputs = op.getOutputs();
41 // TODO: Support multiple output
42 if (outputs.size() != 1)
43 throw std::runtime_error("Only 1 output operator is supported for recording minmax.");
45 auto tensor = tensor_reg->getITensor(outputs.at(0));
47 // Logic copied from MinMaxObserver.cpp.
50 if (tensor->is_constant())
53 if (tensor->data_type() != ir::DataType::FLOAT32)
58 // Operators with multiple outputs
60 case ir::OpCode::Split:
61 case ir::OpCode::SplitV:
62 case ir::OpCode::TopKV2:
63 case ir::OpCode::Unpack:
64 case ir::OpCode::While:
66 // NOTE: Sin, Cos, Tanh's output is in [-1, 1]
67 // We may not need to dump those operators.
68 default:; // Do Nothing
72 assert(tensor->data_type() == ir::DataType::FLOAT32);
73 const auto data = reinterpret_cast<float *>(tensor->buffer());
74 const auto num_elements = tensor->total_size() / sizeof(float);
76 float max = std::numeric_limits<float>::lowest();
77 float min = std::numeric_limits<float>::max();
80 for (size_t i = 0; i < num_elements; ++i)
82 const float number = data[i];
83 if (std::isnan(number))
86 if (number == std::numeric_limits<float>::lowest())
99 throw std::runtime_error("All values are NaN(Not a Number)");
101 _minmax_map.append({subg_idx, op_idx}, min, max);
104 void MinMaxRecorder::handleSubgraphEnd(ir::SubgraphIndex)
106 // It would be better to dump at the end of model execution, not subgraph
107 // But it requires more changes than subgraph.
108 _h5dumper.dump(_minmax_map);