Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / exec / MinMaxRecorder.cc
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "MinMaxRecorder.h"
18
19 #include "backend/ITensor.h"
20
21 #include <cassert>
22 #include <cmath>
23
24 namespace onert
25 {
26 namespace exec
27 {
28
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)
32 {
33 }
34
35 void MinMaxRecorder::handleJobEnd(IExecutor *, ir::SubgraphIndex subg_idx,
36                                   ir::OperationIndex op_idx, const backend::Backend *backend)
37 {
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.");
44
45   auto tensor = tensor_reg->getITensor(outputs.at(0));
46
47   // Logic copied from MinMaxObserver.cpp.
48
49   // Filter Ops
50   if (tensor->is_constant())
51     return;
52
53   if (tensor->data_type() != ir::DataType::FLOAT32)
54     return;
55
56   switch (op.opcode())
57   {
58     // Operators with multiple outputs
59     case ir::OpCode::If:
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:
65       return;
66     // NOTE: Sin, Cos, Tanh's output is in [-1, 1]
67     // We may not need to dump those operators.
68     default:; // Do Nothing
69   }
70
71   // Otherwise, dump!
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);
75
76   float max = std::numeric_limits<float>::lowest();
77   float min = std::numeric_limits<float>::max();
78
79   bool all_nan = true;
80   for (size_t i = 0; i < num_elements; ++i)
81   {
82     const float number = data[i];
83     if (std::isnan(number))
84       continue;
85
86     if (number == std::numeric_limits<float>::lowest())
87       continue;
88
89     all_nan = false;
90
91     if (number > max)
92       max = number;
93
94     if (number < min)
95       min = number;
96   }
97
98   if (all_nan)
99     throw std::runtime_error("All values are NaN(Not a Number)");
100
101   _minmax_map.append({subg_idx, op_idx}, min, max);
102 }
103
104 void MinMaxRecorder::handleSubgraphEnd(ir::SubgraphIndex)
105 {
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);
109 }
110
111 } // namespace exec
112 } // namespace onert