Imported Upstream version 1.18.0
[platform/core/ml/nnfw.git] / compiler / luci-interpreter / include / luci_interpreter / core / Tensor.h
1 /*
2  * Copyright (c) 2020 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 #ifndef LUCI_INTERPRETER_CORE_TENSOR_H
18 #define LUCI_INTERPRETER_CORE_TENSOR_H
19
20 #include "luci_interpreter/core/DataType.h"
21
22 #include <cassert>
23 #include <cstddef>
24 #include <cstdint>
25 #include <memory>
26 #include <string>
27 #include <vector>
28
29 namespace luci_interpreter
30 {
31
32 class Shape
33 {
34 public:
35   explicit Shape(int rank) : _dims(rank, 0) {}
36
37   Shape(std::initializer_list<int32_t> dims) : _dims(dims.begin(), dims.end()) {}
38
39   int num_dims() const { return _dims.size(); }
40
41   int32_t dim(int i) const
42   {
43     assert(i >= 0 && i < static_cast<int>(_dims.size()));
44     return _dims[i];
45   }
46
47   int32_t &dim(int i)
48   {
49     assert(i >= 0 && i < static_cast<int>(_dims.size()));
50     return _dims[i];
51   }
52
53   int32_t num_elements() const
54   {
55     int32_t result = 1;
56     for (const int32_t dim : _dims)
57     {
58       result *= dim;
59     }
60     return result;
61   }
62
63   bool operator==(const Shape &other) const { return _dims == other._dims; }
64
65   bool operator!=(const Shape &other) const { return !operator==(other); }
66
67 private:
68   std::vector<int32_t> _dims;
69 };
70
71 // Tensor affine quantization parameters.
72 //
73 // The relationship between real and quantized values:
74 //   real_value = (quantized_value - zero_point) * scale
75 //
76 // In per-tensor case, 'scale' and 'zero_point' are one element each.
77 // In per-channel case, 'scale' and 'zero_point' are N elements each, where N is the size
78 // of the quantized dimension.
79 //
80 // Note that due to historical and performance reasons, per-tensor quantization uses unsigned
81 // integer types, while per-channel uses signed types assuming 'zero_point' == 0.
82 struct AffineQuantization
83 {
84   std::vector<float> scale;
85   std::vector<int32_t> zero_point;
86   int32_t quantized_dimension;
87 };
88
89 class Tensor
90 {
91 public:
92   Tensor(DataType element_type, Shape shape, AffineQuantization quantization, std::string name);
93
94   DataType element_type() const { return _element_type; }
95
96   const Shape &shape() const { return _shape; }
97
98   float scale() const
99   {
100     assert(_quantization.scale.size() == 1);
101     return _quantization.scale[0];
102   }
103
104   int32_t zero_point() const
105   {
106     assert(_quantization.zero_point.size() == 1);
107     return _quantization.zero_point[0];
108   }
109
110   const std::vector<float> &scales() const { return _quantization.scale; }
111
112   const std::vector<int32_t> &zero_points() const { return _quantization.zero_point; }
113
114   int32_t quantized_dimension() const { return _quantization.quantized_dimension; }
115
116   template <typename T> const T *data() const
117   {
118     static_assert(std::is_same<uint8_t, char>::value or
119                   std::is_same<uint8_t, unsigned char>::value);
120     return reinterpret_cast<const T *>(_data);
121   }
122
123   template <typename T> T *data()
124   {
125     static_assert(std::is_same<uint8_t, char>::value or
126                   std::is_same<uint8_t, unsigned char>::value);
127     return reinterpret_cast<T *>(_data);
128   }
129
130   const std::string &name() const { return _name; }
131
132   void readData(void *data_ptr, size_t data_size) const;
133
134   void writeData(const void *data_ptr, size_t data_size);
135
136   void resize(const Shape &new_shape);
137
138   void set_data_buffer(uint8_t *buffer)
139   {
140     if (buffer == nullptr)
141     {
142       _data_allocated = false;
143     }
144     else
145     {
146       _data_allocated = true;
147     }
148     _data = buffer;
149   }
150
151   bool is_observable() const { return _is_observable; }
152
153   void set_observable(bool value) { _is_observable = value; }
154
155   bool is_allocatable() const { return _is_allocatable; }
156
157   void set_allocatable(bool value) { _is_allocatable = value; }
158
159   bool is_data_allocated() const { return _data_allocated; }
160
161   int32_t get_offset() const { return _offset; }
162
163   void set_offset(int32_t offset) { _offset = offset; }
164
165 private:
166   DataType _element_type;
167   Shape _shape;
168   AffineQuantization _quantization;
169   uint8_t *_data;
170   std::string _name;
171   bool _data_allocated;
172   // Write of tensor is reported to registered Observers only if this tensor is observable
173   // This is needed for tensors used in kernel implementation, but not present in original model.
174   bool _is_observable = true;
175   // Memory manager is called for tensor only if it is "allocatable".
176   // Kernel configuration could disable allocation of some tensors if they are not needed for
177   // particular operation.
178   bool _is_allocatable = true;
179   // Used by static memory manager.
180   // Stores the offset from the beginning of the allocated memory buffer.
181   int32_t _offset = -1;
182 };
183
184 } // namespace luci_interpreter
185
186 #endif // LUCI_INTERPRETER_CORE_TENSOR_H